sequel 3.21.0 → 3.36.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 +855 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +23 -7
- data/Rakefile +42 -24
- data/bin/sequel +26 -8
- data/doc/active_record.rdoc +1 -0
- data/doc/advanced_associations.rdoc +171 -11
- data/doc/association_basics.rdoc +293 -43
- data/doc/dataset_basics.rdoc +5 -5
- data/doc/dataset_filtering.rdoc +8 -0
- data/doc/mass_assignment.rdoc +56 -0
- data/doc/migration.rdoc +85 -552
- data/doc/model_hooks.rdoc +78 -27
- data/doc/object_model.rdoc +541 -0
- data/doc/opening_databases.rdoc +97 -50
- data/doc/prepared_statements.rdoc +40 -14
- data/doc/querying.rdoc +28 -4
- data/doc/reflection.rdoc +30 -4
- 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/release_notes/3.33.0.txt +157 -0
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/release_notes/3.35.0.txt +144 -0
- data/doc/release_notes/3.36.0.txt +245 -0
- data/doc/schema_modification.rdoc +572 -0
- data/doc/sharding.rdoc +95 -3
- data/doc/testing.rdoc +129 -0
- data/doc/thread_safety.rdoc +17 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +51 -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 +17 -11
- data/lib/sequel/adapters/do/postgres.rb +1 -57
- data/lib/sequel/adapters/do/sqlite.rb +0 -10
- data/lib/sequel/adapters/do.rb +18 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +453 -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 +47 -0
- data/lib/sequel/adapters/jdbc/derby.rb +287 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
- data/lib/sequel/adapters/jdbc/h2.rb +73 -31
- data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
- data/lib/sequel/adapters/jdbc/informix.rb +21 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
- data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +58 -48
- data/lib/sequel/adapters/jdbc/progress.rb +21 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
- data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +265 -94
- data/lib/sequel/adapters/mock.rb +361 -0
- data/lib/sequel/adapters/mysql.rb +118 -222
- data/lib/sequel/adapters/mysql2.rb +58 -57
- data/lib/sequel/adapters/odbc/mssql.rb +15 -7
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +3 -5
- data/lib/sequel/adapters/oracle.rb +349 -53
- data/lib/sequel/adapters/postgres.rb +356 -107
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +342 -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 +335 -118
- data/lib/sequel/adapters/shared/mysql.rb +340 -76
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
- data/lib/sequel/adapters/shared/oracle.rb +243 -45
- data/lib/sequel/adapters/shared/postgres.rb +524 -279
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +265 -89
- data/lib/sequel/adapters/sqlite.rb +101 -39
- data/lib/sequel/adapters/swift/mysql.rb +9 -12
- data/lib/sequel/adapters/swift/postgres.rb +9 -74
- data/lib/sequel/adapters/swift/sqlite.rb +8 -6
- data/lib/sequel/adapters/swift.rb +8 -7
- data/lib/sequel/adapters/tinytds.rb +161 -21
- 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 +194 -0
- data/lib/sequel/connection_pool/sharded_single.rb +11 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +28 -2
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +38 -14
- data/lib/sequel/connection_pool.rb +10 -2
- data/lib/sequel/core.rb +118 -11
- data/lib/sequel/database/connecting.rb +38 -28
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +63 -2
- data/lib/sequel/database/logging.rb +7 -2
- data/lib/sequel/database/misc.rb +150 -46
- data/lib/sequel/database/query.rb +215 -65
- data/lib/sequel/database/schema_generator.rb +64 -20
- data/lib/sequel/database/schema_methods.rb +212 -54
- data/lib/sequel/dataset/actions.rb +322 -85
- data/lib/sequel/dataset/features.rb +96 -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 +68 -30
- data/lib/sequel/dataset/query.rb +237 -44
- data/lib/sequel/dataset/sql.rb +698 -278
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/_pretty_table.rb +79 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +108 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +16 -34
- data/lib/sequel/extensions/migration.rb +97 -11
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/null_dataset.rb +90 -0
- data/lib/sequel/extensions/pg_array.rb +460 -0
- data/lib/sequel/extensions/pg_array_ops.rb +220 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +169 -0
- data/lib/sequel/extensions/pg_hstore.rb +296 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
- data/lib/sequel/extensions/pg_inet.rb +89 -0
- data/lib/sequel/extensions/pg_json.rb +178 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
- data/lib/sequel/extensions/pretty_table.rb +5 -71
- data/lib/sequel/extensions/query.rb +1 -1
- data/lib/sequel/extensions/query_literals.rb +79 -0
- data/lib/sequel/extensions/schema_caching.rb +76 -0
- data/lib/sequel/extensions/schema_dumper.rb +251 -37
- data/lib/sequel/extensions/select_remove.rb +35 -0
- data/lib/sequel/extensions/server_block.rb +139 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -110
- 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 +1187 -393
- data/lib/sequel/model/base.rb +578 -170
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model.rb +30 -11
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/active_model.rb +13 -1
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/composition.rb +44 -12
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/dirty.rb +214 -0
- data/lib/sequel/plugins/eager_each.rb +59 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +123 -8
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/instance_hooks.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +58 -6
- data/lib/sequel/plugins/list.rb +12 -2
- data/lib/sequel/plugins/many_through_many.rb +79 -28
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +139 -63
- data/lib/sequel/plugins/optimistic_locking.rb +8 -0
- data/lib/sequel/plugins/prepared_statements.rb +167 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +87 -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/schema.rb +7 -2
- 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 +5 -3
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/subclasses.rb +10 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
- data/lib/sequel/plugins/timestamps.rb +1 -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/validation_class_methods.rb +1 -1
- data/lib/sequel/plugins/xml_serializer.rb +15 -4
- data/lib/sequel/sql.rb +526 -59
- 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/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +142 -40
- data/spec/adapters/mysql_spec.rb +380 -234
- data/spec/adapters/oracle_spec.rb +67 -77
- data/spec/adapters/postgres_spec.rb +1050 -212
- data/spec/adapters/spec_helper.rb +8 -5
- data/spec/adapters/sqlite_spec.rb +139 -27
- data/spec/core/connection_pool_spec.rb +196 -93
- data/spec/core/database_spec.rb +879 -510
- data/spec/core/dataset_spec.rb +1415 -1086
- data/spec/core/expression_filters_spec.rb +554 -109
- data/spec/core/mock_adapter_spec.rb +449 -0
- data/spec/core/object_graph_spec.rb +86 -114
- data/spec/core/schema_generator_spec.rb +4 -4
- data/spec/core/schema_spec.rb +482 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/active_model_spec.rb +13 -0
- data/spec/extensions/arbitrary_servers_spec.rb +110 -0
- data/spec/extensions/association_autoreloading_spec.rb +18 -10
- data/spec/extensions/association_dependencies_spec.rb +15 -25
- data/spec/extensions/association_pks_spec.rb +66 -32
- data/spec/extensions/association_proxies_spec.rb +4 -4
- data/spec/extensions/caching_spec.rb +47 -51
- 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/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +119 -139
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/dirty_spec.rb +155 -0
- data/spec/extensions/eager_each_spec.rb +34 -0
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +69 -92
- data/spec/extensions/identity_map_spec.rb +131 -22
- data/spec/extensions/inflector_spec.rb +0 -4
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +72 -0
- data/spec/extensions/json_serializer_spec.rb +49 -6
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +48 -39
- data/spec/extensions/many_through_many_spec.rb +283 -250
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +140 -35
- data/spec/extensions/named_timezones_spec.rb +29 -11
- data/spec/extensions/nested_attributes_spec.rb +251 -89
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +24 -21
- data/spec/extensions/pg_array_ops_spec.rb +105 -0
- data/spec/extensions/pg_array_spec.rb +196 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
- data/spec/extensions/pg_hstore_spec.rb +195 -0
- data/spec/extensions/pg_inet_spec.rb +44 -0
- data/spec/extensions/pg_json_spec.rb +101 -0
- data/spec/extensions/pg_statement_cache_spec.rb +209 -0
- 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 +87 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +7 -6
- data/spec/extensions/query_literals_spec.rb +168 -0
- data/spec/extensions/query_spec.rb +6 -0
- data/spec/extensions/rcte_tree_spec.rb +50 -43
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +429 -22
- data/spec/extensions/schema_spec.rb +25 -21
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
- data/spec/extensions/serialization_spec.rb +85 -43
- data/spec/extensions/server_block_spec.rb +90 -0
- data/spec/extensions/sharding_spec.rb +69 -143
- data/spec/extensions/single_table_inheritance_spec.rb +23 -29
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +22 -61
- data/spec/extensions/sql_expr_spec.rb +29 -60
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +17 -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 +9 -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 +29 -4
- data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
- data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
- data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
- data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
- data/spec/integration/associations_test.rb +659 -21
- data/spec/integration/database_test.rb +9 -3
- data/spec/integration/dataset_test.rb +605 -91
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +81 -2
- data/spec/integration/plugin_test.rb +454 -143
- data/spec/integration/prepared_statement_test.rb +263 -128
- data/spec/integration/schema_test.rb +309 -43
- data/spec/integration/spec_helper.rb +40 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +183 -8
- data/spec/integration/type_test.rb +18 -4
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +1067 -661
- data/spec/model/base_spec.rb +329 -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 +240 -168
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +490 -232
- data/spec/model/spec_helper.rb +14 -71
- data/spec/model/validations_spec.rb +11 -0
- data/spec/rcov.opts +2 -0
- metadata +178 -80
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
module Sequel
|
|
2
2
|
Dataset::NON_SQL_OPTIONS << :insert_ignore
|
|
3
|
+
Dataset::NON_SQL_OPTIONS << :update_ignore
|
|
3
4
|
Dataset::NON_SQL_OPTIONS << :on_duplicate_key_update
|
|
4
5
|
|
|
5
6
|
module MySQL
|
|
@@ -30,7 +31,7 @@ module Sequel
|
|
|
30
31
|
module DatabaseMethods
|
|
31
32
|
AUTO_INCREMENT = 'AUTO_INCREMENT'.freeze
|
|
32
33
|
CAST_TYPES = {String=>:CHAR, Integer=>:SIGNED, Time=>:DATETIME, DateTime=>:DATETIME, Numeric=>:DECIMAL, BigDecimal=>:DECIMAL, File=>:BINARY}
|
|
33
|
-
COLUMN_DEFINITION_ORDER = [:null, :default, :unique, :primary_key, :auto_increment, :references]
|
|
34
|
+
COLUMN_DEFINITION_ORDER = [:collate, :null, :default, :unique, :primary_key, :auto_increment, :references]
|
|
34
35
|
PRIMARY = 'PRIMARY'.freeze
|
|
35
36
|
|
|
36
37
|
# MySQL's cast rules are restrictive in that you can't just cast to any possible
|
|
@@ -50,6 +51,36 @@ module Sequel
|
|
|
50
51
|
:mysql
|
|
51
52
|
end
|
|
52
53
|
|
|
54
|
+
# Use the Information Schema's KEY_COLUMN_USAGE table to get
|
|
55
|
+
# basic information on foreign key columns, but include the
|
|
56
|
+
# constraint name.
|
|
57
|
+
def foreign_key_list(table, opts={})
|
|
58
|
+
m = output_identifier_meth
|
|
59
|
+
im = input_identifier_meth
|
|
60
|
+
ds = metadata_dataset.
|
|
61
|
+
from(:INFORMATION_SCHEMA__KEY_COLUMN_USAGE).
|
|
62
|
+
where(:TABLE_NAME=>im.call(table)).
|
|
63
|
+
exclude(:CONSTRAINT_NAME=>'PRIMARY').
|
|
64
|
+
exclude(:REFERENCED_TABLE_NAME=>nil).
|
|
65
|
+
select(:CONSTRAINT_NAME___name, :COLUMN_NAME___column, :REFERENCED_TABLE_NAME___table, :REFERENCED_COLUMN_NAME___key)
|
|
66
|
+
|
|
67
|
+
h = {}
|
|
68
|
+
ds.each do |row|
|
|
69
|
+
if r = h[row[:name]]
|
|
70
|
+
r[:columns] << m.call(row[:column])
|
|
71
|
+
r[:key] << m.call(row[:key])
|
|
72
|
+
else
|
|
73
|
+
h[row[:name]] = {:name=>m.call(row[:name]), :columns=>[m.call(row[:column])], :table=>m.call(row[:table]), :key=>[m.call(row[:key])]}
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
h.values
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# MySQL namespaces indexes per table.
|
|
80
|
+
def global_index_namespace?
|
|
81
|
+
false
|
|
82
|
+
end
|
|
83
|
+
|
|
53
84
|
# Use SHOW INDEX FROM to get the index information for the
|
|
54
85
|
# table.
|
|
55
86
|
#
|
|
@@ -83,23 +114,25 @@ module Sequel
|
|
|
83
114
|
@server_version ||= (m[1].to_i * 10000) + (m[2].to_i * 100) + m[3].to_i
|
|
84
115
|
end
|
|
85
116
|
|
|
86
|
-
#
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
# * :server - Set the server to use
|
|
90
|
-
def tables(opts={})
|
|
91
|
-
m = output_identifier_meth
|
|
92
|
-
metadata_dataset.with_sql('SHOW TABLES').server(opts[:server]).map{|r| m.call(r.values.first)}
|
|
117
|
+
# MySQL supports CREATE TABLE IF NOT EXISTS syntax.
|
|
118
|
+
def supports_create_table_if_not_exists?
|
|
119
|
+
true
|
|
93
120
|
end
|
|
94
121
|
|
|
95
122
|
# MySQL supports prepared transactions (two-phase commit) using XA
|
|
96
123
|
def supports_prepared_transactions?
|
|
97
|
-
|
|
124
|
+
server_version >= 50000
|
|
98
125
|
end
|
|
99
126
|
|
|
100
127
|
# MySQL supports savepoints
|
|
101
128
|
def supports_savepoints?
|
|
102
|
-
|
|
129
|
+
server_version >= 50000
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# MySQL doesn't support savepoints inside prepared transactions in from
|
|
133
|
+
# 5.5.12 to 5.5.23, see http://bugs.mysql.com/bug.php?id=64374
|
|
134
|
+
def supports_savepoints_in_prepared_transactions?
|
|
135
|
+
super && (server_version <= 50512 || server_version >= 50523)
|
|
103
136
|
end
|
|
104
137
|
|
|
105
138
|
# MySQL supports transaction isolation levels
|
|
@@ -107,6 +140,14 @@ module Sequel
|
|
|
107
140
|
true
|
|
108
141
|
end
|
|
109
142
|
|
|
143
|
+
# Return an array of symbols specifying table names in the current database.
|
|
144
|
+
#
|
|
145
|
+
# Options:
|
|
146
|
+
# * :server - Set the server to use
|
|
147
|
+
def tables(opts={})
|
|
148
|
+
full_tables('BASE TABLE', opts)
|
|
149
|
+
end
|
|
150
|
+
|
|
110
151
|
# Changes the database in use by issuing a USE statement. I would be
|
|
111
152
|
# very careful if I used this.
|
|
112
153
|
def use(db_name)
|
|
@@ -116,6 +157,14 @@ module Sequel
|
|
|
116
157
|
self
|
|
117
158
|
end
|
|
118
159
|
|
|
160
|
+
# Return an array of symbols specifying view names in the current database.
|
|
161
|
+
#
|
|
162
|
+
# Options:
|
|
163
|
+
# * :server - Set the server to use
|
|
164
|
+
def views(opts={})
|
|
165
|
+
full_tables('VIEW', opts)
|
|
166
|
+
end
|
|
167
|
+
|
|
119
168
|
private
|
|
120
169
|
|
|
121
170
|
# Use MySQL specific syntax for rename column, set column type, and
|
|
@@ -126,6 +175,7 @@ module Sequel
|
|
|
126
175
|
if related = op.delete(:table)
|
|
127
176
|
sql = super(table, op)
|
|
128
177
|
op[:table] = related
|
|
178
|
+
op[:key] ||= primary_key_from_schema(related)
|
|
129
179
|
[sql, "ALTER TABLE #{quote_schema_table(table)} ADD FOREIGN KEY (#{quote_identifier(op[:name])})#{column_references_sql(op)}"]
|
|
130
180
|
else
|
|
131
181
|
super(table, op)
|
|
@@ -142,10 +192,47 @@ module Sequel
|
|
|
142
192
|
"ALTER TABLE #{quote_schema_table(table)} CHANGE COLUMN #{quote_identifier(op[:name])} #{column_definition_sql(op.merge(opts))}"
|
|
143
193
|
when :drop_index
|
|
144
194
|
"#{drop_index_sql(table, op)} ON #{quote_schema_table(table)}"
|
|
195
|
+
when :drop_constraint
|
|
196
|
+
type = case op[:type]
|
|
197
|
+
when :primary_key
|
|
198
|
+
return "ALTER TABLE #{quote_schema_table(table)} DROP PRIMARY KEY"
|
|
199
|
+
when :foreign_key
|
|
200
|
+
'FOREIGN KEY'
|
|
201
|
+
when :unique
|
|
202
|
+
'INDEX'
|
|
203
|
+
else
|
|
204
|
+
raise(Error, "must specify constraint type via :type=>(:foreign_key|:primary_key|:unique) when dropping constraints on MySQL")
|
|
205
|
+
end
|
|
206
|
+
"ALTER TABLE #{quote_schema_table(table)} DROP #{type} #{quote_identifier(op[:name])}"
|
|
207
|
+
when :add_constraint
|
|
208
|
+
if op[:type] == :foreign_key
|
|
209
|
+
op[:key] ||= primary_key_from_schema(op[:table])
|
|
210
|
+
end
|
|
211
|
+
super(table, op)
|
|
145
212
|
else
|
|
146
213
|
super(table, op)
|
|
147
214
|
end
|
|
148
215
|
end
|
|
216
|
+
|
|
217
|
+
# The SQL queries to execute on initial connection
|
|
218
|
+
def mysql_connection_setting_sqls
|
|
219
|
+
sqls = []
|
|
220
|
+
|
|
221
|
+
# Increase timeout so mysql server doesn't disconnect us
|
|
222
|
+
# Value used by default is maximum allowed value on Windows.
|
|
223
|
+
sqls << "SET @@wait_timeout = #{opts[:timeout] || 2147483}"
|
|
224
|
+
|
|
225
|
+
# By default, MySQL 'where id is null' selects the last inserted id
|
|
226
|
+
sqls << "SET SQL_AUTO_IS_NULL=0" unless opts[:auto_is_null]
|
|
227
|
+
|
|
228
|
+
# If the user has specified one or more sql modes, enable them
|
|
229
|
+
if sql_mode = opts[:sql_mode]
|
|
230
|
+
sql_mode = Array(sql_mode).join(',').upcase
|
|
231
|
+
sqls << "SET sql_mode = '#{sql_mode}'"
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
sqls
|
|
235
|
+
end
|
|
149
236
|
|
|
150
237
|
# Use MySQL specific AUTO_INCREMENT text.
|
|
151
238
|
def auto_increment_sql
|
|
@@ -161,9 +248,9 @@ module Sequel
|
|
|
161
248
|
# Use XA START to start a new prepared transaction if the :prepare
|
|
162
249
|
# option is given.
|
|
163
250
|
def begin_transaction(conn, opts={})
|
|
164
|
-
if s = opts[:prepare]
|
|
251
|
+
if (s = opts[:prepare]) && (th = _trans(conn))[:savepoint_level] == 0
|
|
165
252
|
log_connection_execute(conn, "XA START #{literal(s)}")
|
|
166
|
-
|
|
253
|
+
th[:savepoint_level] += 1
|
|
167
254
|
else
|
|
168
255
|
super
|
|
169
256
|
end
|
|
@@ -184,7 +271,7 @@ module Sequel
|
|
|
184
271
|
# Prepare the XA transaction for a two-phase commit if the
|
|
185
272
|
# :prepare option is given.
|
|
186
273
|
def commit_transaction(conn, opts={})
|
|
187
|
-
if s = opts[:prepare]
|
|
274
|
+
if (s = opts[:prepare]) && _trans(conn)[:savepoint_level] <= 1
|
|
188
275
|
log_connection_execute(conn, "XA END #{literal(s)}")
|
|
189
276
|
log_connection_execute(conn, "XA PREPARE #{literal(s)}")
|
|
190
277
|
else
|
|
@@ -197,14 +284,50 @@ module Sequel
|
|
|
197
284
|
engine = options.fetch(:engine, Sequel::MySQL.default_engine)
|
|
198
285
|
charset = options.fetch(:charset, Sequel::MySQL.default_charset)
|
|
199
286
|
collate = options.fetch(:collate, Sequel::MySQL.default_collate)
|
|
287
|
+
generator.constraints.sort_by{|c| (c[:type] == :primary_key) ? -1 : 1}
|
|
288
|
+
|
|
289
|
+
key_proc = lambda do |t|
|
|
290
|
+
if t == name
|
|
291
|
+
if pk = generator.primary_key_name
|
|
292
|
+
[pk]
|
|
293
|
+
elsif !(pkc = generator.constraints.select{|con| con[:type] == :primary_key}).empty?
|
|
294
|
+
pkc.first[:columns]
|
|
295
|
+
end
|
|
296
|
+
else
|
|
297
|
+
primary_key_from_schema(t)
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
generator.constraints.each do |c|
|
|
302
|
+
if c[:type] == :foreign_key
|
|
303
|
+
c[:key] ||= key_proc.call(c[:table])
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
200
307
|
generator.columns.each do |c|
|
|
201
308
|
if t = c.delete(:table)
|
|
202
|
-
|
|
309
|
+
same_table = t == name
|
|
310
|
+
k = c[:key]
|
|
311
|
+
|
|
312
|
+
key ||= key_proc.call(t)
|
|
313
|
+
|
|
314
|
+
if same_table && !k.nil?
|
|
315
|
+
generator.constraints.unshift(:type=>:unique, :columns=>Array(k))
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
generator.foreign_key([c[:name]], t, c.merge(:name=>nil, :type=>:foreign_key, :key=>key))
|
|
203
319
|
end
|
|
204
320
|
end
|
|
321
|
+
|
|
205
322
|
"#{super}#{" ENGINE=#{engine}" if engine}#{" DEFAULT CHARSET=#{charset}" if charset}#{" DEFAULT COLLATE=#{collate}" if collate}"
|
|
206
323
|
end
|
|
207
324
|
|
|
325
|
+
# Backbone of the tables and views support using SHOW FULL TABLES.
|
|
326
|
+
def full_tables(type, opts)
|
|
327
|
+
m = output_identifier_meth
|
|
328
|
+
metadata_dataset.with_sql('SHOW FULL TABLES').server(opts[:server]).map{|r| m.call(r.values.first) if r.delete(:Table_type) == type}.compact
|
|
329
|
+
end
|
|
330
|
+
|
|
208
331
|
# MySQL folds unquoted identifiers to lowercase, so it shouldn't need to upcase identifiers on input.
|
|
209
332
|
def identifier_input_method_default
|
|
210
333
|
nil
|
|
@@ -230,9 +353,14 @@ module Sequel
|
|
|
230
353
|
"CREATE #{index_type}INDEX #{index_name}#{using} ON #{quote_schema_table(table_name)} #{literal(index[:columns])}"
|
|
231
354
|
end
|
|
232
355
|
|
|
356
|
+
# Parse the schema for the given table to get an array of primary key columns
|
|
357
|
+
def primary_key_from_schema(table)
|
|
358
|
+
schema(table).select{|a| a[1][:primary_key]}.map{|a| a[0]}
|
|
359
|
+
end
|
|
360
|
+
|
|
233
361
|
# Rollback the currently open XA transaction
|
|
234
362
|
def rollback_transaction(conn, opts={})
|
|
235
|
-
if s = opts[:prepare]
|
|
363
|
+
if (s = opts[:prepare]) && _trans(conn)[:savepoint_level] <= 1
|
|
236
364
|
log_connection_execute(conn, "XA END #{literal(s)}")
|
|
237
365
|
log_connection_execute(conn, "XA PREPARE #{literal(s)}")
|
|
238
366
|
log_connection_execute(conn, "XA ROLLBACK #{literal(s)}")
|
|
@@ -248,9 +376,11 @@ module Sequel
|
|
|
248
376
|
|
|
249
377
|
# Use the MySQL specific DESCRIBE syntax to get a table description.
|
|
250
378
|
def schema_parse_table(table_name, opts)
|
|
251
|
-
m = output_identifier_meth
|
|
252
|
-
im = input_identifier_meth
|
|
253
|
-
|
|
379
|
+
m = output_identifier_meth(opts[:dataset])
|
|
380
|
+
im = input_identifier_meth(opts[:dataset])
|
|
381
|
+
table = SQL::Identifier.new(im.call(table_name))
|
|
382
|
+
table = SQL::QualifiedIdentifier.new(im.call(opts[:schema]), table) if opts[:schema]
|
|
383
|
+
metadata_dataset.with_sql("DESCRIBE ?", table).map do |row|
|
|
254
384
|
row[:auto_increment] = true if row.delete(:Extra).to_s =~ /auto_increment/io
|
|
255
385
|
row[:allow_null] = row.delete(:Null) == 'YES'
|
|
256
386
|
row[:default] = row.delete(:Default)
|
|
@@ -281,13 +411,17 @@ module Sequel
|
|
|
281
411
|
# MySQL has both datetime and timestamp classes, most people are going
|
|
282
412
|
# to want datetime
|
|
283
413
|
def type_literal_generic_datetime(column)
|
|
284
|
-
:
|
|
414
|
+
if column[:default] == Sequel::CURRENT_TIMESTAMP
|
|
415
|
+
:timestamp
|
|
416
|
+
else
|
|
417
|
+
:datetime
|
|
418
|
+
end
|
|
285
419
|
end
|
|
286
420
|
|
|
287
421
|
# MySQL has both datetime and timestamp classes, most people are going
|
|
288
422
|
# to want datetime
|
|
289
423
|
def type_literal_generic_time(column)
|
|
290
|
-
column[:only_time] ? :time :
|
|
424
|
+
column[:only_time] ? :time : type_literal_generic_datetime(column)
|
|
291
425
|
end
|
|
292
426
|
|
|
293
427
|
# MySQL doesn't have a true boolean class, so it uses tinyint(1)
|
|
@@ -303,27 +437,82 @@ module Sequel
|
|
|
303
437
|
COMMA_SEPARATOR = ', '.freeze
|
|
304
438
|
FOR_SHARE = ' LOCK IN SHARE MODE'.freeze
|
|
305
439
|
SQL_CALC_FOUND_ROWS = ' SQL_CALC_FOUND_ROWS'.freeze
|
|
306
|
-
DELETE_CLAUSE_METHODS = Dataset.clause_methods(:delete, %w'from where order limit')
|
|
307
|
-
INSERT_CLAUSE_METHODS = Dataset.clause_methods(:insert, %w'ignore into columns values on_duplicate_key_update')
|
|
308
|
-
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'distinct calc_found_rows columns from join where group having compounds order limit lock')
|
|
309
|
-
UPDATE_CLAUSE_METHODS = Dataset.clause_methods(:update, %w'table set where order limit')
|
|
440
|
+
DELETE_CLAUSE_METHODS = Dataset.clause_methods(:delete, %w'delete from where order limit')
|
|
441
|
+
INSERT_CLAUSE_METHODS = Dataset.clause_methods(:insert, %w'insert ignore into columns values on_duplicate_key_update')
|
|
442
|
+
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'select distinct calc_found_rows columns from join where group having compounds order limit lock')
|
|
443
|
+
UPDATE_CLAUSE_METHODS = Dataset.clause_methods(:update, %w'update ignore table set where order limit')
|
|
444
|
+
APOS = Dataset::APOS
|
|
445
|
+
APOS_RE = Dataset::APOS_RE
|
|
446
|
+
DOUBLE_APOS = Dataset::DOUBLE_APOS
|
|
447
|
+
SPACE = Dataset::SPACE
|
|
448
|
+
PAREN_OPEN = Dataset::PAREN_OPEN
|
|
449
|
+
PAREN_CLOSE = Dataset::PAREN_CLOSE
|
|
450
|
+
NOT_SPACE = Dataset::NOT_SPACE
|
|
451
|
+
FROM = Dataset::FROM
|
|
452
|
+
INSERT = Dataset::INSERT
|
|
453
|
+
COMMA = Dataset::COMMA
|
|
454
|
+
LIMIT = Dataset::LIMIT
|
|
455
|
+
GROUP_BY = Dataset::GROUP_BY
|
|
456
|
+
REGEXP = 'REGEXP'.freeze
|
|
457
|
+
LIKE = 'LIKE'.freeze
|
|
458
|
+
BINARY = 'BINARY '.freeze
|
|
459
|
+
CONCAT = "CONCAT".freeze
|
|
460
|
+
CAST_BITCOMP_OPEN = "CAST(~".freeze
|
|
461
|
+
CAST_BITCOMP_CLOSE = " AS SIGNED INTEGER)".freeze
|
|
462
|
+
STRAIGHT_JOIN = 'STRAIGHT_JOIN'.freeze
|
|
463
|
+
NATURAL_LEFT_JOIN = 'NATURAL LEFT JOIN'.freeze
|
|
464
|
+
BACKTICK = '`'.freeze
|
|
465
|
+
BACKTICK_RE = /`/.freeze
|
|
466
|
+
DOUBLE_BACKTICK = '``'.freeze
|
|
467
|
+
EMPTY_COLUMNS = " ()".freeze
|
|
468
|
+
EMPTY_VALUES = " VALUES ()".freeze
|
|
469
|
+
IGNORE = " IGNORE".freeze
|
|
470
|
+
REPLACE = 'REPLACE'.freeze
|
|
471
|
+
ON_DUPLICATE_KEY_UPDATE = " ON DUPLICATE KEY UPDATE ".freeze
|
|
472
|
+
EQ_VALUES = '=VALUES('.freeze
|
|
473
|
+
EQ = '='.freeze
|
|
474
|
+
WITH_ROLLUP = ' WITH ROLLUP'.freeze
|
|
475
|
+
MATCH_AGAINST = ["(MATCH ".freeze, " AGAINST (".freeze, "))".freeze].freeze
|
|
476
|
+
MATCH_AGAINST_BOOLEAN = ["(MATCH ".freeze, " AGAINST (".freeze, " IN BOOLEAN MODE))".freeze].freeze
|
|
477
|
+
EXPLAIN = 'EXPLAIN '.freeze
|
|
478
|
+
EXPLAIN_EXTENDED = 'EXPLAIN EXTENDED '.freeze
|
|
479
|
+
BACKSLASH_RE = /\\/.freeze
|
|
480
|
+
QUAD_BACKSLASH = "\\\\\\\\".freeze
|
|
310
481
|
|
|
311
482
|
# MySQL specific syntax for LIKE/REGEXP searches, as well as
|
|
312
483
|
# string concatenation.
|
|
313
|
-
def
|
|
484
|
+
def complex_expression_sql_append(sql, op, args)
|
|
314
485
|
case op
|
|
486
|
+
when :IN, :"NOT IN"
|
|
487
|
+
ds = args.at(1)
|
|
488
|
+
if ds.is_a?(Sequel::Dataset) && ds.opts[:limit]
|
|
489
|
+
super(sql, op, [args.at(0), ds.from_self])
|
|
490
|
+
else
|
|
491
|
+
super
|
|
492
|
+
end
|
|
315
493
|
when :~, :'!~', :'~*', :'!~*', :LIKE, :'NOT LIKE', :ILIKE, :'NOT ILIKE'
|
|
316
|
-
|
|
494
|
+
sql << PAREN_OPEN
|
|
495
|
+
literal_append(sql, args.at(0))
|
|
496
|
+
sql << SPACE
|
|
497
|
+
sql << 'NOT ' if [:'NOT LIKE', :'NOT ILIKE', :'!~', :'!~*'].include?(op)
|
|
498
|
+
sql << ([:~, :'!~', :'~*', :'!~*'].include?(op) ? REGEXP : LIKE)
|
|
499
|
+
sql << SPACE
|
|
500
|
+
sql << BINARY if [:~, :'!~', :LIKE, :'NOT LIKE'].include?(op)
|
|
501
|
+
literal_append(sql, args.at(1))
|
|
502
|
+
sql << PAREN_CLOSE
|
|
317
503
|
when :'||'
|
|
318
504
|
if args.length > 1
|
|
319
|
-
|
|
505
|
+
sql << CONCAT
|
|
506
|
+
array_sql_append(sql, args)
|
|
320
507
|
else
|
|
321
|
-
|
|
508
|
+
literal_append(sql, args.at(0))
|
|
322
509
|
end
|
|
323
510
|
when :'B~'
|
|
324
|
-
|
|
511
|
+
sql << CAST_BITCOMP_OPEN
|
|
512
|
+
literal_append(sql, args.at(0))
|
|
513
|
+
sql << CAST_BITCOMP_CLOSE
|
|
325
514
|
else
|
|
326
|
-
super
|
|
515
|
+
super
|
|
327
516
|
end
|
|
328
517
|
end
|
|
329
518
|
|
|
@@ -340,6 +529,17 @@ module Sequel
|
|
|
340
529
|
clone(:calc_found_rows => true)
|
|
341
530
|
end
|
|
342
531
|
|
|
532
|
+
# Return the results of an EXPLAIN query as a string. Options:
|
|
533
|
+
# :extended :: Use EXPLAIN EXPTENDED instead of EXPLAIN if true.
|
|
534
|
+
def explain(opts={})
|
|
535
|
+
# Load the PrettyTable class, needed for explain output
|
|
536
|
+
Sequel.extension(:_pretty_table) unless defined?(Sequel::PrettyTable)
|
|
537
|
+
|
|
538
|
+
ds = db.send(:metadata_dataset).with_sql((opts[:extended] ? EXPLAIN_EXTENDED : EXPLAIN) + select_sql).naked
|
|
539
|
+
rows = ds.all
|
|
540
|
+
Sequel::PrettyTable.string(rows, ds.columns)
|
|
541
|
+
end
|
|
542
|
+
|
|
343
543
|
# Return a cloned dataset which will use LOCK IN SHARE MODE to lock returned rows.
|
|
344
544
|
def for_share
|
|
345
545
|
lock_style(:share)
|
|
@@ -351,8 +551,9 @@ module Sequel
|
|
|
351
551
|
end
|
|
352
552
|
|
|
353
553
|
# MySQL specific full text search syntax.
|
|
354
|
-
def full_text_sql(cols,
|
|
355
|
-
|
|
554
|
+
def full_text_sql(cols, terms, opts = {})
|
|
555
|
+
terms = terms.join(' ') if terms.is_a?(Array)
|
|
556
|
+
SQL::PlaceholderLiteralString.new((opts[:boolean] ? MATCH_AGAINST_BOOLEAN : MATCH_AGAINST), [Array(cols), terms])
|
|
356
557
|
end
|
|
357
558
|
|
|
358
559
|
# MySQL allows HAVING clause on ungrouped datasets.
|
|
@@ -372,9 +573,12 @@ module Sequel
|
|
|
372
573
|
# STRAIGHT_JOIN.
|
|
373
574
|
def join_type_sql(join_type)
|
|
374
575
|
case join_type
|
|
375
|
-
when :straight
|
|
376
|
-
|
|
377
|
-
|
|
576
|
+
when :straight
|
|
577
|
+
STRAIGHT_JOIN
|
|
578
|
+
when :natural_inner
|
|
579
|
+
NATURAL_LEFT_JOIN
|
|
580
|
+
else
|
|
581
|
+
super
|
|
378
582
|
end
|
|
379
583
|
end
|
|
380
584
|
|
|
@@ -389,7 +593,7 @@ module Sequel
|
|
|
389
593
|
def insert_ignore
|
|
390
594
|
clone(:insert_ignore=>true)
|
|
391
595
|
end
|
|
392
|
-
|
|
596
|
+
|
|
393
597
|
# Sets up the insert methods to use ON DUPLICATE KEY UPDATE
|
|
394
598
|
# If you pass no arguments, ALL fields will be
|
|
395
599
|
# updated with the new values. If you pass the fields you
|
|
@@ -415,25 +619,31 @@ module Sequel
|
|
|
415
619
|
|
|
416
620
|
# MySQL specific syntax for inserting multiple values at once.
|
|
417
621
|
def multi_insert_sql(columns, values)
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
# MySQL uses the number of rows actually modified in the update,
|
|
422
|
-
# instead of the number of matched by the filter.
|
|
423
|
-
def provides_accurate_rows_matched?
|
|
424
|
-
false
|
|
622
|
+
sql = LiteralString.new('VALUES ')
|
|
623
|
+
expression_list_append(sql, values.map{|r| Array(r)})
|
|
624
|
+
[insert_sql(columns, sql)]
|
|
425
625
|
end
|
|
426
626
|
|
|
427
627
|
# MySQL uses the nonstandard ` (backtick) for quoting identifiers.
|
|
428
|
-
def
|
|
429
|
-
|
|
628
|
+
def quoted_identifier_append(sql, c)
|
|
629
|
+
sql << BACKTICK << c.to_s.gsub(BACKTICK_RE, DOUBLE_BACKTICK) << BACKTICK
|
|
430
630
|
end
|
|
431
631
|
|
|
632
|
+
# Execute a REPLACE statement on the database.
|
|
633
|
+
def replace(*values)
|
|
634
|
+
execute_insert(replace_sql(*values))
|
|
635
|
+
end
|
|
636
|
+
|
|
432
637
|
# MySQL specific syntax for REPLACE (aka UPSERT, or update if exists,
|
|
433
638
|
# insert if it doesn't).
|
|
434
639
|
def replace_sql(*values)
|
|
435
640
|
clone(:replace=>true).insert_sql(*values)
|
|
436
641
|
end
|
|
642
|
+
|
|
643
|
+
# Replace multiple rows in a single query.
|
|
644
|
+
def multi_replace(*values)
|
|
645
|
+
clone(:replace=>true).multi_insert(*values)
|
|
646
|
+
end
|
|
437
647
|
|
|
438
648
|
# MySQL can emulate DISTINCT ON with its non-standard GROUP BY implementation,
|
|
439
649
|
# though the rows returned cannot be made deterministic through ordering.
|
|
@@ -441,6 +651,11 @@ module Sequel
|
|
|
441
651
|
true
|
|
442
652
|
end
|
|
443
653
|
|
|
654
|
+
# MySQL supports GROUP BY WITH ROLLUP (but not CUBE)
|
|
655
|
+
def supports_group_rollup?
|
|
656
|
+
true
|
|
657
|
+
end
|
|
658
|
+
|
|
444
659
|
# MySQL does not support INTERSECT or EXCEPT
|
|
445
660
|
def supports_intersect_except?
|
|
446
661
|
false
|
|
@@ -451,6 +666,12 @@ module Sequel
|
|
|
451
666
|
true
|
|
452
667
|
end
|
|
453
668
|
|
|
669
|
+
# MySQL's DISTINCT ON emulation using GROUP BY does not respect the
|
|
670
|
+
# queries ORDER BY clause.
|
|
671
|
+
def supports_ordered_distinct_on?
|
|
672
|
+
false
|
|
673
|
+
end
|
|
674
|
+
|
|
454
675
|
# MySQL does support fractional timestamps in literal timestamps, but it
|
|
455
676
|
# ignores them. Also, using them seems to cause problems on 1.9. Since
|
|
456
677
|
# they are ignored anyway, not using them is probably best.
|
|
@@ -458,13 +679,16 @@ module Sequel
|
|
|
458
679
|
false
|
|
459
680
|
end
|
|
460
681
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
#
|
|
464
|
-
|
|
465
|
-
|
|
682
|
+
# Sets up the update methods to use UPDATE IGNORE.
|
|
683
|
+
# Useful if you have a unique key and want to just skip
|
|
684
|
+
# updating rows that violate the unique key restriction.
|
|
685
|
+
#
|
|
686
|
+
# dataset.update_ignore.update({:name => 'a', :value => 1})
|
|
687
|
+
# # UPDATE IGNORE tablename SET name = 'a', value = 1
|
|
688
|
+
def update_ignore
|
|
689
|
+
clone(:update_ignore=>true)
|
|
466
690
|
end
|
|
467
|
-
|
|
691
|
+
|
|
468
692
|
private
|
|
469
693
|
|
|
470
694
|
# MySQL supports the ORDER BY and LIMIT clauses for DELETE statements
|
|
@@ -476,7 +700,10 @@ module Sequel
|
|
|
476
700
|
# from, but include the others for the purposes of selecting rows.
|
|
477
701
|
def delete_from_sql(sql)
|
|
478
702
|
if joined_dataset?
|
|
479
|
-
sql <<
|
|
703
|
+
sql << SPACE
|
|
704
|
+
source_list_append(sql, @opts[:from][0..0])
|
|
705
|
+
sql << FROM
|
|
706
|
+
source_list_append(sql, @opts[:from])
|
|
480
707
|
select_join_sql(sql)
|
|
481
708
|
else
|
|
482
709
|
super
|
|
@@ -493,7 +720,7 @@ module Sequel
|
|
|
493
720
|
def insert_columns_sql(sql)
|
|
494
721
|
values = opts[:values]
|
|
495
722
|
if values.is_a?(Array) && values.empty?
|
|
496
|
-
sql <<
|
|
723
|
+
sql << EMPTY_COLUMNS
|
|
497
724
|
else
|
|
498
725
|
super
|
|
499
726
|
end
|
|
@@ -501,19 +728,62 @@ module Sequel
|
|
|
501
728
|
|
|
502
729
|
# MySQL supports INSERT IGNORE INTO
|
|
503
730
|
def insert_ignore_sql(sql)
|
|
504
|
-
sql <<
|
|
731
|
+
sql << IGNORE if opts[:insert_ignore]
|
|
732
|
+
end
|
|
733
|
+
|
|
734
|
+
# MySQL supports UPDATE IGNORE
|
|
735
|
+
def update_ignore_sql(sql)
|
|
736
|
+
sql << IGNORE if opts[:update_ignore]
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
# If this is an replace instead of an insert, use replace instead
|
|
740
|
+
def insert_insert_sql(sql)
|
|
741
|
+
sql << (@opts[:replace] ? REPLACE : INSERT)
|
|
505
742
|
end
|
|
506
743
|
|
|
507
744
|
# MySQL supports INSERT ... ON DUPLICATE KEY UPDATE
|
|
508
745
|
def insert_on_duplicate_key_update_sql(sql)
|
|
509
|
-
|
|
746
|
+
if update_cols = opts[:on_duplicate_key_update]
|
|
747
|
+
update_vals = nil
|
|
748
|
+
|
|
749
|
+
if update_cols.empty?
|
|
750
|
+
update_cols = columns
|
|
751
|
+
elsif update_cols.last.is_a?(Hash)
|
|
752
|
+
update_vals = update_cols.last
|
|
753
|
+
update_cols = update_cols[0..-2]
|
|
754
|
+
end
|
|
755
|
+
|
|
756
|
+
sql << ON_DUPLICATE_KEY_UPDATE
|
|
757
|
+
c = false
|
|
758
|
+
co = COMMA
|
|
759
|
+
values = EQ_VALUES
|
|
760
|
+
endp = PAREN_CLOSE
|
|
761
|
+
update_cols.each do |col|
|
|
762
|
+
sql << co if c
|
|
763
|
+
quote_identifier_append(sql, col)
|
|
764
|
+
sql << values
|
|
765
|
+
quote_identifier_append(sql, col)
|
|
766
|
+
sql << endp
|
|
767
|
+
c ||= true
|
|
768
|
+
end
|
|
769
|
+
if update_vals
|
|
770
|
+
eq = EQ
|
|
771
|
+
update_vals.map do |col,v|
|
|
772
|
+
sql << co if c
|
|
773
|
+
quote_identifier_append(sql, col)
|
|
774
|
+
sql << eq
|
|
775
|
+
literal_append(sql, v)
|
|
776
|
+
c ||= true
|
|
777
|
+
end
|
|
778
|
+
end
|
|
779
|
+
end
|
|
510
780
|
end
|
|
511
781
|
|
|
512
782
|
# MySQL doesn't use the standard DEFAULT VALUES for empty values.
|
|
513
783
|
def insert_values_sql(sql)
|
|
514
784
|
values = opts[:values]
|
|
515
785
|
if values.is_a?(Array) && values.empty?
|
|
516
|
-
sql <<
|
|
786
|
+
sql << EMPTY_VALUES
|
|
517
787
|
else
|
|
518
788
|
super
|
|
519
789
|
end
|
|
@@ -521,7 +791,10 @@ module Sequel
|
|
|
521
791
|
|
|
522
792
|
# MySQL allows a LIMIT in DELETE and UPDATE statements.
|
|
523
793
|
def limit_sql(sql)
|
|
524
|
-
|
|
794
|
+
if l = @opts[:limit]
|
|
795
|
+
sql << LIMIT
|
|
796
|
+
literal_append(sql, @opts[:limit])
|
|
797
|
+
end
|
|
525
798
|
end
|
|
526
799
|
alias delete_limit_sql limit_sql
|
|
527
800
|
alias update_limit_sql limit_sql
|
|
@@ -531,30 +804,16 @@ module Sequel
|
|
|
531
804
|
BOOL_FALSE
|
|
532
805
|
end
|
|
533
806
|
|
|
807
|
+
# SQL fragment for String. Doubles \ and ' by default.
|
|
808
|
+
def literal_string_append(sql, v)
|
|
809
|
+
sql << APOS << v.gsub(BACKSLASH_RE, QUAD_BACKSLASH).gsub(APOS_RE, DOUBLE_APOS) << APOS
|
|
810
|
+
end
|
|
811
|
+
|
|
534
812
|
# Use 1 for true on MySQL
|
|
535
813
|
def literal_true
|
|
536
814
|
BOOL_TRUE
|
|
537
815
|
end
|
|
538
816
|
|
|
539
|
-
# MySQL specific syntax for ON DUPLICATE KEY UPDATE
|
|
540
|
-
def on_duplicate_key_update_sql
|
|
541
|
-
if update_cols = opts[:on_duplicate_key_update]
|
|
542
|
-
update_vals = nil
|
|
543
|
-
|
|
544
|
-
if update_cols.empty?
|
|
545
|
-
update_cols = columns
|
|
546
|
-
elsif update_cols.last.is_a?(Hash)
|
|
547
|
-
update_vals = update_cols.last
|
|
548
|
-
update_cols = update_cols[0..-2]
|
|
549
|
-
end
|
|
550
|
-
|
|
551
|
-
updating = update_cols.map{|c| "#{quote_identifier(c)}=VALUES(#{quote_identifier(c)})" }
|
|
552
|
-
updating += update_vals.map{|c,v| "#{quote_identifier(c)}=#{literal(v)}" } if update_vals
|
|
553
|
-
|
|
554
|
-
" ON DUPLICATE KEY UPDATE #{updating.join(COMMA_SEPARATOR)}"
|
|
555
|
-
end
|
|
556
|
-
end
|
|
557
|
-
|
|
558
817
|
# MySQL does not support the SQL WITH clause for SELECT statements
|
|
559
818
|
def select_clause_methods
|
|
560
819
|
SELECT_CLAUSE_METHODS
|
|
@@ -574,6 +833,11 @@ module Sequel
|
|
|
574
833
|
def update_clause_methods
|
|
575
834
|
UPDATE_CLAUSE_METHODS
|
|
576
835
|
end
|
|
836
|
+
|
|
837
|
+
# MySQL uses WITH ROLLUP syntax.
|
|
838
|
+
def uses_with_rollup?
|
|
839
|
+
true
|
|
840
|
+
end
|
|
577
841
|
end
|
|
578
842
|
end
|
|
579
843
|
end
|