sequel 3.38.0 → 3.39.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 +62 -0
- data/README.rdoc +2 -2
- data/bin/sequel +12 -2
- data/doc/advanced_associations.rdoc +1 -1
- data/doc/association_basics.rdoc +13 -0
- data/doc/release_notes/3.39.0.txt +237 -0
- data/doc/schema_modification.rdoc +4 -4
- data/lib/sequel/adapters/jdbc/derby.rb +1 -0
- data/lib/sequel/adapters/mock.rb +5 -0
- data/lib/sequel/adapters/mysql.rb +8 -1
- data/lib/sequel/adapters/mysql2.rb +10 -3
- data/lib/sequel/adapters/postgres.rb +72 -8
- data/lib/sequel/adapters/shared/db2.rb +1 -0
- data/lib/sequel/adapters/shared/mssql.rb +57 -0
- data/lib/sequel/adapters/shared/mysql.rb +95 -19
- data/lib/sequel/adapters/shared/oracle.rb +14 -0
- data/lib/sequel/adapters/shared/postgres.rb +63 -24
- data/lib/sequel/adapters/shared/sqlite.rb +6 -9
- data/lib/sequel/connection_pool/sharded_threaded.rb +8 -3
- data/lib/sequel/connection_pool/threaded.rb +9 -4
- data/lib/sequel/database/query.rb +60 -48
- data/lib/sequel/database/schema_generator.rb +13 -6
- data/lib/sequel/database/schema_methods.rb +65 -12
- data/lib/sequel/dataset/actions.rb +22 -4
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/graph.rb +2 -3
- data/lib/sequel/dataset/misc.rb +2 -2
- data/lib/sequel/dataset/query.rb +0 -2
- data/lib/sequel/dataset/sql.rb +33 -12
- data/lib/sequel/extensions/constraint_validations.rb +451 -0
- data/lib/sequel/extensions/eval_inspect.rb +17 -2
- data/lib/sequel/extensions/pg_array_ops.rb +15 -5
- data/lib/sequel/extensions/pg_interval.rb +2 -2
- data/lib/sequel/extensions/pg_row_ops.rb +18 -0
- data/lib/sequel/extensions/schema_dumper.rb +3 -11
- data/lib/sequel/model/associations.rb +3 -2
- data/lib/sequel/model/base.rb +57 -13
- data/lib/sequel/model/exceptions.rb +20 -2
- data/lib/sequel/plugins/constraint_validations.rb +198 -0
- data/lib/sequel/plugins/defaults_setter.rb +15 -1
- data/lib/sequel/plugins/dirty.rb +2 -2
- data/lib/sequel/plugins/identity_map.rb +12 -8
- data/lib/sequel/plugins/subclasses.rb +19 -1
- data/lib/sequel/plugins/tree.rb +3 -3
- data/lib/sequel/plugins/validation_helpers.rb +24 -4
- data/lib/sequel/sql.rb +64 -24
- data/lib/sequel/timezones.rb +10 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +26 -25
- data/spec/adapters/mysql_spec.rb +57 -23
- data/spec/adapters/oracle_spec.rb +34 -49
- data/spec/adapters/postgres_spec.rb +226 -128
- data/spec/adapters/sqlite_spec.rb +50 -49
- data/spec/core/connection_pool_spec.rb +22 -0
- data/spec/core/database_spec.rb +53 -47
- data/spec/core/dataset_spec.rb +36 -32
- data/spec/core/expression_filters_spec.rb +14 -2
- data/spec/core/mock_adapter_spec.rb +4 -0
- data/spec/core/object_graph_spec.rb +0 -13
- data/spec/core/schema_spec.rb +64 -5
- data/spec/core_extensions_spec.rb +1 -0
- data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
- data/spec/extensions/constraint_validations_spec.rb +316 -0
- data/spec/extensions/defaults_setter_spec.rb +24 -0
- data/spec/extensions/eval_inspect_spec.rb +9 -0
- data/spec/extensions/identity_map_spec.rb +11 -2
- data/spec/extensions/pg_array_ops_spec.rb +9 -0
- data/spec/extensions/pg_row_ops_spec.rb +11 -1
- data/spec/extensions/pg_row_plugin_spec.rb +4 -0
- data/spec/extensions/schema_dumper_spec.rb +8 -5
- data/spec/extensions/subclasses_spec.rb +14 -0
- data/spec/extensions/validation_helpers_spec.rb +15 -2
- data/spec/integration/dataset_test.rb +75 -1
- data/spec/integration/plugin_test.rb +146 -0
- data/spec/integration/schema_test.rb +34 -0
- data/spec/model/dataset_methods_spec.rb +38 -0
- data/spec/model/hooks_spec.rb +6 -0
- data/spec/model/validations_spec.rb +27 -2
- metadata +8 -2
|
@@ -248,6 +248,20 @@ module Sequel
|
|
|
248
248
|
end
|
|
249
249
|
end
|
|
250
250
|
|
|
251
|
+
# Oracle treats empty strings like NULL values, and doesn't support
|
|
252
|
+
# char_length, so make char_length use length with a nonempty string.
|
|
253
|
+
# Unfortunately, as Oracle treats the empty string as NULL, there is
|
|
254
|
+
# no way to get trim to return an empty string instead of nil if
|
|
255
|
+
# the string only contains spaces.
|
|
256
|
+
def emulated_function_sql_append(sql, f)
|
|
257
|
+
case f.f
|
|
258
|
+
when :char_length
|
|
259
|
+
literal_append(sql, Sequel::SQL::Function.new(:length, Sequel.join([f.args.first, 'x'])) - 1)
|
|
260
|
+
else
|
|
261
|
+
super
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
251
265
|
# Oracle uses MINUS instead of EXCEPT, and doesn't support EXCEPT ALL
|
|
252
266
|
def except(dataset, opts={})
|
|
253
267
|
opts = {:all=>opts} unless opts.is_a?(Hash)
|
|
@@ -96,6 +96,7 @@ module Sequel
|
|
|
96
96
|
RE_CURRVAL_ERROR = /currval of sequence "(.*)" is not yet defined in this session|relation "(.*)" does not exist/.freeze
|
|
97
97
|
SYSTEM_TABLE_REGEXP = /^pg|sql/.freeze
|
|
98
98
|
FOREIGN_KEY_LIST_ON_DELETE_MAP = {'a'.freeze=>:no_action, 'r'.freeze=>:restrict, 'c'.freeze=>:cascade, 'n'.freeze=>:set_null, 'd'.freeze=>:set_default}.freeze
|
|
99
|
+
POSTGRES_DEFAULT_RE = /\A(?:B?('.*')::[^']+|\((-?\d+(?:\.\d+)?)\))\z/
|
|
99
100
|
|
|
100
101
|
# SQL fragment for custom sequences (ones not created by serial primary key),
|
|
101
102
|
# Returning the schema and literal form of the sequence name, by parsing
|
|
@@ -136,7 +137,7 @@ module Sequel
|
|
|
136
137
|
SELECT_SERIAL_SEQUENCE_SQL = (<<-end_sql
|
|
137
138
|
SELECT name.nspname AS "schema", seq.relname AS "sequence"
|
|
138
139
|
FROM pg_class seq, pg_attribute attr, pg_depend dep,
|
|
139
|
-
pg_namespace name, pg_constraint cons
|
|
140
|
+
pg_namespace name, pg_constraint cons, pg_class t
|
|
140
141
|
WHERE seq.oid = dep.objid
|
|
141
142
|
AND seq.relnamespace = name.oid
|
|
142
143
|
AND seq.relkind = 'S'
|
|
@@ -144,6 +145,7 @@ module Sequel
|
|
|
144
145
|
AND attr.attnum = dep.refobjsubid
|
|
145
146
|
AND attr.attrelid = cons.conrelid
|
|
146
147
|
AND attr.attnum = cons.conkey[1]
|
|
148
|
+
AND attr.attrelid = t.oid
|
|
147
149
|
AND cons.contype = 'p'
|
|
148
150
|
end_sql
|
|
149
151
|
).strip.gsub(/\s+/, ' ').freeze
|
|
@@ -373,30 +375,31 @@ module Sequel
|
|
|
373
375
|
# Return primary key for the given table.
|
|
374
376
|
def primary_key(table, opts={})
|
|
375
377
|
quoted_table = quote_schema_table(table)
|
|
376
|
-
@primary_keys.
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
378
|
+
Sequel.synchronize{return @primary_keys[quoted_table] if @primary_keys.has_key?(quoted_table)}
|
|
379
|
+
schema, table = schema_and_table(table)
|
|
380
|
+
sql = "#{SELECT_PK_SQL} AND pg_class.relname = #{literal(table)}"
|
|
381
|
+
sql << " AND pg_namespace.nspname = #{literal(schema)}" if schema
|
|
382
|
+
value = fetch(sql).single_value
|
|
383
|
+
Sequel.synchronize{@primary_keys[quoted_table] = value}
|
|
382
384
|
end
|
|
383
385
|
|
|
384
386
|
# Return the sequence providing the default for the primary key for the given table.
|
|
385
387
|
def primary_key_sequence(table, opts={})
|
|
386
388
|
quoted_table = quote_schema_table(table)
|
|
387
|
-
@primary_key_sequences.
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
389
|
+
Sequel.synchronize{return @primary_key_sequences[quoted_table] if @primary_key_sequences.has_key?(quoted_table)}
|
|
390
|
+
schema, table = schema_and_table(table)
|
|
391
|
+
table = literal(table)
|
|
392
|
+
sql = "#{SELECT_SERIAL_SEQUENCE_SQL} AND t.relname = #{table}"
|
|
393
|
+
sql << " AND name.nspname = #{literal(schema)}" if schema
|
|
394
|
+
if pks = fetch(sql).single_record
|
|
395
|
+
value = literal(SQL::QualifiedIdentifier.new(pks[:schema], pks[:sequence]))
|
|
396
|
+
Sequel.synchronize{@primary_key_sequences[quoted_table] = value}
|
|
397
|
+
else
|
|
398
|
+
sql = "#{SELECT_CUSTOM_SEQUENCE_SQL} AND t.relname = #{table}"
|
|
391
399
|
sql << " AND name.nspname = #{literal(schema)}" if schema
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
pks = fetch(sql).single_record
|
|
396
|
-
end
|
|
397
|
-
|
|
398
|
-
@primary_key_sequences[quoted_table] = if pks
|
|
399
|
-
literal(SQL::QualifiedIdentifier.new(pks[:schema], LiteralString.new(pks[:sequence])))
|
|
400
|
+
if pks = fetch(sql).single_record
|
|
401
|
+
value = literal(SQL::QualifiedIdentifier.new(pks[:schema], LiteralString.new(pks[:sequence])))
|
|
402
|
+
Sequel.synchronize{@primary_key_sequences[quoted_table] = value}
|
|
400
403
|
end
|
|
401
404
|
end
|
|
402
405
|
end
|
|
@@ -407,7 +410,7 @@ module Sequel
|
|
|
407
410
|
@conversion_procs = get_conversion_procs
|
|
408
411
|
end
|
|
409
412
|
|
|
410
|
-
# Reset the primary key sequence for the given table,
|
|
413
|
+
# Reset the primary key sequence for the given table, basing it on the
|
|
411
414
|
# maximum current value of the table's primary key.
|
|
412
415
|
def reset_primary_key_sequence(table)
|
|
413
416
|
return unless seq = primary_key_sequence(table)
|
|
@@ -513,7 +516,7 @@ module Sequel
|
|
|
513
516
|
end
|
|
514
517
|
|
|
515
518
|
# Handle :using option for set_column_type op, and the :validate_constraint op.
|
|
516
|
-
def
|
|
519
|
+
def alter_table_op_sql(table, op)
|
|
517
520
|
case op[:op]
|
|
518
521
|
when :set_column_type
|
|
519
522
|
s = super
|
|
@@ -524,7 +527,7 @@ module Sequel
|
|
|
524
527
|
end
|
|
525
528
|
s
|
|
526
529
|
when :validate_constraint
|
|
527
|
-
"
|
|
530
|
+
"VALIDATE CONSTRAINT #{quote_identifier(op[:name])}"
|
|
528
531
|
else
|
|
529
532
|
super
|
|
530
533
|
end
|
|
@@ -549,6 +552,14 @@ module Sequel
|
|
|
549
552
|
end
|
|
550
553
|
end
|
|
551
554
|
|
|
555
|
+
# Handle PostgreSQL specific default format.
|
|
556
|
+
def column_schema_normalize_default(default, type)
|
|
557
|
+
if m = POSTGRES_DEFAULT_RE.match(default)
|
|
558
|
+
default = m[1] || m[2]
|
|
559
|
+
end
|
|
560
|
+
super(default, type)
|
|
561
|
+
end
|
|
562
|
+
|
|
552
563
|
# If the :prepare option is given and we aren't in a savepoint,
|
|
553
564
|
# prepare the transaction for a two-phase commit.
|
|
554
565
|
def commit_transaction(conn, opts={})
|
|
@@ -559,6 +570,12 @@ module Sequel
|
|
|
559
570
|
end
|
|
560
571
|
end
|
|
561
572
|
|
|
573
|
+
# PostgreSQL can't combine rename_column operations, and it can combine
|
|
574
|
+
# the custom validate_constraint operation.
|
|
575
|
+
def combinable_alter_table_op?(op)
|
|
576
|
+
(super || op[:op] == :validate_constraint) && op[:op] != :rename_column
|
|
577
|
+
end
|
|
578
|
+
|
|
562
579
|
# The SQL queries to execute when starting a new connection.
|
|
563
580
|
def connection_configuration_sqls
|
|
564
581
|
sqls = []
|
|
@@ -739,8 +756,10 @@ module Sequel
|
|
|
739
756
|
# changed.
|
|
740
757
|
def remove_cached_schema(table)
|
|
741
758
|
tab = quote_schema_table(table)
|
|
742
|
-
|
|
743
|
-
|
|
759
|
+
Sequel.synchronize do
|
|
760
|
+
@primary_keys.delete(tab)
|
|
761
|
+
@primary_key_sequences.delete(tab)
|
|
762
|
+
end
|
|
744
763
|
super
|
|
745
764
|
end
|
|
746
765
|
|
|
@@ -756,6 +775,16 @@ module Sequel
|
|
|
756
775
|
super && schema[:default] =~ /\Anextval/io
|
|
757
776
|
end
|
|
758
777
|
|
|
778
|
+
# Recognize PostgreSQL interval type.
|
|
779
|
+
def schema_column_type(db_type)
|
|
780
|
+
case db_type
|
|
781
|
+
when /\Ainterval\z/io
|
|
782
|
+
:interval
|
|
783
|
+
else
|
|
784
|
+
super
|
|
785
|
+
end
|
|
786
|
+
end
|
|
787
|
+
|
|
759
788
|
# The dataset used for parsing table schemas, using the pg_* system catalogs.
|
|
760
789
|
def schema_parse_table(table_name, opts)
|
|
761
790
|
m = output_identifier_meth(opts[:dataset])
|
|
@@ -813,6 +842,11 @@ module Sequel
|
|
|
813
842
|
"(#{Array(args).map{|a| Array(a).reverse.join(' ')}.join(', ')})"
|
|
814
843
|
end
|
|
815
844
|
|
|
845
|
+
# PostgreSQL can combine multiple alter table ops into a single query.
|
|
846
|
+
def supports_combining_alter_table_ops?
|
|
847
|
+
true
|
|
848
|
+
end
|
|
849
|
+
|
|
816
850
|
# Handle bigserial type if :serial option is present
|
|
817
851
|
def type_literal_generic_bignum(column)
|
|
818
852
|
column[:serial] ? :bigserial : super
|
|
@@ -1011,6 +1045,11 @@ module Sequel
|
|
|
1011
1045
|
true
|
|
1012
1046
|
end
|
|
1013
1047
|
|
|
1048
|
+
# PostgreSQL supports pattern matching via regular expressions
|
|
1049
|
+
def supports_regexp?
|
|
1050
|
+
true
|
|
1051
|
+
end
|
|
1052
|
+
|
|
1014
1053
|
# PostgreSQL supports timezones in literal timestamps
|
|
1015
1054
|
def supports_timestamp_timezones?
|
|
1016
1055
|
true
|
|
@@ -232,10 +232,8 @@ module Sequel
|
|
|
232
232
|
duplicate_table(table){|columns| columns.each{|s| s[:primary_key] = nil}}
|
|
233
233
|
when :foreign_key
|
|
234
234
|
duplicate_table(table, :no_foreign_keys=>true)
|
|
235
|
-
when :unique
|
|
236
|
-
duplicate_table(table)
|
|
237
235
|
else
|
|
238
|
-
|
|
236
|
+
duplicate_table(table)
|
|
239
237
|
end
|
|
240
238
|
when :add_constraint
|
|
241
239
|
duplicate_table(table, :constraints=>[op])
|
|
@@ -413,6 +411,7 @@ module Sequel
|
|
|
413
411
|
module DatasetMethods
|
|
414
412
|
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'select distinct columns from join where group having compounds order limit')
|
|
415
413
|
CONSTANT_MAP = {:CURRENT_DATE=>"date(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIMESTAMP=>"datetime(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIME=>"time(CURRENT_TIMESTAMP, 'localtime')".freeze}
|
|
414
|
+
EMULATED_FUNCTION_MAP = {:char_length=>'length'.freeze}
|
|
416
415
|
EXTRACT_MAP = {:year=>"'%Y'", :month=>"'%m'", :day=>"'%d'", :hour=>"'%H'", :minute=>"'%M'", :second=>"'%f'"}
|
|
417
416
|
NOT_SPACE = Dataset::NOT_SPACE
|
|
418
417
|
COMMA = Dataset::COMMA
|
|
@@ -445,13 +444,11 @@ module Sequel
|
|
|
445
444
|
end
|
|
446
445
|
end
|
|
447
446
|
|
|
448
|
-
# SQLite
|
|
449
|
-
#
|
|
450
|
-
#
|
|
447
|
+
# SQLite is case insensitive (depending on pragma), so use LIKE for ILIKE.
|
|
448
|
+
# It also doesn't support a NOT LIKE b, you need to use NOT (a LIKE b).
|
|
449
|
+
# It doesn't support xor or the extract function natively, so those have to be emulated.
|
|
451
450
|
def complex_expression_sql_append(sql, op, args)
|
|
452
451
|
case op
|
|
453
|
-
when :~, :'!~', :'~*', :'!~*'
|
|
454
|
-
raise Error, "SQLite does not support pattern matching via regular expressions"
|
|
455
452
|
when :ILIKE
|
|
456
453
|
super(sql, :LIKE, args.map{|a| SQL::Function.new(:upper, a)})
|
|
457
454
|
when :"NOT LIKE", :"NOT ILIKE"
|
|
@@ -578,7 +575,7 @@ module Sequel
|
|
|
578
575
|
col
|
|
579
576
|
end
|
|
580
577
|
end
|
|
581
|
-
|
|
578
|
+
|
|
582
579
|
# SQL fragment specifying a list of identifiers
|
|
583
580
|
def identifier_list(columns)
|
|
584
581
|
columns.map{|i| quote_identifier(i)}.join(COMMA)
|
|
@@ -221,10 +221,15 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
|
221
221
|
if @connections_to_remove.include?(conn)
|
|
222
222
|
remove(thread, conn, server)
|
|
223
223
|
else
|
|
224
|
-
|
|
225
|
-
|
|
224
|
+
conn = allocated(server).delete(thread)
|
|
225
|
+
|
|
226
|
+
case @connection_handling
|
|
227
|
+
when :queue
|
|
228
|
+
available_connections(server).unshift(conn)
|
|
229
|
+
when :disconnect
|
|
230
|
+
@disconnection_proc.call(conn) if @disconnection_proc
|
|
226
231
|
else
|
|
227
|
-
available_connections(server) <<
|
|
232
|
+
available_connections(server) << conn
|
|
228
233
|
end
|
|
229
234
|
end
|
|
230
235
|
end
|
|
@@ -27,7 +27,7 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
|
27
27
|
@max_size = Integer(opts[:max_connections] || 4)
|
|
28
28
|
raise(Sequel::Error, ':max_connections must be positive') if @max_size < 1
|
|
29
29
|
@mutex = Mutex.new
|
|
30
|
-
@
|
|
30
|
+
@connection_handling = opts[:connection_handling]
|
|
31
31
|
@available_connections = []
|
|
32
32
|
@allocated = {}
|
|
33
33
|
@timeout = Integer(opts[:pool_timeout] || 5)
|
|
@@ -157,10 +157,15 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
|
157
157
|
# Releases the connection assigned to the supplied thread back to the pool.
|
|
158
158
|
# The calling code should already have the mutex before calling this.
|
|
159
159
|
def release(thread)
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
conn = @allocated.delete(thread)
|
|
161
|
+
|
|
162
|
+
case @connection_handling
|
|
163
|
+
when :queue
|
|
164
|
+
@available_connections.unshift(conn)
|
|
165
|
+
when :disconnect
|
|
166
|
+
@disconnection_proc.call(conn) if @disconnection_proc
|
|
162
167
|
else
|
|
163
|
-
@available_connections <<
|
|
168
|
+
@available_connections << conn
|
|
164
169
|
end
|
|
165
170
|
end
|
|
166
171
|
|
|
@@ -21,10 +21,10 @@ module Sequel
|
|
|
21
21
|
:repeatable=>'REPEATABLE READ'.freeze,
|
|
22
22
|
:serializable=>'SERIALIZABLE'.freeze}
|
|
23
23
|
|
|
24
|
-
POSTGRES_DEFAULT_RE = /\A(?:B?('.*')::[^']+|\((-?\d+(?:\.\d+)?)\))\z/
|
|
25
|
-
MSSQL_DEFAULT_RE = /\A(?:\(N?('.*')\)|\(\((-?\d+(?:\.\d+)?)\)\))\z/
|
|
26
|
-
MYSQL_TIMESTAMP_RE = /\ACURRENT_(?:DATE|TIMESTAMP)?\z/
|
|
27
24
|
STRING_DEFAULT_RE = /\A'(.*)'\z/
|
|
25
|
+
CURRENT_TIMESTAMP_RE = /now|CURRENT|getdate/io
|
|
26
|
+
COLUMN_SCHEMA_DATETIME_TYPES = [:date, :datetime]
|
|
27
|
+
COLUMN_SCHEMA_STRING_TYPES = [:string, :blob, :date, :datetime, :time, :enum, :set, :interval]
|
|
28
28
|
|
|
29
29
|
# The prepared statement object hash for this database, keyed by name symbol
|
|
30
30
|
attr_reader :prepared_statements
|
|
@@ -390,56 +390,70 @@ module Sequel
|
|
|
390
390
|
SQL_BEGIN
|
|
391
391
|
end
|
|
392
392
|
|
|
393
|
+
# Whether the type should be treated as a string type when parsing the
|
|
394
|
+
# column schema default value.
|
|
395
|
+
def column_schema_default_string_type?(type)
|
|
396
|
+
COLUMN_SCHEMA_STRING_TYPES.include?(type)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
# Transform the given normalized default string into a ruby object for the
|
|
400
|
+
# given type.
|
|
401
|
+
def column_schema_default_to_ruby_value(default, type)
|
|
402
|
+
case type
|
|
403
|
+
when :boolean
|
|
404
|
+
case default
|
|
405
|
+
when /[f0]/i
|
|
406
|
+
false
|
|
407
|
+
when /[t1]/i
|
|
408
|
+
true
|
|
409
|
+
end
|
|
410
|
+
when :string, :enum, :set, :interval
|
|
411
|
+
default
|
|
412
|
+
when :blob
|
|
413
|
+
Sequel::SQL::Blob.new(default)
|
|
414
|
+
when :integer
|
|
415
|
+
Integer(default)
|
|
416
|
+
when :float
|
|
417
|
+
Float(default)
|
|
418
|
+
when :date
|
|
419
|
+
Sequel.string_to_date(default)
|
|
420
|
+
when :datetime
|
|
421
|
+
DateTime.parse(default)
|
|
422
|
+
when :time
|
|
423
|
+
Sequel.string_to_time(default)
|
|
424
|
+
when :decimal
|
|
425
|
+
BigDecimal.new(default)
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
# Normalize the default value string for the given type
|
|
430
|
+
# and return the normalized value.
|
|
431
|
+
def column_schema_normalize_default(default, type)
|
|
432
|
+
if column_schema_default_string_type?(type)
|
|
433
|
+
return unless m = STRING_DEFAULT_RE.match(default)
|
|
434
|
+
m[1].gsub("''", "'")
|
|
435
|
+
else
|
|
436
|
+
default
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
|
|
393
440
|
# Convert the given default, which should be a database specific string, into
|
|
394
441
|
# a ruby object.
|
|
395
442
|
def column_schema_to_ruby_default(default, type)
|
|
396
443
|
return if default.nil?
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
end
|
|
404
|
-
if [:string, :blob, :date, :datetime, :time, :enum].include?(type)
|
|
405
|
-
if database_type == :mysql
|
|
406
|
-
return if [:date, :datetime, :time].include?(type) && MYSQL_TIMESTAMP_RE.match(default)
|
|
407
|
-
orig_default = default = "'#{default.gsub("'", "''").gsub('\\', '\\\\')}'"
|
|
408
|
-
end
|
|
409
|
-
return unless m = STRING_DEFAULT_RE.match(default)
|
|
410
|
-
default = m[1].gsub("''", "'")
|
|
411
|
-
end
|
|
412
|
-
res = begin
|
|
413
|
-
case type
|
|
414
|
-
when :boolean
|
|
415
|
-
case default
|
|
416
|
-
when /[f0]/i
|
|
417
|
-
false
|
|
418
|
-
when /[t1]/i
|
|
419
|
-
true
|
|
444
|
+
if COLUMN_SCHEMA_DATETIME_TYPES.include?(type)
|
|
445
|
+
if CURRENT_TIMESTAMP_RE.match(default)
|
|
446
|
+
if type == :date
|
|
447
|
+
return Sequel::CURRENT_DATE
|
|
448
|
+
else
|
|
449
|
+
return Sequel::CURRENT_TIMESTAMP
|
|
420
450
|
end
|
|
421
|
-
when :string, :enum
|
|
422
|
-
default
|
|
423
|
-
when :blob
|
|
424
|
-
Sequel::SQL::Blob.new(default)
|
|
425
|
-
when :integer
|
|
426
|
-
Integer(default)
|
|
427
|
-
when :float
|
|
428
|
-
Float(default)
|
|
429
|
-
when :date
|
|
430
|
-
Sequel.string_to_date(default)
|
|
431
|
-
when :datetime
|
|
432
|
-
DateTime.parse(default)
|
|
433
|
-
when :time
|
|
434
|
-
Sequel.string_to_time(default)
|
|
435
|
-
when :decimal
|
|
436
|
-
BigDecimal.new(default)
|
|
437
451
|
end
|
|
438
|
-
rescue
|
|
439
|
-
nil
|
|
440
452
|
end
|
|
453
|
+
default = column_schema_normalize_default(default, type)
|
|
454
|
+
column_schema_default_to_ruby_value(default, type) rescue nil
|
|
441
455
|
end
|
|
442
|
-
|
|
456
|
+
|
|
443
457
|
if (! defined?(RUBY_ENGINE) or RUBY_ENGINE == 'ruby' or RUBY_ENGINE == 'rbx') and RUBY_VERSION < '1.9'
|
|
444
458
|
# Whether to commit the current transaction. On ruby 1.8 and rubinius,
|
|
445
459
|
# Thread.current.status is checked because Thread#kill skips rescue
|
|
@@ -568,15 +582,13 @@ module Sequel
|
|
|
568
582
|
# such as :integer or :string.
|
|
569
583
|
def schema_column_type(db_type)
|
|
570
584
|
case db_type
|
|
571
|
-
when /\Ainterval\z/io
|
|
572
|
-
:interval
|
|
573
585
|
when /\A(character( varying)?|n?(var)?char|n?text)/io
|
|
574
586
|
:string
|
|
575
587
|
when /\A(int(eger)?|(big|small|tiny)int)/io
|
|
576
588
|
:integer
|
|
577
589
|
when /\Adate\z/io
|
|
578
590
|
:date
|
|
579
|
-
when /\A((small)?datetime|timestamp( with(out)? time zone)?)\z/io
|
|
591
|
+
when /\A((small)?datetime|timestamp( with(out)? time zone)?)(\(\d+\))?\z/io
|
|
580
592
|
:datetime
|
|
581
593
|
when /\Atime( with(out)? time zone)?\z/io
|
|
582
594
|
:time
|
|
@@ -13,7 +13,7 @@ module Sequel
|
|
|
13
13
|
# the column method, which makes for a nicer DSL.
|
|
14
14
|
#
|
|
15
15
|
# For more information on Sequel's support for schema modification, see
|
|
16
|
-
# the {"
|
|
16
|
+
# the {"Schema Modification" guide}[link:files/doc/schema_modification_rdoc.html].
|
|
17
17
|
class CreateTableGenerator
|
|
18
18
|
# Classes specifying generic types that Sequel will convert to database-specific types.
|
|
19
19
|
GENERIC_TYPES=[String, Integer, Fixnum, Bignum, Float, Numeric, BigDecimal,
|
|
@@ -270,7 +270,7 @@ module Sequel
|
|
|
270
270
|
# alter a table's description.
|
|
271
271
|
#
|
|
272
272
|
# For more information on Sequel's support for schema modification, see
|
|
273
|
-
# the {"
|
|
273
|
+
# the {"Schema Modification" guide}[link:files/doc/schema_modification_rdoc.html].
|
|
274
274
|
class AlterTableGenerator
|
|
275
275
|
# An array of DDL operations to perform
|
|
276
276
|
attr_reader :operations
|
|
@@ -294,7 +294,7 @@ module Sequel
|
|
|
294
294
|
# Add a constraint with the given name and args to the DDL for the table.
|
|
295
295
|
# See CreateTableGenerator#constraint.
|
|
296
296
|
#
|
|
297
|
-
# add_constraint(:valid_name,
|
|
297
|
+
# add_constraint(:valid_name, Sequel.like(:name, 'A%'))
|
|
298
298
|
# # ADD CONSTRAINT valid_name CHECK (name LIKE 'A%')
|
|
299
299
|
def add_constraint(name, *args, &block)
|
|
300
300
|
@operations << {:op => :add_constraint, :name => name, :type => :check, :check => block || args}
|
|
@@ -430,13 +430,20 @@ module Sequel
|
|
|
430
430
|
@operations << {:op => :set_column_type, :name => name, :type => type}.merge(opts)
|
|
431
431
|
end
|
|
432
432
|
|
|
433
|
-
#
|
|
433
|
+
# Set a given column as allowing NULL values.
|
|
434
434
|
#
|
|
435
|
-
# set_column_allow_null(:artist_name
|
|
436
|
-
def set_column_allow_null(name, allow_null)
|
|
435
|
+
# set_column_allow_null(:artist_name) # ALTER COLUMN artist_name DROP NOT NULL
|
|
436
|
+
def set_column_allow_null(name, allow_null=true)
|
|
437
437
|
@operations << {:op => :set_column_null, :name => name, :null => allow_null}
|
|
438
438
|
end
|
|
439
439
|
|
|
440
|
+
# Set a given column as not allowing NULL values.
|
|
441
|
+
#
|
|
442
|
+
# set_column_not_null(:artist_name) # ALTER COLUMN artist_name SET NOT NULL
|
|
443
|
+
def set_column_not_null(name)
|
|
444
|
+
set_column_allow_null(name, false)
|
|
445
|
+
end
|
|
446
|
+
|
|
440
447
|
private
|
|
441
448
|
|
|
442
449
|
# Add a composite primary key constraint
|