sequel_core 2.2.0 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. metadata +30 -101
  2. data/CHANGELOG +0 -1519
  3. data/COPYING +0 -19
  4. data/README +0 -313
  5. data/Rakefile +0 -158
  6. data/bin/sequel +0 -117
  7. data/doc/cheat_sheet.rdoc +0 -225
  8. data/doc/dataset_filtering.rdoc +0 -182
  9. data/lib/sequel_core.rb +0 -136
  10. data/lib/sequel_core/adapters/adapter_skeleton.rb +0 -68
  11. data/lib/sequel_core/adapters/ado.rb +0 -90
  12. data/lib/sequel_core/adapters/db2.rb +0 -160
  13. data/lib/sequel_core/adapters/dbi.rb +0 -127
  14. data/lib/sequel_core/adapters/informix.rb +0 -89
  15. data/lib/sequel_core/adapters/jdbc.rb +0 -110
  16. data/lib/sequel_core/adapters/mysql.rb +0 -486
  17. data/lib/sequel_core/adapters/odbc.rb +0 -167
  18. data/lib/sequel_core/adapters/odbc_mssql.rb +0 -106
  19. data/lib/sequel_core/adapters/openbase.rb +0 -76
  20. data/lib/sequel_core/adapters/oracle.rb +0 -182
  21. data/lib/sequel_core/adapters/postgres.rb +0 -560
  22. data/lib/sequel_core/adapters/sqlite.rb +0 -270
  23. data/lib/sequel_core/connection_pool.rb +0 -194
  24. data/lib/sequel_core/core_ext.rb +0 -197
  25. data/lib/sequel_core/core_sql.rb +0 -184
  26. data/lib/sequel_core/database.rb +0 -462
  27. data/lib/sequel_core/database/schema.rb +0 -156
  28. data/lib/sequel_core/dataset.rb +0 -457
  29. data/lib/sequel_core/dataset/callback.rb +0 -13
  30. data/lib/sequel_core/dataset/convenience.rb +0 -245
  31. data/lib/sequel_core/dataset/pagination.rb +0 -96
  32. data/lib/sequel_core/dataset/query.rb +0 -41
  33. data/lib/sequel_core/dataset/schema.rb +0 -15
  34. data/lib/sequel_core/dataset/sql.rb +0 -889
  35. data/lib/sequel_core/deprecated.rb +0 -26
  36. data/lib/sequel_core/exceptions.rb +0 -42
  37. data/lib/sequel_core/migration.rb +0 -187
  38. data/lib/sequel_core/object_graph.rb +0 -216
  39. data/lib/sequel_core/pretty_table.rb +0 -71
  40. data/lib/sequel_core/schema.rb +0 -2
  41. data/lib/sequel_core/schema/generator.rb +0 -239
  42. data/lib/sequel_core/schema/sql.rb +0 -326
  43. data/lib/sequel_core/sql.rb +0 -812
  44. data/lib/sequel_core/worker.rb +0 -68
  45. data/spec/adapters/informix_spec.rb +0 -96
  46. data/spec/adapters/mysql_spec.rb +0 -765
  47. data/spec/adapters/oracle_spec.rb +0 -222
  48. data/spec/adapters/postgres_spec.rb +0 -441
  49. data/spec/adapters/sqlite_spec.rb +0 -413
  50. data/spec/connection_pool_spec.rb +0 -363
  51. data/spec/core_ext_spec.rb +0 -156
  52. data/spec/core_sql_spec.rb +0 -427
  53. data/spec/database_spec.rb +0 -963
  54. data/spec/dataset_spec.rb +0 -2933
  55. data/spec/expression_filters_spec.rb +0 -316
  56. data/spec/migration_spec.rb +0 -261
  57. data/spec/object_graph_spec.rb +0 -230
  58. data/spec/pretty_table_spec.rb +0 -58
  59. data/spec/rcov.opts +0 -6
  60. data/spec/schema_generator_spec.rb +0 -122
  61. data/spec/schema_spec.rb +0 -422
  62. data/spec/spec.opts +0 -0
  63. data/spec/spec_config.rb +0 -7
  64. data/spec/spec_config.rb.example +0 -8
  65. data/spec/spec_helper.rb +0 -55
  66. data/spec/worker_spec.rb +0 -96
