rails-dbd-mysql 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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