sequel 2.8.0 → 2.9.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 +34 -0
- data/COPYING +1 -1
- data/Rakefile +1 -1
- data/bin/sequel +12 -5
- data/doc/advanced_associations.rdoc +17 -3
- data/lib/sequel_core/adapters/informix.rb +1 -1
- data/lib/sequel_core/adapters/postgres.rb +12 -2
- data/lib/sequel_core/adapters/shared/mssql.rb +3 -1
- data/lib/sequel_core/adapters/shared/mysql.rb +14 -0
- data/lib/sequel_core/adapters/shared/oracle.rb +7 -6
- data/lib/sequel_core/adapters/shared/postgres.rb +170 -3
- data/lib/sequel_core/adapters/shared/progress.rb +1 -1
- data/lib/sequel_core/adapters/shared/sqlite.rb +11 -6
- data/lib/sequel_core/adapters/sqlite.rb +8 -0
- data/lib/sequel_core/dataset/sql.rb +23 -19
- data/lib/sequel_core/dataset/unsupported.rb +12 -0
- data/lib/sequel_core/schema/sql.rb +3 -1
- data/lib/sequel_model.rb +1 -1
- data/lib/sequel_model/associations.rb +1 -1
- data/lib/sequel_model/base.rb +2 -1
- data/lib/sequel_model/dataset_methods.rb +1 -1
- data/lib/sequel_model/eager_loading.rb +1 -1
- data/lib/sequel_model/exceptions.rb +7 -0
- data/lib/sequel_model/record.rb +22 -13
- data/lib/sequel_model/validations.rb +8 -4
- data/spec/adapters/mysql_spec.rb +17 -0
- data/spec/adapters/postgres_spec.rb +69 -0
- data/spec/adapters/sqlite_spec.rb +38 -3
- data/spec/integration/dataset_test.rb +51 -0
- data/spec/integration/schema_test.rb +4 -0
- data/spec/sequel_core/core_ext_spec.rb +2 -2
- data/spec/sequel_core/dataset_spec.rb +35 -1
- data/spec/sequel_core/schema_spec.rb +7 -0
- data/spec/sequel_model/association_reflection_spec.rb +13 -13
- data/spec/sequel_model/hooks_spec.rb +9 -5
- data/spec/sequel_model/validations_spec.rb +1 -1
- metadata +3 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,37 @@
|
|
1
|
+
=== 2.9.0 (2009-01-12)
|
2
|
+
|
3
|
+
* Add -L option to sequel command line tool to load all .rb files in the given directory (pkondzior, jeremyevans)
|
4
|
+
|
5
|
+
* Fix Dataset#destroy for model datasets that can't handle nested queries (jeremyevans)
|
6
|
+
|
7
|
+
* Improve the error messages in parts of Sequel::Model (jeremyevans, pusewicz)
|
8
|
+
|
9
|
+
* Much better support for Dataset#{union,except,intersect}, allowing chaining and respecting order (jeremyevans)
|
10
|
+
|
11
|
+
* Default to logging only WARNING level messages when connecting to PostgreSQL (jeremyevans)
|
12
|
+
|
13
|
+
* Fix add_foreign_key for MySQL (jeremyevans, aphyr)
|
14
|
+
|
15
|
+
* Correctly literalize BigDecimal NaN and (+-)Infinity values (#256) (jeremyevans)
|
16
|
+
|
17
|
+
* Make Sequel raise an Error if you attempt to subclass Sequel::Model before setting up a database connection (jeremyevans)
|
18
|
+
|
19
|
+
* Add Sequel::BeforeHookFailed exception to be raised when a record fails because a before hook fails (bougyman)
|
20
|
+
|
21
|
+
* Add Sequel::ValidationFailed exception to be raised when a record fails because a validation fails (bougyman)
|
22
|
+
|
23
|
+
* Make Database#schema raise an error if given a table that doesn't exist (jeremyevans) (#255)
|
24
|
+
|
25
|
+
* Make Model#inspect call Model#inspect_values private method for easier overloading (bougyman)
|
26
|
+
|
27
|
+
* Add methods to create and drop functions, triggers, and procedural languages on PostgreSQL (jeremyevans)
|
28
|
+
|
29
|
+
* Fix Dataset#count when using UNION, EXCEPT, or INTERSECT (jeremyevans)
|
30
|
+
|
31
|
+
* Make SQLite keep table's primary key information when dropping columns (jmhodges)
|
32
|
+
|
33
|
+
* Support dropping indicies on SQLite (jmhodges)
|
34
|
+
|
1
35
|
=== 2.8.0 (2008-12-05)
|
2
36
|
|
3
37
|
* Support drop column operations inside a transaction on sqlite (jeremyevans)
|
data/COPYING
CHANGED
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.9.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']
|
data/bin/sequel
CHANGED
@@ -10,6 +10,7 @@ env = nil
|
|
10
10
|
logfile = nil
|
11
11
|
migrate_dir = nil
|
12
12
|
migrate_ver = nil
|
13
|
+
load_dir = nil
|
13
14
|
|
14
15
|
opts = OptionParser.new do |opts|
|
15
16
|
opts.banner = "Sequel: The Database Toolkit for Ruby"
|
@@ -29,10 +30,6 @@ opts = OptionParser.new do |opts|
|
|
29
30
|
exit
|
30
31
|
end
|
31
32
|
|
32
|
-
opts.on("-l", "--log logfile", "log SQL statements to log file") do |v|
|
33
|
-
logfile = v
|
34
|
-
end
|
35
|
-
|
36
33
|
opts.on("-e", "--env ENV", "use environment config for database") do |v|
|
37
34
|
env = v
|
38
35
|
end
|
@@ -41,6 +38,14 @@ opts = OptionParser.new do |opts|
|
|
41
38
|
echo = true
|
42
39
|
end
|
43
40
|
|
41
|
+
opts.on("-l", "--log logfile", "log SQL statements to log file") do |v|
|
42
|
+
logfile = v
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.on("-L", "--load-dir DIR", "loads all *.rb from specifed directory") do |v|
|
46
|
+
load_dir = v
|
47
|
+
end
|
48
|
+
|
44
49
|
opts.on("-m", "--migrate-directory DIR", "run the migrations in directory") do |v|
|
45
50
|
migrate_dir = v
|
46
51
|
end
|
@@ -48,7 +53,7 @@ opts = OptionParser.new do |opts|
|
|
48
53
|
opts.on("-M", "--migrate-version VER", "migrate the database to version given") do |v|
|
49
54
|
migrate_ver = Integer(v)
|
50
55
|
end
|
51
|
-
|
56
|
+
|
52
57
|
opts.on_tail("-v", "--version", "Show version") do
|
53
58
|
class << Gem; attr_accessor :loaded_specs; end
|
54
59
|
begin
|
@@ -101,6 +106,8 @@ rescue => e
|
|
101
106
|
exit 1
|
102
107
|
end
|
103
108
|
|
109
|
+
Dir["#{load_dir}/**/*.rb"].each{|f| load(f)} if load_dir
|
110
|
+
|
104
111
|
require 'irb'
|
105
112
|
puts "Your database is stored in DB..."
|
106
113
|
IRB.start
|
@@ -229,7 +229,7 @@ Sequel::Model:
|
|
229
229
|
@author.books
|
230
230
|
|
231
231
|
If you use an association other than belongs_to in the associated model, things
|
232
|
-
are a bit more involved:
|
232
|
+
are a bit more involved (has_many :through a has_many association):
|
233
233
|
|
234
234
|
ActiveRecord:
|
235
235
|
|
@@ -317,8 +317,18 @@ firm.invoices.first.client doesn't do another query to get the firm/client.
|
|
317
317
|
|
318
318
|
===Polymorphic Associations
|
319
319
|
|
320
|
-
Polymorphic associations are really a design flaw
|
321
|
-
|
320
|
+
Polymorphic associations are really a design flaw. The only advantage
|
321
|
+
polymorphic associations offer is that they require fewer join tables.
|
322
|
+
|
323
|
+
Proof by Reductio ad absurdum: If fewer join tables are preferable, then surely
|
324
|
+
fewer tables and columns are preferrable, so you might as well store all of
|
325
|
+
your data in a single column in a single table if you think polymorphic
|
326
|
+
associations are a good idea.
|
327
|
+
|
328
|
+
Compelling Argument: Polymorphic associations are more complex than normal
|
329
|
+
associations, and they break referential integrity, so the only reason you
|
330
|
+
should use them is if you are already stuck with an existing design that
|
331
|
+
uses them. You should never use them in new code.
|
322
332
|
|
323
333
|
ActiveRecord:
|
324
334
|
|
@@ -426,6 +436,10 @@ powerful.
|
|
426
436
|
|
427
437
|
===many_to_one/one_to_many not referencing primary key
|
428
438
|
|
439
|
+
This can now be handled easily in Sequel using the :primary_key association
|
440
|
+
option. However, this example shows how the association was possible before
|
441
|
+
the introduction of that option.
|
442
|
+
|
429
443
|
Let's say you have two tables, invoices and clients, where each client is
|
430
444
|
associated with many invoices. However, instead of using the client's primary
|
431
445
|
key, the invoice is associated to the client by name (this is bad database
|
@@ -37,7 +37,7 @@ module Sequel
|
|
37
37
|
class Dataset < Sequel::Dataset
|
38
38
|
include UnsupportedIntersectExcept
|
39
39
|
|
40
|
-
SELECT_CLAUSE_ORDER = %w'limit distinct columns from join where having group
|
40
|
+
SELECT_CLAUSE_ORDER = %w'limit distinct columns from join where having group compounds order'.freeze
|
41
41
|
|
42
42
|
def literal(v)
|
43
43
|
case v
|
@@ -79,8 +79,6 @@ rescue LoadError => e
|
|
79
79
|
end
|
80
80
|
|
81
81
|
module Sequel
|
82
|
-
# Top level module for holding all PostgreSQL-related modules and classes
|
83
|
-
# for Sequel.
|
84
82
|
module Postgres
|
85
83
|
CONVERTED_EXCEPTIONS << PGError
|
86
84
|
|
@@ -105,12 +103,19 @@ module Sequel
|
|
105
103
|
}
|
106
104
|
|
107
105
|
@use_iso_date_format = true
|
106
|
+
@client_min_messages = :warning
|
108
107
|
|
109
108
|
# As an optimization, Sequel sets the date style to ISO, so that PostgreSQL provides
|
110
109
|
# the date in a known format that Sequel can parse faster. This can be turned off
|
111
110
|
# if you require a date style other than ISO.
|
112
111
|
metaattr_accessor :use_iso_date_format
|
113
112
|
|
113
|
+
# By default, Sequel sets the minimum level of log messages sent to the client
|
114
|
+
# to WARNING, where PostgreSQL uses a default of NOTICE. This is to avoid a lot
|
115
|
+
# of mostly useless messages when running migrations, such as a couple of lines
|
116
|
+
# for every serial primary key field.
|
117
|
+
metaattr_accessor :client_min_messages
|
118
|
+
|
114
119
|
# PGconn subclass for connection specific methods used with the
|
115
120
|
# pg, postgres, or postgres-pr driver.
|
116
121
|
class Adapter < ::PGconn
|
@@ -127,6 +132,11 @@ module Sequel
|
|
127
132
|
@db.log_info(sql)
|
128
133
|
execute(sql)
|
129
134
|
end
|
135
|
+
if cmm = Postgres.client_min_messages
|
136
|
+
sql = "SET client_min_messages = '#{cmm.to_s.upcase}'"
|
137
|
+
@db.log_info(sql)
|
138
|
+
execute(sql)
|
139
|
+
end
|
130
140
|
end
|
131
141
|
|
132
142
|
# Execute the given SQL with this connection. If a block is given,
|
@@ -37,7 +37,7 @@ module Sequel
|
|
37
37
|
module DatasetMethods
|
38
38
|
include Dataset::UnsupportedIntersectExcept
|
39
39
|
|
40
|
-
SELECT_CLAUSE_ORDER = %w'limit distinct columns from with join where group order having
|
40
|
+
SELECT_CLAUSE_ORDER = %w'limit distinct columns from with join where group order having compounds'.freeze
|
41
41
|
|
42
42
|
def complex_expression_sql(op, args)
|
43
43
|
case op
|
@@ -54,6 +54,8 @@ module Sequel
|
|
54
54
|
|
55
55
|
def literal(v)
|
56
56
|
case v
|
57
|
+
when LiteralString
|
58
|
+
v
|
57
59
|
when String
|
58
60
|
"N#{super}"
|
59
61
|
when Time
|
@@ -1,4 +1,10 @@
|
|
1
1
|
module Sequel
|
2
|
+
module Schema
|
3
|
+
module SQL
|
4
|
+
# Keep default column_references_sql for add_foreign_key support
|
5
|
+
alias default_column_references_sql column_references_sql
|
6
|
+
end
|
7
|
+
end
|
2
8
|
module MySQL
|
3
9
|
# Methods shared by Database instances that connect to MySQL,
|
4
10
|
# currently supported by the native and JDBC adapters.
|
@@ -15,6 +21,14 @@ module Sequel
|
|
15
21
|
# drop index cases.
|
16
22
|
def alter_table_sql(table, op)
|
17
23
|
case op[:op]
|
24
|
+
when :add_column
|
25
|
+
if related = op.delete(:table)
|
26
|
+
sql = super(table, op)
|
27
|
+
op[:table] = related
|
28
|
+
[sql, "ALTER TABLE #{quote_schema_table(table)} ADD FOREIGN KEY (#{quote_identifier(op[:name])})#{default_column_references_sql(op)}"]
|
29
|
+
else
|
30
|
+
super(table, op)
|
31
|
+
end
|
18
32
|
when :rename_column
|
19
33
|
"ALTER TABLE #{quote_schema_table(table)} CHANGE COLUMN #{quote_identifier(op[:name])} #{quote_identifier(op[:new_name])} #{type_literal(op)}"
|
20
34
|
when :set_column_type
|
@@ -15,7 +15,13 @@ module Sequel
|
|
15
15
|
module DatasetMethods
|
16
16
|
include Dataset::UnsupportedIntersectExceptAll
|
17
17
|
|
18
|
-
SELECT_CLAUSE_ORDER = %w'distinct columns from join where group having
|
18
|
+
SELECT_CLAUSE_ORDER = %w'distinct columns from join where group having compounds order limit'.freeze
|
19
|
+
|
20
|
+
# Oracle uses MINUS instead of EXCEPT, and doesn't support EXCEPT ALL
|
21
|
+
def except(dataset, all = false)
|
22
|
+
raise(Sequel::Error, "EXCEPT ALL not supported") if all
|
23
|
+
compound_clone(:minus, dataset, all)
|
24
|
+
end
|
19
25
|
|
20
26
|
def empty?
|
21
27
|
db[:dual].where(exists).get(1) == nil
|
@@ -41,11 +47,6 @@ module Sequel
|
|
41
47
|
end
|
42
48
|
end
|
43
49
|
|
44
|
-
# Oracle uses MINUS instead of EXCEPT, and doesn't support EXCEPT ALL
|
45
|
-
def select_except_sql(sql, opts)
|
46
|
-
sql << " MINUS #{opts[:except].sql}" if opts[:except]
|
47
|
-
end
|
48
|
-
|
49
50
|
# Oracle requires a subselect to do limit and offset
|
50
51
|
def select_limit_sql(sql, opts)
|
51
52
|
if limit = opts[:limit]
|
@@ -1,4 +1,32 @@
|
|
1
1
|
module Sequel
|
2
|
+
# Top level module for holding all PostgreSQL-related modules and classes
|
3
|
+
# for Sequel. There are a few module level accessors that are added via
|
4
|
+
# metaprogramming. These are:
|
5
|
+
# * client_min_messages (only available when using the native adapter) -
|
6
|
+
# Change the minimum level of messages that PostgreSQL will send to the
|
7
|
+
# the client. The PostgreSQL default is NOTICE, the Sequel default is
|
8
|
+
# WARNING. Set to nil to not change the server default.
|
9
|
+
# * force_standard_strings - Set to false to not force the use of
|
10
|
+
# standard strings
|
11
|
+
# * use_iso_date_format (only available when using the native adapter) -
|
12
|
+
# Set to false to not change the date format to
|
13
|
+
# ISO. This disables one of Sequel's optimizations.
|
14
|
+
#
|
15
|
+
# Changes in these settings only affect future connections. To make
|
16
|
+
# sure that they are applied, they should generally be called right
|
17
|
+
# after the Database object is instantiated and before a connection
|
18
|
+
# is actually made. For example, to use whatever the server defaults are:
|
19
|
+
#
|
20
|
+
# DB = Sequel.postgres(...)
|
21
|
+
# Sequel::Postgres.client_min_messages = nil
|
22
|
+
# Sequel::Postgres.force_standard_strings = false
|
23
|
+
# Sequel::Postgres.use_iso_date_format = false
|
24
|
+
# # A connection to the server is not made until here
|
25
|
+
# DB[:t].all
|
26
|
+
#
|
27
|
+
# The reason they can't be done earlier is that the Sequel::Postgres
|
28
|
+
# module is not loaded until a Database object which uses PostgreSQL
|
29
|
+
# is created.
|
2
30
|
module Postgres
|
3
31
|
# Array of exceptions that need to be converted. JDBC
|
4
32
|
# uses NativeExceptions, the native adapter uses PGError.
|
@@ -7,7 +35,7 @@ module Sequel
|
|
7
35
|
@force_standard_strings = true
|
8
36
|
|
9
37
|
# By default, Sequel forces the use of standard strings, so that
|
10
|
-
# '\\' is interpreted as
|
38
|
+
# '\\' is interpreted as \\ and not \. While PostgreSQL defaults
|
11
39
|
# to interpreting plain strings as extended strings, this will change
|
12
40
|
# in a future version of PostgreSQL. Sequel assumes that SQL standard
|
13
41
|
# strings will be used.
|
@@ -127,12 +155,122 @@ module Sequel
|
|
127
155
|
SQL_ROLLBACK = 'ROLLBACK'.freeze
|
128
156
|
SQL_RELEASE_SAVEPOINT = 'RELEASE SAVEPOINT autopoint_%d'.freeze
|
129
157
|
SYSTEM_TABLE_REGEXP = /^pg|sql/.freeze
|
158
|
+
|
159
|
+
# Creates the function in the database. See create_function_sql for arguments.
|
160
|
+
def create_function(*args)
|
161
|
+
self << create_function_sql(*args)
|
162
|
+
end
|
163
|
+
|
164
|
+
# SQL statement to create database function. Arguments:
|
165
|
+
# * name : name of the function to create
|
166
|
+
# * definition : string definition of the function, or object file for a dynamically loaded C function.
|
167
|
+
# * opts : options hash:
|
168
|
+
# * :args : function arguments, can be either a symbol or string specifying a type or an array of 1-3 elements:
|
169
|
+
# * element 1 : argument data type
|
170
|
+
# * element 2 : argument name
|
171
|
+
# * element 3 : argument mode (e.g. in, out, inout)
|
172
|
+
# * :behavior : Should be IMMUTABLE, STABLE, or VOLATILE. PostgreSQL assumes VOLATILE by default.
|
173
|
+
# * :cost : The estimated cost of the function, used by the query planner.
|
174
|
+
# * :language : The language the function uses. SQL is the default.
|
175
|
+
# * :link_symbol : For a dynamically loaded see function, the function's link symbol if different from the definition argument.
|
176
|
+
# * :returns : The data type returned by the function. If you are using OUT or INOUT argument modes, this is ignored.
|
177
|
+
# Otherwise, if this is not specified, void is used by default to specify the function is not supposed to return a value.
|
178
|
+
# * :rows : The estimated number of rows the function will return. Only use if the function returns SETOF something.
|
179
|
+
# * :security_definer : Makes the privileges of the function the same as the privileges of the user who defined the function instead of
|
180
|
+
# the privileges of the user who runs the function. There are security implications when doing this, see the PostgreSQL documentation.
|
181
|
+
# * :set : Configuration variables to set while the function is being run, can be a hash or an array of two pairs. search_path is
|
182
|
+
# often used here if :security_definer is used.
|
183
|
+
# * :strict : Makes the function return NULL when any argument is NULL.
|
184
|
+
def create_function_sql(name, definition, opts={})
|
185
|
+
args = opts[:args]
|
186
|
+
if !opts[:args].is_a?(Array) || !opts[:args].any?{|a| Array(a).length == 3 and %w'OUT INOUT'.include?(a[2].to_s)}
|
187
|
+
returns = opts[:returns] || 'void'
|
188
|
+
end
|
189
|
+
language = opts[:language] || 'SQL'
|
190
|
+
<<-END
|
191
|
+
CREATE#{' OR REPLACE' if opts[:replace]} FUNCTION #{name}#{sql_function_args(args)}
|
192
|
+
#{"RETURNS #{returns}" if returns}
|
193
|
+
LANGUAGE #{language}
|
194
|
+
#{opts[:behavior].to_s.upcase if opts[:behavior]}
|
195
|
+
#{'STRICT' if opts[:strict]}
|
196
|
+
#{'SECURITY DEFINER' if opts[:security_definer]}
|
197
|
+
#{"COST #{opts[:cost]}" if opts[:cost]}
|
198
|
+
#{"ROWS #{opts[:rows]}" if opts[:rows]}
|
199
|
+
#{opts[:set].map{|k,v| " SET #{k} = #{v}"}.join("\n") if opts[:set]}
|
200
|
+
AS #{literal(definition.to_s)}#{", #{literal(opts[:link_symbol].to_s)}" if opts[:link_symbol]}
|
201
|
+
END
|
202
|
+
end
|
203
|
+
|
204
|
+
# Create the procedural language in the database. See create_language_sql for arguments.
|
205
|
+
def create_language(*args)
|
206
|
+
self << create_language_sql(*args)
|
207
|
+
end
|
208
|
+
|
209
|
+
# SQL for creating a procedural language. Arguments:
|
210
|
+
# * name : Name of the procedural language (e.g. plpgsql)
|
211
|
+
# * opts : options hash:
|
212
|
+
# * :handler : The name of a previously registered function used as a call handler for this language.
|
213
|
+
# * :trusted : Marks the language being created as trusted, allowing unprivileged users to create functions using this language.
|
214
|
+
# * :validator : The name of previously registered function used as a validator of functions defined in this language.
|
215
|
+
def create_language_sql(name, opts={})
|
216
|
+
"CREATE#{' TRUSTED' if opts[:trusted]} LANGUAGE #{name}#{" HANDLER #{opts[:handler]}" if opts[:handler]}#{" VALIDATOR #{opts[:validator]}" if opts[:validator]}"
|
217
|
+
end
|
218
|
+
|
219
|
+
# Create a trigger in the database. See create_trigger_sql for arguments.
|
220
|
+
def create_trigger(*args)
|
221
|
+
self << create_trigger_sql(*args)
|
222
|
+
end
|
223
|
+
|
224
|
+
# SQL for creating a database trigger. Arguments:
|
225
|
+
# * table : the table on which this trigger operates
|
226
|
+
# * name : the name of this trigger
|
227
|
+
# * function : the function to call for this trigger, which should return type trigger.
|
228
|
+
# * opts : options hash:
|
229
|
+
# * :after : Calls the trigger after execution instead of before.
|
230
|
+
# * :args : An argument or array of arguments to pass to the function.
|
231
|
+
# * :each_row : Calls the trigger for each row instead of for each statement.
|
232
|
+
# * :events : Can be :insert, :update, :delete, or an array of any of those. Calls the trigger whenever that type of statement is used. By default,
|
233
|
+
# the trigger is called for insert, update, or delete.
|
234
|
+
def create_trigger_sql(table, name, function, opts={})
|
235
|
+
events = opts[:events] ? Array(opts[:events]) : [:insert, :update, :delete]
|
236
|
+
whence = opts[:after] ? 'AFTER' : 'BEFORE'
|
237
|
+
"CREATE TRIGGER #{name} #{whence} #{events.map{|e| e.to_s.upcase}.join(' OR ')} ON #{quote_schema_table(table)}#{' FOR EACH ROW' if opts[:each_row]} EXECUTE PROCEDURE #{function}(#{Array(opts[:args]).map{|a| literal(a)}.join(', ')})"
|
238
|
+
end
|
130
239
|
|
131
240
|
# The default schema to use if none is specified (default: public)
|
132
241
|
def default_schema
|
133
242
|
@default_schema ||= :public
|
134
243
|
end
|
135
244
|
|
245
|
+
# Drops the function from the database. See drop_function_sql for arguments.
|
246
|
+
def drop_function(*args)
|
247
|
+
self << drop_function_sql(*args)
|
248
|
+
end
|
249
|
+
|
250
|
+
# SQL for dropping a function from the database. Arguments:
|
251
|
+
# * name : name of the function to drop
|
252
|
+
# * opts : options hash:
|
253
|
+
# * :args : The arguments for the function. See create_function_sql.
|
254
|
+
# * :cascade : Drop other objects depending on this function.
|
255
|
+
# * :if_exists : Don't raise an error if the function doesn't exist.
|
256
|
+
def drop_function_sql(name, opts={})
|
257
|
+
"DROP FUNCTION#{' IF EXISTS' if opts[:if_exists]} #{name}#{sql_function_args(opts[:args])}#{' CASCADE' if opts[:cascade]}"
|
258
|
+
end
|
259
|
+
|
260
|
+
# Drops a procedural language from the database. See drop_language_sql for arguments.
|
261
|
+
def drop_language(*args)
|
262
|
+
self << drop_language_sql(*args)
|
263
|
+
end
|
264
|
+
|
265
|
+
# SQL for dropping a procedural language from the database. Arguments:
|
266
|
+
# * name : name of the procedural language to drop
|
267
|
+
# * opts : options hash:
|
268
|
+
# * :cascade : Drop other objects depending on this function.
|
269
|
+
# * :if_exists : Don't raise an error if the function doesn't exist.
|
270
|
+
def drop_language_sql(name, opts={})
|
271
|
+
"DROP LANGUAGE#{' IF EXISTS' if opts[:if_exists]} #{name}#{' CASCADE' if opts[:cascade]}"
|
272
|
+
end
|
273
|
+
|
136
274
|
# Remove the cached entries for primary keys and sequences when dropping a table.
|
137
275
|
def drop_table(*names)
|
138
276
|
names.each do |name|
|
@@ -148,6 +286,21 @@ module Sequel
|
|
148
286
|
"DROP TABLE #{quote_schema_table(name)} CASCADE"
|
149
287
|
end
|
150
288
|
|
289
|
+
# Drops a trigger from the database. See drop_trigger_sql for arguments.
|
290
|
+
def drop_trigger(*args)
|
291
|
+
self << drop_trigger_sql(*args)
|
292
|
+
end
|
293
|
+
|
294
|
+
# SQL for dropping a trigger from the database. Arguments:
|
295
|
+
# * table : table from which to drop the trigger
|
296
|
+
# * name : name of the trigger to drop
|
297
|
+
# * opts : options hash:
|
298
|
+
# * :cascade : Drop other objects depending on this function.
|
299
|
+
# * :if_exists : Don't raise an error if the function doesn't exist.
|
300
|
+
def drop_trigger_sql(table, name, opts={})
|
301
|
+
"DROP TRIGGER#{' IF EXISTS' if opts[:if_exists]} #{name} ON #{quote_schema_table(table)}#{' CASCADE' if opts[:cascade]}"
|
302
|
+
end
|
303
|
+
|
151
304
|
# PostgreSQL specific index SQL.
|
152
305
|
def index_definition_sql(table_name, index)
|
153
306
|
index_name = index[:name] || default_index_name(table_name, index[:columns])
|
@@ -375,6 +528,11 @@ module Sequel
|
|
375
528
|
end
|
376
529
|
ds
|
377
530
|
end
|
531
|
+
|
532
|
+
# Turns an array of argument specifiers into an SQL fragment used for function arguments. See create_function_sql.
|
533
|
+
def sql_function_args(args)
|
534
|
+
"(#{Array(args).map{|a| Array(a).reverse.join(' ')}.join(', ')})"
|
535
|
+
end
|
378
536
|
end
|
379
537
|
|
380
538
|
# Instance methods for datasets that connect to a PostgreSQL database.
|
@@ -394,7 +552,7 @@ module Sequel
|
|
394
552
|
QUERY_PLAN = 'QUERY PLAN'.to_sym
|
395
553
|
ROW_EXCLUSIVE = 'ROW EXCLUSIVE'.freeze
|
396
554
|
ROW_SHARE = 'ROW SHARE'.freeze
|
397
|
-
SELECT_CLAUSE_ORDER = %w'distinct columns from join where group having
|
555
|
+
SELECT_CLAUSE_ORDER = %w'distinct columns from join where group having compounds order limit lock'.freeze
|
398
556
|
SHARE = 'SHARE'.freeze
|
399
557
|
SHARE_ROW_EXCLUSIVE = 'SHARE ROW EXCLUSIVE'.freeze
|
400
558
|
SHARE_UPDATE_EXCLUSIVE = 'SHARE UPDATE EXCLUSIVE'.freeze
|
@@ -476,7 +634,7 @@ module Sequel
|
|
476
634
|
when LiteralString
|
477
635
|
v
|
478
636
|
when SQL::Blob
|
479
|
-
db.synchronize{|c| "
|
637
|
+
db.synchronize{|c| "'#{c.escape_bytea(v)}'"}
|
480
638
|
when String
|
481
639
|
db.synchronize{|c| "'#{c.escape_string(v)}'"}
|
482
640
|
when Time
|
@@ -526,6 +684,15 @@ module Sequel
|
|
526
684
|
pk = db.primary_key(opts[:from].first)
|
527
685
|
insert_returning_sql(pk ? Sequel::SQL::Identifier.new(pk) : 'NULL'.lit, *values)
|
528
686
|
end
|
687
|
+
|
688
|
+
# PostgreSQL is smart and can use parantheses around all datasets to get
|
689
|
+
# the correct answers.
|
690
|
+
def select_compounds_sql(sql, opts)
|
691
|
+
return unless opts[:compounds]
|
692
|
+
opts[:compounds].each do |type, dataset, all|
|
693
|
+
sql.replace("(#{sql} #{type.to_s.upcase}#{' ALL' if all} #{subselect_sql(dataset)})")
|
694
|
+
end
|
695
|
+
end
|
529
696
|
|
530
697
|
# The order of clauses in the SELECT SQL statement
|
531
698
|
def select_clause_order
|