sequel_core 1.5.1 → 2.0.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/CHANGELOG +116 -0
- data/COPYING +19 -19
- data/README +83 -32
- data/Rakefile +9 -20
- data/bin/sequel +43 -112
- data/doc/cheat_sheet.rdoc +225 -0
- data/doc/dataset_filtering.rdoc +257 -0
- data/lib/sequel_core/adapters/adapter_skeleton.rb +4 -2
- data/lib/sequel_core/adapters/ado.rb +3 -1
- data/lib/sequel_core/adapters/db2.rb +4 -2
- data/lib/sequel_core/adapters/dbi.rb +127 -113
- data/lib/sequel_core/adapters/informix.rb +4 -2
- data/lib/sequel_core/adapters/jdbc.rb +5 -3
- data/lib/sequel_core/adapters/mysql.rb +112 -46
- data/lib/sequel_core/adapters/odbc.rb +5 -7
- data/lib/sequel_core/adapters/odbc_mssql.rb +12 -3
- data/lib/sequel_core/adapters/openbase.rb +3 -1
- data/lib/sequel_core/adapters/oracle.rb +11 -9
- data/lib/sequel_core/adapters/postgres.rb +261 -262
- data/lib/sequel_core/adapters/sqlite.rb +72 -22
- data/lib/sequel_core/connection_pool.rb +140 -73
- data/lib/sequel_core/core_ext.rb +201 -66
- data/lib/sequel_core/core_sql.rb +123 -153
- data/lib/sequel_core/database/schema.rb +156 -0
- data/lib/sequel_core/database.rb +321 -338
- data/lib/sequel_core/dataset/callback.rb +11 -12
- data/lib/sequel_core/dataset/convenience.rb +213 -240
- data/lib/sequel_core/dataset/pagination.rb +58 -43
- data/lib/sequel_core/dataset/parse_tree_sequelizer.rb +331 -0
- data/lib/sequel_core/dataset/query.rb +41 -0
- data/lib/sequel_core/dataset/schema.rb +15 -0
- data/lib/sequel_core/dataset/sequelizer.rb +41 -373
- data/lib/sequel_core/dataset/sql.rb +741 -632
- data/lib/sequel_core/dataset.rb +183 -168
- data/lib/sequel_core/deprecated.rb +1 -169
- data/lib/sequel_core/exceptions.rb +24 -19
- data/lib/sequel_core/migration.rb +44 -52
- data/lib/sequel_core/object_graph.rb +43 -42
- data/lib/sequel_core/pretty_table.rb +71 -76
- data/lib/sequel_core/schema/generator.rb +163 -105
- data/lib/sequel_core/schema/sql.rb +250 -93
- data/lib/sequel_core/schema.rb +2 -8
- data/lib/sequel_core/sql.rb +394 -0
- data/lib/sequel_core/worker.rb +37 -27
- data/lib/sequel_core.rb +99 -45
- data/spec/adapters/informix_spec.rb +0 -1
- data/spec/adapters/mysql_spec.rb +177 -124
- data/spec/adapters/oracle_spec.rb +0 -1
- data/spec/adapters/postgres_spec.rb +98 -58
- data/spec/adapters/sqlite_spec.rb +45 -4
- data/spec/blockless_filters_spec.rb +269 -0
- data/spec/connection_pool_spec.rb +21 -18
- data/spec/core_ext_spec.rb +169 -19
- data/spec/core_sql_spec.rb +56 -49
- data/spec/database_spec.rb +78 -17
- data/spec/dataset_spec.rb +300 -428
- data/spec/migration_spec.rb +1 -1
- data/spec/object_graph_spec.rb +5 -11
- data/spec/rcov.opts +1 -1
- data/spec/schema_generator_spec.rb +16 -4
- data/spec/schema_spec.rb +89 -10
- data/spec/sequelizer_spec.rb +56 -56
- data/spec/spec.opts +0 -5
- data/spec/spec_config.rb +7 -0
- data/spec/spec_config.rb.example +5 -5
- data/spec/spec_helper.rb +6 -0
- data/spec/worker_spec.rb +1 -1
- metadata +78 -63
@@ -1,113 +1,127 @@
|
|
1
|
-
require 'dbi'
|
2
|
-
|
3
|
-
module Sequel
|
4
|
-
module DBI
|
5
|
-
class Database < Sequel::Database
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
20
|
-
:
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
:
|
35
|
-
:
|
36
|
-
:
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
end
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
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
|
@@ -25,13 +25,13 @@ module Sequel
|
|
25
25
|
|
26
26
|
# Returns number of rows affected
|
27
27
|
def execute(sql)
|
28
|
-
|
28
|
+
log_info(sql)
|
29
29
|
@pool.hold {|c| c.immediate(sql)}
|
30
30
|
end
|
31
31
|
alias_method :do, :execute
|
32
32
|
|
33
33
|
def query(sql, &block)
|
34
|
-
|
34
|
+
log_info(sql)
|
35
35
|
@pool.hold {|c| block[c.cursor(sql)]}
|
36
36
|
end
|
37
37
|
end
|
@@ -41,6 +41,8 @@ module Sequel
|
|
41
41
|
case v
|
42
42
|
when Time
|
43
43
|
literal(v.iso8601)
|
44
|
+
when Date, DateTime
|
45
|
+
literal(v.to_s)
|
44
46
|
else
|
45
47
|
super
|
46
48
|
end
|
@@ -38,7 +38,7 @@ module Sequel
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def execute_and_forget(sql)
|
41
|
-
|
41
|
+
log_info(sql)
|
42
42
|
@pool.hold do |conn|
|
43
43
|
stmt = conn.createStatement
|
44
44
|
begin
|
@@ -50,7 +50,7 @@ module Sequel
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def execute(sql)
|
53
|
-
|
53
|
+
log_info(sql)
|
54
54
|
@pool.hold do |conn|
|
55
55
|
stmt = conn.createStatement
|
56
56
|
begin
|
@@ -67,6 +67,8 @@ module Sequel
|
|
67
67
|
case v
|
68
68
|
when Time
|
69
69
|
literal(v.iso8601)
|
70
|
+
when Date, DateTime
|
71
|
+
literal(v.to_s)
|
70
72
|
else
|
71
73
|
super
|
72
74
|
end
|
@@ -105,4 +107,4 @@ module Sequel
|
|
105
107
|
end
|
106
108
|
end
|
107
109
|
end
|
108
|
-
end
|
110
|
+
end
|
@@ -4,7 +4,7 @@ require 'mysql'
|
|
4
4
|
class Mysql::Result
|
5
5
|
MYSQL_TYPES = {
|
6
6
|
0 => :to_d, # MYSQL_TYPE_DECIMAL
|
7
|
-
1 => :to_i, # MYSQL_TYPE_TINY
|
7
|
+
#1 => :to_i, # MYSQL_TYPE_TINY
|
8
8
|
2 => :to_i, # MYSQL_TYPE_SHORT
|
9
9
|
3 => :to_i, # MYSQL_TYPE_LONG
|
10
10
|
4 => :to_f, # MYSQL_TYPE_FLOAT
|
@@ -33,7 +33,17 @@ class Mysql::Result
|
|
33
33
|
}
|
34
34
|
|
35
35
|
def convert_type(v, type)
|
36
|
-
|
36
|
+
if v
|
37
|
+
if type == 1
|
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
|
37
47
|
end
|
38
48
|
|
39
49
|
def columns(with_table = nil)
|
@@ -55,7 +65,6 @@ class Mysql::Result
|
|
55
65
|
row[i] = v.send(t)
|
56
66
|
end
|
57
67
|
end
|
58
|
-
row.keys = c
|
59
68
|
yield row
|
60
69
|
end
|
61
70
|
end
|
@@ -80,8 +89,8 @@ module Sequel
|
|
80
89
|
if conn.respond_to?(:server_version)
|
81
90
|
pool.hold {|c| c.server_version}
|
82
91
|
else
|
83
|
-
|
84
|
-
(
|
92
|
+
m = /(\d+)\.(\d+)\.(\d+)/.match(get(:version[]))
|
93
|
+
(m[1].to_i * 10000) + (m[2].to_i * 100) + m[3].to_i
|
85
94
|
end
|
86
95
|
end
|
87
96
|
end
|
@@ -114,6 +123,8 @@ module Sequel
|
|
114
123
|
if encoding = @opts[:encoding] || @opts[:charset]
|
115
124
|
conn.query("set character_set_connection = '#{encoding}'")
|
116
125
|
conn.query("set character_set_client = '#{encoding}'")
|
126
|
+
conn.query("set character_set_database = '#{encoding}'")
|
127
|
+
conn.query("set character_set_server = '#{encoding}'")
|
117
128
|
conn.query("set character_set_results = '#{encoding}'")
|
118
129
|
end
|
119
130
|
conn.reconnect = true
|
@@ -135,10 +146,14 @@ module Sequel
|
|
135
146
|
end
|
136
147
|
|
137
148
|
def execute(sql, &block)
|
138
|
-
|
139
|
-
|
140
|
-
conn
|
141
|
-
|
149
|
+
begin
|
150
|
+
log_info(sql)
|
151
|
+
@pool.hold do |conn|
|
152
|
+
conn.query(sql)
|
153
|
+
block[conn] if block
|
154
|
+
end
|
155
|
+
rescue Mysql::Error => e
|
156
|
+
raise Error.new(e.message)
|
142
157
|
end
|
143
158
|
end
|
144
159
|
|
@@ -175,7 +190,7 @@ module Sequel
|
|
175
190
|
sql = "#{literal(column[:name].to_sym)} #{TYPES[column[:type]]}"
|
176
191
|
column[:size] ||= 255 if column[:type] == :varchar
|
177
192
|
elements = column[:size] || column[:elements]
|
178
|
-
sql <<
|
193
|
+
sql << literal(Array(elements)) if elements
|
179
194
|
sql << UNSIGNED if column[:unsigned]
|
180
195
|
sql << UNIQUE if column[:unique]
|
181
196
|
sql << NOT_NULL if column[:null] == false
|
@@ -185,7 +200,7 @@ module Sequel
|
|
185
200
|
sql << " #{auto_increment_sql}" if column[:auto_increment]
|
186
201
|
if column[:table]
|
187
202
|
sql << ", FOREIGN KEY (#{literal(column[:name].to_sym)}) REFERENCES #{column[:table]}"
|
188
|
-
sql <<
|
203
|
+
sql << literal(Array(column[:key])) if column[:key]
|
189
204
|
sql << " ON DELETE #{on_delete_clause(column[:on_delete])}" if column[:on_delete]
|
190
205
|
end
|
191
206
|
sql
|
@@ -196,13 +211,13 @@ module Sequel
|
|
196
211
|
unique = "UNIQUE " if index[:unique]
|
197
212
|
case index[:type]
|
198
213
|
when :full_text
|
199
|
-
"CREATE FULLTEXT INDEX #{index_name} ON #{table_name}
|
214
|
+
"CREATE FULLTEXT INDEX #{index_name} ON #{table_name} #{literal(index[:columns])}"
|
200
215
|
when :spatial
|
201
|
-
"CREATE SPATIAL INDEX #{index_name} ON #{table_name}
|
216
|
+
"CREATE SPATIAL INDEX #{index_name} ON #{table_name} #{literal(index[:columns])}"
|
202
217
|
when nil
|
203
|
-
"CREATE #{unique}INDEX #{index_name} ON #{table_name}
|
218
|
+
"CREATE #{unique}INDEX #{index_name} ON #{table_name} #{literal(index[:columns])}"
|
204
219
|
else
|
205
|
-
"CREATE #{unique}INDEX #{index_name} ON #{table_name}
|
220
|
+
"CREATE #{unique}INDEX #{index_name} ON #{table_name} #{literal(index[:columns])} USING #{index[:type]}"
|
206
221
|
end
|
207
222
|
end
|
208
223
|
|
@@ -212,16 +227,20 @@ module Sequel
|
|
212
227
|
if @transactions.include? Thread.current
|
213
228
|
return yield(conn)
|
214
229
|
end
|
230
|
+
log_info(SQL_BEGIN)
|
215
231
|
conn.query(SQL_BEGIN)
|
216
232
|
begin
|
217
233
|
@transactions << Thread.current
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
rescue => e
|
234
|
+
yield(conn)
|
235
|
+
rescue ::Exception => e
|
236
|
+
log_info(SQL_ROLLBACK)
|
222
237
|
conn.query(SQL_ROLLBACK)
|
223
|
-
raise e unless Error::Rollback === e
|
238
|
+
raise (Mysql::Error === e ? Error.new(e.message) : e) unless Error::Rollback === e
|
224
239
|
ensure
|
240
|
+
unless e
|
241
|
+
log_info(SQL_COMMIT)
|
242
|
+
conn.query(SQL_COMMIT)
|
243
|
+
end
|
225
244
|
@transactions.delete(Thread.current)
|
226
245
|
end
|
227
246
|
end
|
@@ -231,12 +250,37 @@ module Sequel
|
|
231
250
|
def use(db_name)
|
232
251
|
disconnect
|
233
252
|
@opts[:database] = db_name if self << "USE #{db_name}"
|
253
|
+
@schemas = nil
|
234
254
|
self
|
235
255
|
end
|
256
|
+
|
257
|
+
private
|
258
|
+
def connection_pool_default_options
|
259
|
+
super.merge(:pool_reuse_connections=>:last_resort, :pool_convert_exceptions=>false)
|
260
|
+
end
|
261
|
+
|
262
|
+
def schema_ds_dataset
|
263
|
+
ds = schema_utility_dataset.clone
|
264
|
+
ds.quote_identifiers = true
|
265
|
+
ds
|
266
|
+
end
|
267
|
+
|
268
|
+
def schema_ds_filter(table_name, opts)
|
269
|
+
filt = super
|
270
|
+
# Restrict it to the given or current database, unless specifically requesting :database = nil
|
271
|
+
filt = SQL::ComplexExpression.new(:AND, filt, {:c__table_schema=>opts[:database] || self.opts[:database]}) if opts[:database] || !opts.include?(:database)
|
272
|
+
filt
|
273
|
+
end
|
274
|
+
|
275
|
+
def schema_ds_join(table_name, opts)
|
276
|
+
[:information_schema__columns, {:table_schema => :table_schema, :table_name => :table_name}, :c]
|
277
|
+
end
|
236
278
|
end
|
237
279
|
|
238
280
|
class Dataset < Sequel::Dataset
|
239
|
-
def
|
281
|
+
def quoted_identifier(c)
|
282
|
+
"`#{c}`"
|
283
|
+
end
|
240
284
|
|
241
285
|
TRUE = '1'
|
242
286
|
FALSE = '0'
|
@@ -268,7 +312,7 @@ module Sequel
|
|
268
312
|
when LiteralString
|
269
313
|
v
|
270
314
|
when String
|
271
|
-
"'#{
|
315
|
+
"'#{::Mysql.quote(v)}'"
|
272
316
|
when true
|
273
317
|
TRUE
|
274
318
|
when false
|
@@ -293,27 +337,44 @@ module Sequel
|
|
293
337
|
#
|
294
338
|
# === Example
|
295
339
|
# @ds = MYSQL_DB[:nodes]
|
296
|
-
# @ds.
|
297
|
-
# # 'NATURAL LEFT OUTER JOIN nodes'
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
type
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
"#{join_type} #{table}"
|
340
|
+
# @ds.join_table(:natural_left_outer, :nodes)
|
341
|
+
# # join SQL is 'NATURAL LEFT OUTER JOIN nodes'
|
342
|
+
def join_table(type, table, expr=nil, table_alias=nil)
|
343
|
+
raise(Error::InvalidJoinType, "Invalid join type: #{type}") unless join_type = JOIN_TYPES[type || :inner]
|
344
|
+
|
345
|
+
server_version = (@opts[:server_version] ||= @db.server_version)
|
346
|
+
type = :inner if (type == :cross) && !expr.nil?
|
347
|
+
return super(type, table, expr, table_alias) unless (server_version >= 50014) && /natural|cross|straight/.match(type.to_s)
|
348
|
+
|
349
|
+
table = if Array === table
|
350
|
+
"( #{table.collect{|t| quote_identifier(t)}.join(', ')} )"
|
308
351
|
else
|
309
|
-
|
352
|
+
quote_identifier(table)
|
310
353
|
end
|
354
|
+
clone(:join => "#{@opts[:join]} #{join_type} #{table}")
|
311
355
|
end
|
312
356
|
|
313
357
|
def insert_default_values_sql
|
314
358
|
"INSERT INTO #{source_list(@opts[:from])} () VALUES ()"
|
315
359
|
end
|
316
360
|
|
361
|
+
def complex_expression_sql(op, args)
|
362
|
+
case op
|
363
|
+
when :~, :'!~'
|
364
|
+
"#{'NOT ' if op == :'!~'}(#{literal(args.at(0))} REGEXP BINARY #{literal(args.at(1))})"
|
365
|
+
when :'~*', :'!~*'
|
366
|
+
"#{'NOT ' if op == :'!~*'}(#{literal(args.at(0))} REGEXP #{literal(args.at(1))})"
|
367
|
+
when :'||'
|
368
|
+
if args.length > 1
|
369
|
+
"CONCAT(#{args.collect{|a| literal(a)}.join(', ')})"
|
370
|
+
else
|
371
|
+
literal(args.at(0))
|
372
|
+
end
|
373
|
+
else
|
374
|
+
super(op, args)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
317
378
|
def match_expr(l, r)
|
318
379
|
case r
|
319
380
|
when Regexp
|
@@ -352,7 +413,7 @@ module Sequel
|
|
352
413
|
end
|
353
414
|
|
354
415
|
if where = opts[:where]
|
355
|
-
sql << " WHERE #{where}"
|
416
|
+
sql << " WHERE #{literal(where)}"
|
356
417
|
end
|
357
418
|
|
358
419
|
if group = opts[:group]
|
@@ -360,7 +421,7 @@ module Sequel
|
|
360
421
|
end
|
361
422
|
|
362
423
|
if having = opts[:having]
|
363
|
-
sql << " HAVING #{having}"
|
424
|
+
sql << " HAVING #{literal(having)}"
|
364
425
|
end
|
365
426
|
|
366
427
|
if order = opts[:order]
|
@@ -391,13 +452,22 @@ module Sequel
|
|
391
452
|
|
392
453
|
def full_text_search(cols, terms, opts = {})
|
393
454
|
mode = opts[:boolean] ? " IN BOOLEAN MODE" : ""
|
394
|
-
|
455
|
+
s = if Array === terms
|
456
|
+
if mode.blank?
|
457
|
+
"MATCH #{literal(Array(cols))} AGAINST #{literal(terms)}"
|
458
|
+
else
|
459
|
+
"MATCH #{literal(Array(cols))} AGAINST (#{literal(terms)[1...-1]}#{mode})"
|
460
|
+
end
|
461
|
+
else
|
462
|
+
"MATCH #{literal(Array(cols))} AGAINST (#{literal(terms)}#{mode})"
|
463
|
+
end
|
464
|
+
filter(s)
|
395
465
|
end
|
396
466
|
|
397
467
|
# MySQL allows HAVING clause on ungrouped datasets.
|
398
468
|
def having(*cond, &block)
|
399
469
|
@opts[:having] = {}
|
400
|
-
filter(*cond, &block)
|
470
|
+
x = filter(*cond, &block)
|
401
471
|
end
|
402
472
|
|
403
473
|
# MySQL supports ORDER and LIMIT clauses in UPDATE statements.
|
@@ -431,12 +501,8 @@ module Sequel
|
|
431
501
|
when Array
|
432
502
|
if values.empty?
|
433
503
|
"REPLACE INTO #{from} DEFAULT VALUES"
|
434
|
-
elsif values.keys
|
435
|
-
fl = values.keys.map {|f| literal(f.is_a?(String) ? f.to_sym : f)}
|
436
|
-
vl = values.values.map {|v| literal(v)}
|
437
|
-
"REPLACE INTO #{from} (#{fl.join(COMMA_SEPARATOR)}) VALUES (#{vl.join(COMMA_SEPARATOR)})"
|
438
504
|
else
|
439
|
-
"REPLACE INTO #{from} VALUES
|
505
|
+
"REPLACE INTO #{from} VALUES #{literal(values)}"
|
440
506
|
end
|
441
507
|
when Hash
|
442
508
|
if values.empty?
|
@@ -498,8 +564,8 @@ module Sequel
|
|
498
564
|
end
|
499
565
|
|
500
566
|
def multi_insert_sql(columns, values)
|
501
|
-
columns =
|
502
|
-
values = values.map {|r|
|
567
|
+
columns = column_list(columns)
|
568
|
+
values = values.map {|r| literal(Array(r))}.join(COMMA_SEPARATOR)
|
503
569
|
["INSERT INTO #{source_list(@opts[:from])} (#{columns}) VALUES #{values}"]
|
504
570
|
end
|
505
571
|
end
|
@@ -46,14 +46,14 @@ module Sequel
|
|
46
46
|
# fetch_rows method source code for an example of how to drop
|
47
47
|
# the statements.
|
48
48
|
def execute(sql)
|
49
|
-
|
49
|
+
log_info(sql)
|
50
50
|
@pool.hold do |conn|
|
51
51
|
conn.run(sql)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
55
|
def do(sql)
|
56
|
-
|
56
|
+
log_info(sql)
|
57
57
|
@pool.hold do |conn|
|
58
58
|
conn.do(sql)
|
59
59
|
end
|
@@ -74,12 +74,10 @@ module Sequel
|
|
74
74
|
BOOL_TRUE
|
75
75
|
when false
|
76
76
|
BOOL_FALSE
|
77
|
-
when Time
|
77
|
+
when Time, DateTime
|
78
78
|
formatted = v.strftime(ODBC_TIMESTAMP_FORMAT)
|
79
|
-
|
80
|
-
|
81
|
-
formatted.insert ODBC_TIMESTAMP_AFTER_SECONDS, ".#{msec}"
|
82
|
-
end
|
79
|
+
usec = (Time === v ? v.usec : (v.sec_fraction * 86400000000))
|
80
|
+
formatted.insert(ODBC_TIMESTAMP_AFTER_SECONDS, ".#{(usec.to_f/1000).round}") if usec >= 1000
|
83
81
|
formatted
|
84
82
|
when Date
|
85
83
|
v.strftime(ODBC_DATE_FORMAT)
|
@@ -58,7 +58,7 @@ module Sequel
|
|
58
58
|
end
|
59
59
|
|
60
60
|
if where = opts[:where]
|
61
|
-
sql << " WHERE #{where}"
|
61
|
+
sql << " WHERE #{literal(where)}"
|
62
62
|
end
|
63
63
|
|
64
64
|
if group = opts[:group]
|
@@ -70,7 +70,7 @@ module Sequel
|
|
70
70
|
end
|
71
71
|
|
72
72
|
if having = opts[:having]
|
73
|
-
sql << " HAVING #{having}"
|
73
|
+
sql << " HAVING #{literal(having)}"
|
74
74
|
end
|
75
75
|
|
76
76
|
if union = opts[:union]
|
@@ -91,7 +91,16 @@ module Sequel
|
|
91
91
|
def full_text_search(cols, terms, opts = {})
|
92
92
|
filter("CONTAINS (#{literal(cols)}, #{literal(terms)})")
|
93
93
|
end
|
94
|
+
|
95
|
+
def complex_expression_sql(op, args)
|
96
|
+
case op
|
97
|
+
when :'||'
|
98
|
+
super(:+, args)
|
99
|
+
else
|
100
|
+
super(op, args)
|
101
|
+
end
|
102
|
+
end
|
94
103
|
end
|
95
104
|
end
|
96
105
|
end
|
97
|
-
end
|
106
|
+
end
|