sequel 2.6.0 → 2.7.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 +64 -0
- data/Rakefile +1 -1
- data/lib/sequel_core/adapters/jdbc.rb +6 -2
- data/lib/sequel_core/adapters/jdbc/oracle.rb +23 -0
- data/lib/sequel_core/adapters/oracle.rb +4 -77
- data/lib/sequel_core/adapters/postgres.rb +39 -26
- data/lib/sequel_core/adapters/shared/mssql.rb +0 -1
- data/lib/sequel_core/adapters/shared/mysql.rb +1 -1
- data/lib/sequel_core/adapters/shared/oracle.rb +82 -0
- data/lib/sequel_core/adapters/shared/postgres.rb +65 -46
- data/lib/sequel_core/core_ext.rb +10 -0
- data/lib/sequel_core/core_sql.rb +7 -0
- data/lib/sequel_core/database.rb +22 -0
- data/lib/sequel_core/database/schema.rb +1 -1
- data/lib/sequel_core/dataset.rb +29 -11
- data/lib/sequel_core/dataset/sql.rb +27 -7
- data/lib/sequel_core/migration.rb +20 -2
- data/lib/sequel_core/object_graph.rb +24 -10
- data/lib/sequel_core/schema/generator.rb +22 -9
- data/lib/sequel_core/schema/sql.rb +13 -9
- data/lib/sequel_core/sql.rb +27 -2
- data/lib/sequel_model/association_reflection.rb +251 -141
- data/lib/sequel_model/associations.rb +114 -61
- data/lib/sequel_model/base.rb +25 -21
- data/lib/sequel_model/eager_loading.rb +17 -40
- data/lib/sequel_model/hooks.rb +25 -24
- data/lib/sequel_model/record.rb +29 -51
- data/lib/sequel_model/schema.rb +1 -1
- data/lib/sequel_model/validations.rb +13 -3
- data/spec/adapters/postgres_spec.rb +104 -18
- data/spec/adapters/spec_helper.rb +4 -1
- data/spec/integration/eager_loader_test.rb +5 -4
- data/spec/integration/spec_helper.rb +4 -1
- data/spec/sequel_core/connection_pool_spec.rb +24 -24
- data/spec/sequel_core/core_sql_spec.rb +12 -0
- data/spec/sequel_core/dataset_spec.rb +77 -2
- data/spec/sequel_core/expression_filters_spec.rb +6 -0
- data/spec/sequel_core/object_graph_spec.rb +40 -2
- data/spec/sequel_core/schema_spec.rb +13 -0
- data/spec/sequel_model/association_reflection_spec.rb +8 -8
- data/spec/sequel_model/associations_spec.rb +164 -3
- data/spec/sequel_model/caching_spec.rb +2 -1
- data/spec/sequel_model/eager_loading_spec.rb +107 -3
- data/spec/sequel_model/hooks_spec.rb +38 -22
- data/spec/sequel_model/model_spec.rb +11 -35
- data/spec/sequel_model/plugins_spec.rb +4 -2
- data/spec/sequel_model/record_spec.rb +8 -5
- data/spec/sequel_model/validations_spec.rb +25 -0
- data/spec/spec_config.rb +4 -3
- metadata +21 -19
data/CHANGELOG
CHANGED
@@ -1,3 +1,67 @@
|
|
1
|
+
=== 2.7.0 (2008-11-03)
|
2
|
+
|
3
|
+
* Transform AssociationReflection from a single class to a class hierarchy (jeremyevans)
|
4
|
+
|
5
|
+
* Optimize Date object creation in PostgreSQL adapter (jeremyevans)
|
6
|
+
|
7
|
+
* Allow easier creation of custom association types, though support for them may still be suboptimal (jeremyevans)
|
8
|
+
|
9
|
+
* Add :eager_grapher option to associations, which the user can use to override the default eager_graph code (jeremyevans)
|
10
|
+
|
11
|
+
* Associations are now inherited when a model class is subclassed (jeremyevans)
|
12
|
+
|
13
|
+
* Instance methods added by associations are now added to an anonymous module the class includes, allowing you to override them and use super (jeremyevans)
|
14
|
+
|
15
|
+
* Add #add_graph_aliases (select_more for graphs), and allow use of arbitrary expressions when graphing (jeremyevans)
|
16
|
+
|
17
|
+
* Fix a corner case where the wrong table name is used in eager_graph (jeremyevans)
|
18
|
+
|
19
|
+
* Make Dataset#join_table take an option hash instead of a table_alias argument, add support for :implicit_qualifier option (jeremyevans)
|
20
|
+
|
21
|
+
* Add :left_primary_key and :right_primary_key options to many_to_many associations (jeremyevans)
|
22
|
+
|
23
|
+
* Add :primary_key option to one_to_many and many_to_one associations (jeremyevans)
|
24
|
+
|
25
|
+
* Make after_load association callbacks take effect when eager loading via eager (jeremyevans)
|
26
|
+
|
27
|
+
* Add a :uniq association option to many_to_many associations (jeremyevans)
|
28
|
+
|
29
|
+
* Support using any expression as the argument to Symbol#like (jeremyevans)
|
30
|
+
|
31
|
+
* Much better support for multiple schemas in PostgreSQL (jeremyevans) (#243)
|
32
|
+
|
33
|
+
* The first argument to Model#initalize can no longer be nil, it must be a hash if it is given (jeremyevans)
|
34
|
+
|
35
|
+
* Remove Sequel::Model.lazy_load_schema= setting (jeremyevans)
|
36
|
+
|
37
|
+
* Lazily load model instance options such as raise_on_save_failure, for better performance (jeremyevans)
|
38
|
+
|
39
|
+
* Make Model::Validiation::Errors more Rails-compatible (jeremyevans)
|
40
|
+
|
41
|
+
* Refactor model hooks for performance (jeremyevans)
|
42
|
+
|
43
|
+
* Major performance enhancement when fetching rows using PostgreSQL (jeremyevans)
|
44
|
+
|
45
|
+
* Don't typecast serialized columns in models (jeremyevans)
|
46
|
+
|
47
|
+
* Add Array#sql_array to handle ruby arrays of all two pairs as SQL arrays (jeremyevans) (#245)
|
48
|
+
|
49
|
+
* Add ComplexExpression#== and #eql?, for checking equality (rubymage) (#244)
|
50
|
+
|
51
|
+
* Allow full text search on PostgreSQL to include rows where a search column is NULL (jeremyevans)
|
52
|
+
|
53
|
+
* PostgreSQL full text search queries with multiple columns are joined with space to prevent joining border words to one (michalbugno)
|
54
|
+
|
55
|
+
* Don't modify a dataset's cached column information if calling #each with an option that modifies the columns (jeremyevans)
|
56
|
+
|
57
|
+
* The PostgreSQL adapter will now generally default to using a unix socket in /tmp if no host is specified, instead of a tcp socket to localhost (jeremyevans)
|
58
|
+
|
59
|
+
* Make Dataset#sql call Dataset#select_sql instead of being an alias, to allow for easier subclassing (jeremyevans)
|
60
|
+
|
61
|
+
* Split Oracle adapter into shared and unshared parts, so Oracle is better supported when using JDBC (jeremyevans)
|
62
|
+
|
63
|
+
* Fix automatic loading of Oracle driver when using JDBC adapter (bburton333) (#242)
|
64
|
+
|
1
65
|
=== 2.6.0 (2008-10-11)
|
2
66
|
|
3
67
|
* Make the sqlite adapter respect the Sequel.datetime_class setting, for timestamp and datetime types (jeremyevans)
|
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ require "fileutils"
|
|
12
12
|
include FileUtils
|
13
13
|
|
14
14
|
NAME = 'sequel'
|
15
|
-
VERS = '2.
|
15
|
+
VERS = '2.7.0'
|
16
16
|
CLEAN.include ["**/.*.sw?", "pkg", ".config", "rdoc", "coverage", "www/public/*.html"]
|
17
17
|
RDOC_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', \
|
18
18
|
'Sequel: The Database Toolkit for Ruby', '--main', 'README']
|
@@ -3,7 +3,7 @@ require 'java'
|
|
3
3
|
module Sequel
|
4
4
|
# Houses Sequel's JDBC support when running on JRuby.
|
5
5
|
# Support for individual database types is done using sub adapters.
|
6
|
-
# PostgreSQL, MySQL, SQLite, and MSSQL all have relatively good support,
|
6
|
+
# PostgreSQL, MySQL, SQLite, Oracle, and MSSQL all have relatively good support,
|
7
7
|
# close the the level supported by the native adapter.
|
8
8
|
# PostgreSQL, MySQL, SQLite can load necessary support using
|
9
9
|
# the jdbc-* gem, if it is installed, though they will work if you
|
@@ -51,7 +51,11 @@ module Sequel
|
|
51
51
|
JDBC.load_gem('sqlite3')
|
52
52
|
org.sqlite.JDBC
|
53
53
|
end,
|
54
|
-
:oracle=>proc
|
54
|
+
:oracle=>proc do |db|
|
55
|
+
require 'sequel_core/adapters/jdbc/oracle'
|
56
|
+
db.extend(Sequel::JDBC::Oracle::DatabaseMethods)
|
57
|
+
Java::oracle.jdbc.driver.OracleDriver
|
58
|
+
end,
|
55
59
|
:sqlserver=>proc do |db|
|
56
60
|
require 'sequel_core/adapters/shared/mssql'
|
57
61
|
db.extend(Sequel::MSSQL::DatabaseMethods)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'sequel_core/adapters/shared/oracle'
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
module JDBC
|
5
|
+
# Database and Dataset support for Oracle databases accessed via JDBC.
|
6
|
+
module Oracle
|
7
|
+
# Instance methods for Oracle Database objects accessed via JDBC.
|
8
|
+
module DatabaseMethods
|
9
|
+
include Sequel::Oracle::DatabaseMethods
|
10
|
+
|
11
|
+
# Return Sequel::JDBC::Oracle::Dataset object with the given opts.
|
12
|
+
def dataset(opts=nil)
|
13
|
+
Sequel::JDBC::Oracle::Dataset.new(self, opts)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Dataset class for Oracle datasets accessed via JDBC.
|
18
|
+
class Dataset < JDBC::Dataset
|
19
|
+
include Sequel::Oracle::DatasetMethods
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'oci8'
|
2
|
+
require 'sequel_core/adapters/shared/oracle'
|
2
3
|
|
3
4
|
module Sequel
|
4
5
|
module Oracle
|
5
6
|
class Database < Sequel::Database
|
7
|
+
include DatabaseMethods
|
6
8
|
set_adapter_scheme :oracle
|
7
9
|
|
8
10
|
def connect(server)
|
@@ -37,16 +39,6 @@ module Sequel
|
|
37
39
|
end
|
38
40
|
alias_method :do, :execute
|
39
41
|
|
40
|
-
def tables
|
41
|
-
from(:tab).select(:tname).filter(:tabtype => 'TABLE').map do |r|
|
42
|
-
r[:tname].downcase.to_sym
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def table_exists?(name)
|
47
|
-
from(:tab).filter(:tname => name.to_s.upcase, :tabtype => 'TABLE').count > 0
|
48
|
-
end
|
49
|
-
|
50
42
|
def transaction(server=nil)
|
51
43
|
synchronize(server) do |conn|
|
52
44
|
return yield(conn) if @transactions.include?(Thread.current)
|
@@ -68,6 +60,8 @@ module Sequel
|
|
68
60
|
end
|
69
61
|
|
70
62
|
class Dataset < Sequel::Dataset
|
63
|
+
include DatasetMethods
|
64
|
+
|
71
65
|
def literal(v)
|
72
66
|
case v
|
73
67
|
when OraDate
|
@@ -92,73 +86,6 @@ module Sequel
|
|
92
86
|
end
|
93
87
|
self
|
94
88
|
end
|
95
|
-
|
96
|
-
def empty?
|
97
|
-
db[:dual].where(exists).get(1) == nil
|
98
|
-
end
|
99
|
-
|
100
|
-
# Formats a SELECT statement using the given options and the dataset
|
101
|
-
# options.
|
102
|
-
def select_sql(opts = nil)
|
103
|
-
opts = opts ? @opts.merge(opts) : @opts
|
104
|
-
|
105
|
-
if sql = opts[:sql]
|
106
|
-
return sql
|
107
|
-
end
|
108
|
-
|
109
|
-
columns = opts[:select]
|
110
|
-
select_columns = columns ? column_list(columns) : WILDCARD
|
111
|
-
sql = opts[:distinct] ? \
|
112
|
-
"SELECT DISTINCT #{select_columns}" : \
|
113
|
-
"SELECT #{select_columns}"
|
114
|
-
|
115
|
-
if opts[:from]
|
116
|
-
sql << " FROM #{source_list(opts[:from])}"
|
117
|
-
end
|
118
|
-
|
119
|
-
if join = opts[:join]
|
120
|
-
join.each{|j| sql << literal(j)}
|
121
|
-
end
|
122
|
-
|
123
|
-
if where = opts[:where]
|
124
|
-
sql << " WHERE #{literal(where)}"
|
125
|
-
end
|
126
|
-
|
127
|
-
if group = opts[:group]
|
128
|
-
sql << " GROUP BY #{expression_list(group)}"
|
129
|
-
end
|
130
|
-
|
131
|
-
if having = opts[:having]
|
132
|
-
sql << " HAVING #{literal(having)}"
|
133
|
-
end
|
134
|
-
|
135
|
-
if union = opts[:union]
|
136
|
-
sql << (opts[:union_all] ? \
|
137
|
-
" UNION ALL #{union.sql}" : " UNION #{union.sql}")
|
138
|
-
elsif intersect = opts[:intersect]
|
139
|
-
sql << (opts[:intersect_all] ? \
|
140
|
-
" INTERSECT ALL #{intersect.sql}" : " INTERSECT #{intersect.sql}")
|
141
|
-
elsif except = opts[:except]
|
142
|
-
sql << (opts[:except_all] ? \
|
143
|
-
" EXCEPT ALL #{except.sql}" : " EXCEPT #{except.sql}")
|
144
|
-
end
|
145
|
-
|
146
|
-
if order = opts[:order]
|
147
|
-
sql << " ORDER BY #{expression_list(order)}"
|
148
|
-
end
|
149
|
-
|
150
|
-
if limit = opts[:limit]
|
151
|
-
if (offset = opts[:offset]) && (offset > 0)
|
152
|
-
sql = "SELECT * FROM (SELECT raw_sql_.*, ROWNUM raw_rnum_ FROM(#{sql}) raw_sql_ WHERE ROWNUM <= #{limit + offset}) WHERE raw_rnum_ > #{offset}"
|
153
|
-
else
|
154
|
-
sql = "SELECT * FROM (#{sql}) WHERE ROWNUM <= #{limit}"
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
sql
|
159
|
-
end
|
160
|
-
|
161
|
-
alias sql select_sql
|
162
89
|
end
|
163
90
|
end
|
164
91
|
end
|
@@ -83,7 +83,7 @@ module Sequel
|
|
83
83
|
|
84
84
|
# Hash with integer keys and proc values for converting PostgreSQL types.
|
85
85
|
PG_TYPES = {
|
86
|
-
16 => lambda{ |s|
|
86
|
+
16 => lambda{ |s| s == 't' }, # boolean
|
87
87
|
17 => lambda{ |s| Adapter.unescape_bytea(s).to_blob }, # bytea
|
88
88
|
20 => lambda{ |s| s.to_i }, # int8
|
89
89
|
21 => lambda{ |s| s.to_i }, # int2
|
@@ -93,7 +93,7 @@ module Sequel
|
|
93
93
|
700 => lambda{ |s| s.to_f }, # float4
|
94
94
|
701 => lambda{ |s| s.to_f }, # float8
|
95
95
|
790 => lambda{ |s| s.to_d }, # money
|
96
|
-
1082 => lambda{ |s| s.to_date }, # date
|
96
|
+
1082 => lambda{ |s| @use_iso_date_format ? Date.new(*s.split("-").map{|x| x.to_i}) : s.to_date }, # date
|
97
97
|
1083 => lambda{ |s| s.to_time }, # time without time zone
|
98
98
|
1114 => lambda{ |s| s.to_sequel_time }, # timestamp without time zone
|
99
99
|
1184 => lambda{ |s| s.to_sequel_time }, # timestamp with time zone
|
@@ -102,16 +102,12 @@ module Sequel
|
|
102
102
|
1700 => lambda{ |s| s.to_d }, # numeric
|
103
103
|
}
|
104
104
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
else
|
112
|
-
false
|
113
|
-
end
|
114
|
-
end
|
105
|
+
@use_iso_date_format = true
|
106
|
+
|
107
|
+
# As an optimization, Sequel sets the date style to ISO, so that PostgreSQL provides
|
108
|
+
# the date in a known format that Sequel can parse faster. This can be turned off
|
109
|
+
# if you require a date style other than ISO.
|
110
|
+
metaattr_accessor :use_iso_date_format
|
115
111
|
|
116
112
|
# PGconn subclass for connection specific methods used with the
|
117
113
|
# pg, postgres, or postgres-pr driver.
|
@@ -119,6 +115,13 @@ module Sequel
|
|
119
115
|
include Sequel::Postgres::AdapterMethods
|
120
116
|
self.translate_results = false if respond_to?(:translate_results=)
|
121
117
|
|
118
|
+
# Apply connection settings for this connection. Current sets
|
119
|
+
# the date style to ISO in order make Date object creation in ruby faster,
|
120
|
+
# if Postgres.use_iso_date_format is true.
|
121
|
+
def apply_connection_settings
|
122
|
+
async_exec("SET DateStyle = 'ISO, YMD'") if Postgres.use_iso_date_format
|
123
|
+
end
|
124
|
+
|
122
125
|
# Execute the given SQL with this connection. If a block is given,
|
123
126
|
# yield the results, otherwise, return the number of changed rows.
|
124
127
|
def execute(sql, args=nil)
|
@@ -138,6 +141,12 @@ module Sequel
|
|
138
141
|
q.clear
|
139
142
|
end
|
140
143
|
end
|
144
|
+
|
145
|
+
# Reapply the connection settings if the connection is reset.
|
146
|
+
def reset(*args, &block)
|
147
|
+
super(*args, &block)
|
148
|
+
apply_connection_settings
|
149
|
+
end
|
141
150
|
|
142
151
|
if SEQUEL_POSTGRES_USES_PG
|
143
152
|
# Hash of prepared statements for this connection. Keys are
|
@@ -170,14 +179,14 @@ module Sequel
|
|
170
179
|
@primary_keys = {}
|
171
180
|
@primary_key_sequences = {}
|
172
181
|
end
|
173
|
-
|
182
|
+
|
174
183
|
# Connects to the database. In addition to the standard database
|
175
184
|
# options, using the :encoding or :charset option changes the
|
176
185
|
# client encoding for the connection.
|
177
186
|
def connect(server)
|
178
187
|
opts = server_opts(server)
|
179
188
|
conn = Adapter.connect(
|
180
|
-
opts[:host]
|
189
|
+
(opts[:host] unless opts[:host].blank?),
|
181
190
|
opts[:port] || 5432,
|
182
191
|
nil, '',
|
183
192
|
opts[:database],
|
@@ -185,8 +194,13 @@ module Sequel
|
|
185
194
|
opts[:password]
|
186
195
|
)
|
187
196
|
if encoding = opts[:encoding] || opts[:charset]
|
188
|
-
conn.set_client_encoding
|
197
|
+
if conn.respond_to?(:set_client_encoding)
|
198
|
+
conn.set_client_encoding(encoding)
|
199
|
+
else
|
200
|
+
conn.async_exec("set client_encoding to '#{encoding}'")
|
201
|
+
end
|
189
202
|
end
|
203
|
+
conn.apply_connection_settings
|
190
204
|
conn.db = self
|
191
205
|
conn
|
192
206
|
end
|
@@ -280,21 +294,20 @@ module Sequel
|
|
280
294
|
class Dataset < Sequel::Dataset
|
281
295
|
include Sequel::Postgres::DatasetMethods
|
282
296
|
|
283
|
-
#
|
297
|
+
# Yield all rows returned by executing the given SQL and converting
|
284
298
|
# the types.
|
285
299
|
def fetch_rows(sql)
|
286
|
-
|
300
|
+
cols = []
|
287
301
|
execute(sql) do |res|
|
288
|
-
|
302
|
+
res.nfields.times do |fieldnum|
|
303
|
+
cols << [fieldnum, PG_TYPES[res.ftype(fieldnum)], res.fname(fieldnum).to_sym]
|
304
|
+
end
|
305
|
+
@columns = cols.map{|c| c.at(2)}
|
306
|
+
res.ntuples.times do |recnum|
|
289
307
|
converted_rec = {}
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
converted_rec[fieldsym] = if value = res.getvalue(recnum,fieldnum)
|
294
|
-
(PG_TYPES[res.ftype(fieldnum)] || lambda{|s| s.to_s}).call(value)
|
295
|
-
else
|
296
|
-
value
|
297
|
-
end
|
308
|
+
cols.each do |fieldnum, type_proc, fieldsym|
|
309
|
+
value = res.getvalue(recnum, fieldnum)
|
310
|
+
converted_rec[fieldsym] = (value && type_proc) ? type_proc.call(value) : value
|
298
311
|
end
|
299
312
|
yield converted_rec
|
300
313
|
end
|
@@ -156,7 +156,7 @@ module Sequel
|
|
156
156
|
|
157
157
|
# Transforms an CROSS JOIN to an INNER JOIN if the expr is not nil.
|
158
158
|
# Raises an error on use of :full_outer type, since MySQL doesn't support it.
|
159
|
-
def join_table(type, table, expr=nil, table_alias=
|
159
|
+
def join_table(type, table, expr=nil, table_alias={})
|
160
160
|
type = :inner if (type == :cross) && !expr.nil?
|
161
161
|
raise(Sequel::Error, "MySQL doesn't support FULL OUTER JOIN") if type == :full_outer
|
162
162
|
super(type, table, expr, table_alias)
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Sequel
|
2
|
+
module Oracle
|
3
|
+
module DatabaseMethods
|
4
|
+
def tables
|
5
|
+
from(:tab).select(:tname).filter(:tabtype => 'TABLE').map do |r|
|
6
|
+
r[:tname].downcase.to_sym
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def table_exists?(name)
|
11
|
+
from(:tab).filter(:tname => name.to_s.upcase, :tabtype => 'TABLE').count > 0
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module DatasetMethods
|
16
|
+
def empty?
|
17
|
+
db[:dual].where(exists).get(1) == nil
|
18
|
+
end
|
19
|
+
|
20
|
+
# Formats a SELECT statement using the given options and the dataset
|
21
|
+
# options.
|
22
|
+
def select_sql(opts = nil)
|
23
|
+
opts = opts ? @opts.merge(opts) : @opts
|
24
|
+
|
25
|
+
if sql = opts[:sql]
|
26
|
+
return sql
|
27
|
+
end
|
28
|
+
|
29
|
+
columns = opts[:select]
|
30
|
+
select_columns = columns ? column_list(columns) : '*'
|
31
|
+
sql = opts[:distinct] ? \
|
32
|
+
"SELECT DISTINCT #{select_columns}" : \
|
33
|
+
"SELECT #{select_columns}"
|
34
|
+
|
35
|
+
if opts[:from]
|
36
|
+
sql << " FROM #{source_list(opts[:from])}"
|
37
|
+
end
|
38
|
+
|
39
|
+
if join = opts[:join]
|
40
|
+
join.each{|j| sql << literal(j)}
|
41
|
+
end
|
42
|
+
|
43
|
+
if where = opts[:where]
|
44
|
+
sql << " WHERE #{literal(where)}"
|
45
|
+
end
|
46
|
+
|
47
|
+
if group = opts[:group]
|
48
|
+
sql << " GROUP BY #{expression_list(group)}"
|
49
|
+
end
|
50
|
+
|
51
|
+
if having = opts[:having]
|
52
|
+
sql << " HAVING #{literal(having)}"
|
53
|
+
end
|
54
|
+
|
55
|
+
if union = opts[:union]
|
56
|
+
sql << (opts[:union_all] ? \
|
57
|
+
" UNION ALL #{union.sql}" : " UNION #{union.sql}")
|
58
|
+
elsif intersect = opts[:intersect]
|
59
|
+
sql << (opts[:intersect_all] ? \
|
60
|
+
" INTERSECT ALL #{intersect.sql}" : " INTERSECT #{intersect.sql}")
|
61
|
+
elsif except = opts[:except]
|
62
|
+
sql << (opts[:except_all] ? \
|
63
|
+
" EXCEPT ALL #{except.sql}" : " EXCEPT #{except.sql}")
|
64
|
+
end
|
65
|
+
|
66
|
+
if order = opts[:order]
|
67
|
+
sql << " ORDER BY #{expression_list(order)}"
|
68
|
+
end
|
69
|
+
|
70
|
+
if limit = opts[:limit]
|
71
|
+
if (offset = opts[:offset]) && (offset > 0)
|
72
|
+
sql = "SELECT * FROM (SELECT raw_sql_.*, ROWNUM raw_rnum_ FROM(#{sql}) raw_sql_ WHERE ROWNUM <= #{limit + offset}) WHERE raw_rnum_ > #{offset}"
|
73
|
+
else
|
74
|
+
sql = "SELECT * FROM (#{sql}) WHERE ROWNUM <= #{limit}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
sql
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|