rails-dbd-mysql 0.1.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.
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ (C) 2008 Erik Hollensbe <erik@hollensbe.org>. All rights reserved.
2
+
3
+ Please see "README" for earlier copyrights.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions
7
+ are met:
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+ 3. The name of the author may not be used to endorse or promote products
14
+ derived from this software without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19
+ THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22
+ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README ADDED
@@ -0,0 +1,271 @@
1
+ = Description
2
+ The DBI package is a vendor independent interface for accessing databases.
3
+ It is similar, but not identical to, Perl's DBI module.
4
+
5
+ = Synopsis
6
+
7
+ require 'dbi'
8
+
9
+ # Connect to a database, old style
10
+ dbh = DBI.connect('DBI:Mysql:test', 'testuser', 'testpwd')
11
+
12
+ # Insert some rows, use placeholders
13
+ 1.upto(13) do |i|
14
+ sql = "insert into simple01 (SongName, SongLength_s) VALUES (?, ?)"
15
+ dbh.do(sql, "Song #{i}", "#{i*10}")
16
+ end
17
+
18
+ # Select all rows from simple01
19
+ sth = dbh.prepare('select * from simple01')
20
+ sth.execute
21
+
22
+ # Print out each row
23
+ while row=sth.fetch do
24
+ p row
25
+ end
26
+
27
+ # Close the statement handle when done
28
+ sth.finish
29
+
30
+ # Don't prepare, just do it!
31
+ dbh.do('delete from simple01 where internal_id > 10')
32
+
33
+ # And finally, disconnect
34
+ dbh.disconnect
35
+
36
+ # Same example, but a little more Ruby-ish
37
+ DBI.connect('DBI:Mysql:test', 'testuser', 'testpwd') do | dbh |
38
+
39
+ sql = "insert into simple01 (SongName, SongLength_s) VALUES (?, ?)"
40
+
41
+ dbh.prepare(sql) do | sth |
42
+ 1.upto(13) { |i| sth.execute("Song #{i}", "#{i*10}") }
43
+ end
44
+
45
+ dbh.select_all('select * from simple01') do | row |
46
+ p row
47
+ end
48
+
49
+ dbh.do('delete from simple01 where internal_id > 10')
50
+
51
+ end
52
+
53
+ = Prerequisites
54
+ Ruby 1.8.6 or later is the test target, however you may have success with
55
+ earlier 1.8.x versions of Ruby.
56
+
57
+ = RubyForge Project
58
+ General information: http://ruby-dbi.rubyforge.org
59
+ Project information: http://rubyforge.org/projects/ruby-dbi/
60
+ Downloads: http://rubyforge.org/frs/?group_id=234
61
+
62
+ = Installation
63
+ There are many database drivers (DBDs) available. You only need to install
64
+ the DBDs for the database software that you will be using.
65
+
66
+ == Gem setup:
67
+
68
+ gem install dbi
69
+ # One or more of:
70
+ gem install dbd-mysql
71
+ gem install dbd-pg
72
+ gem install dbd-sqlite3
73
+ gem install dbd-sqlite
74
+
75
+ == Without rubygems:
76
+
77
+ ruby setup.rb config
78
+ ruby setup.rb setup
79
+ ruby setup.rb install
80
+
81
+ == The bleeding edge:
82
+
83
+ git clone git://hollensbe.org/git/ruby-dbi.git
84
+ git checkout -b development origin/development
85
+
86
+ Also available at
87
+
88
+ git clone git://github.com/erikh/ruby-dbi.git
89
+
90
+ = Available Database Drivers (DBDs)
91
+
92
+ == DBD::MySQL
93
+ MySQL
94
+ Depends on the mysql-ruby package from http://www.tmtm.org/mysql or
95
+ available from the RAA.
96
+
97
+ == DBD::ODBC
98
+ ODBC
99
+ Depends on the ruby-odbc package (0.5 or later, 0.9.3 or later recommended) at
100
+ http://www.ch-werner.de/rubyodbc or available from the RAA. Works together
101
+ with unix-odbc.
102
+
103
+ == DBD::OCI8
104
+ OCI8 (Oracle)
105
+ Depends on the the ruby-oci8 package, available on the RAA and RubyForge.
106
+
107
+ == DBD::Pg
108
+ PostgreSQL
109
+ Depends on the pg package, available on RubyForge.
110
+
111
+ == DBD::SQLite
112
+ SQLite (versions 2.x and earlier)
113
+ Depends on the sqlite-ruby package, available on rubyforge.
114
+
115
+ == DBD::SQLite3
116
+ SQLite 3.x
117
+ Depends on the sqlite3-ruby package, available on rubyforge.
118
+
119
+ = Additional Documentation
120
+ See the directories doc/* for DBI and DBD specific information.
121
+ The DBI specification is at doc/DBI_SPEC.rdoc.
122
+ The DBD specification is at doc/DBD_SPEC.rdoc.
123
+
124
+ = Articles
125
+ == Tutorial: Using the Ruby DBI Module
126
+ http://www.kitebird.com/articles/ruby-dbi.html
127
+
128
+ = Applications
129
+ == dbi
130
+ The SQL command line interpreter dbi is available in directory
131
+ bin/. It gets installed by default.
132
+
133
+ = License
134
+
135
+ Copyright (c) 2008 Erik Hollensbe
136
+
137
+ Copyright (c) 2005-2006 Kirk Haines, Francis Hwang, Patrick May and Daniel
138
+ Berger.
139
+
140
+ Copyright (c) 2001, 2002, 2003, 2004 Michael Neumann <mneumann@ntecs.de>
141
+ and others (see the beginning of each file for copyright holder information).
142
+
143
+ All rights reserved.
144
+
145
+ Redistribution and use in source and binary forms, with or without
146
+ modification, are permitted provided that the following conditions are met:
147
+
148
+ 1. Redistributions of source code must retain the above copyright notice,
149
+ this list of conditions and the following disclaimer.
150
+ 2. Redistributions in binary form must reproduce the above copyright notice,
151
+ this list of conditions and the following disclaimer in the documentation
152
+ and/or other materials provided with the distribution.
153
+ 3. The name of the author may not be used to endorse or promote products
154
+ derived from this software without specific prior written permission.
155
+
156
+ THIS SOFTWARE IS PROVIDED 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES,
157
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
158
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
159
+ THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
160
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
161
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
162
+ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
163
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
164
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
165
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
166
+
167
+ This is the BSD license which is less restrictive than GNU's GPL
168
+ (General Public License).
169
+
170
+ = Contributors
171
+
172
+ Pistos
173
+ Too much to specify. Infinite patience and help.
174
+
175
+ Christopher Maujean
176
+ Lots of initial help when reviving the project.
177
+
178
+ Jun Mukai <mukai@jmuk.org>
179
+ Contributed initial SQLite3 DBD.
180
+
181
+ John J. Fox IV
182
+ Lots of help testing on multiple platforms.
183
+
184
+ Kirk Haines
185
+ One of the authors of the rewrite effort (January 2006).
186
+
187
+ Francis Hwang
188
+ One of the authors of the rewrite effort (January 2006).
189
+
190
+ Patrick May
191
+ One of the authors of the rewrite effort (January 2006).
192
+
193
+ Daniel Berger
194
+ One of the authors of the rewrite effort (January 2006).
195
+
196
+ Michael Neumann
197
+ Original author of Ruby/DBI; wrote the DBI and most of the DBDs.
198
+
199
+ Rainer Perl
200
+ Author of Ruby/DBI 0.0.4 from which many good ideas were taken.
201
+
202
+ Jim Weirich
203
+ Original author of DBD::Pg. Wrote additional code (e.g. sql.rb,
204
+ testcases). Gave many helpful hints and comments.
205
+
206
+ Eli Green
207
+ Implemented DatabaseHandle#columns for Mysql and Pg.
208
+
209
+ Masatoshi SEKI
210
+ For his version of module BasicQuote in sql.rb.
211
+
212
+ John Gorman
213
+ For his case insensitive load_driver patch and parameter parser.
214
+
215
+ David Muse
216
+ For testing the DBD::SQLRelay and for his initial DBD.
217
+
218
+ Jim Menard
219
+ Extended DBD::Oracle for method columns.
220
+
221
+ Joseph McDonald
222
+ Fixed bug in DBD::Pg (default values in method columns).
223
+
224
+ Norbert Gawor
225
+ Fixed bug in DBD::ODBC (method columns) and proxyserver.
226
+
227
+ James F. Hranicky
228
+ Patch for DBD::Pg (cache PGResult#result in Tuples) which increased
229
+ performance by a factor around 100.
230
+
231
+ Stephen Davies
232
+ Added method Statement#fetch_scroll for DBD::Pg.
233
+
234
+ Dave Thomas
235
+ Several enhancements.
236
+
237
+ Brad Hilton
238
+ Column coercing patch for DBD::Mysql.
239
+
240
+ Sean Chittenden
241
+ Originally a co-owner of the project. Submitted several patches
242
+ and helped with lots of comments.
243
+
244
+ MoonWolf
245
+ Provided the quote/escape_byte patch for DBD::Pg, DBD::SQLite patch and
246
+ Database#columns implementation. Further patches.
247
+
248
+ Paul DuBois
249
+ Fixed typos and formatting. Maintains DBD::Mysql.
250
+
251
+ Tim Bates
252
+ Bug fixes for Mysql and DBI.
253
+
254
+ Brian Candler
255
+ Zero-padding date/time/timestamps fix.
256
+
257
+ Florian G. Pflug
258
+ Discussion and helpful comments/benchmarks about DBD::Pg async_exec vs.
259
+ exec.
260
+
261
+ Oliver M. Bolzer
262
+ Patches to support Postgres arrays for DBD::Pg.
263
+
264
+ Stephen R. Veit
265
+ ruby-db2 and DBD::DB2 enhancements.
266
+
267
+ Dennis Vshivkov
268
+ DBD::Pg patches
269
+
270
+ Cail Borrell from frontbase.com
271
+ For the Frontbase DBD and C interface.
@@ -0,0 +1,137 @@
1
+ #--
2
+ # Copyright (c) 2001, 2002 Michael Neumann <neumann@s-direktnet.de>
3
+ #
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions
8
+ # are met:
9
+ # 1. Redistributions of source code must retain the above copyright
10
+ # notice, this list of conditions and the following disclaimer.
11
+ # 2. Redistributions in binary form must reproduce the above copyright
12
+ # notice, this list of conditions and the following disclaimer in the
13
+ # documentation and/or other materials provided with the distribution.
14
+ # 3. The name of the author may not be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18
+ # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19
+ # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20
+ # THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23
+ # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25
+ # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ #
28
+ # $Id$
29
+ #++
30
+
31
+ begin
32
+ require 'rubygems'
33
+ gem 'mysql'
34
+ gem 'dbi'
35
+ rescue LoadError => e
36
+ end
37
+
38
+ require 'dbi'
39
+ require "mysql"
40
+ require "thread" # for Mutex
41
+
42
+ module DBI
43
+ module DBD
44
+ #
45
+ # DBD::Mysql - Database Driver for the MySQL database system.
46
+ #
47
+ # Requires DBI and the 'mysql' gem or package to work.
48
+ #
49
+ # Only things that extend DBI's results are documented.
50
+ #
51
+ module Mysql
52
+ VERSION = "0.4.4"
53
+ DESCRIPTION = "MySQL DBI DBD, Leverages 'mysql' low-level driver"
54
+
55
+ MyError = ::MysqlError
56
+
57
+ #
58
+ # returns 'Mysql'
59
+ #
60
+ # See DBI::TypeUtil#convert for more information.
61
+ #
62
+ def self.driver_name
63
+ "Mysql"
64
+ end
65
+
66
+ DBI::TypeUtil.register_conversion(driver_name) do |obj|
67
+ newobj = case obj
68
+ when ::DBI::Binary
69
+ obj = obj.to_s.gsub(/\\/) { "\\\\" }
70
+ obj = obj.to_s.gsub(/'/) { "''" }
71
+ "'#{obj}'"
72
+ when ::DateTime
73
+ "'#{obj.strftime("%Y-%m-%d %H:%M:%S")}'"
74
+ when ::Time
75
+ "'#{obj.strftime("%H:%M:%S")}'"
76
+ when ::Date
77
+ "'#{obj.strftime("%Y-%m-%d")}'"
78
+ when ::NilClass
79
+ "NULL"
80
+ else
81
+ obj
82
+ end
83
+
84
+ if newobj.object_id == obj.object_id
85
+ [newobj, true]
86
+ else
87
+ [newobj, false]
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ #
95
+ # Utility Methods for the MySQL DBD.
96
+ #
97
+
98
+ module DBI::DBD::Mysql::Util
99
+ private
100
+
101
+ # Raise exception using information from MysqlError object e.
102
+ # For state value, use SQLSTATE value if mysql-ruby defines
103
+ # sqlstate method, otherwise nil.
104
+ def error(e)
105
+ sqlstate = e.respond_to?("sqlstate") ? e.sqlstate : nil
106
+ raise DBI::DatabaseError.new(e.message, e.errno, sqlstate)
107
+ end
108
+
109
+ end # module Util
110
+
111
+ module DBI::DBD::Mysql::Type
112
+ #
113
+ # Custom handling for DATE types in MySQL. See DBI::Type for more
114
+ # information.
115
+ #
116
+ class Date < DBI::Type::Null
117
+ def self.parse(obj)
118
+ obj = super
119
+ return obj unless obj
120
+
121
+ case obj.class
122
+ when ::Date
123
+ return obj
124
+ when ::String
125
+ return ::Date.strptime(obj, "%Y-%m-%d")
126
+ else
127
+ return ::Date.parse(obj.to_s) if obj.respond_to? :to_s
128
+ return ::Date.parse(obj.to_str) if obj.respond_to? :to_str
129
+ return obj
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ require 'dbd/mysql/driver'
136
+ require 'dbd/mysql/database'
137
+ require 'dbd/mysql/statement'
@@ -0,0 +1,405 @@
1
+ module DBI::DBD::Mysql
2
+ #
3
+ # Models the DBI::BaseDatabase API to create DBI::DatabaseHandle objects.
4
+ #
5
+ class Database < DBI::BaseDatabase
6
+ include Util
7
+
8
+ #
9
+ # Hash to translate MySQL type names to DBI SQL type constants
10
+ #
11
+ # Only used in #mysql_type_info.
12
+ #
13
+ #--
14
+ # Eli Green:
15
+ # The hope is that we don't ever need to just assume the default values.
16
+ # However, in some cases (notably floats and doubles), I have seen
17
+ # "show fields from table" return absolutely zero information about size
18
+ # and precision. Sigh. I probably should have made a struct to store
19
+ # this info in ... but I didn't.
20
+ #++
21
+ MYSQL_to_XOPEN = {
22
+ "TINYINT" => [DBI::SQL_TINYINT, 1, nil],
23
+ "SMALLINT" => [DBI::SQL_SMALLINT, 6, nil],
24
+ "MEDIUMINT" => [DBI::SQL_SMALLINT, 6, nil],
25
+ "INT" => [DBI::SQL_INTEGER, 11, nil],
26
+ "INTEGER" => [DBI::SQL_INTEGER, 11, nil],
27
+ "BIGINT" => [DBI::SQL_BIGINT, 25, nil],
28
+ "INT24" => [DBI::SQL_BIGINT, 25, nil],
29
+ "REAL" => [DBI::SQL_REAL, 12, nil],
30
+ "FLOAT" => [DBI::SQL_FLOAT, 12, nil],
31
+ "DECIMAL" => [DBI::SQL_DECIMAL, 12, nil],
32
+ "NUMERIC" => [DBI::SQL_NUMERIC, 12, nil],
33
+ "DOUBLE" => [DBI::SQL_DOUBLE, 22, nil],
34
+ "CHAR" => [DBI::SQL_CHAR, 1, nil],
35
+ "VARCHAR" => [DBI::SQL_VARCHAR, 255, nil],
36
+ "DATE" => [DBI::SQL_DATE, 10, nil],
37
+ "TIME" => [DBI::SQL_TIME, 8, nil],
38
+ "TIMESTAMP" => [DBI::SQL_TIMESTAMP, 19, nil],
39
+ "DATETIME" => [DBI::SQL_TIMESTAMP, 19, nil],
40
+ "TINYBLOB" => [DBI::SQL_BINARY, 255, nil],
41
+ "BLOB" => [DBI::SQL_VARBINARY, 65535, nil],
42
+ "MEDIUMBLOB" => [DBI::SQL_VARBINARY, 16277215, nil],
43
+ "LONGBLOB" => [DBI::SQL_LONGVARBINARY, 2147483657, nil],
44
+ "TINYTEXT" => [DBI::SQL_VARCHAR, 255, nil],
45
+ "TEXT" => [DBI::SQL_LONGVARCHAR, 65535, nil],
46
+ "MEDIUMTEXT" => [DBI::SQL_LONGVARCHAR, 16277215, nil],
47
+ "LONGTEXT" => [DBI::SQL_LONGVARCHAR, 2147483657, nil],
48
+ "ENUM" => [DBI::SQL_CHAR, 255, nil],
49
+ "SET" => [DBI::SQL_CHAR, 255, nil],
50
+ "BIT" => [DBI::SQL_BIT, 8, nil],
51
+ nil => [DBI::SQL_OTHER, nil, nil]
52
+ }
53
+
54
+
55
+ #
56
+ # This maps type names to DBI Types.
57
+ #
58
+ TYPE_MAP = {}
59
+
60
+ ::Mysql::Field.constants.grep(/^TYPE_/).each do |const|
61
+ mysql_type = MysqlField.const_get(const) # numeric type code
62
+ coercion_method = DBI::Type::Varchar # default coercion method
63
+ case const.to_s
64
+ when 'TYPE_TINY'
65
+ mysql_type_name = 'TINYINT'
66
+ coercion_method = DBI::Type::Integer
67
+ when 'TYPE_SHORT'
68
+ mysql_type_name = 'SMALLINT'
69
+ coercion_method = DBI::Type::Integer
70
+ when 'TYPE_INT24'
71
+ mysql_type_name = 'MEDIUMINT'
72
+ coercion_method = DBI::Type::Integer
73
+ when 'TYPE_LONG'
74
+ mysql_type_name = 'INT'
75
+ coercion_method = DBI::Type::Integer
76
+ when 'TYPE_LONGLONG'
77
+ mysql_type_name = 'BIGINT'
78
+ coercion_method = DBI::Type::Integer
79
+ when 'TYPE_FLOAT'
80
+ mysql_type_name = 'FLOAT'
81
+ coercion_method = DBI::Type::Float
82
+ when 'TYPE_DOUBLE'
83
+ mysql_type_name = 'DOUBLE'
84
+ coercion_method = DBI::Type::Float
85
+ when 'TYPE_VAR_STRING', 'TYPE_STRING'
86
+ mysql_type_name = 'VARCHAR' # questionable?
87
+ coercion_method = DBI::Type::Varchar
88
+ when 'TYPE_DATE'
89
+ mysql_type_name = 'DATE'
90
+ coercion_method = DBI::DBD::Mysql::Type::Date
91
+ when 'TYPE_TIME'
92
+ mysql_type_name = 'TIME'
93
+ coercion_method = DBI::Type::Timestamp
94
+ when 'TYPE_DATETIME', 'TYPE_TIMESTAMP'
95
+ mysql_type_name = 'DATETIME'
96
+ coercion_method = DBI::Type::Timestamp
97
+ when 'TYPE_CHAR'
98
+ mysql_type_name = 'TINYINT' # questionable?
99
+ when 'TYPE_TINY_BLOB'
100
+ mysql_type_name = 'TINYBLOB' # questionable?
101
+ when 'TYPE_MEDIUM_BLOB'
102
+ mysql_type_name = 'MEDIUMBLOB' # questionable?
103
+ when 'TYPE_LONG_BLOB'
104
+ mysql_type_name = 'LONGBLOB' # questionable?
105
+ when 'TYPE_GEOMETRY'
106
+ mysql_type_name = 'BLOB' # questionable?
107
+ when 'TYPE_YEAR',
108
+ 'TYPE_DECIMAL', # questionable?
109
+ 'TYPE_BLOB', # questionable?
110
+ 'TYPE_ENUM',
111
+ 'TYPE_SET',
112
+ 'TYPE_BIT',
113
+ 'TYPE_NULL'
114
+ mysql_type_name = const.to_s.sub(/^TYPE_/, '')
115
+ else
116
+ mysql_type_name = 'UNKNOWN'
117
+ end
118
+ TYPE_MAP[mysql_type] = [mysql_type_name, coercion_method]
119
+ end
120
+ TYPE_MAP[nil] = ['UNKNOWN', DBI::Type::Varchar]
121
+ TYPE_MAP[246] = ['NUMERIC', DBI::Type::Decimal]
122
+
123
+ #
124
+ # Constructor. Attributes supported:
125
+ #
126
+ # * AutoCommit: Commit after each executed statement. This will raise
127
+ # a DBI::NotSupportedError if the backend does not support
128
+ # transactions.
129
+ #
130
+ def initialize(handle, attr)
131
+ super
132
+ # check server version to determine transaction capability
133
+ ver_str = @handle.get_server_info
134
+ major, minor, teeny = ver_str.split(".")
135
+ teeny.sub!(/\D*$/, "") # strip any non-numeric suffix if present
136
+ server_version = major.to_i*10000 + minor.to_i*100 + teeny.to_i
137
+ # It's not until 3.23.17 that SET AUTOCOMMIT,
138
+ # BEGIN, COMMIT, and ROLLBACK all are available
139
+ @have_transactions = (server_version >= 32317)
140
+ # assume that the connection begins in AutoCommit mode
141
+ @attr['AutoCommit'] = true
142
+ @mutex = Mutex.new
143
+ end
144
+
145
+ def disconnect
146
+ self.rollback unless @attr['AutoCommit']
147
+ @handle.close
148
+ rescue MyError => err
149
+ error(err)
150
+ end
151
+
152
+ def database_name
153
+ sth = Statement.new(self, @handle, "select DATABASE()", @mutex)
154
+ sth.execute
155
+ res = sth.fetch
156
+ sth.finish
157
+ return res[0]
158
+ end
159
+
160
+ def ping
161
+ begin
162
+ @handle.ping
163
+ return true
164
+ rescue MyError
165
+ return false
166
+ end
167
+ end
168
+
169
+ def tables
170
+ @handle.list_tables
171
+ rescue MyError => err
172
+ error(err)
173
+ end
174
+
175
+ #
176
+ # See DBI::BaseDatabase#columns.
177
+ #
178
+ # Extra attributes:
179
+ #
180
+ # * sql_type: XOPEN integer constant relating to type.
181
+ # * nullable: true if the column allows NULL as a value.
182
+ # * indexed: true if the column belongs to an index.
183
+ # * primary: true if the column is a part of a primary key.
184
+ # * unique: true if the values in this column are unique.
185
+ # * default: the default value if this column is not explicitly set.
186
+ #
187
+ def columns(table)
188
+ dbh = DBI::DatabaseHandle.new(self)
189
+ uniques = []
190
+ dbh.execute("SHOW INDEX FROM #{table}") do |sth|
191
+ sth.each do |row|
192
+ uniques << row[4] if row[1] == 0
193
+ end
194
+ end
195
+
196
+ ret = nil
197
+ dbh.execute("SHOW FIELDS FROM #{table}") do |sth|
198
+ ret = sth.collect do |row|
199
+ name, type, nullable, key, default, extra = row
200
+ #type = row[1]
201
+ #size = type[type.index('(')+1..type.index(')')-1]
202
+ #size = 0
203
+ #type = type[0..type.index('(')-1]
204
+
205
+ sqltype, type, size, decimal = mysql_type_info(row[1])
206
+ col = Hash.new
207
+ col['name'] = name
208
+ col['sql_type'] = sqltype
209
+ col['type_name'] = type
210
+ col['nullable'] = nullable == "YES"
211
+ col['indexed'] = key != ""
212
+ col['primary'] = key == "PRI"
213
+ col['unique'] = uniques.index(name) != nil
214
+ col['precision'] = size
215
+ col['scale'] = decimal
216
+ col['default'] = row[4]
217
+
218
+ case col['type_name']
219
+ when 'timestamp'
220
+ col['dbi_type'] = DBI::Type::Timestamp
221
+ end
222
+
223
+ col
224
+ end # collect
225
+ end # execute
226
+
227
+ ret
228
+ end
229
+
230
+ def do(stmt, *bindvars)
231
+ st = Statement.new(self, @handle, stmt, @mutex)
232
+ st.bind_params(*bindvars)
233
+ res = st.execute
234
+ st.finish
235
+ return res
236
+ rescue MyError => err
237
+ error(err)
238
+ end
239
+
240
+
241
+ def prepare(statement)
242
+ Statement.new(self, @handle, statement, @mutex)
243
+ end
244
+
245
+ #
246
+ # MySQL has several backends, some of which may not support commits.
247
+ # If the backend this database uses doesn't, calling this method will
248
+ # raise a DBI::NotSupportedError.
249
+ #
250
+ def commit
251
+ if @have_transactions
252
+ self.do("COMMIT")
253
+ else
254
+ raise NotSupportedError
255
+ end
256
+ rescue MyError => err
257
+ error(err)
258
+ end
259
+
260
+ #
261
+ # See #commit for information regarding transactionless database
262
+ # backends.
263
+ #
264
+ def rollback
265
+ if @have_transactions
266
+ self.do("ROLLBACK")
267
+ else
268
+ raise NotSupportedError
269
+ end
270
+ rescue MyError => err
271
+ error(err)
272
+ end
273
+
274
+
275
+ # def quote(value)
276
+ # case value
277
+ # when String
278
+ # "'#{@handle.quote(value)}'"
279
+ # when DBI::Binary
280
+ # "'#{@handle.quote(value.to_s)}'"
281
+ # when TrueClass
282
+ # "'1'"
283
+ # when FalseClass
284
+ # "'0'"
285
+ # else
286
+ # super
287
+ # end
288
+ # end
289
+
290
+ #
291
+ # See DBI::DBD::MySQL::Database.new for supported attributes and usage.
292
+ #
293
+ def []=(attr, value)
294
+ case attr
295
+ when 'AutoCommit'
296
+ if @have_transactions
297
+ self.do("SET AUTOCOMMIT=" + (value ? "1" : "0"))
298
+ else
299
+ raise NotSupportedError
300
+ end
301
+ else
302
+ raise NotSupportedError
303
+ end
304
+
305
+ @attr[attr] = value
306
+ end
307
+
308
+ private # -------------------------------------------------
309
+
310
+ #
311
+ # Given a type name, weans some basic information from that and returns
312
+ # it in a format similar to columns.
313
+ #
314
+ # Return is an array of +sqltype+, +type+, +size+, and +decimal+.
315
+ # +sqltype+ is the XOPEN type, and +type+ is the string with the
316
+ # parameters removed.
317
+ #
318
+ # +size+ and +decimal+ refer to +precision+ and +scale+ in most cases,
319
+ # but not always for all types. Please consult the documentation for
320
+ # your MySQL version.
321
+ #
322
+ #
323
+ def mysql_type_info(typedef)
324
+ sqltype, type, size, decimal = nil, nil, nil, nil
325
+
326
+ pos = typedef.index('(')
327
+ if not pos.nil?
328
+ type = typedef[0..pos-1]
329
+ size = typedef[pos+1..-2]
330
+ pos = size.index(',')
331
+ if not pos.nil?
332
+ size, decimal = size.split(',', 2)
333
+ decimal = decimal.to_i
334
+ end
335
+ size = size.to_i
336
+ else
337
+ type = typedef
338
+ end
339
+
340
+ type_info = MYSQL_to_XOPEN[type.upcase] || MYSQL_to_XOPEN[nil]
341
+ sqltype = type_info[0]
342
+ if size.nil? then size = type_info[1] end
343
+ if decimal.nil? then decimal = type_info[2] end
344
+ return sqltype, type, size, decimal
345
+ end
346
+
347
+ #--
348
+ # Driver-specific functions ------------------------------------------------
349
+ #++
350
+
351
+ public
352
+
353
+ def __createdb(db)
354
+ @handle.create_db(db)
355
+ end
356
+
357
+ def __dropdb(db)
358
+ @handle.drop_db(db)
359
+ end
360
+
361
+ def __shutdown
362
+ @handle.shutdown
363
+ end
364
+
365
+ def __reload
366
+ @handle.reload
367
+ end
368
+
369
+ def __insert_id
370
+ @handle.insert_id
371
+ end
372
+
373
+ def __thread_id
374
+ @handle.thread_id
375
+ end
376
+
377
+ def __info
378
+ @handle.info
379
+ end
380
+
381
+ def __host_info
382
+ @handle.host_info
383
+ end
384
+
385
+ def __proto_info
386
+ @handle.proto_info
387
+ end
388
+
389
+ def __server_info
390
+ @handle.server_info
391
+ end
392
+
393
+ def __client_info
394
+ @handle.client_info
395
+ end
396
+
397
+ def __client_version
398
+ @handle.client_version
399
+ end
400
+
401
+ def __stat
402
+ @handle.stat
403
+ end
404
+ end # class Database
405
+ end