sequel 4.39.0 → 4.40.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +34 -0
  3. data/README.rdoc +8 -4
  4. data/doc/active_record.rdoc +1 -1
  5. data/doc/advanced_associations.rdoc +7 -7
  6. data/doc/association_basics.rdoc +7 -7
  7. data/doc/cheat_sheet.rdoc +5 -3
  8. data/doc/core_extensions.rdoc +3 -3
  9. data/doc/dataset_filtering.rdoc +1 -1
  10. data/doc/object_model.rdoc +16 -7
  11. data/doc/postgresql.rdoc +3 -3
  12. data/doc/querying.rdoc +3 -3
  13. data/doc/release_notes/4.40.0.txt +179 -0
  14. data/doc/security.rdoc +2 -1
  15. data/doc/sql.rdoc +34 -18
  16. data/doc/testing.rdoc +1 -0
  17. data/doc/virtual_rows.rdoc +11 -2
  18. data/lib/sequel/adapters/jdbc/derby.rb +7 -1
  19. data/lib/sequel/adapters/jdbc/h2.rb +15 -1
  20. data/lib/sequel/adapters/oracle.rb +9 -5
  21. data/lib/sequel/adapters/postgres.rb +0 -1
  22. data/lib/sequel/adapters/shared/cubrid.rb +11 -11
  23. data/lib/sequel/adapters/shared/db2.rb +4 -8
  24. data/lib/sequel/adapters/shared/mssql.rb +41 -28
  25. data/lib/sequel/adapters/shared/mysql.rb +9 -6
  26. data/lib/sequel/adapters/shared/oracle.rb +16 -5
  27. data/lib/sequel/adapters/shared/postgres.rb +84 -45
  28. data/lib/sequel/adapters/shared/sqlanywhere.rb +29 -15
  29. data/lib/sequel/adapters/shared/sqlite.rb +6 -6
  30. data/lib/sequel/core.rb +61 -10
  31. data/lib/sequel/database/connecting.rb +2 -1
  32. data/lib/sequel/database/features.rb +7 -0
  33. data/lib/sequel/database/query.rb +1 -1
  34. data/lib/sequel/database/schema_methods.rb +30 -3
  35. data/lib/sequel/database/transactions.rb +4 -2
  36. data/lib/sequel/dataset/actions.rb +1 -1
  37. data/lib/sequel/dataset/graph.rb +6 -1
  38. data/lib/sequel/dataset/query.rb +14 -7
  39. data/lib/sequel/dataset/sql.rb +2 -2
  40. data/lib/sequel/extensions/core_extensions.rb +2 -1
  41. data/lib/sequel/extensions/pg_row.rb +2 -2
  42. data/lib/sequel/extensions/s.rb +57 -0
  43. data/lib/sequel/extensions/set_overrides.rb +5 -1
  44. data/lib/sequel/extensions/sql_expr.rb +1 -0
  45. data/lib/sequel/extensions/symbol_aref.rb +71 -0
  46. data/lib/sequel/extensions/symbol_aref_refinement.rb +41 -0
  47. data/lib/sequel/extensions/symbol_as.rb +23 -0
  48. data/lib/sequel/extensions/symbol_as_refinement.rb +35 -0
  49. data/lib/sequel/model/base.rb +3 -3
  50. data/lib/sequel/plugins/class_table_inheritance.rb +14 -3
  51. data/lib/sequel/plugins/column_select.rb +4 -2
  52. data/lib/sequel/plugins/dataset_associations.rb +12 -4
  53. data/lib/sequel/plugins/insert_returning_select.rb +1 -1
  54. data/lib/sequel/plugins/mssql_optimistic_locking.rb +1 -1
  55. data/lib/sequel/plugins/prepared_statements.rb +1 -0
  56. data/lib/sequel/sql.rb +40 -8
  57. data/lib/sequel/version.rb +1 -1
  58. data/spec/adapters/firebird_spec.rb +3 -3
  59. data/spec/adapters/mssql_spec.rb +40 -40
  60. data/spec/adapters/mysql_spec.rb +5 -5
  61. data/spec/adapters/oracle_spec.rb +4 -4
  62. data/spec/adapters/postgres_spec.rb +135 -124
  63. data/spec/adapters/spec_helper.rb +1 -0
  64. data/spec/adapters/sqlite_spec.rb +6 -6
  65. data/spec/core/dataset_spec.rb +2 -2
  66. data/spec/core/expression_filters_spec.rb +43 -2
  67. data/spec/core/schema_spec.rb +35 -1
  68. data/spec/core_extensions_spec.rb +27 -0
  69. data/spec/extensions/class_table_inheritance_spec.rb +8 -0
  70. data/spec/extensions/column_select_spec.rb +8 -0
  71. data/spec/extensions/core_refinements_spec.rb +1 -1
  72. data/spec/extensions/dataset_associations_spec.rb +9 -0
  73. data/spec/extensions/insert_returning_select_spec.rb +20 -0
  74. data/spec/extensions/prepared_statements_spec.rb +7 -0
  75. data/spec/extensions/s_spec.rb +60 -0
  76. data/spec/extensions/symbol_aref_refinement_spec.rb +28 -0
  77. data/spec/extensions/symbol_as_refinement_spec.rb +21 -0
  78. data/spec/integration/associations_test.rb +62 -57
  79. data/spec/integration/dataset_test.rb +54 -54
  80. data/spec/integration/eager_loader_test.rb +7 -7
  81. data/spec/integration/plugin_test.rb +20 -20
  82. data/spec/integration/prepared_statement_test.rb +1 -1
  83. data/spec/integration/schema_test.rb +21 -0
  84. data/spec/integration/spec_helper.rb +1 -0
  85. metadata +12 -2
