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.
- metadata +30 -101
- data/CHANGELOG +0 -1519
- data/COPYING +0 -19
- data/README +0 -313
- data/Rakefile +0 -158
- data/bin/sequel +0 -117
- data/doc/cheat_sheet.rdoc +0 -225
- data/doc/dataset_filtering.rdoc +0 -182
- data/lib/sequel_core.rb +0 -136
- data/lib/sequel_core/adapters/adapter_skeleton.rb +0 -68
- data/lib/sequel_core/adapters/ado.rb +0 -90
- data/lib/sequel_core/adapters/db2.rb +0 -160
- data/lib/sequel_core/adapters/dbi.rb +0 -127
- data/lib/sequel_core/adapters/informix.rb +0 -89
- data/lib/sequel_core/adapters/jdbc.rb +0 -110
- data/lib/sequel_core/adapters/mysql.rb +0 -486
- data/lib/sequel_core/adapters/odbc.rb +0 -167
- data/lib/sequel_core/adapters/odbc_mssql.rb +0 -106
- data/lib/sequel_core/adapters/openbase.rb +0 -76
- data/lib/sequel_core/adapters/oracle.rb +0 -182
- data/lib/sequel_core/adapters/postgres.rb +0 -560
- data/lib/sequel_core/adapters/sqlite.rb +0 -270
- data/lib/sequel_core/connection_pool.rb +0 -194
- data/lib/sequel_core/core_ext.rb +0 -197
- data/lib/sequel_core/core_sql.rb +0 -184
- data/lib/sequel_core/database.rb +0 -462
- data/lib/sequel_core/database/schema.rb +0 -156
- data/lib/sequel_core/dataset.rb +0 -457
- data/lib/sequel_core/dataset/callback.rb +0 -13
- data/lib/sequel_core/dataset/convenience.rb +0 -245
- data/lib/sequel_core/dataset/pagination.rb +0 -96
- data/lib/sequel_core/dataset/query.rb +0 -41
- data/lib/sequel_core/dataset/schema.rb +0 -15
- data/lib/sequel_core/dataset/sql.rb +0 -889
- data/lib/sequel_core/deprecated.rb +0 -26
- data/lib/sequel_core/exceptions.rb +0 -42
- data/lib/sequel_core/migration.rb +0 -187
- data/lib/sequel_core/object_graph.rb +0 -216
- data/lib/sequel_core/pretty_table.rb +0 -71
- data/lib/sequel_core/schema.rb +0 -2
- data/lib/sequel_core/schema/generator.rb +0 -239
- data/lib/sequel_core/schema/sql.rb +0 -326
- data/lib/sequel_core/sql.rb +0 -812
- data/lib/sequel_core/worker.rb +0 -68
- data/spec/adapters/informix_spec.rb +0 -96
- data/spec/adapters/mysql_spec.rb +0 -765
- data/spec/adapters/oracle_spec.rb +0 -222
- data/spec/adapters/postgres_spec.rb +0 -441
- data/spec/adapters/sqlite_spec.rb +0 -413
- data/spec/connection_pool_spec.rb +0 -363
- data/spec/core_ext_spec.rb +0 -156
- data/spec/core_sql_spec.rb +0 -427
- data/spec/database_spec.rb +0 -963
- data/spec/dataset_spec.rb +0 -2933
- data/spec/expression_filters_spec.rb +0 -316
- data/spec/migration_spec.rb +0 -261
- data/spec/object_graph_spec.rb +0 -230
- data/spec/pretty_table_spec.rb +0 -58
- data/spec/rcov.opts +0 -6
- data/spec/schema_generator_spec.rb +0 -122
- data/spec/schema_spec.rb +0 -422
- data/spec/spec.opts +0 -0
- data/spec/spec_config.rb +0 -7
- data/spec/spec_config.rb.example +0 -8
- data/spec/spec_helper.rb +0 -55
- 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
|