sequel 3.41.0 → 3.42.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 +28 -0
- data/README.rdoc +18 -6
- data/Rakefile +45 -40
- data/doc/release_notes/3.42.0.txt +74 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +55 -0
- data/lib/sequel/adapters/postgres.rb +4 -32
- data/lib/sequel/adapters/shared/mssql.rb +9 -3
- data/lib/sequel/adapters/shared/oracle.rb +5 -0
- data/lib/sequel/adapters/shared/postgres.rb +59 -2
- data/lib/sequel/adapters/shared/sqlite.rb +5 -0
- data/lib/sequel/database/misc.rb +21 -0
- data/lib/sequel/database/query.rb +10 -2
- data/lib/sequel/database/schema_generator.rb +9 -4
- data/lib/sequel/database/schema_methods.rb +18 -4
- data/lib/sequel/dataset/actions.rb +28 -12
- data/lib/sequel/dataset/query.rb +1 -1
- data/lib/sequel/dataset/sql.rb +1 -1
- data/lib/sequel/extensions/schema_dumper.rb +1 -0
- data/lib/sequel/model.rb +2 -3
- data/lib/sequel/model/base.rb +54 -33
- data/lib/sequel/model/dataset_module.rb +30 -0
- data/lib/sequel/plugins/force_encoding.rb +4 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +84 -73
- data/spec/core/database_spec.rb +11 -3
- data/spec/core/dataset_spec.rb +22 -0
- data/spec/core/schema_spec.rb +41 -0
- data/spec/extensions/force_encoding_spec.rb +9 -0
- data/spec/integration/schema_test.rb +32 -7
- data/spec/model/base_spec.rb +16 -0
- metadata +5 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
+
=== 3.42.0 (2012-12-03)
|
2
|
+
|
3
|
+
* If an exception occurs while committing a transaction, attempt to rollback (jeremyevans)
|
4
|
+
|
5
|
+
* Support setting default string column sizes on a per-Database basis via default_string_column_size (jeremyevans)
|
6
|
+
|
7
|
+
* Reset Model.instance_dataset when extending the model's dataset (jeremyevans)
|
8
|
+
|
9
|
+
* Make the force_encoding plugin work with frozen strings (jeremyevans)
|
10
|
+
|
11
|
+
* Add Database#do on PostgreSQL for using the DO anonymous code block execution statement (jeremyevans)
|
12
|
+
|
13
|
+
* Remove Model.dataset_methods (jeremyevans)
|
14
|
+
|
15
|
+
* Allow subset to be called inside a dataset_module block (jeremyevans)
|
16
|
+
|
17
|
+
* Make Dataset#avg, #interval, #min, #max, #range, and #sum accept virtual row blocks (jeremyevans)
|
18
|
+
|
19
|
+
* Make Dataset#count use a subselect when the dataset has an offset without a limit (jeremyevans) (#587)
|
20
|
+
|
21
|
+
* Dump deferrable status of unique indexes on PostgreSQL (radford) (#583)
|
22
|
+
|
23
|
+
* Extend deferrable constraint support to all types of constraints, not just foreign keys (radford, jeremyevans) (#583)
|
24
|
+
|
25
|
+
* Support Database#copy_table and #copy_into on jdbc/postgres (bdon) (#580)
|
26
|
+
|
27
|
+
* Make Dataset#update not use a limit (TOP) on Microsoft SQL Server 2000 (jeremyevans) (#578)
|
28
|
+
|
1
29
|
=== 3.41.0 (2012-11-01)
|
2
30
|
|
3
31
|
* Add bin/sequel usage guide (jeremyevans)
|
data/README.rdoc
CHANGED
@@ -395,10 +395,10 @@ and not raise an exception outside the block, you can raise the
|
|
395
395
|
Sequel makes it easy to join tables:
|
396
396
|
|
397
397
|
order_items = DB[:items].join(:order_items, :item_id => :id).
|
398
|
-
where(:
|
398
|
+
where(:order_id => 1234)
|
399
399
|
# SELECT * FROM items INNER JOIN order_items
|
400
400
|
# ON order_items.item_id = items.id
|
401
|
-
# WHERE
|
401
|
+
# WHERE order_id = 1234
|
402
402
|
|
403
403
|
The important thing to note here is that item_id is automatically qualified with
|
404
404
|
the table being joined, and id is automatically qualified with the last table
|
@@ -437,9 +437,10 @@ Ruby strings are generally treated as SQL strings:
|
|
437
437
|
items.where(:x => 'x')
|
438
438
|
# SELECT * FROM items WHERE (x = 'x')
|
439
439
|
|
440
|
-
=== Qualifying column names
|
440
|
+
=== Qualifying identifiers (column/table names)
|
441
441
|
|
442
|
-
|
442
|
+
An identifier in SQL is a name that represents a column, table, or schema.
|
443
|
+
Identifiers can be qualified by using the double underscore special notation <tt>:table__column</tt>:
|
443
444
|
|
444
445
|
items.literal(:items__price)
|
445
446
|
# items.price
|
@@ -449,9 +450,15 @@ Another way to qualify columns is to use the <tt>Sequel.qualify</tt> method:
|
|
449
450
|
items.literal(Sequel.qualify(:items, :price))
|
450
451
|
# items.price
|
451
452
|
|
452
|
-
|
453
|
+
While it is more common to qualify column identifiers with table identifiers, you can also qualify table identifiers with schema identifiers
|
454
|
+
to select from a qualified table:
|
455
|
+
|
456
|
+
posts = DB[:some_schema__posts]
|
457
|
+
# SELECT * FROM some_schema.posts
|
458
|
+
|
459
|
+
=== Identifier aliases
|
453
460
|
|
454
|
-
You can also alias
|
461
|
+
You can also alias identifiers by using the triple undersecore special notation <tt>:column___alias</tt> or <tt>:table__column___alias</tt>:
|
455
462
|
|
456
463
|
items.literal(:price___p)
|
457
464
|
# price AS p
|
@@ -463,6 +470,11 @@ Another way to alias columns is to use the <tt>Sequel.as</tt> method:
|
|
463
470
|
items.literal(Sequel.as(:price, :p))
|
464
471
|
# price AS p
|
465
472
|
|
473
|
+
You can use the <tt>Sequel.as</tt> method to alias arbitrary expressions, not just identifiers:
|
474
|
+
|
475
|
+
items.literal(Sequel.as(DB[:posts].select{max(id)}, :p))
|
476
|
+
# (SELECT max(id) FROM posts) AS p
|
477
|
+
|
466
478
|
== Sequel Models
|
467
479
|
|
468
480
|
A model class wraps a dataset, and an instance of that class wraps a single record in the dataset.
|
data/Rakefile
CHANGED
@@ -32,6 +32,18 @@ task :release=>[:package] do
|
|
32
32
|
sh %{gem push ./#{NAME}-#{VERS.call}.gem}
|
33
33
|
end
|
34
34
|
|
35
|
+
### Website
|
36
|
+
|
37
|
+
desc "Make local version of website"
|
38
|
+
task :website do
|
39
|
+
sh %{#{FileUtils::RUBY} www/make_www.rb}
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "Update Non-RDoc section of sequel.rubyforge.org"
|
43
|
+
task :website_rf_base=>[:website] do
|
44
|
+
sh %{rsync -rt www/public/*.html rubyforge.org:/var/www/gforge-projects/sequel/}
|
45
|
+
end
|
46
|
+
|
35
47
|
### RDoc
|
36
48
|
|
37
49
|
RDOC_DEFAULT_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', 'Sequel: The Database Toolkit for Ruby']
|
@@ -41,54 +53,47 @@ rdoc_task_class = begin
|
|
41
53
|
RDOC_DEFAULT_OPTS.concat(['-f', 'hanna'])
|
42
54
|
RDoc::Task
|
43
55
|
rescue LoadError
|
44
|
-
|
45
|
-
|
56
|
+
begin
|
57
|
+
require "rake/rdoctask"
|
58
|
+
Rake::RDocTask
|
59
|
+
rescue LoadError
|
60
|
+
end
|
46
61
|
end
|
47
62
|
|
48
|
-
|
63
|
+
if rdoc_task_class
|
64
|
+
RDOC_OPTS = RDOC_DEFAULT_OPTS + ['--main', 'README.rdoc']
|
49
65
|
|
50
|
-
rdoc_task_class.new do |rdoc|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
end
|
66
|
+
rdoc_task_class.new do |rdoc|
|
67
|
+
rdoc.rdoc_dir = "rdoc"
|
68
|
+
rdoc.options += RDOC_OPTS
|
69
|
+
rdoc.rdoc_files.add %w"README.rdoc CHANGELOG MIT-LICENSE lib/**/*.rb doc/*.rdoc doc/release_notes/*.txt"
|
70
|
+
end if rdoc_task_class
|
55
71
|
|
56
|
-
|
72
|
+
desc "Make rdoc for website"
|
73
|
+
task :website_rdoc=>[:website_rdoc_main, :website_rdoc_adapters, :website_rdoc_plugins]
|
57
74
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
desc "Make rdoc for website"
|
64
|
-
task :website_rdoc=>[:website_rdoc_main, :website_rdoc_adapters, :website_rdoc_plugins]
|
65
|
-
|
66
|
-
rdoc_task_class.new(:website_rdoc_main) do |rdoc|
|
67
|
-
rdoc.rdoc_dir = "www/public/rdoc"
|
68
|
-
rdoc.options += RDOC_OPTS
|
69
|
-
rdoc.rdoc_files.add %w"README.rdoc CHANGELOG MIT-LICENSE lib/*.rb lib/sequel/*.rb lib/sequel/{connection_pool,dataset,database,model}/*.rb doc/*.rdoc doc/release_notes/*.txt lib/sequel/extensions/migration.rb"
|
70
|
-
end
|
71
|
-
|
72
|
-
rdoc_task_class.new(:website_rdoc_adapters) do |rdoc|
|
73
|
-
rdoc.rdoc_dir = "www/public/rdoc-adapters"
|
74
|
-
rdoc.options += RDOC_DEFAULT_OPTS + %w'--main Sequel'
|
75
|
-
rdoc.rdoc_files.add %w"lib/sequel/adapters/**/*.rb"
|
76
|
-
end
|
75
|
+
rdoc_task_class.new(:website_rdoc_main) do |rdoc|
|
76
|
+
rdoc.rdoc_dir = "www/public/rdoc"
|
77
|
+
rdoc.options += RDOC_OPTS
|
78
|
+
rdoc.rdoc_files.add %w"README.rdoc CHANGELOG MIT-LICENSE lib/*.rb lib/sequel/*.rb lib/sequel/{connection_pool,dataset,database,model}/*.rb doc/*.rdoc doc/release_notes/*.txt lib/sequel/extensions/migration.rb"
|
79
|
+
end
|
77
80
|
|
78
|
-
rdoc_task_class.new(:
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
end
|
81
|
+
rdoc_task_class.new(:website_rdoc_adapters) do |rdoc|
|
82
|
+
rdoc.rdoc_dir = "www/public/rdoc-adapters"
|
83
|
+
rdoc.options += RDOC_DEFAULT_OPTS + %w'--main Sequel'
|
84
|
+
rdoc.rdoc_files.add %w"lib/sequel/adapters/**/*.rb"
|
85
|
+
end
|
83
86
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
87
|
+
rdoc_task_class.new(:website_rdoc_plugins) do |rdoc|
|
88
|
+
rdoc.rdoc_dir = "www/public/rdoc-plugins"
|
89
|
+
rdoc.options += RDOC_DEFAULT_OPTS + %w'--main Sequel'
|
90
|
+
rdoc.rdoc_files.add %w"lib/sequel/{extensions,plugins}/**/*.rb"
|
91
|
+
end
|
88
92
|
|
89
|
-
desc "Update sequel.rubyforge.org"
|
90
|
-
task :website_rf=>[:website, :website_rdoc] do
|
91
|
-
|
93
|
+
desc "Update sequel.rubyforge.org"
|
94
|
+
task :website_rf=>[:website, :website_rdoc] do
|
95
|
+
sh %{rsync -rvt www/public/* rubyforge.org:/var/www/gforge-projects/sequel/}
|
96
|
+
end
|
92
97
|
end
|
93
98
|
|
94
99
|
### Specs
|
@@ -0,0 +1,74 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* Dataset#avg, #interval, #min, #max, #range, and #sum now
|
4
|
+
accept virtual row blocks, allowing you to more easily get
|
5
|
+
aggregate values of expressions based on the table:
|
6
|
+
|
7
|
+
DB[:table].sum{some_function(column1, column2)} # => 134
|
8
|
+
# SELECT sum(some_function(column1, column2)) FROM table
|
9
|
+
|
10
|
+
* Database#do has been added on PostgreSQL for using the DO
|
11
|
+
anonymous code block execution statement.
|
12
|
+
|
13
|
+
* Model.dataset_module now uses a Module subclass, which allows
|
14
|
+
you to call subset inside a dataset_module block, making
|
15
|
+
it easier to consolidate dataset method code:
|
16
|
+
|
17
|
+
class Album < Sequel::Model
|
18
|
+
dataset_module do
|
19
|
+
subset(:gold){copies_sold > 500000}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
* Database#copy_table and #copy_into are now supported on
|
24
|
+
jdbc/postgres.
|
25
|
+
|
26
|
+
* Sequel now supports deferred constraints on constraint types other
|
27
|
+
than foreign keys. The only databases that appear to implement
|
28
|
+
this are Oracle and PostgreSQL.
|
29
|
+
|
30
|
+
* Sequel now supports INITIALLY IMMEDIATE deferred constraints via
|
31
|
+
the :deferrable=>:immediate constraint/column option.
|
32
|
+
|
33
|
+
* Sequel now supports setting the default size of string columns,
|
34
|
+
via the default_string_column_size option or accessor. In some
|
35
|
+
cases, Sequel's default string column size of 255 is too large
|
36
|
+
(e.g. MySQL with utf8mb4 character set), and this allows you to
|
37
|
+
change it.
|
38
|
+
|
39
|
+
= Other Improvements
|
40
|
+
|
41
|
+
* Dataset#count and other methods now use a subselect in the case
|
42
|
+
where the dataset has an offset but no limit.
|
43
|
+
|
44
|
+
* If an error occurs while attempting to commit a transaction, Sequel
|
45
|
+
now attempts to rollback the transaction. Some databases do this
|
46
|
+
automatically, but not all. Among other things, this fixes issues
|
47
|
+
with deferred foreign key constraint violations on SQLite.
|
48
|
+
|
49
|
+
* When extending a model's dataset, the model's instance_dataset is
|
50
|
+
reset, insuring that it will also be extended with the module.
|
51
|
+
|
52
|
+
* When passing an invalid argument to Dataset#filter, the exception
|
53
|
+
message now includes the argument.
|
54
|
+
|
55
|
+
* The force_encoding plugin now works with frozen string values.
|
56
|
+
|
57
|
+
* Public methods added to a model dataset_module now have model
|
58
|
+
class methods created for them even if the method was added outside
|
59
|
+
of a dataset_module block.
|
60
|
+
|
61
|
+
* On PostgreSQL, Database#indexes now includes a :deferrable entry
|
62
|
+
for each index hash, which will be true for unique indexes where
|
63
|
+
the underlying constraint is deferrable.
|
64
|
+
|
65
|
+
* On Microsoft SQL Server 2000, Dataset#update no longer includes a
|
66
|
+
limit (TOP), allowing it to work correctly.
|
67
|
+
|
68
|
+
= Backwards Compatibility
|
69
|
+
|
70
|
+
* Model.dataset_methods has been removed. This was used to store
|
71
|
+
blocks for methods created via def_dataset_method and subset.
|
72
|
+
The internals have been changed so that a dataset_module is
|
73
|
+
always used in these cases, therefore there was no longer a reason
|
74
|
+
for this method.
|
@@ -17,7 +17,62 @@ module Sequel
|
|
17
17
|
def self.extended(db)
|
18
18
|
db.send(:initialize_postgres_adapter)
|
19
19
|
end
|
20
|
+
|
21
|
+
# See Sequel::Postgres::Adapter#copy_into
|
22
|
+
def copy_into(table, opts={})
|
23
|
+
data = opts[:data]
|
24
|
+
data = Array(data) if data.is_a?(String)
|
25
|
+
|
26
|
+
if block_given? && data
|
27
|
+
raise Error, "Cannot provide both a :data option and a block to copy_into"
|
28
|
+
elsif !block_given? && !data
|
29
|
+
raise Error, "Must provide either a :data option or a block to copy_into"
|
30
|
+
end
|
31
|
+
|
32
|
+
transaction(opts) do |conn|
|
33
|
+
begin
|
34
|
+
copy_manager = org.postgresql.copy.CopyManager.new(conn)
|
35
|
+
copier = copy_manager.copy_in(copy_into_sql(table, opts))
|
36
|
+
if block_given?
|
37
|
+
while buf = yield
|
38
|
+
copier.writeToCopy(buf.to_java_bytes, 0, buf.length)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
data.each { |d| copier.writeToCopy(d.to_java_bytes, 0, d.length) }
|
42
|
+
end
|
43
|
+
rescue Exception => e
|
44
|
+
copier.endCopy
|
45
|
+
raise
|
46
|
+
ensure
|
47
|
+
copier.endCopy unless e
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
20
51
|
|
52
|
+
# See Sequel::Postgres::Adapter#copy_table
|
53
|
+
def copy_table(table, opts={})
|
54
|
+
synchronize(opts[:server]) do |conn|
|
55
|
+
copy_manager = org.postgresql.copy.CopyManager.new(conn)
|
56
|
+
copier = copy_manager.copy_out(copy_table_sql(table, opts))
|
57
|
+
begin
|
58
|
+
if block_given?
|
59
|
+
while buf = copier.readFromCopy
|
60
|
+
yield(String.from_java_bytes(buf))
|
61
|
+
end
|
62
|
+
nil
|
63
|
+
else
|
64
|
+
b = ''
|
65
|
+
while buf = copier.readFromCopy
|
66
|
+
b << String.from_java_bytes(buf)
|
67
|
+
end
|
68
|
+
b
|
69
|
+
end
|
70
|
+
ensure
|
71
|
+
raise DatabaseDisconnectError, "disconnecting as a partial COPY may leave the connection in an unusable state" if buf
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
21
76
|
private
|
22
77
|
|
23
78
|
# Use setNull for nil arguments as the default behavior of setString
|
@@ -268,24 +268,8 @@ module Sequel
|
|
268
268
|
# per row. If a block is not provided, a single string is returned with all
|
269
269
|
# of the data.
|
270
270
|
def copy_table(table, opts={})
|
271
|
-
|
272
|
-
|
273
|
-
else
|
274
|
-
if opts[:options] || opts[:format]
|
275
|
-
options = " ("
|
276
|
-
options << "FORMAT #{opts[:format]}" if opts[:format]
|
277
|
-
options << "#{', ' if opts[:format]}#{opts[:options]}" if opts[:options]
|
278
|
-
options << ')'
|
279
|
-
end
|
280
|
-
table = if table.is_a?(::Sequel::Dataset)
|
281
|
-
"(#{table.sql})"
|
282
|
-
else
|
283
|
-
literal(table)
|
284
|
-
end
|
285
|
-
sql = "COPY #{table} TO STDOUT#{options}"
|
286
|
-
end
|
287
|
-
synchronize(opts[:server]) do |conn|
|
288
|
-
conn.execute(sql)
|
271
|
+
synchronize(opts[:server]) do |conn|
|
272
|
+
conn.execute(copy_table_sql(table, opts))
|
289
273
|
begin
|
290
274
|
if block_given?
|
291
275
|
while buf = conn.get_copy_data
|
@@ -323,18 +307,6 @@ module Sequel
|
|
323
307
|
# If a block is provided and :data option is not, this will yield to the block repeatedly.
|
324
308
|
# The block should return a string, or nil to signal that it is finished.
|
325
309
|
def copy_into(table, opts={})
|
326
|
-
sql = "COPY #{literal(table)}"
|
327
|
-
if cols = opts[:columns]
|
328
|
-
sql << literal(Array(cols))
|
329
|
-
end
|
330
|
-
sql << " FROM STDIN"
|
331
|
-
if opts[:options] || opts[:format]
|
332
|
-
sql << " ("
|
333
|
-
sql << "FORMAT #{opts[:format]}" if opts[:format]
|
334
|
-
sql << "#{', ' if opts[:format]}#{opts[:options]}" if opts[:options]
|
335
|
-
sql << ')'
|
336
|
-
end
|
337
|
-
|
338
310
|
data = opts[:data]
|
339
311
|
data = Array(data) if data.is_a?(String)
|
340
312
|
|
@@ -344,8 +316,8 @@ module Sequel
|
|
344
316
|
raise Error, "Must provide either a :data option or a block to copy_into"
|
345
317
|
end
|
346
318
|
|
347
|
-
synchronize(opts[:server]) do |conn|
|
348
|
-
conn.execute(
|
319
|
+
synchronize(opts[:server]) do |conn|
|
320
|
+
conn.execute(copy_into_sql(table, opts))
|
349
321
|
begin
|
350
322
|
if block_given?
|
351
323
|
while buf = yield
|
@@ -380,6 +380,7 @@ module Sequel
|
|
380
380
|
INSERT_CLAUSE_METHODS = Dataset.clause_methods(:insert, %w'with insert into columns output values')
|
381
381
|
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'with select distinct limit columns into from lock join where group having order compounds')
|
382
382
|
UPDATE_CLAUSE_METHODS = Dataset.clause_methods(:update, %w'with update limit table set output from where')
|
383
|
+
UPDATE_CLAUSE_METHODS_2000 = Dataset.clause_methods(:update, %w'update table set output from where')
|
383
384
|
NOLOCK = ' WITH (NOLOCK)'.freeze
|
384
385
|
UPDLOCK = ' WITH (UPDLOCK)'.freeze
|
385
386
|
WILDCARD = LiteralString.new('*').freeze
|
@@ -801,10 +802,15 @@ module Sequel
|
|
801
802
|
alias delete_output_sql output_sql
|
802
803
|
alias update_output_sql output_sql
|
803
804
|
|
804
|
-
# MSSQL supports the OUTPUT clause for UPDATE statements.
|
805
|
-
# It also allows prepending a WITH clause.
|
805
|
+
# MSSQL supports the OUTPUT and TOP clause for UPDATE statements.
|
806
|
+
# It also allows prepending a WITH clause. For MSSQL 2000
|
807
|
+
# and below, exclude WITH and TOP.
|
806
808
|
def update_clause_methods
|
807
|
-
|
809
|
+
if is_2005_or_later?
|
810
|
+
UPDATE_CLAUSE_METHODS
|
811
|
+
else
|
812
|
+
UPDATE_CLAUSE_METHODS_2000
|
813
|
+
end
|
808
814
|
end
|
809
815
|
|
810
816
|
# Only include the primary table in the main update clause
|
@@ -49,6 +49,11 @@ module Sequel
|
|
49
49
|
metadata_dataset.from(:tab).filter(:tname =>m.call(name), :tabtype => 'VIEW').count > 0
|
50
50
|
end
|
51
51
|
|
52
|
+
# Oracle supports deferrable constraints.
|
53
|
+
def supports_deferrable_constraints?
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
52
57
|
private
|
53
58
|
|
54
59
|
# Handle Oracle specific ALTER TABLE SQL
|
@@ -224,6 +224,16 @@ module Sequel
|
|
224
224
|
:postgres
|
225
225
|
end
|
226
226
|
|
227
|
+
# Use PostgreSQL's DO syntax to execute an anonymous code block. The code should
|
228
|
+
# be the literal code string to use in the underlying procedural language. Options:
|
229
|
+
#
|
230
|
+
# :language :: The procedural language the code is written in. The PostgreSQL
|
231
|
+
# default is plpgsql. Can be specified as a string or a symbol.
|
232
|
+
def do(code, opts={})
|
233
|
+
language = opts[:language]
|
234
|
+
run "DO #{"LANGUAGE #{literal(language.to_s)} " if language}#{literal(code)}"
|
235
|
+
end
|
236
|
+
|
227
237
|
# Drops the function from the database. Arguments:
|
228
238
|
# * name : name of the function to drop
|
229
239
|
# * opts : options hash:
|
@@ -343,16 +353,17 @@ module Sequel
|
|
343
353
|
join(:pg_index___ind, :indrelid=>:oid, im.call(table)=>:relname).
|
344
354
|
join(:pg_class___indc, :oid=>:indexrelid).
|
345
355
|
join(:pg_attribute___att, :attrelid=>:tab__oid, :attnum=>attnums).
|
356
|
+
left_join(:pg_constraint___con, :conname=>:indc__relname).
|
346
357
|
filter(:indc__relkind=>'i', :ind__indisprimary=>false, :indexprs=>nil, :indpred=>nil, :indisvalid=>true).
|
347
358
|
order(:indc__relname, SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(:ind__indkey, [x]), x]}, 32, :att__attnum)).
|
348
|
-
select(:indc__relname___name, :ind__indisunique___unique, :att__attname___column)
|
359
|
+
select(:indc__relname___name, :ind__indisunique___unique, :att__attname___column, :con__condeferrable___deferrable)
|
349
360
|
|
350
361
|
ds.join!(:pg_namespace___nsp, :oid=>:tab__relnamespace, :nspname=>schema.to_s) if schema
|
351
362
|
ds.filter!(:indisready=>true, :indcheckxmin=>false) if server_version >= 80300
|
352
363
|
|
353
364
|
indexes = {}
|
354
365
|
ds.each do |r|
|
355
|
-
i = indexes[m.call(r[:name])] ||= {:columns=>[], :unique=>r[:unique]}
|
366
|
+
i = indexes[m.call(r[:name])] ||= {:columns=>[], :unique=>r[:unique], :deferrable=>r[:deferrable]}
|
356
367
|
i[:columns] << m.call(r[:column])
|
357
368
|
end
|
358
369
|
indexes
|
@@ -455,6 +466,16 @@ module Sequel
|
|
455
466
|
server_version >= 90100
|
456
467
|
end
|
457
468
|
|
469
|
+
# PostgreSQL 9.0+ supports some types of deferrable constraints beyond foreign key constraints.
|
470
|
+
def supports_deferrable_constraints?
|
471
|
+
server_version >= 90000
|
472
|
+
end
|
473
|
+
|
474
|
+
# PostgreSQL supports deferrable foreign key constraints.
|
475
|
+
def supports_deferrable_foreign_key_constraints?
|
476
|
+
true
|
477
|
+
end
|
478
|
+
|
458
479
|
# PostgreSQL supports DROP TABLE IF EXISTS
|
459
480
|
def supports_drop_table_if_exists?
|
460
481
|
true
|
@@ -604,6 +625,42 @@ module Sequel
|
|
604
625
|
end
|
605
626
|
end
|
606
627
|
|
628
|
+
# SQL for doing fast table insert from stdin.
|
629
|
+
def copy_into_sql(table, opts)
|
630
|
+
sql = "COPY #{literal(table)}"
|
631
|
+
if cols = opts[:columns]
|
632
|
+
sql << literal(Array(cols))
|
633
|
+
end
|
634
|
+
sql << " FROM STDIN"
|
635
|
+
if opts[:options] || opts[:format]
|
636
|
+
sql << " ("
|
637
|
+
sql << "FORMAT #{opts[:format]}" if opts[:format]
|
638
|
+
sql << "#{', ' if opts[:format]}#{opts[:options]}" if opts[:options]
|
639
|
+
sql << ')'
|
640
|
+
end
|
641
|
+
sql
|
642
|
+
end
|
643
|
+
|
644
|
+
# SQL for doing fast table output to stdout.
|
645
|
+
def copy_table_sql(table, opts)
|
646
|
+
if table.is_a?(String)
|
647
|
+
return table
|
648
|
+
else
|
649
|
+
if opts[:options] || opts[:format]
|
650
|
+
options = " ("
|
651
|
+
options << "FORMAT #{opts[:format]}" if opts[:format]
|
652
|
+
options << "#{', ' if opts[:format]}#{opts[:options]}" if opts[:options]
|
653
|
+
options << ')'
|
654
|
+
end
|
655
|
+
table = if table.is_a?(::Sequel::Dataset)
|
656
|
+
"(#{table.sql})"
|
657
|
+
else
|
658
|
+
literal(table)
|
659
|
+
end
|
660
|
+
return "COPY #{table} TO STDOUT#{options}"
|
661
|
+
end
|
662
|
+
end
|
663
|
+
|
607
664
|
# SQL statement to create database function.
|
608
665
|
def create_function_sql(name, definition, opts={})
|
609
666
|
args = opts[:args]
|