sequel 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1551 -4
- data/README +306 -19
- data/Rakefile +84 -56
- data/bin/sequel +106 -0
- data/doc/cheat_sheet.rdoc +225 -0
- data/doc/dataset_filtering.rdoc +182 -0
- data/lib/sequel_core.rb +136 -0
- data/lib/sequel_core/adapters/adapter_skeleton.rb +54 -0
- data/lib/sequel_core/adapters/ado.rb +80 -0
- data/lib/sequel_core/adapters/db2.rb +148 -0
- data/lib/sequel_core/adapters/dbi.rb +117 -0
- data/lib/sequel_core/adapters/informix.rb +78 -0
- data/lib/sequel_core/adapters/jdbc.rb +186 -0
- data/lib/sequel_core/adapters/jdbc/mysql.rb +55 -0
- data/lib/sequel_core/adapters/jdbc/postgresql.rb +66 -0
- data/lib/sequel_core/adapters/jdbc/sqlite.rb +47 -0
- data/lib/sequel_core/adapters/mysql.rb +231 -0
- data/lib/sequel_core/adapters/odbc.rb +155 -0
- data/lib/sequel_core/adapters/odbc_mssql.rb +106 -0
- data/lib/sequel_core/adapters/openbase.rb +64 -0
- data/lib/sequel_core/adapters/oracle.rb +170 -0
- data/lib/sequel_core/adapters/postgres.rb +199 -0
- data/lib/sequel_core/adapters/shared/mysql.rb +275 -0
- data/lib/sequel_core/adapters/shared/postgres.rb +351 -0
- data/lib/sequel_core/adapters/shared/sqlite.rb +146 -0
- data/lib/sequel_core/adapters/sqlite.rb +138 -0
- data/lib/sequel_core/connection_pool.rb +194 -0
- data/lib/sequel_core/core_ext.rb +203 -0
- data/lib/sequel_core/core_sql.rb +184 -0
- data/lib/sequel_core/database.rb +471 -0
- data/lib/sequel_core/database/schema.rb +156 -0
- data/lib/sequel_core/dataset.rb +457 -0
- data/lib/sequel_core/dataset/callback.rb +13 -0
- data/lib/sequel_core/dataset/convenience.rb +245 -0
- data/lib/sequel_core/dataset/pagination.rb +96 -0
- data/lib/sequel_core/dataset/query.rb +41 -0
- data/lib/sequel_core/dataset/schema.rb +15 -0
- data/lib/sequel_core/dataset/sql.rb +889 -0
- data/lib/sequel_core/deprecated.rb +26 -0
- data/lib/sequel_core/exceptions.rb +42 -0
- data/lib/sequel_core/migration.rb +187 -0
- data/lib/sequel_core/object_graph.rb +216 -0
- data/lib/sequel_core/pretty_table.rb +71 -0
- data/lib/sequel_core/schema.rb +2 -0
- data/lib/sequel_core/schema/generator.rb +239 -0
- data/lib/sequel_core/schema/sql.rb +325 -0
- data/lib/sequel_core/sql.rb +812 -0
- data/lib/sequel_model.rb +5 -1
- data/lib/sequel_model/association_reflection.rb +3 -8
- data/lib/sequel_model/base.rb +15 -10
- data/lib/sequel_model/inflector.rb +3 -5
- data/lib/sequel_model/plugins.rb +1 -1
- data/lib/sequel_model/record.rb +11 -3
- data/lib/sequel_model/schema.rb +4 -4
- data/lib/sequel_model/validations.rb +6 -1
- data/spec/adapters/ado_spec.rb +17 -0
- data/spec/adapters/informix_spec.rb +96 -0
- data/spec/adapters/mysql_spec.rb +764 -0
- data/spec/adapters/oracle_spec.rb +222 -0
- data/spec/adapters/postgres_spec.rb +441 -0
- data/spec/adapters/spec_helper.rb +7 -0
- data/spec/adapters/sqlite_spec.rb +400 -0
- data/spec/integration/dataset_test.rb +51 -0
- data/spec/integration/eager_loader_test.rb +702 -0
- data/spec/integration/schema_test.rb +102 -0
- data/spec/integration/spec_helper.rb +44 -0
- data/spec/integration/type_test.rb +43 -0
- data/spec/rcov.opts +2 -0
- data/spec/sequel_core/connection_pool_spec.rb +363 -0
- data/spec/sequel_core/core_ext_spec.rb +156 -0
- data/spec/sequel_core/core_sql_spec.rb +427 -0
- data/spec/sequel_core/database_spec.rb +964 -0
- data/spec/sequel_core/dataset_spec.rb +2977 -0
- data/spec/sequel_core/expression_filters_spec.rb +346 -0
- data/spec/sequel_core/migration_spec.rb +261 -0
- data/spec/sequel_core/object_graph_spec.rb +234 -0
- data/spec/sequel_core/pretty_table_spec.rb +58 -0
- data/spec/sequel_core/schema_generator_spec.rb +122 -0
- data/spec/sequel_core/schema_spec.rb +497 -0
- data/spec/sequel_core/spec_helper.rb +51 -0
- data/spec/{association_reflection_spec.rb → sequel_model/association_reflection_spec.rb} +6 -6
- data/spec/{associations_spec.rb → sequel_model/associations_spec.rb} +47 -18
- data/spec/{base_spec.rb → sequel_model/base_spec.rb} +2 -1
- data/spec/{caching_spec.rb → sequel_model/caching_spec.rb} +0 -0
- data/spec/{dataset_methods_spec.rb → sequel_model/dataset_methods_spec.rb} +13 -1
- data/spec/{eager_loading_spec.rb → sequel_model/eager_loading_spec.rb} +75 -14
- data/spec/{hooks_spec.rb → sequel_model/hooks_spec.rb} +4 -4
- data/spec/sequel_model/inflector_spec.rb +119 -0
- data/spec/{model_spec.rb → sequel_model/model_spec.rb} +30 -11
- data/spec/{plugins_spec.rb → sequel_model/plugins_spec.rb} +0 -0
- data/spec/{record_spec.rb → sequel_model/record_spec.rb} +47 -6
- data/spec/{schema_spec.rb → sequel_model/schema_spec.rb} +18 -4
- data/spec/{spec_helper.rb → sequel_model/spec_helper.rb} +3 -2
- data/spec/{validations_spec.rb → sequel_model/validations_spec.rb} +37 -17
- data/spec/spec_config.rb +9 -0
- data/spec/spec_config.rb.example +10 -0
- metadata +110 -37
- data/spec/inflector_spec.rb +0 -34
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'odbc'
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
module ODBC
|
5
|
+
class Database < Sequel::Database
|
6
|
+
set_adapter_scheme :odbc
|
7
|
+
|
8
|
+
# def connect
|
9
|
+
# conn = ::ODBC::connect(@opts[:database], @opts[:user], @opts[:password])
|
10
|
+
# conn.autocommit = true
|
11
|
+
# conn
|
12
|
+
# end
|
13
|
+
|
14
|
+
GUARDED_DRV_NAME = /^\{.+\}$/.freeze
|
15
|
+
DRV_NAME_GUARDS = '{%s}'.freeze
|
16
|
+
|
17
|
+
def connect
|
18
|
+
if @opts.include? :driver
|
19
|
+
drv = ::ODBC::Driver.new
|
20
|
+
drv.name = 'Sequel ODBC Driver130'
|
21
|
+
@opts.each do |param, value|
|
22
|
+
if :driver == param and not (value =~ GUARDED_DRV_NAME)
|
23
|
+
value = DRV_NAME_GUARDS % value
|
24
|
+
end
|
25
|
+
drv.attrs[param.to_s.capitalize] = value
|
26
|
+
end
|
27
|
+
db = ::ODBC::Database.new
|
28
|
+
conn = db.drvconnect(drv)
|
29
|
+
else
|
30
|
+
conn = ::ODBC::connect(@opts[:database], @opts[:user], @opts[:password])
|
31
|
+
end
|
32
|
+
conn.autocommit = true
|
33
|
+
conn
|
34
|
+
end
|
35
|
+
|
36
|
+
def disconnect
|
37
|
+
@pool.disconnect {|c| c.disconnect}
|
38
|
+
end
|
39
|
+
|
40
|
+
def dataset(opts = nil)
|
41
|
+
ODBC::Dataset.new(self, opts)
|
42
|
+
end
|
43
|
+
|
44
|
+
# ODBC returns native statement objects, which must be dropped if
|
45
|
+
# you call execute manually, or you will get warnings. See the
|
46
|
+
# fetch_rows method source code for an example of how to drop
|
47
|
+
# the statements.
|
48
|
+
def execute(sql)
|
49
|
+
log_info(sql)
|
50
|
+
@pool.hold do |conn|
|
51
|
+
conn.run(sql)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def do(sql)
|
56
|
+
log_info(sql)
|
57
|
+
@pool.hold do |conn|
|
58
|
+
conn.do(sql)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
alias_method :execute_dui, :do
|
62
|
+
end
|
63
|
+
|
64
|
+
class Dataset < Sequel::Dataset
|
65
|
+
BOOL_TRUE = '1'.freeze
|
66
|
+
BOOL_FALSE = '0'.freeze
|
67
|
+
ODBC_TIMESTAMP_FORMAT = "{ts '%Y-%m-%d %H:%M:%S'}".freeze
|
68
|
+
ODBC_TIMESTAMP_AFTER_SECONDS =
|
69
|
+
ODBC_TIMESTAMP_FORMAT.index( '%S' ).succ - ODBC_TIMESTAMP_FORMAT.length
|
70
|
+
ODBC_DATE_FORMAT = "{d '%Y-%m-%d'}".freeze
|
71
|
+
|
72
|
+
def literal(v)
|
73
|
+
case v
|
74
|
+
when true
|
75
|
+
BOOL_TRUE
|
76
|
+
when false
|
77
|
+
BOOL_FALSE
|
78
|
+
when Time, DateTime
|
79
|
+
formatted = v.strftime(ODBC_TIMESTAMP_FORMAT)
|
80
|
+
usec = (Time === v ? v.usec : (v.sec_fraction * 86400000000))
|
81
|
+
formatted.insert(ODBC_TIMESTAMP_AFTER_SECONDS, ".#{(usec.to_f/1000).round}") if usec >= 1000
|
82
|
+
formatted
|
83
|
+
when Date
|
84
|
+
v.strftime(ODBC_DATE_FORMAT)
|
85
|
+
else
|
86
|
+
super
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
UNTITLED_COLUMN = 'untitled_%d'.freeze
|
91
|
+
|
92
|
+
def fetch_rows(sql, &block)
|
93
|
+
@db.synchronize do
|
94
|
+
s = @db.execute sql
|
95
|
+
begin
|
96
|
+
untitled_count = 0
|
97
|
+
@columns = s.columns(true).map do |c|
|
98
|
+
if (n = c.name).empty?
|
99
|
+
n = UNTITLED_COLUMN % (untitled_count += 1)
|
100
|
+
end
|
101
|
+
n.to_sym
|
102
|
+
end
|
103
|
+
rows = s.fetch_all
|
104
|
+
rows.each {|row| yield hash_row(row)} if rows
|
105
|
+
ensure
|
106
|
+
s.drop unless s.nil? rescue nil
|
107
|
+
end
|
108
|
+
end
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
# def fetch_rows(sql, &block)
|
113
|
+
# @db.synchronize do
|
114
|
+
# s = @db.execute sql
|
115
|
+
# begin
|
116
|
+
# @columns = s.columns(true).map {|c| c.name.to_sym}
|
117
|
+
# rows = s.fetch_all
|
118
|
+
# rows.each {|row| yield hash_row(row)}
|
119
|
+
# ensure
|
120
|
+
# s.drop unless s.nil? rescue nil
|
121
|
+
# end
|
122
|
+
# end
|
123
|
+
# self
|
124
|
+
# end
|
125
|
+
|
126
|
+
def hash_row(row)
|
127
|
+
hash = {}
|
128
|
+
row.each_with_index do |v, idx|
|
129
|
+
hash[@columns[idx]] = convert_odbc_value(v)
|
130
|
+
end
|
131
|
+
hash
|
132
|
+
end
|
133
|
+
|
134
|
+
def convert_odbc_value(v)
|
135
|
+
# When fetching a result set, the Ruby ODBC driver converts all ODBC
|
136
|
+
# SQL types to an equivalent Ruby type; with the exception of
|
137
|
+
# SQL_TYPE_DATE, SQL_TYPE_TIME and SQL_TYPE_TIMESTAMP.
|
138
|
+
#
|
139
|
+
# The conversions below are consistent with the mappings in
|
140
|
+
# ODBCColumn#mapSqlTypeToGenericType and Column#klass.
|
141
|
+
case v
|
142
|
+
when ::ODBC::TimeStamp
|
143
|
+
DateTime.new(v.year, v.month, v.day, v.hour, v.minute, v.second)
|
144
|
+
when ::ODBC::Time
|
145
|
+
now = DateTime.now
|
146
|
+
Time.gm(now.year, now.month, now.day, v.hour, v.minute, v.second)
|
147
|
+
when ::ODBC::Date
|
148
|
+
Date.new(v.year, v.month, v.day)
|
149
|
+
else
|
150
|
+
v
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
if !Sequel.const_defined?('ODBC')
|
2
|
+
require File.join(File.dirname(__FILE__), 'odbc')
|
3
|
+
end
|
4
|
+
|
5
|
+
module Sequel
|
6
|
+
module ODBC
|
7
|
+
module MSSQL
|
8
|
+
class Database < ODBC::Database
|
9
|
+
set_adapter_scheme :odbc_mssql
|
10
|
+
|
11
|
+
def dataset(opts = nil)
|
12
|
+
MSSQL::Dataset.new(self, opts)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Dataset < ODBC::Dataset
|
17
|
+
# Allows you to do .nolock on a query
|
18
|
+
def nolock
|
19
|
+
clone(:with => "(NOLOCK)")
|
20
|
+
end
|
21
|
+
|
22
|
+
# Formats a SELECT statement using the given options and the dataset
|
23
|
+
# options.
|
24
|
+
def select_sql(opts = nil)
|
25
|
+
opts = opts ? @opts.merge(opts) : @opts
|
26
|
+
|
27
|
+
if sql = opts[:sql]
|
28
|
+
return sql
|
29
|
+
end
|
30
|
+
|
31
|
+
# ADD TOP to SELECT string for LIMITS
|
32
|
+
if limit = opts[:limit]
|
33
|
+
top = "TOP #{limit} "
|
34
|
+
raise Error, "Offset not supported" if opts[:offset]
|
35
|
+
end
|
36
|
+
|
37
|
+
columns = opts[:select]
|
38
|
+
select_columns = columns ? column_list(columns) : WILDCARD
|
39
|
+
|
40
|
+
if distinct = opts[:distinct]
|
41
|
+
distinct_clause = distinct.empty? ? "DISTINCT" : "DISTINCT ON (#{expression_list(distinct)})"
|
42
|
+
sql = "SELECT #{top}#{distinct_clause} #{select_columns}"
|
43
|
+
else
|
44
|
+
sql = "SELECT #{top}#{select_columns}"
|
45
|
+
end
|
46
|
+
|
47
|
+
if opts[:from]
|
48
|
+
sql << " FROM #{source_list(opts[:from])}"
|
49
|
+
end
|
50
|
+
|
51
|
+
# ADD WITH to SELECT string for NOLOCK
|
52
|
+
if with = opts[:with]
|
53
|
+
sql << " WITH #{with}"
|
54
|
+
end
|
55
|
+
|
56
|
+
if join = opts[:join]
|
57
|
+
join.each{|j| sql << literal(j)}
|
58
|
+
end
|
59
|
+
|
60
|
+
if where = opts[:where]
|
61
|
+
sql << " WHERE #{literal(where)}"
|
62
|
+
end
|
63
|
+
|
64
|
+
if group = opts[:group]
|
65
|
+
sql << " GROUP BY #{expression_list(group)}"
|
66
|
+
end
|
67
|
+
|
68
|
+
if order = opts[:order]
|
69
|
+
sql << " ORDER BY #{expression_list(order)}"
|
70
|
+
end
|
71
|
+
|
72
|
+
if having = opts[:having]
|
73
|
+
sql << " HAVING #{literal(having)}"
|
74
|
+
end
|
75
|
+
|
76
|
+
if union = opts[:union]
|
77
|
+
sql << (opts[:union_all] ? \
|
78
|
+
" UNION ALL #{union.sql}" : " UNION #{union.sql}")
|
79
|
+
elsif intersect = opts[:intersect]
|
80
|
+
sql << (opts[:intersect_all] ? \
|
81
|
+
" INTERSECT ALL #{intersect.sql}" : " INTERSECT #{intersect.sql}")
|
82
|
+
elsif except = opts[:except]
|
83
|
+
sql << (opts[:except_all] ? \
|
84
|
+
" EXCEPT ALL #{except.sql}" : " EXCEPT #{except.sql}")
|
85
|
+
end
|
86
|
+
|
87
|
+
sql
|
88
|
+
end
|
89
|
+
alias_method :sql, :select_sql
|
90
|
+
|
91
|
+
def full_text_search(cols, terms, opts = {})
|
92
|
+
filter("CONTAINS (#{literal(cols)}, #{literal(terms)})")
|
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
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'openbase'
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
module OpenBase
|
5
|
+
class Database < Sequel::Database
|
6
|
+
set_adapter_scheme :openbase
|
7
|
+
|
8
|
+
def connect
|
9
|
+
OpenBase.new(
|
10
|
+
opts[:database],
|
11
|
+
opts[:host] || 'localhost',
|
12
|
+
opts[:user],
|
13
|
+
opts[:password]
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
def disconnect
|
18
|
+
# would this work?
|
19
|
+
@pool.disconnect {|c| c.disconnect}
|
20
|
+
end
|
21
|
+
|
22
|
+
def dataset(opts = nil)
|
23
|
+
OpenBase::Dataset.new(self, opts)
|
24
|
+
end
|
25
|
+
|
26
|
+
def execute(sql)
|
27
|
+
log_info(sql)
|
28
|
+
@pool.hold {|conn| conn.execute(sql)}
|
29
|
+
end
|
30
|
+
|
31
|
+
alias_method :do, :execute
|
32
|
+
end
|
33
|
+
|
34
|
+
class Dataset < Sequel::Dataset
|
35
|
+
def literal(v)
|
36
|
+
case v
|
37
|
+
when Time
|
38
|
+
literal(v.iso8601)
|
39
|
+
when Date, DateTime
|
40
|
+
literal(v.to_s)
|
41
|
+
else
|
42
|
+
super
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def fetch_rows(sql, &block)
|
47
|
+
@db.synchronize do
|
48
|
+
result = @db.execute sql
|
49
|
+
begin
|
50
|
+
@columns = result.column_infos.map {|c| c.name.to_sym}
|
51
|
+
result.each do |r|
|
52
|
+
row = {}
|
53
|
+
r.each_with_index {|v, i| row[@columns[i]] = v}
|
54
|
+
yield row
|
55
|
+
end
|
56
|
+
ensure
|
57
|
+
# result.close
|
58
|
+
end
|
59
|
+
end
|
60
|
+
self
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
require 'oci8'
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
module Oracle
|
5
|
+
class Database < Sequel::Database
|
6
|
+
set_adapter_scheme :oracle
|
7
|
+
|
8
|
+
# AUTO_INCREMENT = 'IDENTITY(1,1)'.freeze
|
9
|
+
#
|
10
|
+
# def auto_increment_sql
|
11
|
+
# AUTO_INCREMENT
|
12
|
+
# end
|
13
|
+
|
14
|
+
def connect
|
15
|
+
if @opts[:database]
|
16
|
+
dbname = @opts[:host] ? \
|
17
|
+
"//#{@opts[:host]}#{":#{@opts[:port]}" if @opts[:port]}/#{@opts[:database]}" : @opts[:database]
|
18
|
+
else
|
19
|
+
dbname = @opts[:host]
|
20
|
+
end
|
21
|
+
conn = OCI8.new(@opts[:user], @opts[:password], dbname, @opts[:privilege])
|
22
|
+
conn.autocommit = true
|
23
|
+
conn.non_blocking = true
|
24
|
+
conn
|
25
|
+
end
|
26
|
+
|
27
|
+
def disconnect
|
28
|
+
@pool.disconnect {|c| c.logoff}
|
29
|
+
end
|
30
|
+
|
31
|
+
def dataset(opts = nil)
|
32
|
+
Oracle::Dataset.new(self, opts)
|
33
|
+
end
|
34
|
+
|
35
|
+
def execute(sql)
|
36
|
+
log_info(sql)
|
37
|
+
@pool.hold {|conn| conn.exec(sql)}
|
38
|
+
end
|
39
|
+
|
40
|
+
alias_method :do, :execute
|
41
|
+
|
42
|
+
def tables
|
43
|
+
from(:tab).select(:tname).filter(:tabtype => 'TABLE').map do |r|
|
44
|
+
r[:tname].downcase.to_sym
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def table_exists?(name)
|
49
|
+
from(:tab).filter(:tname => name.to_s.upcase, :tabtype => 'TABLE').count > 0
|
50
|
+
end
|
51
|
+
|
52
|
+
def transaction
|
53
|
+
@pool.hold do |conn|
|
54
|
+
@transactions ||= []
|
55
|
+
if @transactions.include? Thread.current
|
56
|
+
return yield(conn)
|
57
|
+
end
|
58
|
+
|
59
|
+
conn.autocommit = false
|
60
|
+
begin
|
61
|
+
@transactions << Thread.current
|
62
|
+
yield(conn)
|
63
|
+
rescue => e
|
64
|
+
conn.rollback
|
65
|
+
raise e unless Error::Rollback === e
|
66
|
+
ensure
|
67
|
+
conn.commit unless e
|
68
|
+
conn.autocommit = true
|
69
|
+
@transactions.delete(Thread.current)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class Dataset < Sequel::Dataset
|
76
|
+
def literal(v)
|
77
|
+
case v
|
78
|
+
when OraDate
|
79
|
+
literal(Time.local(*v.to_a))
|
80
|
+
else
|
81
|
+
super
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def fetch_rows(sql, &block)
|
86
|
+
@db.synchronize do
|
87
|
+
cursor = @db.execute sql
|
88
|
+
begin
|
89
|
+
@columns = cursor.get_col_names.map {|c| c.downcase.to_sym}
|
90
|
+
while r = cursor.fetch
|
91
|
+
row = {}
|
92
|
+
r.each_with_index {|v, i| row[columns[i]] = v unless columns[i] == :raw_rnum_}
|
93
|
+
yield row
|
94
|
+
end
|
95
|
+
ensure
|
96
|
+
cursor.close
|
97
|
+
end
|
98
|
+
end
|
99
|
+
self
|
100
|
+
end
|
101
|
+
|
102
|
+
def empty?
|
103
|
+
db[:dual].where(exists).get(1) == nil
|
104
|
+
end
|
105
|
+
|
106
|
+
# Formats a SELECT statement using the given options and the dataset
|
107
|
+
# options.
|
108
|
+
def select_sql(opts = nil)
|
109
|
+
opts = opts ? @opts.merge(opts) : @opts
|
110
|
+
|
111
|
+
if sql = opts[:sql]
|
112
|
+
return sql
|
113
|
+
end
|
114
|
+
|
115
|
+
columns = opts[:select]
|
116
|
+
select_columns = columns ? column_list(columns) : WILDCARD
|
117
|
+
sql = opts[:distinct] ? \
|
118
|
+
"SELECT DISTINCT #{select_columns}" : \
|
119
|
+
"SELECT #{select_columns}"
|
120
|
+
|
121
|
+
if opts[:from]
|
122
|
+
sql << " FROM #{source_list(opts[:from])}"
|
123
|
+
end
|
124
|
+
|
125
|
+
if join = opts[:join]
|
126
|
+
join.each{|j| sql << literal(j)}
|
127
|
+
end
|
128
|
+
|
129
|
+
if where = opts[:where]
|
130
|
+
sql << " WHERE #{literal(where)}"
|
131
|
+
end
|
132
|
+
|
133
|
+
if group = opts[:group]
|
134
|
+
sql << " GROUP BY #{expression_list(group)}"
|
135
|
+
end
|
136
|
+
|
137
|
+
if having = opts[:having]
|
138
|
+
sql << " HAVING #{literal(having)}"
|
139
|
+
end
|
140
|
+
|
141
|
+
if union = opts[:union]
|
142
|
+
sql << (opts[:union_all] ? \
|
143
|
+
" UNION ALL #{union.sql}" : " UNION #{union.sql}")
|
144
|
+
elsif intersect = opts[:intersect]
|
145
|
+
sql << (opts[:intersect_all] ? \
|
146
|
+
" INTERSECT ALL #{intersect.sql}" : " INTERSECT #{intersect.sql}")
|
147
|
+
elsif except = opts[:except]
|
148
|
+
sql << (opts[:except_all] ? \
|
149
|
+
" EXCEPT ALL #{except.sql}" : " EXCEPT #{except.sql}")
|
150
|
+
end
|
151
|
+
|
152
|
+
if order = opts[:order]
|
153
|
+
sql << " ORDER BY #{expression_list(order)}"
|
154
|
+
end
|
155
|
+
|
156
|
+
if limit = opts[:limit]
|
157
|
+
if (offset = opts[:offset]) && (offset > 0)
|
158
|
+
sql = "SELECT * FROM (SELECT raw_sql_.*, ROWNUM raw_rnum_ FROM(#{sql}) raw_sql_ WHERE ROWNUM <= #{limit + offset}) WHERE raw_rnum_ > #{offset}"
|
159
|
+
else
|
160
|
+
sql = "SELECT * FROM (#{sql}) WHERE ROWNUM <= #{limit}"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
sql
|
165
|
+
end
|
166
|
+
|
167
|
+
alias sql select_sql
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|