@@ -242,7 +242,8 @@ derived from user input unless absolutely necessary.
242
242
 
243
243
  Sequel also allows you to create identifiers using
244
244
  Sequel.identifier[rdoc-ref:Sequel::SQL::Builders#identifier] for plain identifiers,
245
- Sequel.qualify[rdoc-ref:Sequel::SQL::Builders#qualify] for qualified identifiers, and
245
+ Sequel.qualify[rdoc-ref:Sequel::SQL::Builders#qualify] and
246
+ Sequel::SQL::Indentifier#[][rdoc-ref:Sequel::SQL::QualifyingMethods#[]] for qualified identifiers, and
246
247
  Sequel.as[rdoc-ref:Sequel::SQL::Builders#as] for aliased expressions. So if you
247
248
  pass any of those values derived from user input, you are dealing with the same scenario.
248
249
 
@@ -125,6 +125,8 @@ A plain symbol is usually treated as an unqualified identifier. However, if you
125
125
 
126
126
  :table__column # "table"."column"
127
127
 
128
+ This works by default, but it is possible to turn off by setting <tt>Sequel.split_symbols = false</tt>.
129
+
128
130
  Note that you can't use a period to separate them:
129
131
 
130
132
  :table.column # calls the column method on the symbol
@@ -133,14 +135,21 @@ Also note that specifying the period inside the symbol doesn't work if you are q
133
135
 
134
136
  :"table.column" # "table.column"
135
137
 
136
- The other way to qualify an identifier is to use the <tt>Sequel.qualify</tt> with the table and column symbols:
138
+ A couple other ways two create a qualified identifier are to use <tt>Sequel.[]</tt> to create an identifier,
139
+ and call <tt>[]</tt> or +qualify+ on that, or to use the <tt>Sequel.qualify</tt> with the table and column symbols:
137
140
 
141
+ Sequel[:table][:column] # "table"."column"
142
+ Sequel[:column].qualify(:table) # "table"."column"
138
143
  Sequel.qualify(:table, :column) # "table"."column"
139
144
 
140
145
  Another way to generate identifiers is to use Sequel's {virtual row support}[rdoc-ref:doc/virtual_rows.rdoc]:
141
146
 
142
147
  DB[:albums].select{name} # SELECT "name" FROM "albums"
143
- DB[:albums].select{albums__name} # SELECT "albums"."name" FROM "albums"
148
+ DB[:albums].select{albums[:name]} # SELECT "albums"."name" FROM "albums"
149
+
150
+ You can also use the symbol_aref extension for creating qualified identifiers:
151
+
152
+ :table[:column] # "table"."column"
144
153
 
145
154
  === Numbers
146
155
 
@@ -173,10 +182,17 @@ You can combine this with implicit qualification:
173
182
 
174
183
  :table__column___alias # "table"."column" AS "alias"
175
184
 
185
+ As with creating qualified identifiers via a double underscore, This works by default, but it is possible to turn off by setting <tt>Sequel.split_symbols = false</tt>.
186
+
176
187
  You can also use the <tt>Sequel.as</tt> method to create an alias, and the +as+ method on most Sequel-specific expression objects:
177
188
 
178
- Sequel.as(:column, :alias) # "column" AS "alias"
179
- Sequel.qualify(:table, :column).as(:alias) # "table"."column" AS "alias"
189
+ Sequel.as(:column, :alias) # "column" AS "alias"
190
+ Sequel[:column].as(:alias) # "column" AS "alias"
191
+ Sequel[:table][:column].as(:alias) # "table"."column" AS "alias"
192
+
193
+ You can also use the symbol_as extension for creating aliased identifiers:
194
+
195
+ :column.as(:alias) # "column" AS "alias"
180
196
 
181
197
  If you want to use a derived column list, you can provide an array of column aliases:
182
198
 
@@ -231,10 +247,10 @@ If the database supports window functions, Sequel can handle them by calling the
231
247
 
232
248
  If the database supports schema qualified functions, Sequel can handle them by calling the function method on a QuailfiedIdentifier:
233
249
 
234
- DB[:albums].select{schema__function.function}
250
+ DB[:albums].select{schema[:function].function}
235
251
  # SELECT schema.function() FROM albums
236
252
 
237
- DB[:albums].select{schema__function.function(col, 2, "a")}
253
+ DB[:albums].select{schema[:function].function(col, 2, "a")}
238
254
  # SELECT schema.function(col, 2, 'a') FROM albums
239
255
 
240
256
  === Portable/Emulated Functions
@@ -347,8 +363,8 @@ produces <tt>(column != 1)</tt> instead of <tt>NOT (column = 1)</tt>.
347
363
 
348
364
  Sequel defines the inequality operators directly on most Sequel-specific expression objects:
349
365
 
350
- Sequel.qualify(:table, :column) > 1 # ("table"."column" > 1)
351
- Sequel.qualify(:table, :column) < 1 # ("table"."column" < 1)
366
+ Sequel[:table][:column] > 1 # ("table"."column" > 1)
367
+ Sequel[:table][:column] < 1 # ("table"."column" < 1)
352
368
  Sequel.function(:func) >= 1 # (func() >= 1)
353
369
  Sequel.function(:func, :column) <= 1 # (func("column") <= 1)
354
370
 
@@ -365,23 +381,23 @@ A common use of virtual rows is to handle inequality operators:
365
381
  The standard mathematical operates are defined on most Sequel-specific expression objects:
366
382
 
367
383
  Sequel[:column] + 1 # "column" + 1
368
- Sequel[:table__column] - 1 # "table"."column" - 1
369
- Sequel.qualify(:table, :column) * 1 # "table"."column" * 1
384
+ Sequel[:table][:column] - 1 # "table"."column" - 1
385
+ Sequel[:table][:column] * 1 # "table"."column" * 1
370
386
  Sequel[:column] / 1 # "column" / 1
371
387
  Sequel[:column] ** 1 # power("column", 1)
372
388
 
373
389
  You can also call the operator methods directly on the Sequel module:
374
390
 
375
391
  Sequel.+(:column, 1) # "column" + 1
376
- Sequel.-(:table__column, 1) # "table"."column" - 1
377
- Sequel.*(Sequel.qualify(:table, :column), 1) # "table"."column" * 1
392
+ Sequel.-(Sequel[:table][:column], 1) # "table"."column" - 1
393
+ Sequel.*(Sequel[:table][:column], 1) # "table"."column" * 1
378
394
  Sequel./(:column, 1) # "column" / 1
379
395
  Sequel.**(:column, 1) # power("column", 1)
380
396
 
381
397
  Note that since Sequel implements support for ruby's coercion protocol, the following also works:
382
398
 
383
399
  1 + Sequel[:column]
384
- 1 - Sequel.qualify(:table__column)
400
+ 1 - Sequel[:table][:column]
385
401
 
386
402
  === Boolean Operators (AND OR)
387
403
 
@@ -432,7 +448,7 @@ Casting in Sequel is done with the +cast+ method, which is available on most of
432
448
 
433
449
  Sequel[:name].cast(:text) # CAST("name" AS text)
434
450
  Sequel['1'].cast(:integer) # CAST('1' AS integer)
435
- Sequel.qualify(:table, :column).cast(:date) # CAST("table"."column" AS date)
451
+ Sequel[:table][:column].cast(:date) # CAST("table"."column" AS date)
436
452
 
437
453
  You can also use the <tt>Sequel.cast</tt> method:
438
454
 
@@ -516,17 +532,17 @@ Note that using +ilike+ with a regular expression will always make the regexp ca
516
532
  Sequel supports specifying ascending or descending order using the +asc+ and +desc+ method on most Sequel-specific expression objects:
517
533
 
518
534
  Sequel[:column].asc # "column" ASC
519
- Sequel[:column].qualify(:table).desc # "table"."column" DESC
535
+ Sequel[:table][:column].desc # "table"."column" DESC
520
536
 
521
537
  You can also use the <tt>Sequel.asc</tt> and <tt>Sequel.desc</tt> methods:
522
538
 
523
539
  Sequel.asc(:column) # "column" ASC
524
- Sequel.desc(Sequel[:column].qualify(:table)) # "table"."column" DESC
540
+ Sequel.desc(Sequel[:table][:column]) # "table"."column" DESC
525
541
 
526
542
  On some databases, you can specify null ordering:
527
543
 
528
544
  Sequel.asc(:column, :nulls=>:first) # "column" ASC NULLS FIRST
529
- Sequel.desc(Sequel[:column].qualify(:table), :nulls=>:last) # "table"."column" DESC NULLS LAST
545
+ Sequel.desc(Sequel[:table][:column], :nulls=>:last) # "table"."column" DESC NULLS LAST
530
546
 
531
547
  === All Columns (.*)
532
548
 
@@ -556,7 +572,7 @@ If you provide a 3rd argument to <tt>Sequel.case</tt>, it goes between CASE and
556
572
  Sequel supports SQL subscripts using the +sql_subscript+ method on most Sequel-specific expression objects:
557
573
 
558
574
  Sequel[:column].sql_subscript(3) # column[3]
559
- Sequel[:column].qualify(:table).sql_subscript(3) # table.column[3]
575
+ Sequel[:table][:column].sql_subscript(3) # table.column[3]
560
576
 
561
577
  You can also use the <tt>Sequel.subscript</tt> method:
562
578
 
@@ -159,5 +159,6 @@ SEQUEL_ERROR_SQL :: Use the error_sql extension when running the specs
159
159
  SEQUEL_NO_AUTO_LITERAL_STRINGS :: Use the no_auto_string_literals extension when running the specs
160
160
  SEQUEL_NO_CACHE_ASSOCIATIONS :: Don't cache association metadata when running the specs
161
161
  SEQUEL_NO_CHECK_SQLS :: Don't check for specific SQL syntax when running the specs
162
+ SEQUEL_NO_SPLIT_SYMBOLS :: Turn off symbol splitting when running the specs
162
163
  SEQUEL_NO_PENDING :: Don't skip any specs, try running all specs (note, can cause lockups for some adapters)
163
164
  SKIPPED_TEST_WARN :: Warn when skipping any tests because libraries aren't available
@@ -121,8 +121,17 @@ in the method name:
121
121
  # WHERE table.column > 1
122
122
 
123
123
  Using the double underscore for SQL::QualifiedIdentifiers was done to make
124
- usage very similar to using symbols, which also translate the double underscore
125
- into a qualified column.
124
+ usage very similar to using symbols, which by default also translate the
125
+ double underscore into a qualified column.
126
+
127
+ Note that when <tt>Sequel.split_symbols = false</tt> is used, then virtual
128
+ rows do not split symbols either. If you need to create qualified identifers
129
+ when disabling symbol splitting, it is easy to do by calling #[] on the
130
+ SQL::Identifiers returned by regular methods calls:
131
+
132
+ ds.where{|o| o.table[:column] > 1}
133
+ ds.where{table[:column] > 1}
134
+ # WHERE table.column > 1
126
135
 
127
136
  == SQL::Functions - SQL function calls
128
137
 
@@ -82,9 +82,15 @@ module Sequel
82
82
  end
83
83
  end
84
84
 
85
+ # Derby does not allow adding primary key constraints to NULLable columns.
86
+ def can_add_primary_key_constraint_on_nullable_columns?
87
+ false
88
+ end
89
+
85
90
  # Derby doesn't allow specifying NULL for columns, only NOT NULL.
86
91
  def column_definition_null_sql(sql, column)
87
- sql << " NOT NULL" if column.fetch(:null, column[:allow_null]) == false
92
+ null = column.fetch(:null, column[:allow_null])
93
+ sql << " NOT NULL" if null == false || (null.nil? && column[:primary_key])
88
94
  end
89
95
 
90
96
  # Add NOT LOGGED for temporary tables to improve performance.
@@ -58,6 +58,11 @@ module Sequel
58
58
 
59
59
  private
60
60
 
61
+ # H2 does not allow adding primary key constraints to NULLable columns.
62
+ def can_add_primary_key_constraint_on_nullable_columns?
63
+ false
64
+ end
65
+
61
66
  # If the :prepare option is given and we aren't in a savepoint,
62
67
  # prepare the transaction for a two-phase commit.
63
68
  def commit_transaction(conn, opts=OPTS)
@@ -73,12 +78,21 @@ module Sequel
73
78
  case op[:op]
74
79
  when :add_column
75
80
  if (pk = op.delete(:primary_key)) || (ref = op.delete(:table))
81
+ if pk
82
+ op[:null] = false
83
+ end
84
+
76
85
  sqls = [super(table, op)]
77
- sqls << "ALTER TABLE #{quote_schema_table(table)} ADD PRIMARY KEY (#{quote_identifier(op[:name])})" if pk && op[:type] != :identity
86
+
87
+ if pk && op[:type] != :identity
88
+ sqls << "ALTER TABLE #{quote_schema_table(table)} ADD PRIMARY KEY (#{quote_identifier(op[:name])})"
89
+ end
90
+
78
91
  if ref
79
92
  op[:table] = ref
80
93
  sqls << "ALTER TABLE #{quote_schema_table(table)} ADD FOREIGN KEY (#{quote_identifier(op[:name])}) #{column_references_sql(op)}"
81
94
  end
95
+
82
96
  sqls
83
97
  else
84
98
  super(table, op)
@@ -264,11 +264,15 @@ module Sequel
264
264
  im = input_identifier_meth(ds)
265
265
 
266
266
  # Primary Keys
267
- ds = metadata_dataset.from(:all_constraints___cons, :all_cons_columns___cols).
268
- where(:cols__table_name=>im.call(table), :cons__constraint_type=>'P',
269
- :cons__constraint_name=>:cols__constraint_name, :cons__owner=>:cols__owner)
270
- ds = ds.where(:cons__owner=>im.call(schema)) if schema
271
- pks = ds.select_map(:cols__column_name)
267
+ ds = metadata_dataset.
268
+ from{[all_constraints.as(:cons), all_cons_columns.as(:cols)]}.
269
+ where{{
270
+ cols[:table_name]=>im.call(table),
271
+ cons[:constraint_type]=>'P',
272
+ cons[:constraint_name]=>cols[:constraint_name],
273
+ cons[:owner]=>cols[:owner]}}
274
+ ds = ds.where{{cons[:owner]=>im.call(schema)}} if schema
275
+ pks = ds.select_map{cols[:column_name]}
272
276
 
273
277
  # Default values
274
278
  defaults = begin
@@ -94,7 +94,6 @@ rescue LoadError => e
94
94
  end
95
95
 
96
96
  module Sequel
97
- Dataset::NON_SQL_OPTIONS << :cursor
98
97
  module Postgres
99
98
  CONVERTED_EXCEPTIONS << PGError
100
99
 
@@ -23,11 +23,11 @@ module Sequel
23
23
  m2 = input_identifier_meth
24
24
  indexes = {}
25
25
  metadata_dataset.
26
- from(:db_index___i).
27
- join(:db_index_key___k, :index_name=>:index_name, :class_name=>:class_name).
28
- where(:i__class_name=>m2.call(table), :is_primary_key=>'NO').
29
- order(:k__key_order).
30
- select(:i__index_name, :k__key_attr_name___column, :is_unique).
26
+ from{db_index[:i]}.
27
+ join(Sequel[:db_index_key].as(:k), :index_name=>:index_name, :class_name=>:class_name).
28
+ where{{i[:class_name]=>m2.call(table), :is_primary_key=>'NO'}}.
29
+ order{k[:key_order]}.
30
+ select{[i[:index_name], k[:key_attr_name].as(:column), :is_unique]}.
31
31
  each do |row|
32
32
  index = indexes[m.call(row[:index_name])] ||= {:columns=>[], :unique=>row[:is_unique]=='YES'}
33
33
  index[:columns] << m.call(row[:column])
@@ -44,18 +44,18 @@ module Sequel
44
44
  m2 = input_identifier_meth(opts[:dataset])
45
45
 
46
46
  pks = metadata_dataset.
47
- from(:db_index___i).
48
- join(:db_index_key___k, :index_name=>:index_name, :class_name=>:class_name).
49
- where(:i__class_name=>m2.call(table_name), :is_primary_key=>'YES').
50
- order(:k__key_order).
51
- select_map(:k__key_attr_name).
47
+ from{db_index[:i]}.
48
+ join(Sequel[:db_index_key].as(:k), :index_name=>:index_name, :class_name=>:class_name).
49
+ where{{i[:class_name]=>m2.call(table_name), :is_primary_key=>'YES'}}.
50
+ order{k[:key_order]}.
51
+ select_map{k[:key_attr_name]}.
52
52
  map{|c| m.call(c)}
53
53
 
54
54
  metadata_dataset.
55
55
  from(:db_attribute).
56
56
  where(:class_name=>m2.call(table_name)).
57
57
  order(:def_order).
58
- select(:attr_name, :data_type___db_type, :default_value___default, :is_nullable___allow_null, :prec).
58
+ select{[:attr_name, data_type.as(:db_type), default_value.as(:default), is_nullable.as(:allow_null), :prec]}.
59
59
  map do |row|
60
60
  name = m.call(row.delete(:attr_name))
61
61
  row[:allow_null] = row[:allow_null] == 'YES'
@@ -76,7 +76,7 @@ module Sequel
76
76
  m = output_identifier_meth
77
77
  indexes = {}
78
78
  metadata_dataset.
79
- from(:syscat__indexes).
79
+ from(Sequel[:syscat][:indexes]).
80
80
  select(:indname, :uniquerule, :colnames).
81
81
  where(:tabname=>input_identifier_meth.call(table), :system_required=>0).
82
82
  each do |r|
@@ -160,13 +160,9 @@ module Sequel
160
160
  AUTOINCREMENT
161
161
  end
162
162
 
163
- # Add null/not null SQL fragment to column creation SQL.
164
- def column_definition_null_sql(sql, column)
165
- null = column.fetch(:null, column[:allow_null])
166
- null = false if column[:primary_key]
167
-
168
- sql << NOT_NULL if null == false
169
- sql << NULL if null == true
163
+ # DB2 does not allow adding primary key constraints to NULLable columns.
164
+ def can_add_primary_key_constraint_on_nullable_columns?
165
+ false
170
166
  end
171
167
 
172
168
  # Supply columns with NOT NULL if they are part of a composite
@@ -3,7 +3,6 @@
3
3
  Sequel.require %w'emulate_offset_with_row_number split_alter_table', 'adapters/utils'
4
4
 
5
5
  module Sequel
6
- Dataset::NON_SQL_OPTIONS << :disable_insert_output
7
6
  module MSSQL
8
7
  Sequel::Database.set_shared_adapter_scheme(:mssql, self)
9
8
 
@@ -141,20 +140,22 @@ module Sequel
141
140
  schema, table = schema_and_table(table)
142
141
  current_schema = m.call(get(Sequel.function('schema_name')))
143
142
  fk_action_map = FOREIGN_KEY_ACTION_MAP
143
+ fk = Sequel[:fk]
144
+ fkc = Sequel[:fkc]
144
145
  ds = metadata_dataset.from(Sequel.lit('[sys].[foreign_keys]').as(:fk)).
145
146
  join(Sequel.lit('[sys].[foreign_key_columns]').as(:fkc), :constraint_object_id => :object_id).
146
- join(Sequel.lit('[sys].[all_columns]').as(:pc), :object_id => :fkc__parent_object_id, :column_id => :fkc__parent_column_id).
147
- join(Sequel.lit('[sys].[all_columns]').as(:rc), :object_id => :fkc__referenced_object_id, :column_id => :fkc__referenced_column_id).
148
- where{{object_schema_name(:fk__parent_object_id) => im.call(schema || current_schema)}}.
149
- where{{object_name(:fk__parent_object_id) => im.call(table)}}.
150
- select{[:fk__name,
151
- :fk__delete_referential_action,
152
- :fk__update_referential_action,
153
- :pc__name___column,
154
- :rc__name___referenced_column,
155
- object_schema_name(:fk__referenced_object_id).as(:schema),
156
- object_name(:fk__referenced_object_id).as(:table)]}.
157
- order(:fk__name, :fkc__constraint_column_id)
147
+ join(Sequel.lit('[sys].[all_columns]').as(:pc), :object_id => fkc[:parent_object_id], :column_id => fkc[:parent_column_id]).
148
+ join(Sequel.lit('[sys].[all_columns]').as(:rc), :object_id => fkc[:referenced_object_id], :column_id => fkc[:referenced_column_id]).
149
+ where{{object_schema_name(fk[:parent_object_id]) => im.call(schema || current_schema)}}.
150
+ where{{object_name(fk[:parent_object_id]) => im.call(table)}}.
151
+ select{[fk[:name],
152
+ fk[:delete_referential_action],
153
+ fk[:update_referential_action],
154
+ pc[:name].as(:column),
155
+ rc[:name].as(:referenced_column),
156
+ object_schema_name(fk[:referenced_object_id]).as(:schema),
157
+ object_name(fk[:referenced_object_id]).as(:table)]}.
158
+ order(fk[:name], fkc[:constraint_column_id])
158
159
  h = {}
159
160
  ds.each do |row|
160
161
  if r = h[row[:name]]
@@ -179,17 +180,18 @@ module Sequel
179
180
  m = output_identifier_meth
180
181
  im = input_identifier_meth
181
182
  indexes = {}
183
+ i = Sequel[:i]
182
184
  ds = metadata_dataset.from(Sequel.lit('[sys].[tables]').as(:t)).
183
185
  join(Sequel.lit('[sys].[indexes]').as(:i), :object_id=>:object_id).
184
186
  join(Sequel.lit('[sys].[index_columns]').as(:ic), :object_id=>:object_id, :index_id=>:index_id).
185
187
  join(Sequel.lit('[sys].[columns]').as(:c), :object_id=>:object_id, :column_id=>:column_id).
186
- select(:i__name, :i__is_unique, :c__name___column).
187
- where{{t__name=>im.call(table)}}.
188
- where(:i__is_primary_key=>0, :i__is_disabled=>0).
189
- order(:i__name, :ic__index_column_id)
188
+ select(i[:name], i[:is_unique], Sequel[:c][:name].as(:column)).
189
+ where{{t[:name]=>im.call(table)}}.
190
+ where(i[:is_primary_key]=>0, i[:is_disabled]=>0).
191
+ order(i[:name], Sequel[:ic][:index_column_id])
190
192
 
191
193
  if supports_partial_indexes?
192
- ds = ds.where(:i__has_filter=>0)
194
+ ds = ds.where(i[:has_filter]=>0)
193
195
  end
194
196
 
195
197
  ds.each do |r|
@@ -313,6 +315,11 @@ module Sequel
313
315
  SQL_BEGIN
314
316
  end
315
317
 
318
+ # MSSQL does not allow adding primary key constraints to NULLable columns.
319
+ def can_add_primary_key_constraint_on_nullable_columns?
320
+ false
321
+ end
322
+
316
323
  # Handle MSSQL specific default format.
317
324
  def column_schema_normalize_default(default, type)
318
325
  if m = MSSQL_DEFAULT_RE.match(default)
@@ -365,7 +372,7 @@ module Sequel
365
372
  def default_constraint_name(table, column_name)
366
373
  if server_version >= 9000000
367
374
  table_name = schema_and_table(table).compact.join('.')
368
- self[:sys__default_constraints].
375
+ self[Sequel[:sys][:default_constraints]].
369
376
  where{{:parent_object_id => Sequel::SQL::Function.new(:object_id, table_name), col_name(:parent_object_id, :parent_column_id) => column_name.to_s}}.
370
377
  get(:name)
371
378
  end
@@ -390,7 +397,7 @@ module Sequel
390
397
  # Backbone of the tables and views support.
391
398
  def information_schema_tables(type, opts)
392
399
  m = output_identifier_meth
393
- metadata_dataset.from(:information_schema__tables___t).
400
+ metadata_dataset.from(Sequel[:information_schema][:tables].as(:t)).
394
401
  select(:table_name).
395
402
  filter(:table_type=>type, :table_schema=>(opts[:schema]||'dbo').to_s).
396
403
  map{|x| m.call(x[:table_name])}
@@ -453,17 +460,17 @@ module Sequel
453
460
  get(:indid)
454
461
  pk_cols = metadata_dataset.from(sys_qual.call(Sequel.lit('sysindexkeys')).as(:sik)).
455
462
  join(sys_qual.call(Sequel.lit('syscolumns')).as(:sc), :id=>:id, :colid=>:colid).
456
- where(:sik__id=>table_id, :sik__indid=>pk_index_id).
457
- select_order_map(:sc__name)
463
+ where{{sik[:id]=>table_id, sik[:indid]=>pk_index_id}}.
464
+ select_order_map{sc[:name]}
458
465
 
459
- ds = metadata_dataset.from(inf_sch_qual.call(:information_schema__tables).as(:t)).
460
- join(inf_sch_qual.call(:information_schema__columns).as(:c), :table_catalog=>:table_catalog,
466
+ ds = metadata_dataset.from(inf_sch_qual.call(Sequel[:information_schema][:tables]).as(:t)).
467
+ join(inf_sch_qual.call(Sequel[:information_schema][:columns]).as(:c), :table_catalog=>:table_catalog,
461
468
  :table_schema => :table_schema, :table_name => :table_name).
462
- select(:column_name___column, :data_type___db_type, :character_maximum_length___max_chars, :column_default___default, :is_nullable___allow_null, :numeric_precision___column_size, :numeric_scale___scale).
463
- filter(:c__table_name=>tn)
469
+ select{[column_name.as(:column), data_type.as(:db_type), character_maximum_length.as(:max_chars), column_default.as(:default), is_nullable.as(:allow_null), numeric_precision.as(:column_size), numeric_scale.as(:scale)]}.
470
+ where{{c[:table_name]=>tn}}
464
471
 
465
472
  if schema = opts[:schema]
466
- ds.filter!(:c__table_schema=>schema)
473
+ ds = ds.where{{c[:table_schema]=>schema}}
467
474
  end
468
475
 
469
476
  ds.map do |row|
@@ -567,12 +574,13 @@ module Sequel
567
574
  ROWS_ONLY = " ROWS ONLY".freeze
568
575
  FETCH_NEXT = " FETCH NEXT ".freeze
569
576
 
577
+ NON_SQL_OPTIONS = (Dataset::NON_SQL_OPTIONS + [:disable_insert_output]).freeze
578
+
570
579
  Dataset.def_mutation_method(:disable_insert_output, :output, :module=>self)
571
580
  Dataset.def_sql_method(self, :delete, %w'with delete from output from2 where')
572
581
  Dataset.def_sql_method(self, :insert, %w'with insert into columns output values')
573
582
  Dataset.def_sql_method(self, :update, [['if is_2005_or_later?', %w'with update limit table set output from where'], ['else', %w'update table set output from where']])
574
583
 
575
-
576
584
  # Allow overriding of the mssql_unicode_strings option at the dataset level.
577
585
  attr_writer :mssql_unicode_strings
578
586
 
@@ -953,6 +961,11 @@ module Sequel
953
961
  is_2008_or_later? ? :values : :union
954
962
  end
955
963
 
964
+ # Dataset options that do not affect the generated SQL.
965
+ def non_sql_options
966
+ NON_SQL_OPTIONS
967
+ end
968
+
956
969
  def select_into_sql(sql)
957
970
  if i = @opts[:into]
958
971
  sql << INTO