sequel 3.41.0 → 3.42.0
Sign up to get free protection for your applications and to get access to all the features.
- 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]
|