sequel 3.21.0 → 3.32.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 +539 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +20 -6
- data/Rakefile +37 -19
- data/bin/sequel +1 -5
- data/doc/advanced_associations.rdoc +17 -0
- data/doc/association_basics.rdoc +293 -43
- data/doc/dataset_basics.rdoc +4 -4
- data/doc/dataset_filtering.rdoc +8 -0
- data/doc/mass_assignment.rdoc +54 -0
- data/doc/migration.rdoc +15 -538
- data/doc/model_hooks.rdoc +72 -27
- data/doc/opening_databases.rdoc +89 -50
- data/doc/prepared_statements.rdoc +40 -13
- data/doc/reflection.rdoc +8 -2
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/release_notes/3.31.0.txt +146 -0
- data/doc/release_notes/3.32.0.txt +202 -0
- data/doc/schema_modification.rdoc +547 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +129 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +2 -2
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/ado.rb +40 -18
- data/lib/sequel/adapters/amalgalite.rb +17 -9
- data/lib/sequel/adapters/db2.rb +175 -86
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do/mysql.rb +5 -7
- data/lib/sequel/adapters/do/postgres.rb +0 -5
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/do.rb +17 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +448 -0
- data/lib/sequel/adapters/informix.rb +6 -23
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/db2.rb +52 -0
- data/lib/sequel/adapters/jdbc/derby.rb +260 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
- data/lib/sequel/adapters/jdbc/h2.rb +66 -30
- data/lib/sequel/adapters/jdbc/hsqldb.rb +177 -0
- data/lib/sequel/adapters/jdbc/informix.rb +26 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
- data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
- data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
- data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +231 -78
- data/lib/sequel/adapters/mock.rb +339 -0
- data/lib/sequel/adapters/mysql.rb +85 -184
- data/lib/sequel/adapters/mysql2.rb +26 -25
- data/lib/sequel/adapters/odbc/db2.rb +17 -0
- data/lib/sequel/adapters/odbc/mssql.rb +1 -6
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +3 -5
- data/lib/sequel/adapters/oracle.rb +355 -53
- data/lib/sequel/adapters/postgres.rb +194 -33
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +328 -0
- data/lib/sequel/adapters/shared/firebird.rb +221 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +278 -107
- data/lib/sequel/adapters/shared/mysql.rb +203 -65
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
- data/lib/sequel/adapters/shared/oracle.rb +237 -46
- data/lib/sequel/adapters/shared/postgres.rb +214 -82
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +200 -50
- data/lib/sequel/adapters/sqlite.rb +29 -21
- data/lib/sequel/adapters/swift/mysql.rb +12 -7
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +8 -6
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/tinytds.rb +160 -19
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
- data/lib/sequel/ast_transformer.rb +190 -0
- data/lib/sequel/connection_pool/threaded.rb +3 -2
- data/lib/sequel/connection_pool.rb +1 -1
- data/lib/sequel/core.rb +68 -5
- data/lib/sequel/database/connecting.rb +5 -6
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +59 -1
- data/lib/sequel/database/logging.rb +1 -1
- data/lib/sequel/database/misc.rb +104 -19
- data/lib/sequel/database/query.rb +163 -59
- data/lib/sequel/database/schema_generator.rb +17 -7
- data/lib/sequel/database/schema_methods.rb +59 -29
- data/lib/sequel/dataset/actions.rb +240 -76
- data/lib/sequel/dataset/features.rb +91 -8
- data/lib/sequel/dataset/graph.rb +38 -11
- data/lib/sequel/dataset/misc.rb +50 -23
- data/lib/sequel/dataset/mutation.rb +12 -7
- data/lib/sequel/dataset/prepared_statements.rb +59 -27
- data/lib/sequel/dataset/query.rb +236 -43
- data/lib/sequel/dataset/sql.rb +676 -267
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/extensions/migration.rb +6 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/query.rb +1 -1
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model/associations.rb +1081 -344
- data/lib/sequel/model/base.rb +420 -133
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +20 -10
- data/lib/sequel/plugins/active_model.rb +13 -1
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/composition.rb +43 -10
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +114 -7
- data/lib/sequel/plugins/many_through_many.rb +68 -7
- data/lib/sequel/plugins/nested_attributes.rb +65 -10
- data/lib/sequel/plugins/prepared_statements.rb +151 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/serialization.rb +98 -49
- data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
- data/lib/sequel/plugins/sharding.rb +21 -54
- data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +2 -2
- data/lib/sequel/plugins/xml_serializer.rb +3 -3
- data/lib/sequel/sql.rb +109 -52
- data/lib/sequel/timezones.rb +57 -38
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/mssql_spec.rb +135 -30
- data/spec/adapters/mysql_spec.rb +244 -212
- data/spec/adapters/oracle_spec.rb +67 -77
- data/spec/adapters/postgres_spec.rb +267 -78
- data/spec/adapters/spec_helper.rb +6 -5
- data/spec/adapters/sqlite_spec.rb +35 -21
- data/spec/core/connection_pool_spec.rb +71 -92
- data/spec/core/core_sql_spec.rb +21 -30
- data/spec/core/database_spec.rb +789 -512
- data/spec/core/dataset_spec.rb +1176 -1061
- data/spec/core/expression_filters_spec.rb +159 -42
- data/spec/core/mock_adapter_spec.rb +419 -0
- data/spec/core/object_graph_spec.rb +86 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +298 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/active_model_spec.rb +13 -0
- data/spec/extensions/association_autoreloading_spec.rb +1 -10
- data/spec/extensions/association_dependencies_spec.rb +2 -12
- data/spec/extensions/association_pks_spec.rb +66 -32
- data/spec/extensions/caching_spec.rb +23 -50
- data/spec/extensions/class_table_inheritance_spec.rb +31 -83
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/hook_class_methods_spec.rb +65 -91
- data/spec/extensions/identity_map_spec.rb +114 -22
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +53 -0
- data/spec/extensions/json_serializer_spec.rb +4 -5
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +17 -39
- data/spec/extensions/many_through_many_spec.rb +283 -250
- data/spec/extensions/migration_spec.rb +35 -32
- data/spec/extensions/named_timezones_spec.rb +23 -3
- data/spec/extensions/nested_attributes_spec.rb +97 -88
- data/spec/extensions/optimistic_locking_spec.rb +9 -20
- data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
- data/spec/extensions/prepared_statements_spec.rb +53 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +1 -6
- data/spec/extensions/query_spec.rb +6 -0
- data/spec/extensions/rcte_tree_spec.rb +41 -43
- data/spec/extensions/schema_dumper_spec.rb +5 -8
- data/spec/extensions/schema_spec.rb +13 -21
- data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
- data/spec/extensions/serialization_spec.rb +81 -43
- data/spec/extensions/sharding_spec.rb +66 -140
- data/spec/extensions/single_table_inheritance_spec.rb +18 -29
- data/spec/extensions/spec_helper.rb +13 -61
- data/spec/extensions/sql_expr_spec.rb +20 -60
- data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +4 -7
- data/spec/extensions/touch_spec.rb +13 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/typecast_on_load_spec.rb +1 -6
- data/spec/extensions/update_primary_key_spec.rb +30 -24
- data/spec/extensions/validation_class_methods_spec.rb +30 -51
- data/spec/extensions/validation_helpers_spec.rb +16 -35
- data/spec/extensions/xml_serializer_spec.rb +16 -4
- data/spec/integration/associations_test.rb +661 -21
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +500 -67
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +367 -119
- data/spec/integration/prepared_statement_test.rb +222 -125
- data/spec/integration/schema_test.rb +217 -39
- data/spec/integration/spec_helper.rb +39 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +182 -5
- data/spec/integration/type_test.rb +17 -3
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +955 -662
- data/spec/model/base_spec.rb +275 -95
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +677 -676
- data/spec/model/hooks_spec.rb +349 -67
- data/spec/model/model_spec.rb +222 -168
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +381 -218
- data/spec/model/spec_helper.rb +13 -71
- data/spec/model/validations_spec.rb +11 -0
- metadata +117 -73
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
Sequel.require 'adapters/utils/emulate_offset_with_row_number'
|
|
2
|
+
|
|
1
3
|
module Sequel
|
|
2
4
|
Dataset::NON_SQL_OPTIONS << :disable_insert_output
|
|
3
5
|
module MSSQL
|
|
@@ -11,15 +13,41 @@ module Sequel
|
|
|
11
13
|
SQL_ROLLBACK_TO_SAVEPOINT = 'IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION autopoint_%d'.freeze
|
|
12
14
|
SQL_SAVEPOINT = 'SAVE TRANSACTION autopoint_%d'.freeze
|
|
13
15
|
|
|
16
|
+
# Whether to use N'' to quote strings, which allows unicode characters inside the
|
|
17
|
+
# strings. True by default for compatibility, can be set to false for a possible
|
|
18
|
+
# performance increase. This sets the default for all datasets created from this
|
|
19
|
+
# Database object.
|
|
20
|
+
attr_accessor :mssql_unicode_strings
|
|
21
|
+
|
|
14
22
|
# The types to check for 0 scale to transform :decimal types
|
|
15
23
|
# to :integer.
|
|
16
24
|
DECIMAL_TYPE_RE = /number|numeric|decimal/io
|
|
17
|
-
|
|
25
|
+
|
|
18
26
|
# Microsoft SQL Server uses the :mssql type.
|
|
19
27
|
def database_type
|
|
20
28
|
:mssql
|
|
21
29
|
end
|
|
22
30
|
|
|
31
|
+
# Use the system tables to get index information
|
|
32
|
+
def indexes(table, opts={})
|
|
33
|
+
m = output_identifier_meth
|
|
34
|
+
im = input_identifier_meth
|
|
35
|
+
indexes = {}
|
|
36
|
+
metadata_dataset.from(:sys__tables___t).
|
|
37
|
+
join(:sys__indexes___i, :object_id=>:object_id).
|
|
38
|
+
join(:sys__index_columns___ic, :object_id=>:object_id, :index_id=>:index_id).
|
|
39
|
+
join(:sys__columns___c, :object_id=>:object_id, :column_id=>:column_id).
|
|
40
|
+
select(:i__name, :i__is_unique, :c__name___column).
|
|
41
|
+
where{{t__name=>im.call(table)}}.
|
|
42
|
+
where(:i__is_primary_key=>0, :i__is_disabled=>0).
|
|
43
|
+
order(:i__name, :ic__index_column_id).
|
|
44
|
+
each do |r|
|
|
45
|
+
index = indexes[m.call(r[:name])] ||= {:columns=>[], :unique=>(r[:is_unique] && r[:is_unique]!=0)}
|
|
46
|
+
index[:columns] << m.call(r[:column])
|
|
47
|
+
end
|
|
48
|
+
indexes
|
|
49
|
+
end
|
|
50
|
+
|
|
23
51
|
# The version of the MSSQL server, as an integer (e.g. 10001600 for
|
|
24
52
|
# SQL Server 2008 Express).
|
|
25
53
|
def server_version(server=nil)
|
|
@@ -47,11 +75,13 @@ module Sequel
|
|
|
47
75
|
# Microsoft SQL Server supports using the INFORMATION_SCHEMA to get
|
|
48
76
|
# information on tables.
|
|
49
77
|
def tables(opts={})
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
78
|
+
information_schema_tables('BASE TABLE', opts)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Microsoft SQL Server supports using the INFORMATION_SCHEMA to get
|
|
82
|
+
# information on views.
|
|
83
|
+
def views(opts={})
|
|
84
|
+
information_schema_tables('VIEW', opts)
|
|
55
85
|
end
|
|
56
86
|
|
|
57
87
|
private
|
|
@@ -69,7 +99,21 @@ module Sequel
|
|
|
69
99
|
when :rename_column
|
|
70
100
|
"sp_rename #{literal("#{quote_schema_table(table)}.#{quote_identifier(op[:name])}")}, #{literal(op[:new_name].to_s)}, 'COLUMN'"
|
|
71
101
|
when :set_column_type
|
|
72
|
-
|
|
102
|
+
sqls = []
|
|
103
|
+
if sch = schema(table)
|
|
104
|
+
if cs = sch.each{|k, v| break v if k == op[:name]; nil}
|
|
105
|
+
cs = cs.dup
|
|
106
|
+
if constraint = default_constraint_name(table, op[:name])
|
|
107
|
+
sqls << "ALTER TABLE #{quote_schema_table(table)} DROP CONSTRAINT #{constraint}"
|
|
108
|
+
end
|
|
109
|
+
cs[:default] = cs[:ruby_default]
|
|
110
|
+
op = cs.merge!(op)
|
|
111
|
+
default = op.delete(:default)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
sqls << "ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{column_definition_sql(op)}"
|
|
115
|
+
sqls << alter_table_sql(table, op.merge(:op=>:set_column_default, :default=>default)) if default
|
|
116
|
+
sqls
|
|
73
117
|
when :set_column_null
|
|
74
118
|
sch = schema(table).find{|k,v| k.to_s == op[:name].to_s}.last
|
|
75
119
|
type = sch[:db_type]
|
|
@@ -97,7 +141,7 @@ module Sequel
|
|
|
97
141
|
# Commit the active transaction on the connection, does not commit/release
|
|
98
142
|
# savepoints.
|
|
99
143
|
def commit_transaction(conn, opts={})
|
|
100
|
-
log_connection_execute(conn, commit_transaction_sql) unless
|
|
144
|
+
log_connection_execute(conn, commit_transaction_sql) unless @transactions[conn][:savepoint_level] > 1
|
|
101
145
|
end
|
|
102
146
|
|
|
103
147
|
# SQL to COMMIT a transaction.
|
|
@@ -112,11 +156,32 @@ module Sequel
|
|
|
112
156
|
"CREATE TABLE #{quote_schema_table(options[:temp] ? "##{name}" : name)} (#{column_list_sql(generator)})"
|
|
113
157
|
end
|
|
114
158
|
|
|
159
|
+
# The name of the constraint for setting the default value on the table and column.
|
|
160
|
+
def default_constraint_name(table, column)
|
|
161
|
+
from(:sysobjects___c_obj).
|
|
162
|
+
join(:syscomments___com, :id=>:id).
|
|
163
|
+
join(:sysobjects___t_obj, :id=>:c_obj__parent_obj).
|
|
164
|
+
join(:sysconstraints___con, :constid=>:c_obj__id).
|
|
165
|
+
join(:syscolumns___col, :id=>:t_obj__id, :colid=>:colid).
|
|
166
|
+
where{{c_obj__uid=>user_id{}}}.
|
|
167
|
+
where(:c_obj__xtype=>'D', :t_obj__name=>table.to_s, :col__name=>column.to_s).
|
|
168
|
+
get(:c_obj__name)
|
|
169
|
+
end
|
|
170
|
+
|
|
115
171
|
# The SQL to drop an index for the table.
|
|
116
172
|
def drop_index_sql(table, op)
|
|
117
173
|
"DROP INDEX #{quote_identifier(op[:name] || default_index_name(table, op[:columns]))} ON #{quote_schema_table(table)}"
|
|
118
174
|
end
|
|
119
175
|
|
|
176
|
+
# Backbone of the tables and views support.
|
|
177
|
+
def information_schema_tables(type, opts)
|
|
178
|
+
m = output_identifier_meth
|
|
179
|
+
metadata_dataset.from(:information_schema__tables___t).
|
|
180
|
+
select(:table_name).
|
|
181
|
+
filter(:table_type=>type, :table_schema=>(opts[:schema]||default_schema||'dbo').to_s).
|
|
182
|
+
map{|x| m.call(x[:table_name])}
|
|
183
|
+
end
|
|
184
|
+
|
|
120
185
|
# Always quote identifiers in the metadata_dataset, so schema parsing works.
|
|
121
186
|
def metadata_dataset
|
|
122
187
|
ds = super
|
|
@@ -139,20 +204,41 @@ module Sequel
|
|
|
139
204
|
SQL_ROLLBACK
|
|
140
205
|
end
|
|
141
206
|
|
|
142
|
-
# MSSQL
|
|
143
|
-
|
|
207
|
+
# The closest MSSQL equivalent of a boolean datatype is the bit type.
|
|
208
|
+
def schema_column_type(db_type)
|
|
209
|
+
case db_type
|
|
210
|
+
when /\A(bit)\z/io
|
|
211
|
+
:boolean
|
|
212
|
+
else
|
|
213
|
+
super
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# MSSQL uses the INFORMATION_SCHEMA to hold column information, and
|
|
218
|
+
# parses primary key information from the sysindexes, sysindexkeys,
|
|
219
|
+
# and syscolumns system tables.
|
|
144
220
|
def schema_parse_table(table_name, opts)
|
|
145
|
-
m = output_identifier_meth
|
|
146
|
-
m2 = input_identifier_meth
|
|
221
|
+
m = output_identifier_meth(opts[:dataset])
|
|
222
|
+
m2 = input_identifier_meth(opts[:dataset])
|
|
223
|
+
tn = m2.call(table_name.to_s)
|
|
224
|
+
table_id = get{object_id(tn)}
|
|
225
|
+
pk_index_id = metadata_dataset.from(:sysindexes).
|
|
226
|
+
where(:id=>table_id, :indid=>1..254){{(status & 2048)=>2048}}.
|
|
227
|
+
get(:indid)
|
|
228
|
+
pk_cols = metadata_dataset.from(:sysindexkeys___sik).
|
|
229
|
+
join(:syscolumns___sc, :id=>:id, :colid=>:colid).
|
|
230
|
+
where(:sik__id=>table_id, :sik__indid=>pk_index_id).
|
|
231
|
+
select_order_map(:sc__name)
|
|
147
232
|
ds = metadata_dataset.from(:information_schema__tables___t).
|
|
148
233
|
join(:information_schema__columns___c, :table_catalog=>:table_catalog,
|
|
149
234
|
:table_schema => :table_schema, :table_name => :table_name).
|
|
150
235
|
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).
|
|
151
|
-
filter(:c__table_name=>
|
|
236
|
+
filter(:c__table_name=>tn)
|
|
152
237
|
if schema = opts[:schema] || default_schema
|
|
153
238
|
ds.filter!(:c__table_schema=>schema)
|
|
154
239
|
end
|
|
155
240
|
ds.map do |row|
|
|
241
|
+
row[:primary_key] = pk_cols.include?(row[:column])
|
|
156
242
|
row[:allow_null] = row[:allow_null] == 'YES' ? true : false
|
|
157
243
|
row[:default] = nil if blank_object?(row[:default])
|
|
158
244
|
row[:type] = if row[:db_type] =~ DECIMAL_TYPE_RE && row[:scale] == 0
|
|
@@ -163,6 +249,11 @@ module Sequel
|
|
|
163
249
|
[m.call(row.delete(:column)), row]
|
|
164
250
|
end
|
|
165
251
|
end
|
|
252
|
+
|
|
253
|
+
# Set the mssql_unicode_strings settings from the given options.
|
|
254
|
+
def set_mssql_unicode_strings
|
|
255
|
+
@mssql_unicode_strings = typecast_value_boolean(@opts.fetch(:mssql_unicode_strings, true))
|
|
256
|
+
end
|
|
166
257
|
|
|
167
258
|
# MSSQL has both datetime and timestamp classes, most people are going
|
|
168
259
|
# to want datetime
|
|
@@ -189,49 +280,103 @@ module Sequel
|
|
|
189
280
|
# support for clustered index type
|
|
190
281
|
def index_definition_sql(table_name, index)
|
|
191
282
|
index_name = index[:name] || default_index_name(table_name, index[:columns])
|
|
192
|
-
|
|
193
|
-
if index[:
|
|
194
|
-
|
|
283
|
+
raise Error, "Partial indexes are not supported for this database" if index[:where]
|
|
284
|
+
if index[:type] == :full_text
|
|
285
|
+
"CREATE FULLTEXT INDEX ON #{quote_schema_table(table_name)} #{literal(index[:columns])} KEY INDEX #{literal(index[:key_index])}"
|
|
195
286
|
else
|
|
196
|
-
"CREATE #{'UNIQUE ' if index[:unique]}#{'CLUSTERED ' if clustered}INDEX #{quote_identifier(index_name)} ON #{quote_schema_table(table_name)} #{literal(index[:columns])}"
|
|
287
|
+
"CREATE #{'UNIQUE ' if index[:unique]}#{'CLUSTERED ' if index[:type] == :clustered}INDEX #{quote_identifier(index_name)} ON #{quote_schema_table(table_name)} #{literal(index[:columns])}#{" INCLUDE #{literal(index[:include])}" if index[:include]}"
|
|
197
288
|
end
|
|
198
289
|
end
|
|
199
290
|
end
|
|
200
291
|
|
|
201
292
|
module DatasetMethods
|
|
293
|
+
include EmulateOffsetWithRowNumber
|
|
294
|
+
|
|
202
295
|
BOOL_TRUE = '1'.freeze
|
|
203
296
|
BOOL_FALSE = '0'.freeze
|
|
204
297
|
COMMA_SEPARATOR = ', '.freeze
|
|
205
|
-
DELETE_CLAUSE_METHODS = Dataset.clause_methods(:delete, %w'with from output from2 where')
|
|
206
|
-
INSERT_CLAUSE_METHODS = Dataset.clause_methods(:insert, %w'with into columns output values')
|
|
207
|
-
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'with distinct limit columns into from lock join where group having order compounds')
|
|
208
|
-
UPDATE_CLAUSE_METHODS = Dataset.clause_methods(:update, %w'with table set output from where')
|
|
298
|
+
DELETE_CLAUSE_METHODS = Dataset.clause_methods(:delete, %w'with delete from output from2 where')
|
|
299
|
+
INSERT_CLAUSE_METHODS = Dataset.clause_methods(:insert, %w'with insert into columns output values')
|
|
300
|
+
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'with select distinct limit columns into from lock join where group having order compounds')
|
|
301
|
+
UPDATE_CLAUSE_METHODS = Dataset.clause_methods(:update, %w'with update table set output from where')
|
|
209
302
|
NOLOCK = ' WITH (NOLOCK)'.freeze
|
|
210
303
|
UPDLOCK = ' WITH (UPDLOCK)'.freeze
|
|
211
304
|
WILDCARD = LiteralString.new('*').freeze
|
|
212
305
|
CONSTANT_MAP = {:CURRENT_DATE=>'CAST(CURRENT_TIMESTAMP AS DATE)'.freeze, :CURRENT_TIME=>'CAST(CURRENT_TIMESTAMP AS TIME)'.freeze}
|
|
306
|
+
EXTRACT_MAP = {:year=>"yy", :month=>"m", :day=>"d", :hour=>"hh", :minute=>"n", :second=>"s"}
|
|
307
|
+
BRACKET_CLOSE = Dataset::BRACKET_CLOSE
|
|
308
|
+
BRACKET_OPEN = Dataset::BRACKET_OPEN
|
|
309
|
+
COMMA = Dataset::COMMA
|
|
310
|
+
PAREN_CLOSE = Dataset::PAREN_CLOSE
|
|
311
|
+
PAREN_SPACE_OPEN = Dataset::PAREN_SPACE_OPEN
|
|
312
|
+
SPACE = Dataset::SPACE
|
|
313
|
+
FROM = Dataset::FROM
|
|
314
|
+
APOS = Dataset::APOS
|
|
315
|
+
APOS_RE = Dataset::APOS_RE
|
|
316
|
+
DOUBLE_APOS = Dataset::DOUBLE_APOS
|
|
317
|
+
INTO = Dataset::INTO
|
|
318
|
+
DATEPART_SECOND_OPEN = "CAST((datepart(".freeze
|
|
319
|
+
DATEPART_SECOND_MIDDLE = ') + datepart(ns, '.freeze
|
|
320
|
+
DATEPART_SECOND_CLOSE = ")/1000000000.0) AS double precision)".freeze
|
|
321
|
+
DATEPART_OPEN = "datepart(".freeze
|
|
322
|
+
UNION_ALL = ' UNION ALL '.freeze
|
|
323
|
+
SELECT_SPACE = 'SELECT '.freeze
|
|
324
|
+
TIMESTAMP_USEC_FORMAT = ".%03d".freeze
|
|
325
|
+
OUTPUT_INSERTED = " OUTPUT INSERTED.*".freeze
|
|
326
|
+
HEX_START = '0x'.freeze
|
|
327
|
+
UNICODE_STRING_START = "N'".freeze
|
|
328
|
+
TOP_PAREN = " TOP (".freeze
|
|
329
|
+
TOP = " TOP ".freeze
|
|
330
|
+
OUTPUT = " OUTPUT ".freeze
|
|
331
|
+
HSTAR = "H*".freeze
|
|
332
|
+
CASE_SENSITIVE_COLLATION = 'Latin1_General_CS_AS'.freeze
|
|
333
|
+
CASE_INSENSITIVE_COLLATION = 'Latin1_General_CI_AS'.freeze
|
|
334
|
+
|
|
335
|
+
# Allow overriding of the mssql_unicode_strings option at the dataset level.
|
|
336
|
+
attr_accessor :mssql_unicode_strings
|
|
337
|
+
|
|
338
|
+
# Copy the mssql_unicode_strings option from the +db+ object.
|
|
339
|
+
def initialize(db, opts={})
|
|
340
|
+
super
|
|
341
|
+
@mssql_unicode_strings = db.mssql_unicode_strings
|
|
342
|
+
end
|
|
213
343
|
|
|
214
344
|
# MSSQL uses + for string concatenation, and LIKE is case insensitive by default.
|
|
215
|
-
def
|
|
345
|
+
def complex_expression_sql_append(sql, op, args)
|
|
216
346
|
case op
|
|
217
347
|
when :'||'
|
|
218
|
-
super(:+, args)
|
|
219
|
-
when :
|
|
220
|
-
super(
|
|
221
|
-
when :"NOT ILIKE"
|
|
222
|
-
super(:"NOT LIKE", args)
|
|
348
|
+
super(sql, :+, args)
|
|
349
|
+
when :LIKE, :"NOT LIKE"
|
|
350
|
+
super(sql, op, args.map{|a| LiteralString.new("(#{literal(a)} COLLATE #{CASE_SENSITIVE_COLLATION})")})
|
|
351
|
+
when :ILIKE, :"NOT ILIKE"
|
|
352
|
+
super(sql, (op == :ILIKE ? :LIKE : :"NOT LIKE"), args.map{|a| LiteralString.new("(#{literal(a)} COLLATE #{CASE_INSENSITIVE_COLLATION})")})
|
|
223
353
|
when :<<
|
|
224
|
-
"(#{literal(
|
|
354
|
+
sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} * POWER(2, #{literal(b)}))"}
|
|
225
355
|
when :>>
|
|
226
|
-
"(#{literal(
|
|
356
|
+
sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} / POWER(2, #{literal(b)}))"}
|
|
357
|
+
when :extract
|
|
358
|
+
part = args.at(0)
|
|
359
|
+
raise(Sequel::Error, "unsupported extract argument: #{part.inspect}") unless format = EXTRACT_MAP[part]
|
|
360
|
+
if part == :second
|
|
361
|
+
expr = literal(args.at(1))
|
|
362
|
+
sql << DATEPART_SECOND_OPEN << format.to_s << COMMA << expr << DATEPART_SECOND_MIDDLE << expr << DATEPART_SECOND_CLOSE
|
|
363
|
+
else
|
|
364
|
+
sql << DATEPART_OPEN << format.to_s << COMMA
|
|
365
|
+
literal_append(sql, args.at(1))
|
|
366
|
+
sql << PAREN_CLOSE
|
|
367
|
+
end
|
|
227
368
|
else
|
|
228
|
-
super
|
|
369
|
+
super
|
|
229
370
|
end
|
|
230
371
|
end
|
|
231
372
|
|
|
232
373
|
# MSSQL doesn't support the SQL standard CURRENT_DATE or CURRENT_TIME
|
|
233
|
-
def
|
|
234
|
-
CONSTANT_MAP[constant]
|
|
374
|
+
def constant_sql_append(sql, constant)
|
|
375
|
+
if c = CONSTANT_MAP[constant]
|
|
376
|
+
sql << c
|
|
377
|
+
else
|
|
378
|
+
super
|
|
379
|
+
end
|
|
235
380
|
end
|
|
236
381
|
|
|
237
382
|
# Disable the use of INSERT OUTPUT
|
|
@@ -244,21 +389,16 @@ module Sequel
|
|
|
244
389
|
mutation_method(:disable_insert_output)
|
|
245
390
|
end
|
|
246
391
|
|
|
247
|
-
# When returning all rows, if an offset is used, delete the row_number column
|
|
248
|
-
# before yielding the row.
|
|
249
|
-
def fetch_rows(sql, &block)
|
|
250
|
-
@opts[:offset] ? super(sql){|r| r.delete(row_number_column); yield r} : super(sql, &block)
|
|
251
|
-
end
|
|
252
|
-
|
|
253
392
|
# MSSQL uses the CONTAINS keyword for full text search
|
|
254
393
|
def full_text_search(cols, terms, opts = {})
|
|
255
|
-
|
|
394
|
+
terms = "\"#{terms.join('" OR "')}\"" if terms.is_a?(Array)
|
|
395
|
+
filter("CONTAINS (?, ?)", cols, terms)
|
|
256
396
|
end
|
|
257
397
|
|
|
258
398
|
# Use the OUTPUT clause to get the value of all columns for the newly inserted record.
|
|
259
399
|
def insert_select(*values)
|
|
260
|
-
return unless
|
|
261
|
-
naked.clone(default_server_opts(:sql=>output(nil, [:inserted
|
|
400
|
+
return unless supports_insert_select?
|
|
401
|
+
naked.clone(default_server_opts(:sql=>output(nil, [SQL::ColumnAll.new(:inserted)]).insert_sql(*values))).single_record
|
|
262
402
|
end
|
|
263
403
|
|
|
264
404
|
# Specify a table for a SELECT ... INTO query.
|
|
@@ -266,17 +406,18 @@ module Sequel
|
|
|
266
406
|
clone(:into => table)
|
|
267
407
|
end
|
|
268
408
|
|
|
269
|
-
# SQL Server does not support CTEs on subqueries, so move any CTEs
|
|
270
|
-
# on joined datasets to the top level. The user is responsible for
|
|
271
|
-
# resolving any name clashes this may cause.
|
|
272
|
-
def join_table(type, table, expr=nil, table_alias={}, &block)
|
|
273
|
-
return super unless Dataset === table && table.opts[:with]
|
|
274
|
-
clone(:with => (opts[:with] || []) + table.opts[:with]).join_table(type, table.clone(:with => nil), expr, table_alias, &block)
|
|
275
|
-
end
|
|
276
|
-
|
|
277
409
|
# MSSQL uses a UNION ALL statement to insert multiple values at once.
|
|
278
410
|
def multi_insert_sql(columns, values)
|
|
279
|
-
|
|
411
|
+
c = false
|
|
412
|
+
sql = LiteralString.new('')
|
|
413
|
+
u = UNION_ALL
|
|
414
|
+
values.each do |v|
|
|
415
|
+
sql << u if c
|
|
416
|
+
sql << SELECT_SPACE
|
|
417
|
+
expression_list_append(sql, v)
|
|
418
|
+
c ||= true
|
|
419
|
+
end
|
|
420
|
+
[insert_sql(columns, sql)]
|
|
280
421
|
end
|
|
281
422
|
|
|
282
423
|
# Allows you to do a dirty read of uncommitted data using WITH (NOLOCK).
|
|
@@ -315,38 +456,30 @@ module Sequel
|
|
|
315
456
|
end
|
|
316
457
|
|
|
317
458
|
# MSSQL uses [] to quote identifiers
|
|
318
|
-
def
|
|
319
|
-
|
|
459
|
+
def quoted_identifier_append(sql, name)
|
|
460
|
+
sql << BRACKET_OPEN << name.to_s << BRACKET_CLOSE
|
|
320
461
|
end
|
|
321
462
|
|
|
322
|
-
# MSSQL Requires the use of the ROW_NUMBER window function to emulate
|
|
323
|
-
# an offset. This implementation requires MSSQL 2005 or greater (offset
|
|
324
|
-
# can't be emulated well in MSSQL 2000).
|
|
325
|
-
#
|
|
326
|
-
# The implementation is ugly, cloning the current dataset and modifying
|
|
327
|
-
# the clone to add a ROW_NUMBER window function (and some other things),
|
|
328
|
-
# then using the modified clone in a subselect which is selected from.
|
|
329
|
-
#
|
|
330
|
-
# If offset is used, an order must be provided, because the use of ROW_NUMBER
|
|
331
|
-
# requires an order.
|
|
332
|
-
def select_sql
|
|
333
|
-
return super unless o = @opts[:offset]
|
|
334
|
-
raise(Error, 'MSSQL requires an order be provided if using an offset') unless order = @opts[:order]
|
|
335
|
-
dsa1 = dataset_alias(1)
|
|
336
|
-
rn = row_number_column
|
|
337
|
-
subselect_sql(unlimited.
|
|
338
|
-
unordered.
|
|
339
|
-
select_append{ROW_NUMBER(:over, :order=>order){}.as(rn)}.
|
|
340
|
-
from_self(:alias=>dsa1).
|
|
341
|
-
limit(@opts[:limit]).
|
|
342
|
-
where(SQL::Identifier.new(rn) > o))
|
|
343
|
-
end
|
|
344
|
-
|
|
345
463
|
# The version of the database server.
|
|
346
464
|
def server_version
|
|
347
465
|
db.server_version(@opts[:server])
|
|
348
466
|
end
|
|
349
467
|
|
|
468
|
+
# MSSQL 2005+ supports GROUP BY CUBE.
|
|
469
|
+
def supports_group_cube?
|
|
470
|
+
is_2005_or_later?
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
# MSSQL 2005+ supports GROUP BY ROLLUP
|
|
474
|
+
def supports_group_rollup?
|
|
475
|
+
is_2005_or_later?
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
# MSSQL supports insert_select via the OUTPUT clause.
|
|
479
|
+
def supports_insert_select?
|
|
480
|
+
supports_output_clause? && !opts[:disable_insert_output]
|
|
481
|
+
end
|
|
482
|
+
|
|
350
483
|
# MSSQL 2005+ supports INTERSECT and EXCEPT
|
|
351
484
|
def supports_intersect_except?
|
|
352
485
|
is_2005_or_later?
|
|
@@ -381,14 +514,38 @@ module Sequel
|
|
|
381
514
|
def supports_window_functions?
|
|
382
515
|
true
|
|
383
516
|
end
|
|
517
|
+
|
|
518
|
+
# MSSQL cannot use WHERE 1.
|
|
519
|
+
def supports_where_true?
|
|
520
|
+
false
|
|
521
|
+
end
|
|
384
522
|
|
|
385
523
|
protected
|
|
524
|
+
|
|
525
|
+
# If returned primary keys are requested, use OUTPUT unless already set on the
|
|
526
|
+
# dataset. If OUTPUT is already set, use existing returning values. If OUTPUT
|
|
527
|
+
# is only set to return a single columns, return an array of just that column.
|
|
528
|
+
# Otherwise, return an array of hashes.
|
|
529
|
+
def _import(columns, values, opts={})
|
|
530
|
+
if opts[:return] == :primary_key && !@opts[:output]
|
|
531
|
+
output(nil, [SQL::QualifiedIdentifier.new(:inserted, first_primary_key)])._import(columns, values, opts)
|
|
532
|
+
elsif @opts[:output]
|
|
533
|
+
statements = multi_insert_sql(columns, values)
|
|
534
|
+
@db.transaction(opts.merge(:server=>@opts[:server])) do
|
|
535
|
+
statements.map{|st| with_sql(st)}
|
|
536
|
+
end.first.map{|v| v.length == 1 ? v.values.first : v}
|
|
537
|
+
else
|
|
538
|
+
super
|
|
539
|
+
end
|
|
540
|
+
end
|
|
541
|
+
|
|
386
542
|
# MSSQL does not allow ordering in sub-clauses unless 'top' (limit) is specified
|
|
387
543
|
def aggregate_dataset
|
|
388
544
|
(options_overlap(Sequel::Dataset::COUNT_FROM_SELF_OPTS) && !options_overlap([:limit])) ? unordered.from_self : super
|
|
389
545
|
end
|
|
390
546
|
|
|
391
547
|
private
|
|
548
|
+
|
|
392
549
|
def is_2005_or_later?
|
|
393
550
|
server_version >= 9000000
|
|
394
551
|
end
|
|
@@ -401,7 +558,8 @@ module Sequel
|
|
|
401
558
|
|
|
402
559
|
# Only include the primary table in the main delete clause
|
|
403
560
|
def delete_from_sql(sql)
|
|
404
|
-
sql <<
|
|
561
|
+
sql << FROM
|
|
562
|
+
source_list_append(sql, @opts[:from][0..0])
|
|
405
563
|
end
|
|
406
564
|
|
|
407
565
|
# MSSQL supports FROM clauses in DELETE and UPDATE statements.
|
|
@@ -413,19 +571,17 @@ module Sequel
|
|
|
413
571
|
end
|
|
414
572
|
alias update_from_sql delete_from2_sql
|
|
415
573
|
|
|
416
|
-
#
|
|
417
|
-
#
|
|
418
|
-
def
|
|
419
|
-
|
|
574
|
+
# Return the first primary key for the current table. If this table has
|
|
575
|
+
# multiple primary keys, this will only return one of them. Used by #_import.
|
|
576
|
+
def first_primary_key
|
|
577
|
+
@db.schema(self).map{|k, v| k if v[:primary_key] == true}.compact.first
|
|
420
578
|
end
|
|
421
|
-
|
|
422
|
-
alias update_with_sql delete_with_sql
|
|
423
|
-
|
|
579
|
+
|
|
424
580
|
# MSSQL raises an error if you try to provide more than 3 decimal places
|
|
425
581
|
# for a fractional timestamp. This probably doesn't work for smalldatetime
|
|
426
582
|
# fields.
|
|
427
583
|
def format_timestamp_usec(usec)
|
|
428
|
-
sprintf(
|
|
584
|
+
sprintf(TIMESTAMP_USEC_FORMAT, usec/1000)
|
|
429
585
|
end
|
|
430
586
|
|
|
431
587
|
# MSSQL supports the OUTPUT clause for INSERT statements.
|
|
@@ -434,16 +590,26 @@ module Sequel
|
|
|
434
590
|
INSERT_CLAUSE_METHODS
|
|
435
591
|
end
|
|
436
592
|
|
|
593
|
+
# Use OUTPUT INSERTED.* to return all columns of the inserted row,
|
|
594
|
+
# for use with the prepared statement code.
|
|
595
|
+
def insert_output_sql(sql)
|
|
596
|
+
if @opts.has_key?(:returning)
|
|
597
|
+
sql << OUTPUT_INSERTED
|
|
598
|
+
else
|
|
599
|
+
output_sql(sql)
|
|
600
|
+
end
|
|
601
|
+
end
|
|
602
|
+
|
|
437
603
|
# MSSQL uses a literal hexidecimal number for blob strings
|
|
438
|
-
def
|
|
439
|
-
|
|
440
|
-
v.each_byte{|x| blob << sprintf('%02x', x)}
|
|
441
|
-
blob
|
|
604
|
+
def literal_blob_append(sql, v)
|
|
605
|
+
sql << HEX_START << v.unpack(HSTAR).first
|
|
442
606
|
end
|
|
443
607
|
|
|
444
|
-
#
|
|
445
|
-
|
|
446
|
-
|
|
608
|
+
# Optionally use unicode string syntax for all strings. Don't double
|
|
609
|
+
# backslashes.
|
|
610
|
+
def literal_string_append(sql, v)
|
|
611
|
+
sql << (mssql_unicode_strings ? UNICODE_STRING_START : APOS)
|
|
612
|
+
sql << v.gsub(APOS_RE, DOUBLE_APOS) << APOS
|
|
447
613
|
end
|
|
448
614
|
|
|
449
615
|
# Use 0 for false on MSSQL
|
|
@@ -456,27 +622,30 @@ module Sequel
|
|
|
456
622
|
BOOL_TRUE
|
|
457
623
|
end
|
|
458
624
|
|
|
459
|
-
# The alias to use for the row_number column when emulating OFFSET
|
|
460
|
-
def row_number_column
|
|
461
|
-
:x_sequel_row_number_x
|
|
462
|
-
end
|
|
463
|
-
|
|
464
625
|
# MSSQL adds the limit before the columns
|
|
465
626
|
def select_clause_methods
|
|
466
627
|
SELECT_CLAUSE_METHODS
|
|
467
628
|
end
|
|
468
629
|
|
|
469
630
|
def select_into_sql(sql)
|
|
470
|
-
|
|
631
|
+
if i = @opts[:into]
|
|
632
|
+
sql << INTO
|
|
633
|
+
table_ref_append(sql, i)
|
|
634
|
+
end
|
|
471
635
|
end
|
|
472
636
|
|
|
473
637
|
# MSSQL uses TOP N for limit. For MSSQL 2005+ TOP (N) is used
|
|
474
638
|
# to allow the limit to be a bound variable.
|
|
475
639
|
def select_limit_sql(sql)
|
|
476
640
|
if l = @opts[:limit]
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
641
|
+
if is_2005_or_later?
|
|
642
|
+
sql << TOP_PAREN
|
|
643
|
+
literal_append(sql, l)
|
|
644
|
+
sql << PAREN_CLOSE
|
|
645
|
+
else
|
|
646
|
+
sql << TOP
|
|
647
|
+
literal_append(sql, l)
|
|
648
|
+
end
|
|
480
649
|
end
|
|
481
650
|
end
|
|
482
651
|
|
|
@@ -496,19 +665,20 @@ module Sequel
|
|
|
496
665
|
def output_sql(sql)
|
|
497
666
|
return unless supports_output_clause?
|
|
498
667
|
return unless output = @opts[:output]
|
|
499
|
-
sql <<
|
|
668
|
+
sql << OUTPUT
|
|
669
|
+
column_list_append(sql, output[:select_list])
|
|
500
670
|
if into = output[:into]
|
|
501
|
-
sql <<
|
|
671
|
+
sql << INTO
|
|
672
|
+
table_ref_append(sql, into)
|
|
502
673
|
if column_list = output[:column_list]
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
sql <<
|
|
674
|
+
sql << PAREN_SPACE_OPEN
|
|
675
|
+
source_list_append(sql, column_list)
|
|
676
|
+
sql << PAREN_CLOSE
|
|
506
677
|
end
|
|
507
678
|
end
|
|
508
679
|
end
|
|
509
680
|
alias delete_output_sql output_sql
|
|
510
681
|
alias update_output_sql output_sql
|
|
511
|
-
alias insert_output_sql output_sql
|
|
512
682
|
|
|
513
683
|
# MSSQL supports the OUTPUT clause for UPDATE statements.
|
|
514
684
|
# It also allows prepending a WITH clause.
|
|
@@ -518,7 +688,8 @@ module Sequel
|
|
|
518
688
|
|
|
519
689
|
# Only include the primary table in the main update clause
|
|
520
690
|
def update_table_sql(sql)
|
|
521
|
-
sql <<
|
|
691
|
+
sql << SPACE
|
|
692
|
+
source_list_append(sql, @opts[:from][0..0])
|
|
522
693
|
end
|
|
523
694
|
end
|
|
524
695
|
end
|