sequel 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/CHANGELOG +1551 -4
  2. data/README +306 -19
  3. data/Rakefile +84 -56
  4. data/bin/sequel +106 -0
  5. data/doc/cheat_sheet.rdoc +225 -0
  6. data/doc/dataset_filtering.rdoc +182 -0
  7. data/lib/sequel_core.rb +136 -0
  8. data/lib/sequel_core/adapters/adapter_skeleton.rb +54 -0
  9. data/lib/sequel_core/adapters/ado.rb +80 -0
  10. data/lib/sequel_core/adapters/db2.rb +148 -0
  11. data/lib/sequel_core/adapters/dbi.rb +117 -0
  12. data/lib/sequel_core/adapters/informix.rb +78 -0
  13. data/lib/sequel_core/adapters/jdbc.rb +186 -0
  14. data/lib/sequel_core/adapters/jdbc/mysql.rb +55 -0
  15. data/lib/sequel_core/adapters/jdbc/postgresql.rb +66 -0
  16. data/lib/sequel_core/adapters/jdbc/sqlite.rb +47 -0
  17. data/lib/sequel_core/adapters/mysql.rb +231 -0
  18. data/lib/sequel_core/adapters/odbc.rb +155 -0
  19. data/lib/sequel_core/adapters/odbc_mssql.rb +106 -0
  20. data/lib/sequel_core/adapters/openbase.rb +64 -0
  21. data/lib/sequel_core/adapters/oracle.rb +170 -0
  22. data/lib/sequel_core/adapters/postgres.rb +199 -0
  23. data/lib/sequel_core/adapters/shared/mysql.rb +275 -0
  24. data/lib/sequel_core/adapters/shared/postgres.rb +351 -0
  25. data/lib/sequel_core/adapters/shared/sqlite.rb +146 -0
  26. data/lib/sequel_core/adapters/sqlite.rb +138 -0
  27. data/lib/sequel_core/connection_pool.rb +194 -0
  28. data/lib/sequel_core/core_ext.rb +203 -0
  29. data/lib/sequel_core/core_sql.rb +184 -0
  30. data/lib/sequel_core/database.rb +471 -0
  31. data/lib/sequel_core/database/schema.rb +156 -0
  32. data/lib/sequel_core/dataset.rb +457 -0
  33. data/lib/sequel_core/dataset/callback.rb +13 -0
  34. data/lib/sequel_core/dataset/convenience.rb +245 -0
  35. data/lib/sequel_core/dataset/pagination.rb +96 -0
  36. data/lib/sequel_core/dataset/query.rb +41 -0
  37. data/lib/sequel_core/dataset/schema.rb +15 -0
  38. data/lib/sequel_core/dataset/sql.rb +889 -0
  39. data/lib/sequel_core/deprecated.rb +26 -0
  40. data/lib/sequel_core/exceptions.rb +42 -0
  41. data/lib/sequel_core/migration.rb +187 -0
  42. data/lib/sequel_core/object_graph.rb +216 -0
  43. data/lib/sequel_core/pretty_table.rb +71 -0
  44. data/lib/sequel_core/schema.rb +2 -0
  45. data/lib/sequel_core/schema/generator.rb +239 -0
  46. data/lib/sequel_core/schema/sql.rb +325 -0
  47. data/lib/sequel_core/sql.rb +812 -0
  48. data/lib/sequel_model.rb +5 -1
  49. data/lib/sequel_model/association_reflection.rb +3 -8
  50. data/lib/sequel_model/base.rb +15 -10
  51. data/lib/sequel_model/inflector.rb +3 -5
  52. data/lib/sequel_model/plugins.rb +1 -1
  53. data/lib/sequel_model/record.rb +11 -3
  54. data/lib/sequel_model/schema.rb +4 -4
  55. data/lib/sequel_model/validations.rb +6 -1
  56. data/spec/adapters/ado_spec.rb +17 -0
  57. data/spec/adapters/informix_spec.rb +96 -0
  58. data/spec/adapters/mysql_spec.rb +764 -0
  59. data/spec/adapters/oracle_spec.rb +222 -0
  60. data/spec/adapters/postgres_spec.rb +441 -0
  61. data/spec/adapters/spec_helper.rb +7 -0
  62. data/spec/adapters/sqlite_spec.rb +400 -0
  63. data/spec/integration/dataset_test.rb +51 -0
  64. data/spec/integration/eager_loader_test.rb +702 -0
  65. data/spec/integration/schema_test.rb +102 -0
  66. data/spec/integration/spec_helper.rb +44 -0
  67. data/spec/integration/type_test.rb +43 -0
  68. data/spec/rcov.opts +2 -0
  69. data/spec/sequel_core/connection_pool_spec.rb +363 -0
  70. data/spec/sequel_core/core_ext_spec.rb +156 -0
  71. data/spec/sequel_core/core_sql_spec.rb +427 -0
  72. data/spec/sequel_core/database_spec.rb +964 -0
  73. data/spec/sequel_core/dataset_spec.rb +2977 -0
  74. data/spec/sequel_core/expression_filters_spec.rb +346 -0
  75. data/spec/sequel_core/migration_spec.rb +261 -0
  76. data/spec/sequel_core/object_graph_spec.rb +234 -0
  77. data/spec/sequel_core/pretty_table_spec.rb +58 -0
  78. data/spec/sequel_core/schema_generator_spec.rb +122 -0
  79. data/spec/sequel_core/schema_spec.rb +497 -0
  80. data/spec/sequel_core/spec_helper.rb +51 -0
  81. data/spec/{association_reflection_spec.rb → sequel_model/association_reflection_spec.rb} +6 -6
  82. data/spec/{associations_spec.rb → sequel_model/associations_spec.rb} +47 -18
  83. data/spec/{base_spec.rb → sequel_model/base_spec.rb} +2 -1
  84. data/spec/{caching_spec.rb → sequel_model/caching_spec.rb} +0 -0
  85. data/spec/{dataset_methods_spec.rb → sequel_model/dataset_methods_spec.rb} +13 -1
  86. data/spec/{eager_loading_spec.rb → sequel_model/eager_loading_spec.rb} +75 -14
  87. data/spec/{hooks_spec.rb → sequel_model/hooks_spec.rb} +4 -4
  88. data/spec/sequel_model/inflector_spec.rb +119 -0
  89. data/spec/{model_spec.rb → sequel_model/model_spec.rb} +30 -11
  90. data/spec/{plugins_spec.rb → sequel_model/plugins_spec.rb} +0 -0
  91. data/spec/{record_spec.rb → sequel_model/record_spec.rb} +47 -6
  92. data/spec/{schema_spec.rb → sequel_model/schema_spec.rb} +18 -4
  93. data/spec/{spec_helper.rb → sequel_model/spec_helper.rb} +3 -2
  94. data/spec/{validations_spec.rb → sequel_model/validations_spec.rb} +37 -17
  95. data/spec/spec_config.rb +9 -0
  96. data/spec/spec_config.rb.example +10 -0
  97. metadata +110 -37
  98. data/spec/inflector_spec.rb +0 -34
