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.
Files changed (79) hide show
  1. data/CHANGELOG +62 -0
  2. data/README.rdoc +2 -2
  3. data/bin/sequel +12 -2
  4. data/doc/advanced_associations.rdoc +1 -1
  5. data/doc/association_basics.rdoc +13 -0
  6. data/doc/release_notes/3.39.0.txt +237 -0
  7. data/doc/schema_modification.rdoc +4 -4
  8. data/lib/sequel/adapters/jdbc/derby.rb +1 -0
  9. data/lib/sequel/adapters/mock.rb +5 -0
  10. data/lib/sequel/adapters/mysql.rb +8 -1
  11. data/lib/sequel/adapters/mysql2.rb +10 -3
  12. data/lib/sequel/adapters/postgres.rb +72 -8
  13. data/lib/sequel/adapters/shared/db2.rb +1 -0
  14. data/lib/sequel/adapters/shared/mssql.rb +57 -0
  15. data/lib/sequel/adapters/shared/mysql.rb +95 -19
  16. data/lib/sequel/adapters/shared/oracle.rb +14 -0
  17. data/lib/sequel/adapters/shared/postgres.rb +63 -24
  18. data/lib/sequel/adapters/shared/sqlite.rb +6 -9
  19. data/lib/sequel/connection_pool/sharded_threaded.rb +8 -3
  20. data/lib/sequel/connection_pool/threaded.rb +9 -4
  21. data/lib/sequel/database/query.rb +60 -48
  22. data/lib/sequel/database/schema_generator.rb +13 -6
  23. data/lib/sequel/database/schema_methods.rb +65 -12
  24. data/lib/sequel/dataset/actions.rb +22 -4
  25. data/lib/sequel/dataset/features.rb +5 -0
  26. data/lib/sequel/dataset/graph.rb +2 -3
  27. data/lib/sequel/dataset/misc.rb +2 -2
  28. data/lib/sequel/dataset/query.rb +0 -2
  29. data/lib/sequel/dataset/sql.rb +33 -12
  30. data/lib/sequel/extensions/constraint_validations.rb +451 -0
  31. data/lib/sequel/extensions/eval_inspect.rb +17 -2
  32. data/lib/sequel/extensions/pg_array_ops.rb +15 -5
  33. data/lib/sequel/extensions/pg_interval.rb +2 -2
  34. data/lib/sequel/extensions/pg_row_ops.rb +18 -0
  35. data/lib/sequel/extensions/schema_dumper.rb +3 -11
  36. data/lib/sequel/model/associations.rb +3 -2
  37. data/lib/sequel/model/base.rb +57 -13
  38. data/lib/sequel/model/exceptions.rb +20 -2
  39. data/lib/sequel/plugins/constraint_validations.rb +198 -0
  40. data/lib/sequel/plugins/defaults_setter.rb +15 -1
  41. data/lib/sequel/plugins/dirty.rb +2 -2
  42. data/lib/sequel/plugins/identity_map.rb +12 -8
  43. data/lib/sequel/plugins/subclasses.rb +19 -1
  44. data/lib/sequel/plugins/tree.rb +3 -3
  45. data/lib/sequel/plugins/validation_helpers.rb +24 -4
  46. data/lib/sequel/sql.rb +64 -24
  47. data/lib/sequel/timezones.rb +10 -2
  48. data/lib/sequel/version.rb +1 -1
  49. data/spec/adapters/mssql_spec.rb +26 -25
  50. data/spec/adapters/mysql_spec.rb +57 -23
  51. data/spec/adapters/oracle_spec.rb +34 -49
  52. data/spec/adapters/postgres_spec.rb +226 -128
  53. data/spec/adapters/sqlite_spec.rb +50 -49
  54. data/spec/core/connection_pool_spec.rb +22 -0
  55. data/spec/core/database_spec.rb +53 -47
  56. data/spec/core/dataset_spec.rb +36 -32
  57. data/spec/core/expression_filters_spec.rb +14 -2
  58. data/spec/core/mock_adapter_spec.rb +4 -0
  59. data/spec/core/object_graph_spec.rb +0 -13
  60. data/spec/core/schema_spec.rb +64 -5
  61. data/spec/core_extensions_spec.rb +1 -0
  62. data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
  63. data/spec/extensions/constraint_validations_spec.rb +316 -0
  64. data/spec/extensions/defaults_setter_spec.rb +24 -0
  65. data/spec/extensions/eval_inspect_spec.rb +9 -0
  66. data/spec/extensions/identity_map_spec.rb +11 -2
  67. data/spec/extensions/pg_array_ops_spec.rb +9 -0
  68. data/spec/extensions/pg_row_ops_spec.rb +11 -1
  69. data/spec/extensions/pg_row_plugin_spec.rb +4 -0
  70. data/spec/extensions/schema_dumper_spec.rb +8 -5
  71. data/spec/extensions/subclasses_spec.rb +14 -0
  72. data/spec/extensions/validation_helpers_spec.rb +15 -2
  73. data/spec/integration/dataset_test.rb +75 -1
  74. data/spec/integration/plugin_test.rb +146 -0
  75. data/spec/integration/schema_test.rb +34 -0
  76. data/spec/model/dataset_methods_spec.rb +38 -0
  77. data/spec/model/hooks_spec.rb +6 -0
  78. data/spec/model/validations_spec.rb +27 -2
  79. 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.fetch(quoted_table) do
