sequel 3.21.0 → 3.41.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 +1131 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +106 -65
- data/Rakefile +59 -27
- data/bin/sequel +50 -26
- data/doc/active_record.rdoc +68 -52
- data/doc/advanced_associations.rdoc +201 -75
- data/doc/association_basics.rdoc +327 -79
- data/doc/bin_sequel.rdoc +144 -0
- data/doc/cheat_sheet.rdoc +21 -21
- data/doc/core_extensions.rdoc +374 -0
- data/doc/dataset_basics.rdoc +10 -10
- data/doc/dataset_filtering.rdoc +54 -42
- data/doc/mass_assignment.rdoc +56 -0
- data/doc/migration.rdoc +89 -557
- data/doc/model_hooks.rdoc +80 -29
- data/doc/object_model.rdoc +576 -0
- data/doc/opening_databases.rdoc +121 -53
- data/doc/prepared_statements.rdoc +41 -15
- data/doc/querying.rdoc +137 -56
- data/doc/reflection.rdoc +36 -10
- 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/release_notes/3.37.0.txt +338 -0
- data/doc/release_notes/3.38.0.txt +234 -0
- data/doc/release_notes/3.39.0.txt +237 -0
- data/doc/release_notes/3.40.0.txt +73 -0
- data/doc/release_notes/3.41.0.txt +155 -0
- data/doc/schema_modification.rdoc +585 -0
- data/doc/sharding.rdoc +99 -8
- data/doc/sql.rdoc +154 -112
- data/doc/testing.rdoc +169 -0
- data/doc/thread_safety.rdoc +17 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/validations.rdoc +1 -1
- data/doc/virtual_rows.rdoc +78 -43
- data/lib/sequel/adapters/ado/access.rb +334 -0
- data/lib/sequel/adapters/ado/mssql.rb +18 -12
- data/lib/sequel/adapters/ado.rb +69 -21
- data/lib/sequel/adapters/amalgalite.rb +17 -14
- data/lib/sequel/adapters/cubrid.rb +143 -0
- data/lib/sequel/adapters/db2.rb +178 -85
- data/lib/sequel/adapters/dbi.rb +19 -21
- data/lib/sequel/adapters/do/mysql.rb +17 -11
- data/lib/sequel/adapters/do/postgres.rb +2 -61
- data/lib/sequel/adapters/do/sqlite.rb +0 -10
- data/lib/sequel/adapters/do.rb +20 -39
- data/lib/sequel/adapters/firebird.rb +33 -210
- data/lib/sequel/adapters/ibmdb.rb +452 -0
- data/lib/sequel/adapters/informix.rb +6 -29
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/cubrid.rb +52 -0
- data/lib/sequel/adapters/jdbc/db2.rb +78 -0
- data/lib/sequel/adapters/jdbc/derby.rb +325 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
- data/lib/sequel/adapters/jdbc/h2.rb +68 -31
- data/lib/sequel/adapters/jdbc/hsqldb.rb +189 -0
- data/lib/sequel/adapters/jdbc/informix.rb +21 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +40 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +16 -28
- data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +77 -52
- 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 +72 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +308 -114
- data/lib/sequel/adapters/mock.rb +372 -0
- data/lib/sequel/adapters/mysql.rb +130 -230
- data/lib/sequel/adapters/mysql2.rb +64 -63
- data/lib/sequel/adapters/odbc/mssql.rb +17 -9
- data/lib/sequel/adapters/odbc.rb +29 -10
- data/lib/sequel/adapters/openbase.rb +7 -11
- data/lib/sequel/adapters/oracle.rb +364 -57
- data/lib/sequel/adapters/postgres.rb +379 -145
- data/lib/sequel/adapters/shared/access.rb +236 -11
- data/lib/sequel/adapters/shared/cubrid.rb +216 -0
- data/lib/sequel/adapters/shared/db2.rb +353 -0
- data/lib/sequel/adapters/shared/firebird.rb +231 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +412 -116
- data/lib/sequel/adapters/shared/mysql.rb +396 -89
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +166 -0
- data/lib/sequel/adapters/shared/oracle.rb +262 -45
- data/lib/sequel/adapters/shared/postgres.rb +688 -279
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +317 -96
- data/lib/sequel/adapters/sqlite.rb +109 -46
- data/lib/sequel/adapters/swift/mysql.rb +10 -12
- data/lib/sequel/adapters/swift/postgres.rb +13 -79
- data/lib/sequel/adapters/swift/sqlite.rb +9 -6
- data/lib/sequel/adapters/swift.rb +31 -27
- data/lib/sequel/adapters/tinytds.rb +177 -25
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +77 -0
- data/lib/sequel/adapters/utils/pg_types.rb +81 -0
- data/lib/sequel/adapters/utils/split_alter_table.rb +36 -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 +23 -13
- data/lib/sequel/connection_pool/sharded_threaded.rb +64 -13
- data/lib/sequel/connection_pool/single.rb +11 -3
- data/lib/sequel/connection_pool/threaded.rb +69 -20
- data/lib/sequel/connection_pool.rb +20 -18
- data/lib/sequel/core.rb +143 -11
- data/lib/sequel/database/connecting.rb +66 -29
- 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 +192 -51
- data/lib/sequel/database/query.rb +299 -114
- data/lib/sequel/database/schema_generator.rb +103 -36
- data/lib/sequel/database/schema_methods.rb +310 -69
- data/lib/sequel/dataset/actions.rb +344 -90
- data/lib/sequel/dataset/features.rb +101 -8
- data/lib/sequel/dataset/graph.rb +42 -15
- data/lib/sequel/dataset/misc.rb +52 -25
- data/lib/sequel/dataset/mutation.rb +12 -7
- data/lib/sequel/dataset/prepared_statements.rb +68 -30
- data/lib/sequel/dataset/query.rb +322 -68
- data/lib/sequel/dataset/sql.rb +716 -293
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/_pretty_table.rb +83 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +109 -0
- data/lib/sequel/extensions/blank.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +72 -0
- data/lib/sequel/extensions/connection_validator.rb +109 -0
- data/lib/sequel/extensions/constraint_validations.rb +451 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +30 -46
- data/lib/sequel/extensions/eval_inspect.rb +173 -0
- data/lib/sequel/extensions/inflector.rb +4 -0
- data/lib/sequel/extensions/looser_typecasting.rb +5 -4
- data/lib/sequel/extensions/migration.rb +100 -11
- data/lib/sequel/extensions/named_timezones.rb +9 -0
- data/lib/sequel/extensions/null_dataset.rb +94 -0
- data/lib/sequel/extensions/pagination.rb +4 -0
- data/lib/sequel/extensions/pg_array.rb +539 -0
- data/lib/sequel/extensions/pg_array_ops.rb +263 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +175 -0
- data/lib/sequel/extensions/pg_hstore.rb +334 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +293 -0
- data/lib/sequel/extensions/pg_inet.rb +113 -0
- data/lib/sequel/extensions/pg_interval.rb +191 -0
- data/lib/sequel/extensions/pg_json.rb +212 -0
- data/lib/sequel/extensions/pg_range.rb +513 -0
- data/lib/sequel/extensions/pg_range_ops.rb +150 -0
- data/lib/sequel/extensions/pg_row.rb +576 -0
- data/lib/sequel/extensions/pg_row_ops.rb +182 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +317 -0
- data/lib/sequel/extensions/pretty_table.rb +17 -72
- data/lib/sequel/extensions/query.rb +8 -4
- 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 +282 -76
- data/lib/sequel/extensions/select_remove.rb +39 -0
- data/lib/sequel/extensions/server_block.rb +140 -0
- data/lib/sequel/extensions/split_array_nil.rb +65 -0
- data/lib/sequel/extensions/sql_expr.rb +8 -110
- data/lib/sequel/extensions/string_date_time.rb +4 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +10 -4
- data/lib/sequel/extensions/to_dot.rb +99 -83
- data/lib/sequel/model/associations.rb +1263 -409
- data/lib/sequel/model/base.rb +624 -171
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +24 -2
- 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 +137 -16
- 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/constraint_validations.rb +198 -0
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +72 -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 +134 -15
- 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 +77 -6
- data/lib/sequel/plugins/list.rb +13 -2
- data/lib/sequel/plugins/many_through_many.rb +103 -51
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +150 -66
- data/lib/sequel/plugins/optimistic_locking.rb +8 -0
- data/lib/sequel/plugins/pg_row.rb +121 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
- data/lib/sequel/plugins/prepared_statements.rb +168 -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 +31 -17
- data/lib/sequel/plugins/schema.rb +8 -3
- 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 +57 -12
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/subclasses.rb +29 -3
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/touch.rb +18 -6
- data/lib/sequel/plugins/tree.rb +3 -3
- 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 +2 -1
- data/lib/sequel/plugins/validation_helpers.rb +57 -4
- data/lib/sequel/plugins/xml_serializer.rb +15 -4
- data/lib/sequel/sql.rb +721 -141
- data/lib/sequel/timezones.rb +67 -40
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/firebird_spec.rb +53 -39
- data/spec/adapters/mssql_spec.rb +261 -66
- data/spec/adapters/mysql_spec.rb +597 -352
- data/spec/adapters/oracle_spec.rb +92 -117
- data/spec/adapters/postgres_spec.rb +2103 -341
- data/spec/adapters/spec_helper.rb +16 -6
- data/spec/adapters/sqlite_spec.rb +237 -76
- data/spec/core/connection_pool_spec.rb +270 -141
- data/spec/core/database_spec.rb +980 -524
- data/spec/core/dataset_spec.rb +1658 -1243
- data/spec/core/expression_filters_spec.rb +741 -334
- data/spec/core/mock_adapter_spec.rb +453 -0
- data/spec/core/object_graph_spec.rb +88 -129
- data/spec/core/schema_generator_spec.rb +4 -4
- data/spec/core/schema_spec.rb +556 -53
- data/spec/core/spec_helper.rb +7 -48
- data/spec/core_extensions_spec.rb +626 -0
- 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 +227 -33
- data/spec/extensions/association_proxies_spec.rb +4 -4
- data/spec/extensions/boolean_readers_spec.rb +25 -25
- 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/extensions/connection_validator_spec.rb +118 -0
- data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
- data/spec/extensions/constraint_validations_spec.rb +316 -0
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +88 -0
- data/spec/extensions/dirty_spec.rb +155 -0
- data/spec/extensions/eager_each_spec.rb +34 -0
- data/spec/extensions/eval_inspect_spec.rb +67 -0
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +97 -128
- data/spec/extensions/identity_map_spec.rb +142 -24
- 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 -12
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +49 -40
- data/spec/extensions/looser_typecasting_spec.rb +7 -7
- data/spec/extensions/many_through_many_spec.rb +368 -254
- 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 +268 -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 +112 -0
- data/spec/extensions/pg_array_spec.rb +324 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +140 -0
- data/spec/extensions/pg_hstore_spec.rb +200 -0
- data/spec/extensions/pg_inet_spec.rb +47 -0
- data/spec/extensions/pg_interval_spec.rb +72 -0
- data/spec/extensions/pg_json_spec.rb +99 -0
- data/spec/extensions/pg_range_ops_spec.rb +56 -0
- data/spec/extensions/pg_range_spec.rb +395 -0
- data/spec/extensions/pg_row_ops_spec.rb +58 -0
- data/spec/extensions/pg_row_plugin_spec.rb +49 -0
- data/spec/extensions/pg_row_spec.rb +340 -0
- data/spec/extensions/pg_statement_cache_spec.rb +208 -0
- data/spec/extensions/pg_typecast_on_load_spec.rb +58 -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 +167 -0
- data/spec/extensions/query_spec.rb +9 -3
- 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 +434 -49
- data/spec/extensions/schema_spec.rb +30 -49
- 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 +86 -48
- 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 +65 -29
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +34 -67
- data/spec/extensions/split_array_nil_spec.rb +24 -0
- data/spec/extensions/sql_expr_spec.rb +29 -60
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/subclasses_spec.rb +14 -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 +8 -11
- data/spec/extensions/touch_spec.rb +53 -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 +77 -68
- data/spec/extensions/validation_helpers_spec.rb +48 -37
- 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 +25 -5
- data/spec/integration/dataset_test.rb +729 -141
- data/spec/integration/eager_loader_test.rb +38 -54
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +81 -2
- data/spec/integration/plugin_test.rb +871 -160
- data/spec/integration/prepared_statement_test.rb +272 -128
- data/spec/integration/schema_test.rb +377 -57
- data/spec/integration/spec_helper.rb +49 -32
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +183 -8
- data/spec/integration/type_test.rb +40 -8
- data/spec/model/association_reflection_spec.rb +207 -8
- data/spec/model/associations_spec.rb +1206 -693
- data/spec/model/base_spec.rb +334 -100
- data/spec/model/dataset_methods_spec.rb +45 -27
- data/spec/model/eager_loading_spec.rb +828 -692
- data/spec/model/hooks_spec.rb +355 -67
- data/spec/model/model_spec.rb +251 -179
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +506 -232
- data/spec/model/spec_helper.rb +16 -77
- data/spec/model/validations_spec.rb +38 -2
- data/spec/rcov.opts +2 -0
- metadata +223 -81
- data/spec/core/core_sql_spec.rb +0 -451
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
Sequel.require 'adapters/utils/split_alter_table'
|
|
2
|
+
|
|
1
3
|
module Sequel
|
|
2
4
|
Dataset::NON_SQL_OPTIONS << :insert_ignore
|
|
5
|
+
Dataset::NON_SQL_OPTIONS << :update_ignore
|
|
3
6
|
Dataset::NON_SQL_OPTIONS << :on_duplicate_key_update
|
|
4
7
|
|
|
5
8
|
module MySQL
|
|
@@ -30,8 +33,11 @@ module Sequel
|
|
|
30
33
|
module DatabaseMethods
|
|
31
34
|
AUTO_INCREMENT = 'AUTO_INCREMENT'.freeze
|
|
32
35
|
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]
|
|
36
|
+
COLUMN_DEFINITION_ORDER = [:collate, :null, :default, :unique, :primary_key, :auto_increment, :references]
|
|
34
37
|
PRIMARY = 'PRIMARY'.freeze
|
|
38
|
+
MYSQL_TIMESTAMP_RE = /\ACURRENT_(?:DATE|TIMESTAMP)?\z/
|
|
39
|
+
|
|
40
|
+
include Sequel::Database::SplitAlterTable
|
|
35
41
|
|
|
36
42
|
# MySQL's cast rules are restrictive in that you can't just cast to any possible
|
|
37
43
|
# database type.
|
|
@@ -50,6 +56,36 @@ module Sequel
|
|
|
50
56
|
:mysql
|
|
51
57
|
end
|
|
52
58
|
|
|
59
|
+
# Use the Information Schema's KEY_COLUMN_USAGE table to get
|
|
60
|
+
# basic information on foreign key columns, but include the
|
|
61
|
+
# constraint name.
|
|
62
|
+
def foreign_key_list(table, opts={})
|
|
63
|
+
m = output_identifier_meth
|
|
64
|
+
im = input_identifier_meth
|
|
65
|
+
ds = metadata_dataset.
|
|
66
|
+
from(:INFORMATION_SCHEMA__KEY_COLUMN_USAGE).
|
|
67
|
+
where(:TABLE_NAME=>im.call(table)).
|
|
68
|
+
exclude(:CONSTRAINT_NAME=>'PRIMARY').
|
|
69
|
+
exclude(:REFERENCED_TABLE_NAME=>nil).
|
|
70
|
+
select(:CONSTRAINT_NAME___name, :COLUMN_NAME___column, :REFERENCED_TABLE_NAME___table, :REFERENCED_COLUMN_NAME___key)
|
|
71
|
+
|
|
72
|
+
h = {}
|
|
73
|
+
ds.each do |row|
|
|
74
|
+
if r = h[row[:name]]
|
|
75
|
+
r[:columns] << m.call(row[:column])
|
|
76
|
+
r[:key] << m.call(row[:key])
|
|
77
|
+
else
|
|
78
|
+
h[row[:name]] = {:name=>m.call(row[:name]), :columns=>[m.call(row[:column])], :table=>m.call(row[:table]), :key=>[m.call(row[:key])]}
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
h.values
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# MySQL namespaces indexes per table.
|
|
85
|
+
def global_index_namespace?
|
|
86
|
+
false
|
|
87
|
+
end
|
|
88
|
+
|
|
53
89
|
# Use SHOW INDEX FROM to get the index information for the
|
|
54
90
|
# table.
|
|
55
91
|
#
|
|
@@ -79,27 +115,31 @@ module Sequel
|
|
|
79
115
|
|
|
80
116
|
# Get version of MySQL server, used for determined capabilities.
|
|
81
117
|
def server_version
|
|
82
|
-
|
|
83
|
-
|
|
118
|
+
@server_version ||= begin
|
|
119
|
+
m = /(\d+)\.(\d+)\.(\d+)/.match(get(SQL::Function.new(:version)))
|
|
120
|
+
(m[1].to_i * 10000) + (m[2].to_i * 100) + m[3].to_i
|
|
121
|
+
end
|
|
84
122
|
end
|
|
85
123
|
|
|
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)}
|
|
124
|
+
# MySQL supports CREATE TABLE IF NOT EXISTS syntax.
|
|
125
|
+
def supports_create_table_if_not_exists?
|
|
126
|
+
true
|
|
93
127
|
end
|
|
94
128
|
|
|
95
129
|
# MySQL supports prepared transactions (two-phase commit) using XA
|
|
96
130
|
def supports_prepared_transactions?
|
|
97
|
-
|
|
131
|
+
server_version >= 50000
|
|
98
132
|
end
|
|
99
133
|
|
|
100
134
|
# MySQL supports savepoints
|
|
101
135
|
def supports_savepoints?
|
|
102
|
-
|
|
136
|
+
server_version >= 50000
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# MySQL doesn't support savepoints inside prepared transactions in from
|
|
140
|
+
# 5.5.12 to 5.5.23, see http://bugs.mysql.com/bug.php?id=64374
|
|
141
|
+
def supports_savepoints_in_prepared_transactions?
|
|
142
|
+
super && (server_version <= 50512 || server_version >= 50523)
|
|
103
143
|
end
|
|
104
144
|
|
|
105
145
|
# MySQL supports transaction isolation levels
|
|
@@ -107,6 +147,14 @@ module Sequel
|
|
|
107
147
|
true
|
|
108
148
|
end
|
|
109
149
|
|
|
150
|
+
# Return an array of symbols specifying table names in the current database.
|
|
151
|
+
#
|
|
152
|
+
# Options:
|
|
153
|
+
# * :server - Set the server to use
|
|
154
|
+
def tables(opts={})
|
|
155
|
+
full_tables('BASE TABLE', opts)
|
|
156
|
+
end
|
|
157
|
+
|
|
110
158
|
# Changes the database in use by issuing a USE statement. I would be
|
|
111
159
|
# very careful if I used this.
|
|
112
160
|
def use(db_name)
|
|
@@ -116,19 +164,27 @@ module Sequel
|
|
|
116
164
|
self
|
|
117
165
|
end
|
|
118
166
|
|
|
167
|
+
# Return an array of symbols specifying view names in the current database.
|
|
168
|
+
#
|
|
169
|
+
# Options:
|
|
170
|
+
# * :server - Set the server to use
|
|
171
|
+
def views(opts={})
|
|
172
|
+
full_tables('VIEW', opts)
|
|
173
|
+
end
|
|
174
|
+
|
|
119
175
|
private
|
|
120
176
|
|
|
121
|
-
# Use MySQL specific syntax for
|
|
122
|
-
|
|
123
|
-
def alter_table_sql(table, op)
|
|
177
|
+
# Use MySQL specific syntax for some alter table operations.
|
|
178
|
+
def alter_table_op_sql(table, op)
|
|
124
179
|
case op[:op]
|
|
125
180
|
when :add_column
|
|
126
181
|
if related = op.delete(:table)
|
|
127
|
-
sql = super
|
|
182
|
+
sql = super
|
|
128
183
|
op[:table] = related
|
|
129
|
-
|
|
184
|
+
op[:key] ||= primary_key_from_schema(related)
|
|
185
|
+
sql << ", ADD FOREIGN KEY (#{quote_identifier(op[:name])})#{column_references_sql(op)}"
|
|
130
186
|
else
|
|
131
|
-
super
|
|
187
|
+
super
|
|
132
188
|
end
|
|
133
189
|
when :rename_column, :set_column_type, :set_column_null, :set_column_default
|
|
134
190
|
o = op[:op]
|
|
@@ -139,12 +195,71 @@ module Sequel
|
|
|
139
195
|
opts[:null] = o == :set_column_null ? op[:null] : opts[:allow_null]
|
|
140
196
|
opts[:default] = o == :set_column_default ? op[:default] : opts[:ruby_default]
|
|
141
197
|
opts.delete(:default) if opts[:default] == nil
|
|
142
|
-
|
|
198
|
+
opts.delete(:primary_key)
|
|
199
|
+
"CHANGE COLUMN #{quote_identifier(op[:name])} #{column_definition_sql(op.merge(opts))}"
|
|
200
|
+
when :drop_constraint
|
|
201
|
+
type = case op[:type]
|
|
202
|
+
when :primary_key
|
|
203
|
+
"DROP PRIMARY KEY"
|
|
204
|
+
when :foreign_key
|
|
205
|
+
"DROP FOREIGN KEY #{quote_identifier(op[:name])}"
|
|
206
|
+
when :unique
|
|
207
|
+
"DROP INDEX #{quote_identifier(op[:name])}"
|
|
208
|
+
end
|
|
209
|
+
when :add_constraint
|
|
210
|
+
if op[:type] == :foreign_key
|
|
211
|
+
op[:key] ||= primary_key_from_schema(op[:table])
|
|
212
|
+
end
|
|
213
|
+
super
|
|
214
|
+
else
|
|
215
|
+
super
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# MySQL server requires table names when dropping indexes.
|
|
220
|
+
def alter_table_sql(table, op)
|
|
221
|
+
case op[:op]
|
|
143
222
|
when :drop_index
|
|
144
223
|
"#{drop_index_sql(table, op)} ON #{quote_schema_table(table)}"
|
|
145
224
|
else
|
|
146
|
-
super
|
|
225
|
+
super
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Handle MySQL specific default format.
|
|
230
|
+
def column_schema_normalize_default(default, type)
|
|
231
|
+
if column_schema_default_string_type?(type)
|
|
232
|
+
return if [:date, :datetime, :time].include?(type) && MYSQL_TIMESTAMP_RE.match(default)
|
|
233
|
+
default = "'#{default.gsub("'", "''").gsub('\\', '\\\\')}'"
|
|
234
|
+
end
|
|
235
|
+
super(default, type)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Don't allow combining adding foreign key operations with other
|
|
239
|
+
# operations, since in some cases adding a foreign key constraint in
|
|
240
|
+
# the same query as other operations results in MySQL error 150.
|
|
241
|
+
def combinable_alter_table_op?(op)
|
|
242
|
+
super && !(op[:op] == :add_constraint && op[:type] == :foreign_key)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# The SQL queries to execute on initial connection
|
|
246
|
+
def mysql_connection_setting_sqls
|
|
247
|
+
sqls = []
|
|
248
|
+
|
|
249
|
+
# Increase timeout so mysql server doesn't disconnect us
|
|
250
|
+
# Value used by default is maximum allowed value on Windows.
|
|
251
|
+
sqls << "SET @@wait_timeout = #{opts[:timeout] || 2147483}"
|
|
252
|
+
|
|
253
|
+
# By default, MySQL 'where id is null' selects the last inserted id
|
|
254
|
+
sqls << "SET SQL_AUTO_IS_NULL=0" unless opts[:auto_is_null]
|
|
255
|
+
|
|
256
|
+
# If the user has specified one or more sql modes, enable them
|
|
257
|
+
if sql_mode = opts[:sql_mode]
|
|
258
|
+
sql_mode = Array(sql_mode).join(',').upcase
|
|
259
|
+
sqls << "SET sql_mode = '#{sql_mode}'"
|
|
147
260
|
end
|
|
261
|
+
|
|
262
|
+
sqls
|
|
148
263
|
end
|
|
149
264
|
|
|
150
265
|
# Use MySQL specific AUTO_INCREMENT text.
|
|
@@ -161,9 +276,9 @@ module Sequel
|
|
|
161
276
|
# Use XA START to start a new prepared transaction if the :prepare
|
|
162
277
|
# option is given.
|
|
163
278
|
def begin_transaction(conn, opts={})
|
|
164
|
-
if s = opts[:prepare]
|
|
279
|
+
if (s = opts[:prepare]) && (th = _trans(conn))[:savepoint_level] == 0
|
|
165
280
|
log_connection_execute(conn, "XA START #{literal(s)}")
|
|
166
|
-
|
|
281
|
+
th[:savepoint_level] += 1
|
|
167
282
|
else
|
|
168
283
|
super
|
|
169
284
|
end
|
|
@@ -184,7 +299,7 @@ module Sequel
|
|
|
184
299
|
# Prepare the XA transaction for a two-phase commit if the
|
|
185
300
|
# :prepare option is given.
|
|
186
301
|
def commit_transaction(conn, opts={})
|
|
187
|
-
if s = opts[:prepare]
|
|
302
|
+
if (s = opts[:prepare]) && _trans(conn)[:savepoint_level] <= 1
|
|
188
303
|
log_connection_execute(conn, "XA END #{literal(s)}")
|
|
189
304
|
log_connection_execute(conn, "XA PREPARE #{literal(s)}")
|
|
190
305
|
else
|
|
@@ -197,14 +312,50 @@ module Sequel
|
|
|
197
312
|
engine = options.fetch(:engine, Sequel::MySQL.default_engine)
|
|
198
313
|
charset = options.fetch(:charset, Sequel::MySQL.default_charset)
|
|
199
314
|
collate = options.fetch(:collate, Sequel::MySQL.default_collate)
|
|
315
|
+
generator.constraints.sort_by{|c| (c[:type] == :primary_key) ? -1 : 1}
|
|
316
|
+
|
|
317
|
+
key_proc = lambda do |t|
|
|
318
|
+
if t == name
|
|
319
|
+
if pk = generator.primary_key_name
|
|
320
|
+
[pk]
|
|
321
|
+
elsif !(pkc = generator.constraints.select{|con| con[:type] == :primary_key}).empty?
|
|
322
|
+
pkc.first[:columns]
|
|
323
|
+
end
|
|
324
|
+
else
|
|
325
|
+
primary_key_from_schema(t)
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
generator.constraints.each do |c|
|
|
330
|
+
if c[:type] == :foreign_key
|
|
331
|
+
c[:key] ||= key_proc.call(c[:table])
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
200
335
|
generator.columns.each do |c|
|
|
201
336
|
if t = c.delete(:table)
|
|
202
|
-
|
|
337
|
+
same_table = t == name
|
|
338
|
+
k = c[:key]
|
|
339
|
+
|
|
340
|
+
key ||= key_proc.call(t)
|
|
341
|
+
|
|
342
|
+
if same_table && !k.nil?
|
|
343
|
+
generator.constraints.unshift(:type=>:unique, :columns=>Array(k))
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
generator.foreign_key([c[:name]], t, c.merge(:name=>nil, :type=>:foreign_key, :key=>key))
|
|
203
347
|
end
|
|
204
348
|
end
|
|
349
|
+
|
|
205
350
|
"#{super}#{" ENGINE=#{engine}" if engine}#{" DEFAULT CHARSET=#{charset}" if charset}#{" DEFAULT COLLATE=#{collate}" if collate}"
|
|
206
351
|
end
|
|
207
352
|
|
|
353
|
+
# Backbone of the tables and views support using SHOW FULL TABLES.
|
|
354
|
+
def full_tables(type, opts)
|
|
355
|
+
m = output_identifier_meth
|
|
356
|
+
metadata_dataset.with_sql('SHOW FULL TABLES').server(opts[:server]).map{|r| m.call(r.values.first) if r.delete(:Table_type) == type}.compact
|
|
357
|
+
end
|
|
358
|
+
|
|
208
359
|
# MySQL folds unquoted identifiers to lowercase, so it shouldn't need to upcase identifiers on input.
|
|
209
360
|
def identifier_input_method_default
|
|
210
361
|
nil
|
|
@@ -230,9 +381,14 @@ module Sequel
|
|
|
230
381
|
"CREATE #{index_type}INDEX #{index_name}#{using} ON #{quote_schema_table(table_name)} #{literal(index[:columns])}"
|
|
231
382
|
end
|
|
232
383
|
|
|
384
|
+
# Parse the schema for the given table to get an array of primary key columns
|
|
385
|
+
def primary_key_from_schema(table)
|
|
386
|
+
schema(table).select{|a| a[1][:primary_key]}.map{|a| a[0]}
|
|
387
|
+
end
|
|
388
|
+
|
|
233
389
|
# Rollback the currently open XA transaction
|
|
234
390
|
def rollback_transaction(conn, opts={})
|
|
235
|
-
if s = opts[:prepare]
|
|
391
|
+
if (s = opts[:prepare]) && _trans(conn)[:savepoint_level] <= 1
|
|
236
392
|
log_connection_execute(conn, "XA END #{literal(s)}")
|
|
237
393
|
log_connection_execute(conn, "XA PREPARE #{literal(s)}")
|
|
238
394
|
log_connection_execute(conn, "XA ROLLBACK #{literal(s)}")
|
|
@@ -241,16 +397,23 @@ module Sequel
|
|
|
241
397
|
end
|
|
242
398
|
end
|
|
243
399
|
|
|
244
|
-
# MySQL
|
|
245
|
-
def
|
|
246
|
-
|
|
400
|
+
# Recognize MySQL set type.
|
|
401
|
+
def schema_column_type(db_type)
|
|
402
|
+
case db_type
|
|
403
|
+
when /\Aset/io
|
|
404
|
+
:set
|
|
405
|
+
else
|
|
406
|
+
super
|
|
407
|
+
end
|
|
247
408
|
end
|
|
248
409
|
|
|
249
410
|
# Use the MySQL specific DESCRIBE syntax to get a table description.
|
|
250
411
|
def schema_parse_table(table_name, opts)
|
|
251
|
-
m = output_identifier_meth
|
|
252
|
-
im = input_identifier_meth
|
|
253
|
-
|
|
412
|
+
m = output_identifier_meth(opts[:dataset])
|
|
413
|
+
im = input_identifier_meth(opts[:dataset])
|
|
414
|
+
table = SQL::Identifier.new(im.call(table_name))
|
|
415
|
+
table = SQL::QualifiedIdentifier.new(im.call(opts[:schema]), table) if opts[:schema]
|
|
416
|
+
metadata_dataset.with_sql("DESCRIBE ?", table).map do |row|
|
|
254
417
|
row[:auto_increment] = true if row.delete(:Extra).to_s =~ /auto_increment/io
|
|
255
418
|
row[:allow_null] = row.delete(:Null) == 'YES'
|
|
256
419
|
row[:default] = row.delete(:Default)
|
|
@@ -262,6 +425,11 @@ module Sequel
|
|
|
262
425
|
end
|
|
263
426
|
end
|
|
264
427
|
|
|
428
|
+
# MySQL can combine multiple alter table ops into a single query.
|
|
429
|
+
def supports_combining_alter_table_ops?
|
|
430
|
+
true
|
|
431
|
+
end
|
|
432
|
+
|
|
265
433
|
# Respect the :size option if given to produce
|
|
266
434
|
# tinyblob, mediumblob, and longblob if :tiny,
|
|
267
435
|
# :medium, or :long is given.
|
|
@@ -281,13 +449,17 @@ module Sequel
|
|
|
281
449
|
# MySQL has both datetime and timestamp classes, most people are going
|
|
282
450
|
# to want datetime
|
|
283
451
|
def type_literal_generic_datetime(column)
|
|
284
|
-
:
|
|
452
|
+
if column[:default] == Sequel::CURRENT_TIMESTAMP
|
|
453
|
+
:timestamp
|
|
454
|
+
else
|
|
455
|
+
:datetime
|
|
456
|
+
end
|
|
285
457
|
end
|
|
286
458
|
|
|
287
459
|
# MySQL has both datetime and timestamp classes, most people are going
|
|
288
460
|
# to want datetime
|
|
289
461
|
def type_literal_generic_time(column)
|
|
290
|
-
column[:only_time] ? :time :
|
|
462
|
+
column[:only_time] ? :time : type_literal_generic_datetime(column)
|
|
291
463
|
end
|
|
292
464
|
|
|
293
465
|
# MySQL doesn't have a true boolean class, so it uses tinyint(1)
|
|
@@ -303,27 +475,82 @@ module Sequel
|
|
|
303
475
|
COMMA_SEPARATOR = ', '.freeze
|
|
304
476
|
FOR_SHARE = ' LOCK IN SHARE MODE'.freeze
|
|
305
477
|
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')
|
|
478
|
+
DELETE_CLAUSE_METHODS = Dataset.clause_methods(:delete, %w'delete from where order limit')
|
|
479
|
+
INSERT_CLAUSE_METHODS = Dataset.clause_methods(:insert, %w'insert ignore into columns values on_duplicate_key_update')
|
|
480
|
+
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'select distinct calc_found_rows columns from join where group having compounds order limit lock')
|
|
481
|
+
UPDATE_CLAUSE_METHODS = Dataset.clause_methods(:update, %w'update ignore table set where order limit')
|
|
482
|
+
APOS = Dataset::APOS
|
|
483
|
+
APOS_RE = Dataset::APOS_RE
|
|
484
|
+
DOUBLE_APOS = Dataset::DOUBLE_APOS
|
|
485
|
+
SPACE = Dataset::SPACE
|
|
486
|
+
PAREN_OPEN = Dataset::PAREN_OPEN
|
|
487
|
+
PAREN_CLOSE = Dataset::PAREN_CLOSE
|
|
488
|
+
NOT_SPACE = Dataset::NOT_SPACE
|
|
489
|
+
FROM = Dataset::FROM
|
|
490
|
+
INSERT = Dataset::INSERT
|
|
491
|
+
COMMA = Dataset::COMMA
|
|
492
|
+
LIMIT = Dataset::LIMIT
|
|
493
|
+
GROUP_BY = Dataset::GROUP_BY
|
|
494
|
+
REGEXP = 'REGEXP'.freeze
|
|
495
|
+
LIKE = 'LIKE'.freeze
|
|
496
|
+
BINARY = 'BINARY '.freeze
|
|
497
|
+
CONCAT = "CONCAT".freeze
|
|
498
|
+
CAST_BITCOMP_OPEN = "CAST(~".freeze
|
|
499
|
+
CAST_BITCOMP_CLOSE = " AS SIGNED INTEGER)".freeze
|
|
500
|
+
STRAIGHT_JOIN = 'STRAIGHT_JOIN'.freeze
|
|
501
|
+
NATURAL_LEFT_JOIN = 'NATURAL LEFT JOIN'.freeze
|
|
502
|
+
BACKTICK = '`'.freeze
|
|
503
|
+
BACKTICK_RE = /`/.freeze
|
|
504
|
+
DOUBLE_BACKTICK = '``'.freeze
|
|
505
|
+
EMPTY_COLUMNS = " ()".freeze
|
|
506
|
+
EMPTY_VALUES = " VALUES ()".freeze
|
|
507
|
+
IGNORE = " IGNORE".freeze
|
|
508
|
+
REPLACE = 'REPLACE'.freeze
|
|
509
|
+
ON_DUPLICATE_KEY_UPDATE = " ON DUPLICATE KEY UPDATE ".freeze
|
|
510
|
+
EQ_VALUES = '=VALUES('.freeze
|
|
511
|
+
EQ = '='.freeze
|
|
512
|
+
WITH_ROLLUP = ' WITH ROLLUP'.freeze
|
|
513
|
+
MATCH_AGAINST = ["(MATCH ".freeze, " AGAINST (".freeze, "))".freeze].freeze
|
|
514
|
+
MATCH_AGAINST_BOOLEAN = ["(MATCH ".freeze, " AGAINST (".freeze, " IN BOOLEAN MODE))".freeze].freeze
|
|
515
|
+
EXPLAIN = 'EXPLAIN '.freeze
|
|
516
|
+
EXPLAIN_EXTENDED = 'EXPLAIN EXTENDED '.freeze
|
|
517
|
+
BACKSLASH_RE = /\\/.freeze
|
|
518
|
+
QUAD_BACKSLASH = "\\\\\\\\".freeze
|
|
310
519
|
|
|
311
520
|
# MySQL specific syntax for LIKE/REGEXP searches, as well as
|
|
312
521
|
# string concatenation.
|
|
313
|
-
def
|
|
522
|
+
def complex_expression_sql_append(sql, op, args)
|
|
314
523
|
case op
|
|
524
|
+
when :IN, :"NOT IN"
|
|
525
|
+
ds = args.at(1)
|
|
526
|
+
if ds.is_a?(Sequel::Dataset) && ds.opts[:limit]
|
|
527
|
+
super(sql, op, [args.at(0), ds.from_self])
|
|
528
|
+
else
|
|
529
|
+
super
|
|
530
|
+
end
|
|
315
531
|
when :~, :'!~', :'~*', :'!~*', :LIKE, :'NOT LIKE', :ILIKE, :'NOT ILIKE'
|
|
316
|
-
|
|
532
|
+
sql << PAREN_OPEN
|
|
533
|
+
literal_append(sql, args.at(0))
|
|
534
|
+
sql << SPACE
|
|
535
|
+
sql << 'NOT ' if [:'NOT LIKE', :'NOT ILIKE', :'!~', :'!~*'].include?(op)
|
|
536
|
+
sql << ([:~, :'!~', :'~*', :'!~*'].include?(op) ? REGEXP : LIKE)
|
|
537
|
+
sql << SPACE
|
|
538
|
+
sql << BINARY if [:~, :'!~', :LIKE, :'NOT LIKE'].include?(op)
|
|
539
|
+
literal_append(sql, args.at(1))
|
|
540
|
+
sql << PAREN_CLOSE
|
|
317
541
|
when :'||'
|
|
318
542
|
if args.length > 1
|
|
319
|
-
|
|
543
|
+
sql << CONCAT
|
|
544
|
+
array_sql_append(sql, args)
|
|
320
545
|
else
|
|
321
|
-
|
|
546
|
+
literal_append(sql, args.at(0))
|
|
322
547
|
end
|
|
323
548
|
when :'B~'
|
|
324
|
-
|
|
549
|
+
sql << CAST_BITCOMP_OPEN
|
|
550
|
+
literal_append(sql, args.at(0))
|
|
551
|
+
sql << CAST_BITCOMP_CLOSE
|
|
325
552
|
else
|
|
326
|
-
super
|
|
553
|
+
super
|
|
327
554
|
end
|
|
328
555
|
end
|
|
329
556
|
|
|
@@ -340,6 +567,17 @@ module Sequel
|
|
|
340
567
|
clone(:calc_found_rows => true)
|
|
341
568
|
end
|
|
342
569
|
|
|
570
|
+
# Return the results of an EXPLAIN query as a string. Options:
|
|
571
|
+
# :extended :: Use EXPLAIN EXPTENDED instead of EXPLAIN if true.
|
|
572
|
+
def explain(opts={})
|
|
573
|
+
# Load the PrettyTable class, needed for explain output
|
|
574
|
+
Sequel.extension(:_pretty_table) unless defined?(Sequel::PrettyTable)
|
|
575
|
+
|
|
576
|
+
ds = db.send(:metadata_dataset).with_sql((opts[:extended] ? EXPLAIN_EXTENDED : EXPLAIN) + select_sql).naked
|
|
577
|
+
rows = ds.all
|
|
578
|
+
Sequel::PrettyTable.string(rows, ds.columns)
|
|
579
|
+
end
|
|
580
|
+
|
|
343
581
|
# Return a cloned dataset which will use LOCK IN SHARE MODE to lock returned rows.
|
|
344
582
|
def for_share
|
|
345
583
|
lock_style(:share)
|
|
@@ -351,8 +589,9 @@ module Sequel
|
|
|
351
589
|
end
|
|
352
590
|
|
|
353
591
|
# MySQL specific full text search syntax.
|
|
354
|
-
def full_text_sql(cols,
|
|
355
|
-
|
|
592
|
+
def full_text_sql(cols, terms, opts = {})
|
|
593
|
+
terms = terms.join(' ') if terms.is_a?(Array)
|
|
594
|
+
SQL::PlaceholderLiteralString.new((opts[:boolean] ? MATCH_AGAINST_BOOLEAN : MATCH_AGAINST), [Array(cols), terms])
|
|
356
595
|
end
|
|
357
596
|
|
|
358
597
|
# MySQL allows HAVING clause on ungrouped datasets.
|
|
@@ -372,9 +611,12 @@ module Sequel
|
|
|
372
611
|
# STRAIGHT_JOIN.
|
|
373
612
|
def join_type_sql(join_type)
|
|
374
613
|
case join_type
|
|
375
|
-
when :straight
|
|
376
|
-
|
|
377
|
-
|
|
614
|
+
when :straight
|
|
615
|
+
STRAIGHT_JOIN
|
|
616
|
+
when :natural_inner
|
|
617
|
+
NATURAL_LEFT_JOIN
|
|
618
|
+
else
|
|
619
|
+
super
|
|
378
620
|
end
|
|
379
621
|
end
|
|
380
622
|
|
|
@@ -389,7 +631,7 @@ module Sequel
|
|
|
389
631
|
def insert_ignore
|
|
390
632
|
clone(:insert_ignore=>true)
|
|
391
633
|
end
|
|
392
|
-
|
|
634
|
+
|
|
393
635
|
# Sets up the insert methods to use ON DUPLICATE KEY UPDATE
|
|
394
636
|
# If you pass no arguments, ALL fields will be
|
|
395
637
|
# updated with the new values. If you pass the fields you
|
|
@@ -415,25 +657,31 @@ module Sequel
|
|
|
415
657
|
|
|
416
658
|
# MySQL specific syntax for inserting multiple values at once.
|
|
417
659
|
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
|
|
660
|
+
sql = LiteralString.new('VALUES ')
|
|
661
|
+
expression_list_append(sql, values.map{|r| Array(r)})
|
|
662
|
+
[insert_sql(columns, sql)]
|
|
425
663
|
end
|
|
426
664
|
|
|
427
665
|
# MySQL uses the nonstandard ` (backtick) for quoting identifiers.
|
|
428
|
-
def
|
|
429
|
-
|
|
666
|
+
def quoted_identifier_append(sql, c)
|
|
667
|
+
sql << BACKTICK << c.to_s.gsub(BACKTICK_RE, DOUBLE_BACKTICK) << BACKTICK
|
|
430
668
|
end
|
|
431
669
|
|
|
670
|
+
# Execute a REPLACE statement on the database.
|
|
671
|
+
def replace(*values)
|
|
672
|
+
execute_insert(replace_sql(*values))
|
|
673
|
+
end
|
|
674
|
+
|
|
432
675
|
# MySQL specific syntax for REPLACE (aka UPSERT, or update if exists,
|
|
433
676
|
# insert if it doesn't).
|
|
434
677
|
def replace_sql(*values)
|
|
435
678
|
clone(:replace=>true).insert_sql(*values)
|
|
436
679
|
end
|
|
680
|
+
|
|
681
|
+
# Replace multiple rows in a single query.
|
|
682
|
+
def multi_replace(*values)
|
|
683
|
+
clone(:replace=>true).multi_insert(*values)
|
|
684
|
+
end
|
|
437
685
|
|
|
438
686
|
# MySQL can emulate DISTINCT ON with its non-standard GROUP BY implementation,
|
|
439
687
|
# though the rows returned cannot be made deterministic through ordering.
|
|
@@ -441,6 +689,11 @@ module Sequel
|
|
|
441
689
|
true
|
|
442
690
|
end
|
|
443
691
|
|
|
692
|
+
# MySQL supports GROUP BY WITH ROLLUP (but not CUBE)
|
|
693
|
+
def supports_group_rollup?
|
|
694
|
+
true
|
|
695
|
+
end
|
|
696
|
+
|
|
444
697
|
# MySQL does not support INTERSECT or EXCEPT
|
|
445
698
|
def supports_intersect_except?
|
|
446
699
|
false
|
|
@@ -451,6 +704,17 @@ module Sequel
|
|
|
451
704
|
true
|
|
452
705
|
end
|
|
453
706
|
|
|
707
|
+
# MySQL's DISTINCT ON emulation using GROUP BY does not respect the
|
|
708
|
+
# queries ORDER BY clause.
|
|
709
|
+
def supports_ordered_distinct_on?
|
|
710
|
+
false
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
# MySQL supports pattern matching via regular expressions
|
|
714
|
+
def supports_regexp?
|
|
715
|
+
true
|
|
716
|
+
end
|
|
717
|
+
|
|
454
718
|
# MySQL does support fractional timestamps in literal timestamps, but it
|
|
455
719
|
# ignores them. Also, using them seems to cause problems on 1.9. Since
|
|
456
720
|
# they are ignored anyway, not using them is probably best.
|
|
@@ -458,13 +722,16 @@ module Sequel
|
|
|
458
722
|
false
|
|
459
723
|
end
|
|
460
724
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
#
|
|
464
|
-
|
|
465
|
-
|
|
725
|
+
# Sets up the update methods to use UPDATE IGNORE.
|
|
726
|
+
# Useful if you have a unique key and want to just skip
|
|
727
|
+
# updating rows that violate the unique key restriction.
|
|
728
|
+
#
|
|
729
|
+
# dataset.update_ignore.update({:name => 'a', :value => 1})
|
|
730
|
+
# # UPDATE IGNORE tablename SET name = 'a', value = 1
|
|
731
|
+
def update_ignore
|
|
732
|
+
clone(:update_ignore=>true)
|
|
466
733
|
end
|
|
467
|
-
|
|
734
|
+
|
|
468
735
|
private
|
|
469
736
|
|
|
470
737
|
# MySQL supports the ORDER BY and LIMIT clauses for DELETE statements
|
|
@@ -476,7 +743,10 @@ module Sequel
|
|
|
476
743
|
# from, but include the others for the purposes of selecting rows.
|
|
477
744
|
def delete_from_sql(sql)
|
|
478
745
|
if joined_dataset?
|
|
479
|
-
sql <<
|
|
746
|
+
sql << SPACE
|
|
747
|
+
source_list_append(sql, @opts[:from][0..0])
|
|
748
|
+
sql << FROM
|
|
749
|
+
source_list_append(sql, @opts[:from])
|
|
480
750
|
select_join_sql(sql)
|
|
481
751
|
else
|
|
482
752
|
super
|
|
@@ -493,7 +763,7 @@ module Sequel
|
|
|
493
763
|
def insert_columns_sql(sql)
|
|
494
764
|
values = opts[:values]
|
|
495
765
|
if values.is_a?(Array) && values.empty?
|
|
496
|
-
sql <<
|
|
766
|
+
sql << EMPTY_COLUMNS
|
|
497
767
|
else
|
|
498
768
|
super
|
|
499
769
|
end
|
|
@@ -501,19 +771,62 @@ module Sequel
|
|
|
501
771
|
|
|
502
772
|
# MySQL supports INSERT IGNORE INTO
|
|
503
773
|
def insert_ignore_sql(sql)
|
|
504
|
-
sql <<
|
|
774
|
+
sql << IGNORE if opts[:insert_ignore]
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
# MySQL supports UPDATE IGNORE
|
|
778
|
+
def update_ignore_sql(sql)
|
|
779
|
+
sql << IGNORE if opts[:update_ignore]
|
|
780
|
+
end
|
|
781
|
+
|
|
782
|
+
# If this is an replace instead of an insert, use replace instead
|
|
783
|
+
def insert_insert_sql(sql)
|
|
784
|
+
sql << (@opts[:replace] ? REPLACE : INSERT)
|
|
505
785
|
end
|
|
506
786
|
|
|
507
787
|
# MySQL supports INSERT ... ON DUPLICATE KEY UPDATE
|
|
508
788
|
def insert_on_duplicate_key_update_sql(sql)
|
|
509
|
-
|
|
789
|
+
if update_cols = opts[:on_duplicate_key_update]
|
|
790
|
+
update_vals = nil
|
|
791
|
+
|
|
792
|
+
if update_cols.empty?
|
|
793
|
+
update_cols = columns
|
|
794
|
+
elsif update_cols.last.is_a?(Hash)
|
|
795
|
+
update_vals = update_cols.last
|
|
796
|
+
update_cols = update_cols[0..-2]
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
sql << ON_DUPLICATE_KEY_UPDATE
|
|
800
|
+
c = false
|
|
801
|
+
co = COMMA
|
|
802
|
+
values = EQ_VALUES
|
|
803
|
+
endp = PAREN_CLOSE
|
|
804
|
+
update_cols.each do |col|
|
|
805
|
+
sql << co if c
|
|
806
|
+
quote_identifier_append(sql, col)
|
|
807
|
+
sql << values
|
|
808
|
+
quote_identifier_append(sql, col)
|
|
809
|
+
sql << endp
|
|
810
|
+
c ||= true
|
|
811
|
+
end
|
|
812
|
+
if update_vals
|
|
813
|
+
eq = EQ
|
|
814
|
+
update_vals.map do |col,v|
|
|
815
|
+
sql << co if c
|
|
816
|
+
quote_identifier_append(sql, col)
|
|
817
|
+
sql << eq
|
|
818
|
+
literal_append(sql, v)
|
|
819
|
+
c ||= true
|
|
820
|
+
end
|
|
821
|
+
end
|
|
822
|
+
end
|
|
510
823
|
end
|
|
511
824
|
|
|
512
825
|
# MySQL doesn't use the standard DEFAULT VALUES for empty values.
|
|
513
826
|
def insert_values_sql(sql)
|
|
514
827
|
values = opts[:values]
|
|
515
828
|
if values.is_a?(Array) && values.empty?
|
|
516
|
-
sql <<
|
|
829
|
+
sql << EMPTY_VALUES
|
|
517
830
|
else
|
|
518
831
|
super
|
|
519
832
|
end
|
|
@@ -521,7 +834,10 @@ module Sequel
|
|
|
521
834
|
|
|
522
835
|
# MySQL allows a LIMIT in DELETE and UPDATE statements.
|
|
523
836
|
def limit_sql(sql)
|
|
524
|
-
|
|
837
|
+
if l = @opts[:limit]
|
|
838
|
+
sql << LIMIT
|
|
839
|
+
literal_append(sql, @opts[:limit])
|
|
840
|
+
end
|
|
525
841
|
end
|
|
526
842
|
alias delete_limit_sql limit_sql
|
|
527
843
|
alias update_limit_sql limit_sql
|
|
@@ -531,30 +847,16 @@ module Sequel
|
|
|
531
847
|
BOOL_FALSE
|
|
532
848
|
end
|
|
533
849
|
|
|
850
|
+
# SQL fragment for String. Doubles \ and ' by default.
|
|
851
|
+
def literal_string_append(sql, v)
|
|
852
|
+
sql << APOS << v.gsub(BACKSLASH_RE, QUAD_BACKSLASH).gsub(APOS_RE, DOUBLE_APOS) << APOS
|
|
853
|
+
end
|
|
854
|
+
|
|
534
855
|
# Use 1 for true on MySQL
|
|
535
856
|
def literal_true
|
|
536
857
|
BOOL_TRUE
|
|
537
858
|
end
|
|
538
859
|
|
|
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
860
|
# MySQL does not support the SQL WITH clause for SELECT statements
|
|
559
861
|
def select_clause_methods
|
|
560
862
|
SELECT_CLAUSE_METHODS
|
|
@@ -574,6 +876,11 @@ module Sequel
|
|
|
574
876
|
def update_clause_methods
|
|
575
877
|
UPDATE_CLAUSE_METHODS
|
|
576
878
|
end
|
|
879
|
+
|
|
880
|
+
# MySQL uses WITH ROLLUP syntax.
|
|
881
|
+
def uses_with_rollup?
|
|
882
|
+
true
|
|
883
|
+
end
|
|
577
884
|
end
|
|
578
885
|
end
|
|
579
886
|
end
|