@@ -1,127 +0,0 @@
1
- require 'dbi'
2
-
3
- module Sequel
4
- module DBI
5
- class Database < Sequel::Database
6
- attr_writer :lowercase
7
-
8
- set_adapter_scheme :dbi
9
-
10
- DBI_ADAPTERS = {
11
- :ado => "ADO",
12
- :db2 => "DB2",
13
- :frontbase => "FrontBase",
14
- :interbase => "InterBase",
15
- :msql => "Msql",
16
- :mysql => "Mysql",
17
- :odbc => "ODBC",
18
- :oracle => "Oracle",
19
- :pg => "pg",
20
- :proxy => "Proxy",
21
- :sqlite => "SQLite",
22
- :sqlrelay => "SQLRelay"
23
- }
24
-
25
- # Converts a uri to an options hash. These options are then passed
26
- # to a newly created database object.
27
- def self.uri_to_options(uri)
28
- database = (m = /\/(.*)/.match(uri.path)) && (m[1])
29
- if m = /dbi-(.+)/.match(uri.scheme)
30
- adapter = DBI_ADAPTERS[m[1].to_sym] || m[1]
31
- database = "#{adapter}:dbname=#{database}"
32
- end
33
- {
34
- :user => uri.user,
35
- :password => uri.password,
36
- :host => uri.host,
37
- :port => uri.port,
38
- :database => database
39
- }
40
- end
41
-
42
-
43
- def connect
44
- dbname = @opts[:database]
45
- if dbname !~ /^DBI:/ then
46
- dbname = "DBI:#{dbname}"
47
- [:host, :port].each{|sym| dbname += ";#{sym}=#{@opts[sym]}" unless @opts[sym].blank?}
48
- end
49
- ::DBI.connect(dbname, @opts[:user], @opts[:password])
50
- end
51
-
52
- def disconnect
53
- @pool.disconnect {|c| c.disconnect}
54
- end
55
-
56
- def dataset(opts = nil)
57
- DBI::Dataset.new(self, opts)
58
- end
59
-
60
- def execute(sql)
61
- log_info(sql)
62
- @pool.hold do |conn|
63
- conn.execute(sql)
64
- end
65
- end
66
-
67
- def do(sql)
68
- log_info(sql)
69
- @pool.hold do |conn|
70
- conn.do(sql)
71
- end
72
- end
73
-
74
- # Converts all column names to lowercase
75
- def lowercase
76
- @lowercase ||= false
77
- end
78
- end
79
-
80
- class Dataset < Sequel::Dataset
81
- def literal(v)
82
- case v
83
- when Time
84
- literal(v.iso8601)
85
- when Date, DateTime
86
- literal(v.to_s)
87
- else
88
- super
89
- end
90
- end
91
-
92
- def fetch_rows(sql, &block)
93
- @db.synchronize do
94
- s = @db.execute sql
95
- begin
96
- @columns = s.column_names.map do |c|
97
- @db.lowercase ? c.downcase.to_sym : c.to_sym
98
- end
99
- s.fetch {|r| yield hash_row(s, r)}
100
- ensure
101
- s.finish rescue nil
102
- end
103
- end
104
- self
105
- end
106
-
107
- def hash_row(stmt, row)
108
- @columns.inject({}) do |m, c|
109
- m[c] = row.shift
110
- m
111
- end
112
- end
113
-
114
- def insert(*values)
115
- @db.do insert_sql(*values)
116
- end
117
-
118
- def update(*args, &block)
119
- @db.do update_sql(*args, &block)
120
- end
121
-
122
- def delete(opts = nil)
123
- @db.do delete_sql(opts)
124
- end
125
- end
126
- end
127
- end
@@ -1,89 +0,0 @@
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(sql)
28
- log_info(sql)
29
- @pool.hold {|c| c.immediate(sql)}
30
- end
31
- alias_method :do, :execute
32
-
33
- def query(sql, &block)
34
- log_info(sql)
35
- @pool.hold {|c| block[c.cursor(sql)]}
36
- end
37
- end
38
-
39
- class Dataset < Sequel::Dataset
40
- def literal(v)
41
- case v
42
- when Time
43
- literal(v.iso8601)
44
- when Date, DateTime
45
- literal(v.to_s)
46
- else
47
- super
48
- end
49
- end
50
-
51
- def select_sql(opts = nil)
52
- limit = opts.delete(:limit)
53
- offset = opts.delete(:offset)
54
- sql = super
55
- if limit
56
- limit = "FIRST #{limit}"
57
- offset = offset ? "SKIP #{offset}" : ""
58
- sql.sub!(/^select /i,"SELECT #{offset} #{limit} ")
59
- end
60
- sql
61
- end
62
-
63
- def fetch_rows(sql, &block)
64
- @db.synchronize do
65
- @db.query(sql) do |cursor|
66
- begin
67
- cursor.open.each_hash(&block)
68
- ensure
69
- cursor.drop
70
- end
71
- end
72
- end
73
- self
74
- end
75
-
76
- def insert(*values)
77
- @db.do insert_sql(*values)
78
- end
79
-
80
- def update(*args, &block)
81
- @db.do update_sql(*args, &block)
82
- end
83
-
84
- def delete(opts = nil)
85
- @db.do delete_sql(opts)
86
- end
87
- end
88
- end
89
- end
@@ -1,110 +0,0 @@
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
-
8
- def self.load_driver(driver)
9
- JavaLang::Class.forName(driver)
10
- # "com.mysql.jdbc.Driver"
11
- end
12
-
13
- class Database < Sequel::Database
14
- set_adapter_scheme :jdbc
15
-
16
- def connect
17
- unless conn_string = @opts[:uri] || @opts[:url] || @opts[:database]
18
- raise Error, "No connection string specified"
19
- end
20
- unless conn_string =~ /^jdbc:/
21
- conn_string = "jdbc:#{conn_string}"
22
- end
23
- JavaSQL::DriverManager.getConnection(
24
- conn_string,
25
- @opts[:user],
26
- @opts[:password]
27
- )
28
- # "jdbc:mysql://127.0.0.1:3306/ruby?user=root"
29
- # "mysql://127.0.0.1:3306/ruby?user=root"
30
- end
31
-
32
- def disconnect
33
- @pool.disconnect {|c| c.close}
34
- end
35
-
36
- def dataset(opts = nil)
37
- JDBC::Dataset.new(self, opts)
38
- end
39
-
40
- def execute_and_forget(sql)
41
- log_info(sql)
42
- @pool.hold do |conn|
43
- stmt = conn.createStatement
44
- begin
45
- stmt.executeQuery(sql)
46
- ensure
47
- stmt.close
48
- end
49
- end
50
- end
51
-
52
- def execute(sql)
53
- log_info(sql)
54
- @pool.hold do |conn|
55
- stmt = conn.createStatement
56
- begin
57
- yield stmt.executeQuery(sql)
58
- ensure
59
- stmt.close
60
- end
61
- end
62
- end
63
- end
64
-
65
- class Dataset < Sequel::Dataset
66
- def literal(v)
67
- case v
68
- when Time
69
- literal(v.iso8601)
70
- when Date, DateTime
71
- literal(v.to_s)
72
- else
73
- super
74
- end
75
- end
76
-
77
- def fetch_rows(sql, &block)
78
- @db.synchronize do
79
- @db.execute(sql) do |result|
80
- # get column names
81
- meta = result.getMetaData
82
- column_count = meta.getColumnCount
83
- @columns = []
84
- column_count.times {|i| @columns << meta.getColumnName(i+1).to_sym}
85
-
86
- # get rows
87
- while result.next
88
- row = {}
89
- @columns.each_with_index {|v, i| row[v] = result.getObject(i+1)}
90
- yield row
91
- end
92
- end
93
- end
94
- self
95
- end
96
-
97
- def insert(*values)
98
- @db.execute_and_forget insert_sql(*values)
99
- end
100
-
101
- def update(*args, &block)
102
- @db.execute_and_forget update_sql(*args, &block)
103
- end
104
-
105
- def delete(opts = nil)
106
- @db.execute_and_forget delete_sql(opts)
107
- end
108
- end
109
- end
110
- end
@@ -1,486 +0,0 @@
1
- require 'mysql'
2
-
3
- # Monkey patch Mysql::Result to yield hashes with symbol keys
4
- class Mysql::Result
5
- MYSQL_TYPES = {
6
- 0 => :to_d, # MYSQL_TYPE_DECIMAL
7
- 1 => :to_i, # MYSQL_TYPE_TINY
8
- 2 => :to_i, # MYSQL_TYPE_SHORT
9
- 3 => :to_i, # MYSQL_TYPE_LONG
10
- 4 => :to_f, # MYSQL_TYPE_FLOAT
11
- 5 => :to_f, # MYSQL_TYPE_DOUBLE
12
- # 6 => ??, # MYSQL_TYPE_NULL
13
- 7 => :to_sequel_time, # MYSQL_TYPE_TIMESTAMP
14
- 8 => :to_i, # MYSQL_TYPE_LONGLONG
15
- 9 => :to_i, # MYSQL_TYPE_INT24
16
- 10 => :to_date, # MYSQL_TYPE_DATE
17
- 11 => :to_time, # MYSQL_TYPE_TIME
18
- 12 => :to_sequel_time, # MYSQL_TYPE_DATETIME
19
- 13 => :to_i, # MYSQL_TYPE_YEAR
20
- 14 => :to_date, # MYSQL_TYPE_NEWDATE
21
- # 15 => :to_s # MYSQL_TYPE_VARCHAR
22
- # 16 => :to_s, # MYSQL_TYPE_BIT
23
- 246 => :to_d, # MYSQL_TYPE_NEWDECIMAL
24
- 247 => :to_i, # MYSQL_TYPE_ENUM
25
- 248 => :to_i, # MYSQL_TYPE_SET
26
- 249 => :to_blob, # MYSQL_TYPE_TINY_BLOB
27
- 250 => :to_blob, # MYSQL_TYPE_MEDIUM_BLOB
28
- 251 => :to_blob, # MYSQL_TYPE_LONG_BLOB
29
- 252 => :to_blob, # MYSQL_TYPE_BLOB
30
- # 253 => :to_s, # MYSQL_TYPE_VAR_STRING
31
- # 254 => :to_s, # MYSQL_TYPE_STRING
32
- # 255 => :to_s # MYSQL_TYPE_GEOMETRY
33
- }
34
-
35
- def convert_type(v, type)
36
- if v
37
- if type == 1 && Sequel.convert_tinyint_to_bool
38
- # We special case tinyint here to avoid adding
39
- # a method to an ancestor of Fixnum
40
- v.to_i == 0 ? false : true
41
- else
42
- (t = MYSQL_TYPES[type]) ? v.send(t) : v
43
- end
44
- else
45
- nil
46
- end
47
- end
48
-
49
- def columns(with_table = nil)
50
- unless @columns
51
- @column_types = []
52
- @columns = fetch_fields.map do |f|
53
- @column_types << f.type
54
- (with_table ? "#{f.table}.#{f.name}" : f.name).to_sym
55
- end
56
- end
57
- @columns
58
- end
59
-
60
- def each_array(with_table = nil)
61
- c = columns
62
- while row = fetch_row
63
- c.each_with_index do |f, i|
64
- if (t = MYSQL_TYPES[@column_types[i]]) && (v = row[i])
65
- row[i] = v.send(t)
66
- end
67
- end
68
- yield row
69
- end
70
- end
71
-
72
- def sequel_each_hash(with_table = nil)
73
- c = columns
74
- while row = fetch_row
75
- h = {}
76
- c.each_with_index {|f, i| h[f] = convert_type(row[i], @column_types[i])}
77
- yield h
78
- end
79
- end
80
-
81
- end
82
-
83
- module Sequel
84
- module MySQL
85
- class Database < Sequel::Database
86
- set_adapter_scheme :mysql
87
-
88
- def server_version
89
- @server_version ||= pool.hold do |conn|
90
- if conn.respond_to?(:server_version)
91
- pool.hold {|c| c.server_version}
92
- else
93
- m = /(\d+)\.(\d+)\.(\d+)/.match(get(:version[]))
94
- (m[1].to_i * 10000) + (m[2].to_i * 100) + m[3].to_i
95
- end
96
- end
97
- end
98
-
99
- def serial_primary_key_options
100
- {:primary_key => true, :type => :integer, :auto_increment => true}
101
- end
102
-
103
- AUTO_INCREMENT = 'AUTO_INCREMENT'.freeze
104
-
105
- def auto_increment_sql
106
- AUTO_INCREMENT
107
- end
108
-
109
- def connect
110
- conn = Mysql.init
111
- conn.options(Mysql::OPT_LOCAL_INFILE, "client")
112
- conn.real_connect(
113
- @opts[:host] || 'localhost',
114
- @opts[:user],
115
- @opts[:password],
116
- @opts[:database],
117
- @opts[:port],
118
- @opts[:socket],
119
- Mysql::CLIENT_MULTI_RESULTS +
120
- Mysql::CLIENT_MULTI_STATEMENTS +
121
- Mysql::CLIENT_COMPRESS
122
- )
123
- conn.query_with_result = false
124
- if encoding = @opts[:encoding] || @opts[:charset]
125
- conn.query("set character_set_connection = '#{encoding}'")
126
- conn.query("set character_set_client = '#{encoding}'")
127
- conn.query("set character_set_database = '#{encoding}'")
128
- conn.query("set character_set_server = '#{encoding}'")
129
- conn.query("set character_set_results = '#{encoding}'")
130
- end
131
- conn.reconnect = true
132
- conn
133
- end
134
-
135
- def disconnect
136
- @pool.disconnect {|c| c.close}
137
- end
138
-
139
- def tables
140
- @pool.hold do |conn|
141
- conn.list_tables.map {|t| t.to_sym}
142
- end
143
- end
144
-
145
- def dataset(opts = nil)
146
- MySQL::Dataset.new(self, opts)
147
- end
148
-
149
- def execute(sql, &block)
150
- begin
151
- log_info(sql)
152
- @pool.hold do |conn|
153
- conn.query(sql)
154
- block[conn] if block
155
- end
156
- rescue Mysql::Error => e
157
- raise Error.new(e.message)
158
- end
159
- end
160
-
161
- def execute_select(sql, &block)
162
- execute(sql) do |c|
163
- r = c.use_result
164
- begin
165
- block[r]
166
- ensure
167
- r.free
168
- end
169
- end
170
- end
171
-
172
- def alter_table_sql(table, op)
173
- type = type_literal(op[:type])
174
- type << '(255)' if type == 'varchar'
175
- case op[:op]
176
- when :rename_column
177
- "ALTER TABLE #{table} CHANGE COLUMN #{literal(op[:name])} #{literal(op[:new_name])} #{type}"
178
- when :set_column_type
179
- "ALTER TABLE #{table} CHANGE COLUMN #{literal(op[:name])} #{literal(op[:name])} #{type}"
180
- when :drop_index
181
- "DROP INDEX #{default_index_name(table, op[:columns])} ON #{table}"
182
- else
183
- super(table, op)
184
- end
185
- end
186
-
187
- def column_definition_sql(column)
188
- if column[:type] == :check
189
- return constraint_definition_sql(column)
190
- end
191
- sql = "#{literal(column[:name].to_sym)} #{TYPES[column[:type]]}"
192
- column[:size] ||= 255 if column[:type] == :varchar
193
- elements = column[:size] || column[:elements]
194
- sql << literal(Array(elements)) if elements
195
- sql << UNSIGNED if column[:unsigned]
196
- sql << UNIQUE if column[:unique]
197
- sql << NOT_NULL if column[:null] == false
198
- sql << NULL if column[:null] == true
199
- sql << " DEFAULT #{literal(column[:default])}" if column.include?(:default)
200
- sql << PRIMARY_KEY if column[:primary_key]
201
- sql << " #{auto_increment_sql}" if column[:auto_increment]
202
- if column[:table]
203
- sql << ", FOREIGN KEY (#{literal(column[:name].to_sym)}) REFERENCES #{column[:table]}"
204
- sql << literal(Array(column[:key])) if column[:key]
205
- sql << " ON DELETE #{on_delete_clause(column[:on_delete])}" if column[:on_delete]
206
- end
207
- sql
208
- end
209
-
210
- def index_definition_sql(table_name, index)
211
- index_name = index[:name] || default_index_name(table_name, index[:columns])
212
- unique = "UNIQUE " if index[:unique]
213
- case index[:type]
214
- when :full_text
215
- "CREATE FULLTEXT INDEX #{index_name} ON #{table_name} #{literal(index[:columns])}"
216
- when :spatial
217
- "CREATE SPATIAL INDEX #{index_name} ON #{table_name} #{literal(index[:columns])}"
218
- when nil
219
- "CREATE #{unique}INDEX #{index_name} ON #{table_name} #{literal(index[:columns])}"
220
- else
221
- "CREATE #{unique}INDEX #{index_name} ON #{table_name} #{literal(index[:columns])} USING #{index[:type]}"
222
- end
223
- end
224
-
225
- def transaction
226
- @pool.hold do |conn|
227
- @transactions ||= []
228
- if @transactions.include? Thread.current
229
- return yield(conn)
230
- end
231
- log_info(SQL_BEGIN)
232
- conn.query(SQL_BEGIN)
233
- begin
234
- @transactions << Thread.current
235
- yield(conn)
236
- rescue ::Exception => e
237
- log_info(SQL_ROLLBACK)
238
- conn.query(SQL_ROLLBACK)
239
- raise (Mysql::Error === e ? Error.new(e.message) : e) unless Error::Rollback === e
240
- ensure
241
- unless e
242
- log_info(SQL_COMMIT)
243
- conn.query(SQL_COMMIT)
244
- end
245
- @transactions.delete(Thread.current)
246
- end
247
- end
248
- end
249
-
250
- # Changes the database in use by issuing a USE statement.
251
- def use(db_name)
252
- disconnect
253
- @opts[:database] = db_name if self << "USE #{db_name}"
254
- @schemas = nil
255
- self
256
- end
257
-
258
- private
259
- def connection_pool_default_options
260
- super.merge(:pool_convert_exceptions=>false)
261
- end
262
-
263
- def schema_ds_dataset
264
- ds = schema_utility_dataset.clone
265
- ds.quote_identifiers = true
266
- ds
267
- end
268
-
269
- def schema_ds_filter(table_name, opts)
270
- filt = super
271
- # Restrict it to the given or current database, unless specifically requesting :database = nil
272
- filt = SQL::BooleanExpression.new(:AND, filt, {:c__table_schema=>opts[:database] || self.opts[:database]}) if opts[:database] || !opts.include?(:database)
273
- filt
274
- end
275
-
276
- def schema_ds_join(table_name, opts)
277
- [:information_schema__columns, {:table_schema => :table_schema, :table_name => :table_name}, :c]
278
- end
279
- end
280
-
281
- class Dataset < Sequel::Dataset
282
- def quoted_identifier(c)
283
- "`#{c}`"
284
- end
285
-
286
- TRUE = '1'
287
- FALSE = '0'
288
-
289
- def literal(v)
290
- case v
291
- when LiteralString
292
- v
293
- when String
294
- "'#{::Mysql.quote(v)}'"
295
- when true
296
- TRUE
297
- when false
298
- FALSE
299
- else
300
- super
301
- end
302
- end
303
-
304
- # Returns a join clause based on the specified join type
305
- # and condition. MySQL's NATURAL join is 'semantically
306
- # equivalent to a JOIN with a USING clause that names all
307
- # columns that exist in both tables. The constraint
308
- # expression may be nil, so join expression can accept two
309
- # arguments.
310
- #
311
- # === Note
312
- # Full outer joins (:full_outer) are not implemented in
313
- # MySQL (as of v6.0), nor is there currently a work around
314
- # implementation in Sequel. Straight joins with 'ON
315
- # <condition>' are not yet implemented.
316
- #
317
- # === Example
318
- # @ds = MYSQL_DB[:nodes]
319
- # @ds.join_table(:natural_left_outer, :nodes)
320
- # # join SQL is 'NATURAL LEFT OUTER JOIN nodes'
321
- def join_table(type, table, expr=nil, table_alias=nil)
322
- type = :inner if (type == :cross) && !expr.nil?
323
- raise(Sequel::Error::InvalidJoinType, "MySQL doesn't support FULL OUTER JOIN") if type == :full_outer
324
- super(type, table, expr, table_alias)
325
- end
326
-
327
-
328
- def join_type_sql(join_type)
329
- case join_type
330
- when :straight then 'STRAIGHT_JOIN'
331
- when :natural_inner then 'NATURAL LEFT JOIN'
332
- else super
333
- end
334
- end
335
-
336
- def insert_default_values_sql
337
- "INSERT INTO #{source_list(@opts[:from])} () VALUES ()"
338
- end
339
-
340
- def complex_expression_sql(op, args)
341
- case op
342
- when :~, :'!~', :'~*', :'!~*', :LIKE, :'NOT LIKE', :ILIKE, :'NOT ILIKE'
343
- "(#{literal(args.at(0))} #{'NOT ' if [:'NOT LIKE', :'NOT ILIKE', :'!~', :'!~*'].include?(op)}#{[:~, :'!~', :'~*', :'!~*'].include?(op) ? 'REGEXP' : 'LIKE'} #{'BINARY ' if [:~, :'!~', :LIKE, :'NOT LIKE'].include?(op)}#{literal(args.at(1))})"
344
- when :'||'
345
- if args.length > 1
346
- "CONCAT(#{args.collect{|a| literal(a)}.join(', ')})"
347
- else
348
- literal(args.at(0))
349
- end
350
- else
351
- super(op, args)
352
- end
353
- end
354
-
355
- def match_expr(l, r)
356
- case r
357
- when Regexp
358
- r.casefold? ? \
359
- "(#{literal(l)} REGEXP #{literal(r.source)})" :
360
- "(#{literal(l)} REGEXP BINARY #{literal(r.source)})"
361
- else
362
- super
363
- end
364
- end
365
-
366
- def full_text_search(cols, terms, opts = {})
367
- mode = opts[:boolean] ? " IN BOOLEAN MODE" : ""
368
- s = if Array === terms
369
- if mode.blank?
370
- "MATCH #{literal(Array(cols))} AGAINST #{literal(terms)}"
371
- else
372
- "MATCH #{literal(Array(cols))} AGAINST (#{literal(terms)[1...-1]}#{mode})"
373
- end
374
- else
375
- "MATCH #{literal(Array(cols))} AGAINST (#{literal(terms)}#{mode})"
376
- end
377
- filter(s)
378
- end
379
-
380
- # MySQL allows HAVING clause on ungrouped datasets.
381
- def having(*cond, &block)
382
- @opts[:having] = {}
383
- x = filter(*cond, &block)
384
- end
385
-
386
- # MySQL supports ORDER and LIMIT clauses in UPDATE statements.
387
- def update_sql(values, opts = nil, &block)
388
- sql = super
389
- opts = opts ? @opts.merge(opts) : @opts
390
-
391
- if order = opts[:order]
392
- sql << " ORDER BY #{expression_list(order)}"
393
- end
394
- if limit = opts[:limit]
395
- sql << " LIMIT #{limit}"
396
- end
397
-
398
- sql
399
- end
400
-
401
- def replace_sql(*values)
402
- from = source_list(@opts[:from])
403
- if values.empty?
404
- "REPLACE INTO #{from} DEFAULT VALUES"
405
- else
406
- values = values[0] if values.size == 1
407
-
408
- # if hash or array with keys we need to transform the values
409
- if @transform && (values.is_a?(Hash) || (values.is_a?(Array) && values.keys))
410
- values = transform_save(values)
411
- end
412
-
413
- case values
414
- when Array
415
- if values.empty?
416
- "REPLACE INTO #{from} DEFAULT VALUES"
417
- else
418
- "REPLACE INTO #{from} VALUES #{literal(values)}"
419
- end
420
- when Hash
421
- if values.empty?
422
- "REPLACE INTO #{from} DEFAULT VALUES"
423
- else
424
- fl, vl = [], []
425
- values.each {|k, v| fl << literal(k.is_a?(String) ? k.to_sym : k); vl << literal(v)}
426
- "REPLACE INTO #{from} (#{fl.join(COMMA_SEPARATOR)}) VALUES (#{vl.join(COMMA_SEPARATOR)})"
427
- end
428
- when Dataset
429
- "REPLACE INTO #{from} #{literal(values)}"
430
- else
431
- if values.respond_to?(:values)
432
- replace_sql(values.values)
433
- else
434
- "REPLACE INTO #{from} VALUES (#{literal(values)})"
435
- end
436
- end
437
- end
438
- end
439
-
440
- # MySQL supports ORDER and LIMIT clauses in DELETE statements.
441
- def delete_sql(opts = nil)
442
- sql = super
443
- opts = opts ? @opts.merge(opts) : @opts
444
-
445
- if order = opts[:order]
446
- sql << " ORDER BY #{expression_list(order)}"
447
- end
448
- if limit = opts[:limit]
449
- sql << " LIMIT #{limit}"
450
- end
451
-
452
- sql
453
- end
454
-
455
- def insert(*values)
456
- @db.execute(insert_sql(*values)) {|c| c.insert_id}
457
- end
458
-
459
- def update(*args, &block)
460
- @db.execute(update_sql(*args, &block)) {|c| c.affected_rows}
461
- end
462
-
463
- def replace(*args)
464
- @db.execute(replace_sql(*args)) {|c| c.insert_id}
465
- end
466
-
467
- def delete(opts = nil)
468
- @db.execute(delete_sql(opts)) {|c| c.affected_rows}
469
- end
470
-
471
- def fetch_rows(sql)
472
- @db.execute_select(sql) do |r|
473
- @columns = r.columns
474
- r.sequel_each_hash {|row| yield row}
475
- end
476
- self
477
- end
478
-
479
- def multi_insert_sql(columns, values)
480
- columns = column_list(columns)
481
- values = values.map {|r| literal(Array(r))}.join(COMMA_SEPARATOR)
482
- ["INSERT INTO #{source_list(@opts[:from])} (#{columns}) VALUES #{values}"]
483
- end
484
- end
485
- end
486
- end