@@ -0,0 +1,78 @@
1
+ require 'informix'
2
+
3
+ module Sequel
4
+ module Informix
5
+ class Database < Sequel::Database
6
+ set_adapter_scheme :informix
7
+
8
+ # AUTO_INCREMENT = 'IDENTITY(1,1)'.freeze
9
+ #
10
+ # def auto_increment_sql
11
+ # AUTO_INCREMENT
12
+ # end
13
+
14
+ def connect
15
+ ::Informix.connect(@opts[:database], @opts[:user], @opts[:password])
16
+ end
17
+
18
+ def disconnect
19
+ @pool.disconnect {|c| c.close}
20
+ end
21
+
22
+ def dataset(opts = nil)
23
+ Sequel::Informix::Dataset.new(self, opts)
24
+ end
25
+
26
+ # Returns number of rows affected
27
+ def execute_dui(sql)
28
+ log_info(sql)
29
+ @pool.hold {|c| c.immediate(sql)}
30
+ end
31
+ alias_method :do, :execute_dui
32
+
33
+ def execute(sql, &block)
34
+ log_info(sql)
35
+ @pool.hold {|c| block[c.cursor(sql)]}
36
+ end
37
+ alias_method :query, :execute
38
+ end
39
+
40
+ class Dataset < Sequel::Dataset
41
+ def literal(v)
42
+ case v
43
+ when Time
44
+ literal(v.iso8601)
45
+ when Date, DateTime
46
+ literal(v.to_s)
47
+ else
48
+ super
49
+ end
50
+ end
51
+
52
+ def select_sql(opts = nil)
53
+ limit = opts.delete(:limit)
54
+ offset = opts.delete(:offset)
55
+ sql = super
56
+ if limit
57
+ limit = "FIRST #{limit}"
58
+ offset = offset ? "SKIP #{offset}" : ""
59
+ sql.sub!(/^select /i,"SELECT #{offset} #{limit} ")
60
+ end
61
+ sql
62
+ end
63
+
64
+ def fetch_rows(sql, &block)
65
+ @db.synchronize do
66
+ @db.execute(sql) do |cursor|
67
+ begin
68
+ cursor.open.each_hash(&block)
69
+ ensure
70
+ cursor.drop
71
+ end
72
+ end
73
+ end
74
+ self
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,186 @@
1
+ require 'java'
2
+
3
+ module Sequel
4
+ module JDBC
5
+ module JavaLang; include_package 'java.lang'; end
6
+ module JavaSQL; include_package 'java.sql'; end
7
+ DATABASE_SETUP = {:postgresql=>proc do |db|
8
+ require 'sequel_core/adapters/jdbc/postgresql'
9
+ db.extend(Sequel::JDBC::Postgres::DatabaseMethods)
10
+ JDBC.load_gem('postgres')
11
+ org.postgresql.Driver
12
+ end,
13
+ :mysql=>proc do |db|
14
+ require 'sequel_core/adapters/jdbc/mysql'
15
+ db.extend(Sequel::JDBC::MySQL::DatabaseMethods)
16
+ JDBC.load_gem('mysql')
17
+ com.mysql.jdbc.Driver
18
+ end,
19
+ :sqlite=>proc do |db|
20
+ require 'sequel_core/adapters/jdbc/sqlite'
21
+ db.extend(Sequel::JDBC::SQLite::DatabaseMethods)
22
+ JDBC.load_gem('sqlite3')
23
+ org.sqlite.JDBC
24
+ end,
25
+ :oracle=>proc{oracle.jdbc.driver.OracleDriver},
26
+ :sqlserver=>proc{com.microsoft.sqlserver.jdbc.SQLServerDriver}
27
+ }
28
+
29
+ def self.load_gem(name)
30
+ begin
31
+ require "jdbc/#{name}"
32
+ rescue LoadError
33
+ # jdbc gem not used, hopefully the user has the .jar in their CLASSPATH
34
+ end
35
+ end
36
+
37
+ class Database < Sequel::Database
38
+ set_adapter_scheme :jdbc
39
+
40
+ # The type of database we are connecting to
41
+ attr_reader :database_type
42
+
43
+ def initialize(opts)
44
+ super(opts)
45
+ raise(Error, "No connection string specified") unless uri
46
+ if match = /\Ajdbc:([^:]+)/.match(uri) and prok = DATABASE_SETUP[match[1].to_sym]
47
+ prok.call(self)
48
+ end
49
+ end
50
+
51
+ def connect
52
+ setup_connection(JavaSQL::DriverManager.getConnection(uri))
53
+ end
54
+
55
+ def dataset(opts = nil)
56
+ JDBC::Dataset.new(self, opts)
57
+ end
58
+
59
+ def disconnect
60
+ @pool.disconnect {|c| c.close}
61
+ end
62
+
63
+ def execute(sql)
64
+ log_info(sql)
65
+ @pool.hold do |conn|
66
+ stmt = conn.createStatement
67
+ begin
68
+ yield stmt.executeQuery(sql)
69
+ rescue NativeException, JavaSQL::SQLException => e
70
+ raise Error, e.message
71
+ ensure
72
+ stmt.close
73
+ end
74
+ end
75
+ end
76
+
77
+ def execute_ddl(sql)
78
+ log_info(sql)
79
+ @pool.hold do |conn|
80
+ stmt = conn.createStatement
81
+ begin
82
+ stmt.execute(sql)
83
+ rescue NativeException, JavaSQL::SQLException => e
84
+ raise Error, e.message
85
+ ensure
86
+ stmt.close
87
+ end
88
+ end
89
+ end
90
+
91
+ def execute_dui(sql)
92
+ log_info(sql)
93
+ @pool.hold do |conn|
94
+ stmt = conn.createStatement
95
+ begin
96
+ stmt.executeUpdate(sql)
97
+ rescue NativeException, JavaSQL::SQLException => e
98
+ raise Error, e.message
99
+ ensure
100
+ stmt.close
101
+ end
102
+ end
103
+ end
104
+
105
+ def setup_connection(conn)
106
+ conn
107
+ end
108
+
109
+ def transaction
110
+ @pool.hold do |conn|
111
+ @transactions ||= []
112
+ return yield(conn) if @transactions.include?(Thread.current)
113
+ stmt = conn.createStatement
114
+ begin
115
+ log_info(Sequel::Database::SQL_BEGIN)
116
+ stmt.execute(Sequel::Database::SQL_BEGIN)
117
+ @transactions << Thread.current
118
+ yield(conn)
119
+ rescue Exception => e
120
+ log_info(Sequel::Database::SQL_ROLLBACK)
121
+ stmt.execute(Sequel::Database::SQL_ROLLBACK)
122
+ raise e unless Error::Rollback === e
123
+ ensure
124
+ unless e
125
+ log_info(Sequel::Database::SQL_COMMIT)
126
+ stmt.execute(Sequel::Database::SQL_COMMIT)
127
+ end
128
+ stmt.close
129
+ @transactions.delete(Thread.current)
130
+ end
131
+ end
132
+ end
133
+
134
+ def uri
135
+ ur = @opts[:uri] || @opts[:url] || @opts[:database]
136
+ ur =~ /^\Ajdbc:/ ? ur : "jdbc:#{ur}"
137
+ end
138
+ alias url uri
139
+
140
+ private
141
+
142
+ def connection_pool_default_options
143
+ super.merge(:pool_convert_exceptions=>false)
144
+ end
145
+ end
146
+
147
+ class Dataset < Sequel::Dataset
148
+ def literal(v)
149
+ case v
150
+ when Time
151
+ literal(v.iso8601)
152
+ when Date, DateTime, Java::JavaSql::Timestamp
153
+ literal(v.to_s)
154
+ else
155
+ super
156
+ end
157
+ end
158
+
159
+ def fetch_rows(sql, &block)
160
+ @db.synchronize do
161
+ @db.execute(sql) do |result|
162
+ # get column names
163
+ meta = result.getMetaData
164
+ column_count = meta.getColumnCount
165
+ @columns = []
166
+ column_count.times {|i| @columns << meta.getColumnName(i+1).to_sym}
167
+
168
+ # get rows
169
+ while result.next
170
+ row = {}
171
+ @columns.each_with_index {|v, i| row[v] = result.getObject(i+1)}
172
+ yield row
173
+ end
174
+ end
175
+ end
176
+ self
177
+ end
178
+ end
179
+ end
180
+ end
181
+
182
+ class Java::JavaSQL::Timestamp
183
+ def usec
184
+ getNanos/1000
185
+ end
186
+ end
@@ -0,0 +1,55 @@
1
+ require 'sequel_core/adapters/shared/mysql'
2
+
3
+ module Sequel
4
+ module JDBC
5
+ module MySQL
6
+ module DatabaseMethods
7
+ include Sequel::MySQL::DatabaseMethods
8
+
9
+ def dataset(opts=nil)
10
+ Sequel::JDBC::MySQL::Dataset.new(self, opts)
11
+ end
12
+
13
+ def execute_insert(sql)
14
+ begin
15
+ log_info(sql)
16
+ @pool.hold do |conn|
17
+ stmt = conn.createStatement
18
+ begin
19
+ stmt.executeUpdate(sql)
20
+ rs = stmt.executeQuery('SELECT LAST_INSERT_ID()')
21
+ rs.next
22
+ rs.getInt(1)
23
+ rescue NativeException, JavaSQL::SQLException => e
24
+ raise Error, e.message
25
+ ensure
26
+ stmt.close
27
+ end
28
+ end
29
+ rescue NativeException, JavaSQL::SQLException => e
30
+ raise Error, "#{sql}\r\n#{e.message}"
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def database_name
37
+ u = URI.parse(uri.sub(/\Ajdbc:/, ''))
38
+ (m = /\/(.*)/.match(u.path)) && m[1]
39
+ end
40
+ end
41
+
42
+ class Dataset < JDBC::Dataset
43
+ include Sequel::MySQL::DatasetMethods
44
+
45
+ def insert(*values)
46
+ @db.execute_insert(insert_sql(*values))
47
+ end
48
+
49
+ def replace(*args)
50
+ @db.execute_insert(replace_sql(*args))
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,66 @@
1
+ require 'sequel_core/adapters/shared/postgres'
2
+
3
+ module Sequel
4
+ Postgres::CONVERTED_EXCEPTIONS << NativeException
5
+
6
+ module JDBC
7
+ module Postgres
8
+ module AdapterMethods
9
+ include Sequel::Postgres::AdapterMethods
10
+
11
+ def execute(sql, method=:execute)
12
+ method = :executeQuery if block_given?
13
+ stmt = createStatement
14
+ begin
15
+ rows = stmt.send(method, sql)
16
+ yield(rows) if block_given?
17
+ rescue NativeException => e
18
+ raise Error, e.message
19
+ ensure
20
+ stmt.close
21
+ end
22
+ end
23
+
24
+ def result_set_values(r, *vals)
25
+ return if r.nil?
26
+ r.next
27
+ return if r.getRow == 0
28
+ case vals.length
29
+ when 1
30
+ r.getString(vals.first+1)
31
+ else
32
+ vals.collect{|col| r.getString(col+1)}
33
+ end
34
+ end
35
+ end
36
+
37
+ module DatabaseMethods
38
+ include Sequel::Postgres::DatabaseMethods
39
+
40
+ def dataset(opts=nil)
41
+ Sequel::JDBC::Postgres::Dataset.new(self, opts)
42
+ end
43
+
44
+ def setup_connection(conn)
45
+ conn.extend(Sequel::JDBC::Postgres::AdapterMethods)
46
+ conn
47
+ end
48
+ end
49
+
50
+ class Dataset < JDBC::Dataset
51
+ include Sequel::Postgres::DatasetMethods
52
+
53
+ def literal(v)
54
+ case v
55
+ when SQL::Blob
56
+ "'#{v.gsub(/[\000-\037\047\134\177-\377]/){|b| "\\#{ b[0].to_s(8).rjust(3, '0') }"}}'"
57
+ when Java::JavaSql::Timestamp
58
+ "TIMESTAMP #{literal(v.to_s)}"
59
+ else
60
+ super
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,47 @@
1
+ require 'sequel_core/adapters/shared/sqlite'
2
+
3
+ module Sequel
4
+ module JDBC
5
+ module SQLite
6
+ module DatabaseMethods
7
+ include Sequel::SQLite::DatabaseMethods
8
+
9
+ def dataset(opts=nil)
10
+ Sequel::JDBC::SQLite::Dataset.new(self, opts)
11
+ end
12
+
13
+ def execute_insert(sql)
14
+ begin
15
+ log_info(sql)
16
+ @pool.hold do |conn|
17
+ stmt = conn.createStatement
18
+ begin
19
+ stmt.executeUpdate(sql)
20
+ rs = stmt.executeQuery('SELECT last_insert_rowid()')
21
+ rs.next
22
+ rs.getInt(1)
23
+ rescue NativeException, JavaSQL::SQLException => e
24
+ raise Error, e.message
25
+ ensure
26
+ stmt.close
27
+ end
28
+ end
29
+ rescue NativeException, JavaSQL::SQLException => e
30
+ raise Error, "#{sql}\r\n#{e.message}"
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def connection_pool_default_options
37
+ o = super
38
+ uri == 'jdbc:sqlite::memory:' ? o.merge(:max_connections=>1) : o
39
+ end
40
+ end
41
+
42
+ class Dataset < JDBC::Dataset
43
+ include Sequel::SQLite::DatasetMethods
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,231 @@
1
+ require 'mysql'
2
+ require 'sequel_core/adapters/shared/mysql'
3
+
4
+ # Monkey patch Mysql::Result to yield hashes with symbol keys
5
+ class Mysql::Result
6
+ MYSQL_TYPES = {
7
+ 0 => :to_d, # MYSQL_TYPE_DECIMAL
8
+ 1 => :to_i, # MYSQL_TYPE_TINY
9
+ 2 => :to_i, # MYSQL_TYPE_SHORT
10
+ 3 => :to_i, # MYSQL_TYPE_LONG
11
+ 4 => :to_f, # MYSQL_TYPE_FLOAT
12
+ 5 => :to_f, # MYSQL_TYPE_DOUBLE
13
+ # 6 => ??, # MYSQL_TYPE_NULL
14
+ 7 => :to_sequel_time, # MYSQL_TYPE_TIMESTAMP
15
+ 8 => :to_i, # MYSQL_TYPE_LONGLONG
16
+ 9 => :to_i, # MYSQL_TYPE_INT24
17
+ 10 => :to_date, # MYSQL_TYPE_DATE
18
+ 11 => :to_time, # MYSQL_TYPE_TIME
19
+ 12 => :to_sequel_time, # MYSQL_TYPE_DATETIME
20
+ 13 => :to_i, # MYSQL_TYPE_YEAR
21
+ 14 => :to_date, # MYSQL_TYPE_NEWDATE
22
+ # 15 => :to_s # MYSQL_TYPE_VARCHAR
23
+ # 16 => :to_s, # MYSQL_TYPE_BIT
24
+ 246 => :to_d, # MYSQL_TYPE_NEWDECIMAL
25
+ 247 => :to_i, # MYSQL_TYPE_ENUM
26
+ 248 => :to_i, # MYSQL_TYPE_SET
27
+ 249 => :to_blob, # MYSQL_TYPE_TINY_BLOB
28
+ 250 => :to_blob, # MYSQL_TYPE_MEDIUM_BLOB
29
+ 251 => :to_blob, # MYSQL_TYPE_LONG_BLOB
30
+ 252 => :to_blob, # MYSQL_TYPE_BLOB
31
+ # 253 => :to_s, # MYSQL_TYPE_VAR_STRING
32
+ # 254 => :to_s, # MYSQL_TYPE_STRING
33
+ # 255 => :to_s # MYSQL_TYPE_GEOMETRY
34
+ }
35
+
36
+ def convert_type(v, type)
37
+ if v
38
+ if type == 1 && Sequel.convert_tinyint_to_bool
39
+ # We special case tinyint here to avoid adding
40
+ # a method to an ancestor of Fixnum
41
+ v.to_i == 0 ? false : true
42
+ else
43
+ (t = MYSQL_TYPES[type]) ? v.send(t) : v
44
+ end
45
+ else
46
+ nil
47
+ end
48
+ end
49
+
50
+ def columns(with_table = nil)
51
+ unless @columns
52
+ @column_types = []
53
+ @columns = fetch_fields.map do |f|
54
+ @column_types << f.type
55
+ (with_table ? "#{f.table}.#{f.name}" : f.name).to_sym
56
+ end
57
+ end
58
+ @columns
59
+ end
60
+
61
+ def each_array(with_table = nil)
62
+ c = columns
63
+ while row = fetch_row
64
+ c.each_with_index do |f, i|
65
+ if (t = MYSQL_TYPES[@column_types[i]]) && (v = row[i])
66
+ row[i] = v.send(t)
67
+ end
68
+ end
69
+ yield row
70
+ end
71
+ end
72
+
73
+ def sequel_each_hash(with_table = nil)
74
+ c = columns
75
+ while row = fetch_row
76
+ h = {}
77
+ c.each_with_index {|f, i| h[f] = convert_type(row[i], @column_types[i])}
78
+ yield h
79
+ end
80
+ end
81
+
82
+ end
83
+
84
+ module Sequel
85
+ module MySQL
86
+ class Database < Sequel::Database
87
+ include Sequel::MySQL::DatabaseMethods
88
+
89
+ set_adapter_scheme :mysql
90
+
91
+ def connect
92
+ conn = Mysql.init
93
+ conn.options(Mysql::OPT_LOCAL_INFILE, "client")
94
+ conn.real_connect(
95
+ @opts[:host] || 'localhost',
96
+ @opts[:user],
97
+ @opts[:password],
98
+ @opts[:database],
99
+ @opts[:port],
100
+ @opts[:socket],
101
+ Mysql::CLIENT_MULTI_RESULTS +
102
+ Mysql::CLIENT_MULTI_STATEMENTS +
103
+ Mysql::CLIENT_COMPRESS
104
+ )
105
+ conn.query_with_result = false
106
+ if encoding = @opts[:encoding] || @opts[:charset]
107
+ conn.query("set character_set_connection = '#{encoding}'")
108
+ conn.query("set character_set_client = '#{encoding}'")
109
+ conn.query("set character_set_database = '#{encoding}'")
110
+ conn.query("set character_set_server = '#{encoding}'")
111
+ conn.query("set character_set_results = '#{encoding}'")
112
+ end
113
+ conn.reconnect = true
114
+ conn
115
+ end
116
+
117
+ def dataset(opts = nil)
118
+ MySQL::Dataset.new(self, opts)
119
+ end
120
+
121
+ def disconnect
122
+ @pool.disconnect {|c| c.close}
123
+ end
124
+
125
+ def execute(sql, &block)
126
+ begin
127
+ log_info(sql)
128
+ @pool.hold do |conn|
129
+ conn.query(sql)
130
+ block[conn] if block
131
+ end
132
+ rescue Mysql::Error => e
133
+ raise Error.new(e.message)
134
+ end
135
+ end
136
+
137
+ def execute_select(sql, &block)
138
+ execute(sql) do |c|
139
+ r = c.use_result
140
+ begin
141
+ block[r]
142
+ ensure
143
+ r.free
144
+ end
145
+ end
146
+ end
147
+
148
+ def server_version
149
+ @server_version ||= (synchronize{|conn| conn.server_version if conn.respond_to?(:server_version)} || super)
150
+ end
151
+
152
+ def tables
153
+ @pool.hold do |conn|
154
+ conn.list_tables.map {|t| t.to_sym}
155
+ end
156
+ end
157
+
158
+ def transaction
159
+ @pool.hold do |conn|
160
+ @transactions ||= []
161
+ return yield(conn) if @transactions.include? Thread.current
162
+ log_info(SQL_BEGIN)
163
+ conn.query(SQL_BEGIN)
164
+ begin
165
+ @transactions << Thread.current
166
+ yield(conn)
167
+ rescue ::Exception => e
168
+ log_info(SQL_ROLLBACK)
169
+ conn.query(SQL_ROLLBACK)
170
+ raise (Mysql::Error === e ? Error.new(e.message) : e) unless Error::Rollback === e
171
+ ensure
172
+ unless e
173
+ log_info(SQL_COMMIT)
174
+ conn.query(SQL_COMMIT)
175
+ end
176
+ @transactions.delete(Thread.current)
177
+ end
178
+ end
179
+ end
180
+
181
+ private
182
+
183
+ def connection_pool_default_options
184
+ super.merge(:pool_convert_exceptions=>false)
185
+ end
186
+
187
+ def database_name
188
+ @opts[:database]
189
+ end
190
+ end
191
+
192
+ class Dataset < Sequel::Dataset
193
+ include Sequel::MySQL::DatasetMethods
194
+
195
+ def delete(opts = nil)
196
+ @db.execute(delete_sql(opts)) {|c| c.affected_rows}
197
+ end
198
+
199
+ def fetch_rows(sql)
200
+ @db.execute_select(sql) do |r|
201
+ @columns = r.columns
202
+ r.sequel_each_hash {|row| yield row}
203
+ end
204
+ self
205
+ end
206
+
207
+ def insert(*values)
208
+ @db.execute(insert_sql(*values)) {|c| c.insert_id}
209
+ end
210
+
211
+ def literal(v)
212
+ case v
213
+ when LiteralString
214
+ v
215
+ when String
216
+ "'#{::Mysql.quote(v)}'"
217
+ else
218
+ super
219
+ end
220
+ end
221
+
222
+ def replace(*args)
223
+ @db.execute(replace_sql(*args)) {|c| c.insert_id}
224
+ end
225
+
226
+ def update(*args)
227
+ @db.execute(update_sql(*args)) {|c| c.affected_rows}
228
+ end
229
+ end
230
+ end
231
+ end