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