sequel 3.36.1 → 3.37.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 +84 -0
- data/Rakefile +13 -0
- data/bin/sequel +12 -16
- data/doc/advanced_associations.rdoc +36 -67
- data/doc/association_basics.rdoc +11 -16
- data/doc/release_notes/3.37.0.txt +338 -0
- data/doc/schema_modification.rdoc +4 -0
- data/lib/sequel/adapters/jdbc/h2.rb +1 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +26 -8
- data/lib/sequel/adapters/mysql2.rb +4 -3
- data/lib/sequel/adapters/odbc/mssql.rb +2 -2
- data/lib/sequel/adapters/postgres.rb +4 -60
- data/lib/sequel/adapters/shared/mssql.rb +2 -1
- data/lib/sequel/adapters/shared/mysql.rb +0 -5
- data/lib/sequel/adapters/shared/postgres.rb +68 -2
- data/lib/sequel/adapters/shared/sqlite.rb +17 -1
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +12 -1
- data/lib/sequel/adapters/utils/pg_types.rb +76 -0
- data/lib/sequel/core.rb +13 -0
- data/lib/sequel/database/misc.rb +41 -1
- data/lib/sequel/database/schema_generator.rb +23 -10
- data/lib/sequel/database/schema_methods.rb +26 -4
- data/lib/sequel/dataset/graph.rb +2 -1
- data/lib/sequel/dataset/query.rb +62 -2
- data/lib/sequel/extensions/_pretty_table.rb +7 -3
- data/lib/sequel/extensions/arbitrary_servers.rb +5 -4
- data/lib/sequel/extensions/blank.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +13 -2
- data/lib/sequel/extensions/core_extensions.rb +6 -0
- data/lib/sequel/extensions/eval_inspect.rb +158 -0
- data/lib/sequel/extensions/inflector.rb +4 -0
- data/lib/sequel/extensions/looser_typecasting.rb +5 -4
- data/lib/sequel/extensions/migration.rb +4 -1
- data/lib/sequel/extensions/named_timezones.rb +4 -0
- data/lib/sequel/extensions/null_dataset.rb +4 -0
- data/lib/sequel/extensions/pagination.rb +4 -0
- data/lib/sequel/extensions/pg_array.rb +219 -168
- data/lib/sequel/extensions/pg_array_ops.rb +7 -2
- data/lib/sequel/extensions/pg_auto_parameterize.rb +10 -4
- data/lib/sequel/extensions/pg_hstore.rb +3 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +7 -2
- data/lib/sequel/extensions/pg_inet.rb +28 -3
- data/lib/sequel/extensions/pg_interval.rb +192 -0
- data/lib/sequel/extensions/pg_json.rb +21 -9
- data/lib/sequel/extensions/pg_range.rb +487 -0
- data/lib/sequel/extensions/pg_range_ops.rb +122 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +3 -2
- data/lib/sequel/extensions/pretty_table.rb +12 -1
- data/lib/sequel/extensions/query.rb +4 -0
- data/lib/sequel/extensions/query_literals.rb +6 -6
- data/lib/sequel/extensions/schema_dumper.rb +39 -38
- data/lib/sequel/extensions/select_remove.rb +4 -0
- data/lib/sequel/extensions/server_block.rb +3 -2
- data/lib/sequel/extensions/split_array_nil.rb +65 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -0
- data/lib/sequel/extensions/string_date_time.rb +4 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +9 -3
- data/lib/sequel/extensions/to_dot.rb +4 -0
- data/lib/sequel/model/associations.rb +150 -91
- data/lib/sequel/plugins/identity_map.rb +2 -2
- data/lib/sequel/plugins/list.rb +1 -0
- data/lib/sequel/plugins/many_through_many.rb +33 -32
- data/lib/sequel/plugins/nested_attributes.rb +11 -3
- data/lib/sequel/plugins/rcte_tree.rb +2 -2
- data/lib/sequel/plugins/schema.rb +1 -1
- data/lib/sequel/sql.rb +14 -14
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/mysql_spec.rb +25 -0
- data/spec/adapters/postgres_spec.rb +572 -28
- data/spec/adapters/sqlite_spec.rb +16 -1
- data/spec/core/database_spec.rb +61 -2
- data/spec/core/dataset_spec.rb +92 -0
- data/spec/core/expression_filters_spec.rb +12 -0
- data/spec/extensions/arbitrary_servers_spec.rb +1 -1
- data/spec/extensions/boolean_readers_spec.rb +25 -25
- data/spec/extensions/eval_inspect_spec.rb +58 -0
- data/spec/extensions/json_serializer_spec.rb +0 -6
- data/spec/extensions/list_spec.rb +1 -1
- data/spec/extensions/looser_typecasting_spec.rb +7 -7
- data/spec/extensions/many_through_many_spec.rb +81 -0
- data/spec/extensions/nested_attributes_spec.rb +21 -4
- data/spec/extensions/pg_array_ops_spec.rb +1 -11
- data/spec/extensions/pg_array_spec.rb +181 -90
- data/spec/extensions/pg_auto_parameterize_spec.rb +3 -3
- data/spec/extensions/pg_hstore_spec.rb +1 -3
- data/spec/extensions/pg_inet_spec.rb +6 -1
- data/spec/extensions/pg_interval_spec.rb +73 -0
- data/spec/extensions/pg_json_spec.rb +5 -9
- data/spec/extensions/pg_range_ops_spec.rb +49 -0
- data/spec/extensions/pg_range_spec.rb +372 -0
- data/spec/extensions/pg_statement_cache_spec.rb +1 -2
- data/spec/extensions/query_literals_spec.rb +1 -2
- data/spec/extensions/schema_dumper_spec.rb +48 -89
- data/spec/extensions/serialization_spec.rb +1 -5
- data/spec/extensions/server_block_spec.rb +2 -2
- data/spec/extensions/spec_helper.rb +12 -2
- data/spec/extensions/split_array_nil_spec.rb +24 -0
- data/spec/integration/associations_test.rb +4 -4
- data/spec/integration/database_test.rb +2 -2
- data/spec/integration/dataset_test.rb +4 -4
- data/spec/integration/eager_loader_test.rb +6 -6
- data/spec/integration/plugin_test.rb +2 -2
- data/spec/integration/spec_helper.rb +2 -2
- data/spec/model/association_reflection_spec.rb +5 -0
- data/spec/model/associations_spec.rb +156 -49
- data/spec/model/eager_loading_spec.rb +137 -2
- data/spec/model/model_spec.rb +10 -10
- metadata +15 -2
|
@@ -98,6 +98,10 @@ You've seen this one used already. It's used to create an autoincrementing inte
|
|
|
98
98
|
|
|
99
99
|
create_table(:a0){primary_key :id}
|
|
100
100
|
|
|
101
|
+
If you want an autoincrementing 64-bit integer:
|
|
102
|
+
|
|
103
|
+
create_table(:a0){primary_key :id, :type=>Bignum}
|
|
104
|
+
|
|
101
105
|
If you want to create a primary key column that doesn't use an autoincrementing integer, you should
|
|
102
106
|
not use this method. Instead, you should use the :primary_key option to the +column+ method or type
|
|
103
107
|
method:
|
|
@@ -112,7 +112,7 @@ module Sequel
|
|
|
112
112
|
|
|
113
113
|
# Treat clob as string instead of blob
|
|
114
114
|
def schema_column_type(db_type)
|
|
115
|
-
db_type == 'clob' ? :string : super
|
|
115
|
+
db_type.downcase == 'clob' ? :string : super
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
# Use BIGINT IDENTITY for identity columns that use bigint, fixes
|
|
@@ -45,24 +45,43 @@ module Sequel
|
|
|
45
45
|
APOS = Dataset::APOS
|
|
46
46
|
|
|
47
47
|
class ::Sequel::JDBC::Dataset::TYPE_TRANSLATOR
|
|
48
|
-
# Convert Java::OrgPostgresqlJdbc4::Jdbc4Array to ruby arrays
|
|
49
|
-
def pg_array(v)
|
|
50
|
-
_pg_array(v.array)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
48
|
# Convert Java::OrgPostgresqlUtil::PGobject to ruby strings
|
|
54
49
|
def pg_object(v)
|
|
55
50
|
v.to_string
|
|
56
51
|
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Handle conversions of PostgreSQL array instances
|
|
55
|
+
class PGArrayConverter
|
|
56
|
+
# Set the method that will return the correct conversion
|
|
57
|
+
# proc for elements of this array.
|
|
58
|
+
def initialize(meth)
|
|
59
|
+
@conversion_proc_method = meth
|
|
60
|
+
@conversion_proc = nil
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Convert Java::OrgPostgresqlJdbc4::Jdbc4Array to ruby arrays
|
|
64
|
+
def call(v)
|
|
65
|
+
_pg_array(v.array)
|
|
66
|
+
end
|
|
57
67
|
|
|
58
68
|
private
|
|
59
69
|
|
|
60
70
|
# Handle multi-dimensional Java arrays by recursively mapping them
|
|
61
|
-
# to ruby arrays.
|
|
71
|
+
# to ruby arrays of ruby values.
|
|
62
72
|
def _pg_array(v)
|
|
63
73
|
v.to_ary.map do |i|
|
|
64
74
|
if i.respond_to?(:to_ary)
|
|
65
75
|
_pg_array(i)
|
|
76
|
+
elsif i
|
|
77
|
+
if @conversion_proc.nil?
|
|
78
|
+
@conversion_proc = @conversion_proc_method.call(i)
|
|
79
|
+
end
|
|
80
|
+
if @conversion_proc
|
|
81
|
+
@conversion_proc.call(i)
|
|
82
|
+
else
|
|
83
|
+
i
|
|
84
|
+
end
|
|
66
85
|
else
|
|
67
86
|
i
|
|
68
87
|
end
|
|
@@ -70,7 +89,6 @@ module Sequel
|
|
|
70
89
|
end
|
|
71
90
|
end
|
|
72
91
|
|
|
73
|
-
PG_ARRAY_METHOD = TYPE_TRANSLATOR_INSTANCE.method(:pg_array)
|
|
74
92
|
PG_OBJECT_METHOD = TYPE_TRANSLATOR_INSTANCE.method(:pg_object)
|
|
75
93
|
|
|
76
94
|
# Add the shared PostgreSQL prepared statement methods
|
|
@@ -88,7 +106,7 @@ module Sequel
|
|
|
88
106
|
def convert_type_proc(v)
|
|
89
107
|
case v
|
|
90
108
|
when Java::OrgPostgresqlJdbc4::Jdbc4Array
|
|
91
|
-
|
|
109
|
+
PGArrayConverter.new(method(:convert_type_proc))
|
|
92
110
|
when Java::OrgPostgresqlUtil::PGobject
|
|
93
111
|
PG_OBJECT_METHOD
|
|
94
112
|
else
|
|
@@ -47,6 +47,7 @@ module Sequel
|
|
|
47
47
|
opts[:username] ||= opts[:user]
|
|
48
48
|
opts[:flags] = ::Mysql2::Client::FOUND_ROWS if ::Mysql2::Client.const_defined?(:FOUND_ROWS)
|
|
49
49
|
conn = ::Mysql2::Client.new(opts)
|
|
50
|
+
conn.query_options.merge!(:symbolize_keys=>true, :cache_rows=>false)
|
|
50
51
|
|
|
51
52
|
sqls = mysql_connection_setting_sqls
|
|
52
53
|
|
|
@@ -86,7 +87,7 @@ module Sequel
|
|
|
86
87
|
# yield the connection if a block is given.
|
|
87
88
|
def _execute(conn, sql, opts)
|
|
88
89
|
begin
|
|
89
|
-
r = log_yield((log_sql = opts[:log_sql]) ? sql + log_sql : sql){conn.query(sql, :
|
|
90
|
+
r = log_yield((log_sql = opts[:log_sql]) ? sql + log_sql : sql){conn.query(sql, :database_timezone => timezone, :application_timezone => Sequel.application_timezone, :cast_booleans => convert_tinyint_to_bool)}
|
|
90
91
|
if opts[:type] == :select
|
|
91
92
|
yield r if r
|
|
92
93
|
elsif block_given?
|
|
@@ -149,7 +150,7 @@ module Sequel
|
|
|
149
150
|
cols = r.fields
|
|
150
151
|
@columns = cols2 = cols.map{|c| output_identifier(c.to_s)}
|
|
151
152
|
cs = cols.zip(cols2)
|
|
152
|
-
r.each
|
|
153
|
+
r.each do |row|
|
|
153
154
|
h = {}
|
|
154
155
|
cs.each do |a, b|
|
|
155
156
|
h[b] = row[a]
|
|
@@ -158,7 +159,7 @@ module Sequel
|
|
|
158
159
|
end
|
|
159
160
|
else
|
|
160
161
|
@columns = r.fields
|
|
161
|
-
r.each
|
|
162
|
+
r.each{|h| yield h}
|
|
162
163
|
end
|
|
163
164
|
end
|
|
164
165
|
self
|
|
@@ -16,8 +16,8 @@ module Sequel
|
|
|
16
16
|
log_yield(sql){conn.do(sql)}
|
|
17
17
|
begin
|
|
18
18
|
s = log_yield(LAST_INSERT_ID_SQL){conn.run(LAST_INSERT_ID_SQL)}
|
|
19
|
-
if (rows = s.fetch_all) and (row = rows.first)
|
|
20
|
-
Integer(
|
|
19
|
+
if (rows = s.fetch_all) and (row = rows.first) and (v = row.first)
|
|
20
|
+
Integer(v)
|
|
21
21
|
end
|
|
22
22
|
ensure
|
|
23
23
|
s.drop if s
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
Sequel.require 'adapters/shared/postgres'
|
|
2
|
+
Sequel.require 'adapters/utils/pg_types'
|
|
2
3
|
|
|
3
4
|
begin
|
|
4
5
|
require 'pg'
|
|
@@ -87,68 +88,11 @@ module Sequel
|
|
|
87
88
|
Dataset::NON_SQL_OPTIONS << :cursor
|
|
88
89
|
module Postgres
|
|
89
90
|
CONVERTED_EXCEPTIONS << PGError
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
PLUS_INFINITY = 1.0/0.0
|
|
93
|
-
MINUS_INFINITY = -1.0/0.0
|
|
94
|
-
NAN_STR = 'NaN'.freeze
|
|
95
|
-
PLUS_INFINITY_STR = 'Infinity'.freeze
|
|
96
|
-
MINUS_INFINITY_STR = '-Infinity'.freeze
|
|
97
|
-
TRUE_STR = 't'.freeze
|
|
98
|
-
DASH_STR = '-'.freeze
|
|
99
|
-
|
|
100
|
-
TYPE_TRANSLATOR = tt = Class.new do
|
|
101
|
-
def boolean(s) s == TRUE_STR end
|
|
91
|
+
|
|
92
|
+
PG_TYPES[17] = Class.new do
|
|
102
93
|
def bytea(s) ::Sequel::SQL::Blob.new(Adapter.unescape_bytea(s)) end
|
|
103
|
-
|
|
104
|
-
def float(s)
|
|
105
|
-
case s
|
|
106
|
-
when NAN_STR
|
|
107
|
-
NAN
|
|
108
|
-
when PLUS_INFINITY_STR
|
|
109
|
-
PLUS_INFINITY
|
|
110
|
-
when MINUS_INFINITY_STR
|
|
111
|
-
MINUS_INFINITY
|
|
112
|
-
else
|
|
113
|
-
s.to_f
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
def date(s) ::Date.new(*s.split(DASH_STR).map{|x| x.to_i}) end
|
|
117
|
-
end.new
|
|
118
|
-
|
|
119
|
-
# Hash with type name strings/symbols and callable values for converting PostgreSQL types.
|
|
120
|
-
# Non-builtin types that don't have fixed numbers should use this to register
|
|
121
|
-
# conversion procs.
|
|
122
|
-
PG_NAMED_TYPES = {} unless defined?(PG_NAMED_TYPES)
|
|
123
|
-
|
|
124
|
-
# Hash with integer keys and callable values for converting PostgreSQL types.
|
|
125
|
-
PG_TYPES = {} unless defined?(PG_TYPES)
|
|
126
|
-
|
|
127
|
-
{
|
|
128
|
-
[16] => tt.method(:boolean),
|
|
129
|
-
[17] => tt.method(:bytea),
|
|
130
|
-
[20, 21, 22, 23, 26] => tt.method(:integer),
|
|
131
|
-
[700, 701] => tt.method(:float),
|
|
132
|
-
[790, 1700] => ::BigDecimal.method(:new),
|
|
133
|
-
[1083, 1266] => ::Sequel.method(:string_to_time),
|
|
134
|
-
}.each do |k,v|
|
|
135
|
-
k.each{|n| PG_TYPES[n] = v}
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
class << self
|
|
139
|
-
# As an optimization, Sequel sets the date style to ISO, so that PostgreSQL provides
|
|
140
|
-
# the date in a known format that Sequel can parse faster. This can be turned off
|
|
141
|
-
# if you require a date style other than ISO.
|
|
142
|
-
attr_reader :use_iso_date_format
|
|
143
|
-
end
|
|
94
|
+
end.new.method(:bytea)
|
|
144
95
|
|
|
145
|
-
# Modify the type translator for the date type depending on the value given.
|
|
146
|
-
def self.use_iso_date_format=(v)
|
|
147
|
-
PG_TYPES[1082] = v ? TYPE_TRANSLATOR.method(:date) : Sequel.method(:string_to_date)
|
|
148
|
-
@use_iso_date_format = v
|
|
149
|
-
end
|
|
150
|
-
self.use_iso_date_format = true
|
|
151
|
-
|
|
152
96
|
# PGconn subclass for connection specific methods used with the
|
|
153
97
|
# pg, postgres, or postgres-pr driver.
|
|
154
98
|
class Adapter < ::PGconn
|
|
@@ -316,7 +316,7 @@ module Sequel
|
|
|
316
316
|
DELETE_CLAUSE_METHODS = Dataset.clause_methods(:delete, %w'with delete from output from2 where')
|
|
317
317
|
INSERT_CLAUSE_METHODS = Dataset.clause_methods(:insert, %w'with insert into columns output values')
|
|
318
318
|
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'with select distinct limit columns into from lock join where group having order compounds')
|
|
319
|
-
UPDATE_CLAUSE_METHODS = Dataset.clause_methods(:update, %w'with update table set output from where')
|
|
319
|
+
UPDATE_CLAUSE_METHODS = Dataset.clause_methods(:update, %w'with update limit table set output from where')
|
|
320
320
|
NOLOCK = ' WITH (NOLOCK)'.freeze
|
|
321
321
|
UPDLOCK = ' WITH (UPDLOCK)'.freeze
|
|
322
322
|
WILDCARD = LiteralString.new('*').freeze
|
|
@@ -690,6 +690,7 @@ module Sequel
|
|
|
690
690
|
end
|
|
691
691
|
end
|
|
692
692
|
end
|
|
693
|
+
alias update_limit_sql select_limit_sql
|
|
693
694
|
|
|
694
695
|
# Support different types of locking styles
|
|
695
696
|
def select_lock_sql(sql)
|
|
@@ -369,11 +369,6 @@ module Sequel
|
|
|
369
369
|
end
|
|
370
370
|
end
|
|
371
371
|
|
|
372
|
-
# MySQL treats integer primary keys as autoincrementing.
|
|
373
|
-
def schema_autoincrementing_primary_key?(schema)
|
|
374
|
-
super and schema[:db_type] =~ /int/io
|
|
375
|
-
end
|
|
376
|
-
|
|
377
372
|
# Use the MySQL specific DESCRIBE syntax to get a table description.
|
|
378
373
|
def schema_parse_table(table_name, opts)
|
|
379
374
|
m = output_identifier_meth(opts[:dataset])
|
|
@@ -50,6 +50,43 @@ module Sequel
|
|
|
50
50
|
attr_accessor :force_standard_strings
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
class CreateTableGenerator < Sequel::Schema::Generator
|
|
54
|
+
# Add an exclusion constraint when creating the table. elements should be
|
|
55
|
+
# an array of 2 element arrays, with the first element being the column or
|
|
56
|
+
# expression the exclusion constraint is applied to, and the second element
|
|
57
|
+
# being the operator to use for the column/expression to check for exclusion.
|
|
58
|
+
#
|
|
59
|
+
# Example:
|
|
60
|
+
#
|
|
61
|
+
# exclusion_constraint([[:col1, '&&'], [:col2, '=']])
|
|
62
|
+
# # EXCLUDE USING gist (col1 WITH &&, col2 WITH =)
|
|
63
|
+
#
|
|
64
|
+
# Options supported:
|
|
65
|
+
#
|
|
66
|
+
# :name :: Name the constraint with the given name (useful if you may
|
|
67
|
+
# need to drop the constraint later)
|
|
68
|
+
# :using :: Override the index_method for the exclusion constraint (defaults to gist).
|
|
69
|
+
# :where :: Create a partial exclusion constraint, which only affects
|
|
70
|
+
# a subset of table rows, value should be a filter expression.
|
|
71
|
+
def exclude(elements, opts={})
|
|
72
|
+
constraints << {:type => :exclude, :elements => elements}.merge(opts)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
class AlterTableGenerator < Sequel::Schema::AlterTableGenerator
|
|
77
|
+
# Adds an exclusion constraint to an existing table, see
|
|
78
|
+
# CreateTableGenerator#exclude.
|
|
79
|
+
def add_exclusion_constraint(elements, opts={})
|
|
80
|
+
@operations << {:op => :add_constraint, :type => :exclude, :elements => elements}.merge(opts)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Validate the constraint with the given name, which should have
|
|
84
|
+
# been added previously with NOT VALID.
|
|
85
|
+
def validate_constraint(name)
|
|
86
|
+
@operations << {:op => :validate_constraint, :name => name}
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
53
90
|
# Methods shared by Database instances that connect to PostgreSQL.
|
|
54
91
|
module DatabaseMethods
|
|
55
92
|
EXCLUDE_SCHEMAS = /pg_*|information_schema/i
|
|
@@ -444,7 +481,12 @@ module Sequel
|
|
|
444
481
|
|
|
445
482
|
private
|
|
446
483
|
|
|
447
|
-
#
|
|
484
|
+
# Use a PostgreSQL-specific alter table generator
|
|
485
|
+
def alter_table_generator_class
|
|
486
|
+
Postgres::AlterTableGenerator
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
# Handle :using option for set_column_type op, and the :validate_constraint op.
|
|
448
490
|
def alter_table_sql(table, op)
|
|
449
491
|
case op[:op]
|
|
450
492
|
when :set_column_type
|
|
@@ -455,6 +497,8 @@ module Sequel
|
|
|
455
497
|
s << literal(using)
|
|
456
498
|
end
|
|
457
499
|
s
|
|
500
|
+
when :validate_constraint
|
|
501
|
+
"ALTER TABLE #{quote_schema_table(table)} VALIDATE CONSTRAINT #{quote_identifier(op[:name])}"
|
|
458
502
|
else
|
|
459
503
|
super
|
|
460
504
|
end
|
|
@@ -499,6 +543,23 @@ module Sequel
|
|
|
499
543
|
sqls
|
|
500
544
|
end
|
|
501
545
|
|
|
546
|
+
# Handle exclusion constraints.
|
|
547
|
+
def constraint_definition_sql(constraint)
|
|
548
|
+
case constraint[:type]
|
|
549
|
+
when :exclude
|
|
550
|
+
elements = constraint[:elements].map{|c, op| "#{literal(c)} WITH #{op}"}.join(', ')
|
|
551
|
+
"#{"CONSTRAINT #{quote_identifier(constraint[:name])} " if constraint[:name]}EXCLUDE USING #{constraint[:using]||'gist'} (#{elements})#{" WHERE #{filter_expr(constraint[:where])}" if constraint[:where]}"
|
|
552
|
+
when :foreign_key
|
|
553
|
+
sql = super
|
|
554
|
+
if constraint[:not_valid]
|
|
555
|
+
sql << " NOT VALID"
|
|
556
|
+
end
|
|
557
|
+
sql
|
|
558
|
+
else
|
|
559
|
+
super
|
|
560
|
+
end
|
|
561
|
+
end
|
|
562
|
+
|
|
502
563
|
# SQL statement to create database function.
|
|
503
564
|
def create_function_sql(name, definition, opts={})
|
|
504
565
|
args = opts[:args]
|
|
@@ -530,6 +591,11 @@ module Sequel
|
|
|
530
591
|
"CREATE SCHEMA #{quote_identifier(name)}"
|
|
531
592
|
end
|
|
532
593
|
|
|
594
|
+
# Use a PostgreSQL-specific create table generator
|
|
595
|
+
def create_table_generator_class
|
|
596
|
+
Postgres::CreateTableGenerator
|
|
597
|
+
end
|
|
598
|
+
|
|
533
599
|
# SQL for creating a database trigger.
|
|
534
600
|
def create_trigger_sql(table, name, function, opts={})
|
|
535
601
|
events = opts[:events] ? Array(opts[:events]) : [:insert, :update, :delete]
|
|
@@ -642,7 +708,7 @@ module Sequel
|
|
|
642
708
|
# PostgreSQL's autoincrementing primary keys are of type integer or bigint
|
|
643
709
|
# using a nextval function call as a default.
|
|
644
710
|
def schema_autoincrementing_primary_key?(schema)
|
|
645
|
-
super
|
|
711
|
+
super && schema[:default] =~ /\Anextval/io
|
|
646
712
|
end
|
|
647
713
|
|
|
648
714
|
# The dataset used for parsing table schemas, using the pg_* system catalogs.
|
|
@@ -383,7 +383,7 @@ module Sequel
|
|
|
383
383
|
|
|
384
384
|
# SQLite treats integer primary keys as autoincrementing (alias of rowid).
|
|
385
385
|
def schema_autoincrementing_primary_key?(schema)
|
|
386
|
-
super
|
|
386
|
+
super && schema[:db_type].downcase == 'integer'
|
|
387
387
|
end
|
|
388
388
|
|
|
389
389
|
# SQLite supports schema parsing using the table_info PRAGMA, so
|
|
@@ -428,6 +428,22 @@ module Sequel
|
|
|
428
428
|
DOUBLE_BACKTICK = '``'.freeze
|
|
429
429
|
BLOB_START = "X'".freeze
|
|
430
430
|
HSTAR = "H*".freeze
|
|
431
|
+
DATE_OPEN = "date(".freeze
|
|
432
|
+
DATETIME_OPEN = "datetime(".freeze
|
|
433
|
+
|
|
434
|
+
def cast_sql_append(sql, expr, type)
|
|
435
|
+
if type == Time or type == DateTime
|
|
436
|
+
sql << DATETIME_OPEN
|
|
437
|
+
literal_append(sql, expr)
|
|
438
|
+
sql << PAREN_CLOSE
|
|
439
|
+
elsif type == Date
|
|
440
|
+
sql << DATE_OPEN
|
|
441
|
+
literal_append(sql, expr)
|
|
442
|
+
sql << PAREN_CLOSE
|
|
443
|
+
else
|
|
444
|
+
super
|
|
445
|
+
end
|
|
446
|
+
end
|
|
431
447
|
|
|
432
448
|
# SQLite does not support pattern matching via regular expressions.
|
|
433
449
|
# SQLite is case insensitive (depending on pragma), so use LIKE for
|
|
@@ -41,7 +41,12 @@ module Sequel
|
|
|
41
41
|
# requires an order.
|
|
42
42
|
def select_sql
|
|
43
43
|
return super unless o = @opts[:offset]
|
|
44
|
-
|
|
44
|
+
|
|
45
|
+
order = @opts[:order] || default_offset_order
|
|
46
|
+
if order.nil? || order.empty?
|
|
47
|
+
raise(Error, "#{db.database_type} requires an order be provided if using an offset")
|
|
48
|
+
end
|
|
49
|
+
|
|
45
50
|
dsa1 = dataset_alias(1)
|
|
46
51
|
rn = row_number_column
|
|
47
52
|
sql = @opts[:append_sql] || ''
|
|
@@ -57,6 +62,12 @@ module Sequel
|
|
|
57
62
|
|
|
58
63
|
private
|
|
59
64
|
|
|
65
|
+
# The default order to use for datasets with offsets, if no order is defined.
|
|
66
|
+
# By default, orders by all of the columns in the dataset.
|
|
67
|
+
def default_offset_order
|
|
68
|
+
clone(:append_sql=>'').columns
|
|
69
|
+
end
|
|
70
|
+
|
|
60
71
|
# This emulation adds an extra row number column that should be
|
|
61
72
|
# eliminated.
|
|
62
73
|
def offset_returns_row_number_column?
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module Sequel
|
|
2
|
+
module Postgres
|
|
3
|
+
NAN = 0.0/0.0
|
|
4
|
+
PLUS_INFINITY = 1.0/0.0
|
|
5
|
+
MINUS_INFINITY = -1.0/0.0
|
|
6
|
+
NAN_STR = 'NaN'.freeze
|
|
7
|
+
PLUS_INFINITY_STR = 'Infinity'.freeze
|
|
8
|
+
MINUS_INFINITY_STR = '-Infinity'.freeze
|
|
9
|
+
TRUE_STR = 't'.freeze
|
|
10
|
+
DASH_STR = '-'.freeze
|
|
11
|
+
|
|
12
|
+
TYPE_TRANSLATOR = tt = Class.new do
|
|
13
|
+
def boolean(s) s == TRUE_STR end
|
|
14
|
+
def integer(s) s.to_i end
|
|
15
|
+
def float(s)
|
|
16
|
+
case s
|
|
17
|
+
when NAN_STR
|
|
18
|
+
NAN
|
|
19
|
+
when PLUS_INFINITY_STR
|
|
20
|
+
PLUS_INFINITY
|
|
21
|
+
when MINUS_INFINITY_STR
|
|
22
|
+
MINUS_INFINITY
|
|
23
|
+
else
|
|
24
|
+
s.to_f
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
def date(s) ::Date.new(*s.split(DASH_STR).map{|x| x.to_i}) end
|
|
28
|
+
def bytea(str)
|
|
29
|
+
str = if str =~ /\A\\x/
|
|
30
|
+
# PostgreSQL 9.0+ bytea hex format
|
|
31
|
+
str[2..-1].gsub(/(..)/){|s| s.to_i(16).chr}
|
|
32
|
+
else
|
|
33
|
+
# Historical PostgreSQL bytea escape format
|
|
34
|
+
str.gsub(/\\(\\|'|[0-3][0-7][0-7])/) {|s|
|
|
35
|
+
if s.size == 2 then s[1,1] else s[1,3].oct.chr end
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
::Sequel::SQL::Blob.new(str)
|
|
39
|
+
end
|
|
40
|
+
end.new
|
|
41
|
+
|
|
42
|
+
# Hash with type name strings/symbols and callable values for converting PostgreSQL types.
|
|
43
|
+
# Non-builtin types that don't have fixed numbers should use this to register
|
|
44
|
+
# conversion procs.
|
|
45
|
+
PG_NAMED_TYPES = {} unless defined?(PG_NAMED_TYPES)
|
|
46
|
+
|
|
47
|
+
# Hash with integer keys and callable values for converting PostgreSQL types.
|
|
48
|
+
PG_TYPES = {} unless defined?(PG_TYPES)
|
|
49
|
+
|
|
50
|
+
{
|
|
51
|
+
[16] => tt.method(:boolean),
|
|
52
|
+
[17] => tt.method(:bytea),
|
|
53
|
+
[20, 21, 23, 26] => tt.method(:integer),
|
|
54
|
+
[700, 701] => tt.method(:float),
|
|
55
|
+
[1700] => ::BigDecimal.method(:new),
|
|
56
|
+
[1083, 1266] => ::Sequel.method(:string_to_time),
|
|
57
|
+
[1184, 1114] => ::Sequel.method(:database_to_application_timestamp),
|
|
58
|
+
}.each do |k,v|
|
|
59
|
+
k.each{|n| PG_TYPES[n] = v}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class << self
|
|
63
|
+
# As an optimization, Sequel sets the date style to ISO, so that PostgreSQL provides
|
|
64
|
+
# the date in a known format that Sequel can parse faster. This can be turned off
|
|
65
|
+
# if you require a date style other than ISO.
|
|
66
|
+
attr_reader :use_iso_date_format
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Modify the type translator for the date type depending on the value given.
|
|
70
|
+
def self.use_iso_date_format=(v)
|
|
71
|
+
PG_TYPES[1082] = v ? TYPE_TRANSLATOR.method(:date) : Sequel.method(:string_to_date)
|
|
72
|
+
@use_iso_date_format = v
|
|
73
|
+
end
|
|
74
|
+
self.use_iso_date_format = true
|
|
75
|
+
end
|
|
76
|
+
end
|