377
- schema, table = schema_and_table(table)
378
- sql = "#{SELECT_PK_SQL} AND pg_class.relname = #{literal(table)}"
379
- sql << "AND pg_namespace.nspname = #{literal(schema)}" if schema
380
- @primary_keys[quoted_table] = fetch(sql).single_value
381
- end
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.fetch(quoted_table) do
388
- schema, table = schema_and_table(table)
389
- table = literal(table)
390
- sql = "#{SELECT_SERIAL_SEQUENCE_SQL} AND seq.relname = #{table}"
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
- unless pks = fetch(sql).single_record
393
- sql = "#{SELECT_CUSTOM_SEQUENCE_SQL} AND t.relname = #{table}"
394
- sql << " AND name.nspname = #{literal(schema)}" if schema
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, baseing it on the
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 alter_table_sql(table, op)
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
- "ALTER TABLE #{quote_schema_table(table)} VALIDATE CONSTRAINT #{quote_identifier(op[:name])}"
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
- @primary_keys.delete(tab)
743
- @primary_key_sequences.delete(tab)
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
- raise Error, "Unsupported :type option for drop_constraint: #{op[:type].inspect}"
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 does not support pattern matching via regular expressions.
449
- # SQLite is case insensitive (depending on pragma), so use LIKE for
450
- # ILIKE.
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
- if @queue
225
- available_connections(server).unshift(allocated(server).delete(thread))
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) << allocated(server).delete(thread)
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
- @queue = opts[:connection_handling] == :queue
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
- if @queue
161
- @available_connections.unshift(@allocated.delete(thread))
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 << @allocated.delete(thread)
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
- orig_default = default
398
- if database_type == :postgres and m = POSTGRES_DEFAULT_RE.match(default)
399
- default = m[1] || m[2]
400
- end
401
- if database_type == :mssql and m = MSSQL_DEFAULT_RE.match(default)
402
- default = m[1] || m[2]
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 {"Migrations and Schema Modification" guide}[link:files/doc/migration_rdoc.html].
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 {"Migrations and Schema Modification" guide}[link:files/doc/migration_rdoc.html].
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, :name.like('A%'))
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
- # Modify a column's NOT NULL constraint.
433
+ # Set a given column as allowing NULL values.
434
434
  #
435
- # set_column_allow_null(:artist_name, false) # ALTER COLUMN artist_name SET NOT NULL
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