sequel 4.26.0 → 5.37.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.
- checksums.yaml +5 -5
- data/CHANGELOG +405 -5656
- data/MIT-LICENSE +1 -1
- data/README.rdoc +232 -157
- data/bin/sequel +32 -9
- data/doc/advanced_associations.rdoc +252 -188
- data/doc/association_basics.rdoc +231 -273
- data/doc/bin_sequel.rdoc +5 -3
- data/doc/cheat_sheet.rdoc +75 -48
- data/doc/code_order.rdoc +28 -10
- data/doc/core_extensions.rdoc +104 -63
- data/doc/dataset_basics.rdoc +12 -21
- data/doc/dataset_filtering.rdoc +99 -86
- data/doc/extensions.rdoc +3 -10
- data/doc/mass_assignment.rdoc +74 -31
- data/doc/migration.rdoc +72 -46
- data/doc/model_dataset_method_design.rdoc +129 -0
- data/doc/model_hooks.rdoc +15 -25
- data/doc/model_plugins.rdoc +12 -12
- data/doc/mssql_stored_procedures.rdoc +3 -3
- data/doc/object_model.rdoc +59 -69
- data/doc/opening_databases.rdoc +84 -94
- data/doc/postgresql.rdoc +268 -38
- data/doc/prepared_statements.rdoc +29 -24
- data/doc/querying.rdoc +184 -164
- data/doc/reflection.rdoc +5 -6
- data/doc/release_notes/5.0.0.txt +159 -0
- data/doc/release_notes/5.1.0.txt +31 -0
- data/doc/release_notes/5.10.0.txt +84 -0
- data/doc/release_notes/5.11.0.txt +83 -0
- data/doc/release_notes/5.12.0.txt +141 -0
- data/doc/release_notes/5.13.0.txt +27 -0
- data/doc/release_notes/5.14.0.txt +63 -0
- data/doc/release_notes/5.15.0.txt +39 -0
- data/doc/release_notes/5.16.0.txt +110 -0
- data/doc/release_notes/5.17.0.txt +31 -0
- data/doc/release_notes/5.18.0.txt +69 -0
- data/doc/release_notes/5.19.0.txt +28 -0
- data/doc/release_notes/5.2.0.txt +33 -0
- data/doc/release_notes/5.20.0.txt +89 -0
- data/doc/release_notes/5.21.0.txt +87 -0
- data/doc/release_notes/5.22.0.txt +48 -0
- data/doc/release_notes/5.23.0.txt +56 -0
- data/doc/release_notes/5.24.0.txt +56 -0
- data/doc/release_notes/5.25.0.txt +32 -0
- data/doc/release_notes/5.26.0.txt +35 -0
- data/doc/release_notes/5.27.0.txt +21 -0
- data/doc/release_notes/5.28.0.txt +16 -0
- data/doc/release_notes/5.29.0.txt +22 -0
- data/doc/release_notes/5.3.0.txt +121 -0
- data/doc/release_notes/5.30.0.txt +20 -0
- data/doc/release_notes/5.31.0.txt +148 -0
- data/doc/release_notes/5.32.0.txt +46 -0
- data/doc/release_notes/5.33.0.txt +24 -0
- data/doc/release_notes/5.34.0.txt +40 -0
- data/doc/release_notes/5.35.0.txt +56 -0
- data/doc/release_notes/5.36.0.txt +60 -0
- data/doc/release_notes/5.37.0.txt +30 -0
- data/doc/release_notes/5.4.0.txt +80 -0
- data/doc/release_notes/5.5.0.txt +61 -0
- data/doc/release_notes/5.6.0.txt +31 -0
- data/doc/release_notes/5.7.0.txt +108 -0
- data/doc/release_notes/5.8.0.txt +170 -0
- data/doc/release_notes/5.9.0.txt +99 -0
- data/doc/schema_modification.rdoc +102 -77
- data/doc/security.rdoc +160 -87
- data/doc/sharding.rdoc +74 -47
- data/doc/sql.rdoc +135 -122
- data/doc/testing.rdoc +34 -18
- data/doc/thread_safety.rdoc +2 -4
- data/doc/transactions.rdoc +101 -19
- data/doc/validations.rdoc +64 -51
- data/doc/virtual_rows.rdoc +90 -109
- data/lib/sequel.rb +3 -1
- data/lib/sequel/adapters/ado.rb +154 -22
- data/lib/sequel/adapters/ado/access.rb +21 -21
- data/lib/sequel/adapters/ado/mssql.rb +8 -15
- data/lib/sequel/adapters/amalgalite.rb +17 -25
- data/lib/sequel/adapters/ibmdb.rb +52 -58
- data/lib/sequel/adapters/jdbc.rb +149 -127
- data/lib/sequel/adapters/jdbc/db2.rb +32 -40
- data/lib/sequel/adapters/jdbc/derby.rb +56 -58
- data/lib/sequel/adapters/jdbc/h2.rb +40 -30
- data/lib/sequel/adapters/jdbc/hsqldb.rb +22 -33
- data/lib/sequel/adapters/jdbc/jtds.rb +4 -10
- data/lib/sequel/adapters/jdbc/mssql.rb +6 -12
- data/lib/sequel/adapters/jdbc/mysql.rb +17 -18
- data/lib/sequel/adapters/jdbc/oracle.rb +25 -19
- data/lib/sequel/adapters/jdbc/postgresql.rb +90 -69
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +14 -24
- data/lib/sequel/adapters/jdbc/sqlite.rb +50 -12
- data/lib/sequel/adapters/jdbc/sqlserver.rb +36 -9
- data/lib/sequel/adapters/jdbc/transactions.rb +25 -39
- data/lib/sequel/adapters/mock.rb +104 -113
- data/lib/sequel/adapters/mysql.rb +42 -61
- data/lib/sequel/adapters/mysql2.rb +126 -35
- data/lib/sequel/adapters/odbc.rb +21 -28
- data/lib/sequel/adapters/odbc/db2.rb +3 -1
- data/lib/sequel/adapters/odbc/mssql.rb +11 -15
- data/lib/sequel/adapters/odbc/oracle.rb +11 -0
- data/lib/sequel/adapters/oracle.rb +62 -68
- data/lib/sequel/adapters/postgres.rb +257 -311
- data/lib/sequel/adapters/postgresql.rb +3 -1
- data/lib/sequel/adapters/shared/access.rb +75 -79
- data/lib/sequel/adapters/shared/db2.rb +96 -74
- data/lib/sequel/adapters/shared/mssql.rb +258 -213
- data/lib/sequel/adapters/shared/mysql.rb +284 -216
- data/lib/sequel/adapters/shared/oracle.rb +175 -60
- data/lib/sequel/adapters/shared/postgres.rb +829 -383
- data/lib/sequel/adapters/shared/sqlanywhere.rb +105 -127
- data/lib/sequel/adapters/shared/sqlite.rb +382 -159
- data/lib/sequel/adapters/sqlanywhere.rb +53 -38
- data/lib/sequel/adapters/sqlite.rb +111 -105
- data/lib/sequel/adapters/tinytds.rb +38 -46
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +8 -9
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +7 -5
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +87 -0
- data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +56 -0
- data/lib/sequel/adapters/utils/replace.rb +3 -4
- data/lib/sequel/adapters/utils/split_alter_table.rb +2 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +9 -22
- data/lib/sequel/adapters/utils/unmodified_identifiers.rb +28 -0
- data/lib/sequel/ast_transformer.rb +13 -89
- data/lib/sequel/connection_pool.rb +54 -26
- data/lib/sequel/connection_pool/sharded_single.rb +19 -12
- data/lib/sequel/connection_pool/sharded_threaded.rb +160 -111
- data/lib/sequel/connection_pool/single.rb +21 -12
- data/lib/sequel/connection_pool/threaded.rb +137 -119
- data/lib/sequel/core.rb +352 -320
- data/lib/sequel/database.rb +19 -2
- data/lib/sequel/database/connecting.rb +70 -55
- data/lib/sequel/database/dataset.rb +15 -5
- data/lib/sequel/database/dataset_defaults.rb +20 -102
- data/lib/sequel/database/features.rb +20 -4
- data/lib/sequel/database/logging.rb +25 -7
- data/lib/sequel/database/misc.rb +132 -118
- data/lib/sequel/database/query.rb +51 -28
- data/lib/sequel/database/schema_generator.rb +188 -75
- data/lib/sequel/database/schema_methods.rb +161 -92
- data/lib/sequel/database/transactions.rb +260 -58
- data/lib/sequel/dataset.rb +28 -12
- data/lib/sequel/dataset/actions.rb +354 -170
- data/lib/sequel/dataset/dataset_module.rb +46 -0
- data/lib/sequel/dataset/features.rb +81 -34
- data/lib/sequel/dataset/graph.rb +82 -58
- data/lib/sequel/dataset/misc.rb +139 -47
- data/lib/sequel/dataset/placeholder_literalizer.rb +66 -26
- data/lib/sequel/dataset/prepared_statements.rb +188 -85
- data/lib/sequel/dataset/query.rb +428 -214
- data/lib/sequel/dataset/sql.rb +446 -339
- data/lib/sequel/deprecated.rb +14 -2
- data/lib/sequel/exceptions.rb +48 -16
- data/lib/sequel/extensions/_model_constraint_validations.rb +16 -0
- data/lib/sequel/extensions/_model_pg_row.rb +43 -0
- data/lib/sequel/extensions/_pretty_table.rb +10 -9
- data/lib/sequel/extensions/any_not_empty.rb +45 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +15 -11
- data/lib/sequel/extensions/auto_literal_strings.rb +74 -0
- data/lib/sequel/extensions/blank.rb +2 -0
- data/lib/sequel/extensions/caller_logging.rb +79 -0
- data/lib/sequel/extensions/columns_introspection.rb +9 -4
- data/lib/sequel/extensions/connection_expiration.rb +99 -0
- data/lib/sequel/extensions/connection_validator.rb +26 -13
- data/lib/sequel/extensions/constant_sql_override.rb +65 -0
- data/lib/sequel/extensions/constraint_validations.rb +93 -38
- data/lib/sequel/extensions/core_extensions.rb +45 -53
- data/lib/sequel/extensions/core_refinements.rb +44 -46
- data/lib/sequel/extensions/current_datetime_timestamp.rb +5 -4
- data/lib/sequel/extensions/dataset_source_alias.rb +4 -0
- data/lib/sequel/extensions/date_arithmetic.rb +42 -16
- data/lib/sequel/extensions/datetime_parse_to_time.rb +37 -0
- data/lib/sequel/extensions/duplicate_columns_handler.rb +94 -0
- data/lib/sequel/extensions/empty_array_consider_nulls.rb +7 -3
- data/lib/sequel/extensions/error_sql.rb +7 -3
- data/lib/sequel/extensions/escaped_like.rb +100 -0
- data/lib/sequel/extensions/eval_inspect.rb +14 -15
- data/lib/sequel/extensions/exclude_or_null.rb +68 -0
- data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
- data/lib/sequel/extensions/freeze_datasets.rb +3 -0
- data/lib/sequel/extensions/from_block.rb +2 -31
- data/lib/sequel/extensions/graph_each.rb +19 -6
- data/lib/sequel/extensions/identifier_mangling.rb +180 -0
- data/lib/sequel/extensions/implicit_subquery.rb +48 -0
- data/lib/sequel/extensions/index_caching.rb +109 -0
- data/lib/sequel/extensions/inflector.rb +8 -4
- data/lib/sequel/extensions/integer64.rb +32 -0
- data/lib/sequel/extensions/looser_typecasting.rb +19 -9
- data/lib/sequel/extensions/migration.rb +132 -80
- data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +4 -0
- data/lib/sequel/extensions/named_timezones.rb +88 -23
- data/lib/sequel/extensions/no_auto_literal_strings.rb +4 -0
- data/lib/sequel/extensions/null_dataset.rb +12 -8
- data/lib/sequel/extensions/pagination.rb +35 -28
- data/lib/sequel/extensions/pg_array.rb +227 -316
- data/lib/sequel/extensions/pg_array_ops.rb +19 -7
- data/lib/sequel/extensions/pg_enum.rb +69 -24
- data/lib/sequel/extensions/pg_extended_date_support.rb +250 -0
- data/lib/sequel/extensions/pg_hstore.rb +50 -59
- data/lib/sequel/extensions/pg_hstore_ops.rb +9 -3
- data/lib/sequel/extensions/pg_inet.rb +34 -15
- data/lib/sequel/extensions/pg_inet_ops.rb +5 -1
- data/lib/sequel/extensions/pg_interval.rb +26 -26
- data/lib/sequel/extensions/pg_json.rb +422 -141
- data/lib/sequel/extensions/pg_json_ops.rb +248 -9
- data/lib/sequel/extensions/pg_loose_count.rb +5 -1
- data/lib/sequel/extensions/pg_range.rb +162 -146
- data/lib/sequel/extensions/pg_range_ops.rb +10 -5
- data/lib/sequel/extensions/pg_row.rb +53 -87
- data/lib/sequel/extensions/pg_row_ops.rb +36 -13
- data/lib/sequel/extensions/pg_static_cache_updater.rb +6 -2
- data/lib/sequel/extensions/pg_timestamptz.rb +28 -0
- data/lib/sequel/extensions/pretty_table.rb +4 -0
- data/lib/sequel/extensions/query.rb +12 -7
- data/lib/sequel/extensions/round_timestamps.rb +6 -9
- data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
- data/lib/sequel/extensions/s.rb +59 -0
- data/lib/sequel/extensions/schema_caching.rb +14 -1
- data/lib/sequel/extensions/schema_dumper.rb +83 -55
- data/lib/sequel/extensions/select_remove.rb +8 -4
- data/lib/sequel/extensions/sequel_4_dataset_methods.rb +85 -0
- data/lib/sequel/extensions/server_block.rb +50 -17
- data/lib/sequel/extensions/server_logging.rb +61 -0
- data/lib/sequel/extensions/split_array_nil.rb +8 -4
- data/lib/sequel/extensions/sql_comments.rb +96 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -1
- data/lib/sequel/extensions/string_agg.rb +181 -0
- data/lib/sequel/extensions/string_date_time.rb +2 -0
- data/lib/sequel/extensions/symbol_aref.rb +53 -0
- data/lib/sequel/extensions/symbol_aref_refinement.rb +43 -0
- data/lib/sequel/extensions/symbol_as.rb +23 -0
- data/lib/sequel/extensions/symbol_as_refinement.rb +37 -0
- data/lib/sequel/extensions/synchronize_sql.rb +45 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +4 -0
- data/lib/sequel/extensions/to_dot.rb +15 -5
- data/lib/sequel/extensions/virtual_row_method_block.rb +44 -0
- data/lib/sequel/model.rb +36 -126
- data/lib/sequel/model/associations.rb +850 -257
- data/lib/sequel/model/base.rb +652 -764
- data/lib/sequel/model/dataset_module.rb +13 -10
- data/lib/sequel/model/default_inflections.rb +3 -1
- data/lib/sequel/model/errors.rb +3 -3
- data/lib/sequel/model/exceptions.rb +12 -12
- data/lib/sequel/model/inflections.rb +8 -19
- data/lib/sequel/model/plugins.rb +111 -0
- data/lib/sequel/plugins/accessed_columns.rb +2 -0
- data/lib/sequel/plugins/active_model.rb +32 -7
- data/lib/sequel/plugins/after_initialize.rb +3 -1
- data/lib/sequel/plugins/association_dependencies.rb +27 -18
- data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
- data/lib/sequel/plugins/association_multi_add_remove.rb +85 -0
- data/lib/sequel/plugins/association_pks.rb +181 -83
- data/lib/sequel/plugins/association_proxies.rb +33 -9
- data/lib/sequel/plugins/auto_validations.rb +58 -23
- data/lib/sequel/plugins/before_after_save.rb +8 -0
- data/lib/sequel/plugins/blacklist_security.rb +23 -12
- data/lib/sequel/plugins/boolean_readers.rb +9 -6
- data/lib/sequel/plugins/boolean_subsets.rb +64 -0
- data/lib/sequel/plugins/caching.rb +27 -16
- data/lib/sequel/plugins/class_table_inheritance.rb +192 -94
- data/lib/sequel/plugins/column_conflicts.rb +18 -3
- data/lib/sequel/plugins/column_select.rb +9 -5
- data/lib/sequel/plugins/columns_updated.rb +42 -0
- data/lib/sequel/plugins/composition.rb +36 -24
- data/lib/sequel/plugins/constraint_validations.rb +37 -16
- data/lib/sequel/plugins/csv_serializer.rb +58 -35
- data/lib/sequel/plugins/dataset_associations.rb +60 -18
- data/lib/sequel/plugins/def_dataset_method.rb +90 -0
- data/lib/sequel/plugins/defaults_setter.rb +74 -13
- data/lib/sequel/plugins/delay_add_association.rb +4 -1
- data/lib/sequel/plugins/dirty.rb +65 -24
- data/lib/sequel/plugins/eager_each.rb +27 -3
- data/lib/sequel/plugins/eager_graph_eager.rb +139 -0
- data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
- data/lib/sequel/plugins/error_splitter.rb +19 -12
- data/lib/sequel/plugins/finder.rb +246 -0
- data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
- data/lib/sequel/plugins/force_encoding.rb +9 -12
- data/lib/sequel/plugins/hook_class_methods.rb +39 -54
- data/lib/sequel/plugins/input_transformer.rb +20 -10
- data/lib/sequel/plugins/insert_conflict.rb +72 -0
- data/lib/sequel/plugins/insert_returning_select.rb +4 -2
- data/lib/sequel/plugins/instance_filters.rb +12 -8
- data/lib/sequel/plugins/instance_hooks.rb +36 -17
- data/lib/sequel/plugins/instance_specific_default.rb +113 -0
- data/lib/sequel/plugins/inverted_subsets.rb +24 -13
- data/lib/sequel/plugins/json_serializer.rb +123 -47
- data/lib/sequel/plugins/lazy_attributes.rb +20 -14
- data/lib/sequel/plugins/list.rb +40 -26
- data/lib/sequel/plugins/many_through_many.rb +28 -12
- data/lib/sequel/plugins/modification_detection.rb +17 -5
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -5
- data/lib/sequel/plugins/nested_attributes.rb +55 -28
- data/lib/sequel/plugins/optimistic_locking.rb +5 -3
- data/lib/sequel/plugins/pg_array_associations.rb +52 -18
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +348 -0
- data/lib/sequel/plugins/pg_row.rb +7 -51
- data/lib/sequel/plugins/prepared_statements.rb +53 -72
- data/lib/sequel/plugins/prepared_statements_safe.rb +13 -5
- data/lib/sequel/plugins/rcte_tree.rb +43 -63
- data/lib/sequel/plugins/serialization.rb +37 -44
- data/lib/sequel/plugins/serialization_modification_detection.rb +3 -1
- data/lib/sequel/plugins/sharding.rb +17 -10
- data/lib/sequel/plugins/single_table_inheritance.rb +62 -28
- data/lib/sequel/plugins/singular_table_names.rb +2 -0
- data/lib/sequel/plugins/skip_create_refresh.rb +5 -3
- data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
- data/lib/sequel/plugins/split_values.rb +13 -6
- data/lib/sequel/plugins/static_cache.rb +79 -53
- data/lib/sequel/plugins/static_cache_cache.rb +53 -0
- data/lib/sequel/plugins/string_stripper.rb +5 -3
- data/lib/sequel/plugins/subclasses.rb +20 -2
- data/lib/sequel/plugins/subset_conditions.rb +48 -0
- data/lib/sequel/plugins/table_select.rb +4 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +120 -6
- data/lib/sequel/plugins/throw_failures.rb +110 -0
- data/lib/sequel/plugins/timestamps.rb +22 -8
- data/lib/sequel/plugins/touch.rb +21 -8
- data/lib/sequel/plugins/tree.rb +57 -30
- data/lib/sequel/plugins/typecast_on_load.rb +14 -4
- data/lib/sequel/plugins/unlimited_update.rb +3 -7
- data/lib/sequel/plugins/update_or_create.rb +6 -4
- data/lib/sequel/plugins/update_primary_key.rb +3 -1
- data/lib/sequel/plugins/update_refresh.rb +28 -15
- data/lib/sequel/plugins/uuid.rb +70 -0
- data/lib/sequel/plugins/validate_associated.rb +20 -0
- data/lib/sequel/plugins/validation_class_methods.rb +40 -19
- data/lib/sequel/plugins/validation_contexts.rb +49 -0
- data/lib/sequel/plugins/validation_helpers.rb +49 -31
- data/lib/sequel/plugins/whitelist_security.rb +122 -0
- data/lib/sequel/plugins/xml_serializer.rb +31 -30
- data/lib/sequel/sql.rb +479 -329
- data/lib/sequel/timezones.rb +62 -32
- data/lib/sequel/version.rb +10 -3
- metadata +177 -477
- data/Rakefile +0 -165
- data/doc/active_record.rdoc +0 -912
- data/doc/release_notes/1.0.txt +0 -38
- data/doc/release_notes/1.1.txt +0 -143
- data/doc/release_notes/1.3.txt +0 -101
- data/doc/release_notes/1.4.0.txt +0 -53
- data/doc/release_notes/1.5.0.txt +0 -155
- data/doc/release_notes/2.0.0.txt +0 -298
- data/doc/release_notes/2.1.0.txt +0 -271
- data/doc/release_notes/2.10.0.txt +0 -328
- data/doc/release_notes/2.11.0.txt +0 -215
- data/doc/release_notes/2.12.0.txt +0 -534
- data/doc/release_notes/2.2.0.txt +0 -253
- data/doc/release_notes/2.3.0.txt +0 -88
- data/doc/release_notes/2.4.0.txt +0 -106
- data/doc/release_notes/2.5.0.txt +0 -137
- data/doc/release_notes/2.6.0.txt +0 -157
- data/doc/release_notes/2.7.0.txt +0 -166
- data/doc/release_notes/2.8.0.txt +0 -171
- data/doc/release_notes/2.9.0.txt +0 -97
- data/doc/release_notes/3.0.0.txt +0 -221
- data/doc/release_notes/3.1.0.txt +0 -406
- data/doc/release_notes/3.10.0.txt +0 -286
- data/doc/release_notes/3.11.0.txt +0 -254
- data/doc/release_notes/3.12.0.txt +0 -304
- data/doc/release_notes/3.13.0.txt +0 -210
- data/doc/release_notes/3.14.0.txt +0 -118
- data/doc/release_notes/3.15.0.txt +0 -78
- data/doc/release_notes/3.16.0.txt +0 -45
- data/doc/release_notes/3.17.0.txt +0 -58
- data/doc/release_notes/3.18.0.txt +0 -120
- data/doc/release_notes/3.19.0.txt +0 -67
- data/doc/release_notes/3.2.0.txt +0 -268
- data/doc/release_notes/3.20.0.txt +0 -41
- data/doc/release_notes/3.21.0.txt +0 -87
- data/doc/release_notes/3.22.0.txt +0 -39
- data/doc/release_notes/3.23.0.txt +0 -172
- data/doc/release_notes/3.24.0.txt +0 -420
- data/doc/release_notes/3.25.0.txt +0 -88
- data/doc/release_notes/3.26.0.txt +0 -88
- data/doc/release_notes/3.27.0.txt +0 -82
- data/doc/release_notes/3.28.0.txt +0 -304
- data/doc/release_notes/3.29.0.txt +0 -459
- data/doc/release_notes/3.3.0.txt +0 -192
- data/doc/release_notes/3.30.0.txt +0 -135
- data/doc/release_notes/3.31.0.txt +0 -146
- data/doc/release_notes/3.32.0.txt +0 -202
- data/doc/release_notes/3.33.0.txt +0 -157
- data/doc/release_notes/3.34.0.txt +0 -671
- data/doc/release_notes/3.35.0.txt +0 -144
- data/doc/release_notes/3.36.0.txt +0 -245
- data/doc/release_notes/3.37.0.txt +0 -338
- data/doc/release_notes/3.38.0.txt +0 -234
- data/doc/release_notes/3.39.0.txt +0 -237
- data/doc/release_notes/3.4.0.txt +0 -325
- data/doc/release_notes/3.40.0.txt +0 -73
- data/doc/release_notes/3.41.0.txt +0 -155
- data/doc/release_notes/3.42.0.txt +0 -74
- data/doc/release_notes/3.43.0.txt +0 -105
- data/doc/release_notes/3.44.0.txt +0 -152
- data/doc/release_notes/3.45.0.txt +0 -179
- data/doc/release_notes/3.46.0.txt +0 -122
- data/doc/release_notes/3.47.0.txt +0 -270
- data/doc/release_notes/3.48.0.txt +0 -477
- data/doc/release_notes/3.5.0.txt +0 -510
- data/doc/release_notes/3.6.0.txt +0 -366
- data/doc/release_notes/3.7.0.txt +0 -179
- data/doc/release_notes/3.8.0.txt +0 -151
- data/doc/release_notes/3.9.0.txt +0 -233
- data/doc/release_notes/4.0.0.txt +0 -262
- data/doc/release_notes/4.1.0.txt +0 -85
- data/doc/release_notes/4.10.0.txt +0 -226
- data/doc/release_notes/4.11.0.txt +0 -147
- data/doc/release_notes/4.12.0.txt +0 -105
- data/doc/release_notes/4.13.0.txt +0 -169
- data/doc/release_notes/4.14.0.txt +0 -68
- data/doc/release_notes/4.15.0.txt +0 -56
- data/doc/release_notes/4.16.0.txt +0 -36
- data/doc/release_notes/4.17.0.txt +0 -38
- data/doc/release_notes/4.18.0.txt +0 -36
- data/doc/release_notes/4.19.0.txt +0 -45
- data/doc/release_notes/4.2.0.txt +0 -129
- data/doc/release_notes/4.20.0.txt +0 -79
- data/doc/release_notes/4.21.0.txt +0 -94
- data/doc/release_notes/4.22.0.txt +0 -72
- data/doc/release_notes/4.23.0.txt +0 -65
- data/doc/release_notes/4.24.0.txt +0 -99
- data/doc/release_notes/4.25.0.txt +0 -181
- data/doc/release_notes/4.26.0.txt +0 -44
- data/doc/release_notes/4.3.0.txt +0 -40
- data/doc/release_notes/4.4.0.txt +0 -92
- data/doc/release_notes/4.5.0.txt +0 -34
- data/doc/release_notes/4.6.0.txt +0 -30
- data/doc/release_notes/4.7.0.txt +0 -103
- data/doc/release_notes/4.8.0.txt +0 -175
- data/doc/release_notes/4.9.0.txt +0 -190
- data/lib/sequel/adapters/cubrid.rb +0 -142
- data/lib/sequel/adapters/do.rb +0 -156
- data/lib/sequel/adapters/do/mysql.rb +0 -64
- data/lib/sequel/adapters/do/postgres.rb +0 -42
- data/lib/sequel/adapters/do/sqlite3.rb +0 -40
- data/lib/sequel/adapters/jdbc/as400.rb +0 -82
- data/lib/sequel/adapters/jdbc/cubrid.rb +0 -62
- data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -34
- data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -31
- data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -31
- data/lib/sequel/adapters/odbc/progress.rb +0 -8
- data/lib/sequel/adapters/shared/cubrid.rb +0 -243
- data/lib/sequel/adapters/shared/firebird.rb +0 -245
- data/lib/sequel/adapters/shared/informix.rb +0 -52
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +0 -150
- data/lib/sequel/adapters/shared/progress.rb +0 -38
- data/lib/sequel/adapters/swift.rb +0 -158
- data/lib/sequel/adapters/swift/mysql.rb +0 -47
- data/lib/sequel/adapters/swift/postgres.rb +0 -45
- data/lib/sequel/adapters/swift/sqlite.rb +0 -47
- data/lib/sequel/adapters/utils/pg_types.rb +0 -68
- data/lib/sequel/dataset/mutation.rb +0 -109
- data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -3
- data/lib/sequel/extensions/filter_having.rb +0 -59
- data/lib/sequel/extensions/hash_aliases.rb +0 -45
- data/lib/sequel/extensions/meta_def.rb +0 -31
- data/lib/sequel/extensions/query_literals.rb +0 -80
- data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -22
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -118
- data/lib/sequel/extensions/set_overrides.rb +0 -72
- data/lib/sequel/no_core_ext.rb +0 -1
- data/lib/sequel/plugins/association_autoreloading.rb +0 -7
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -7
- data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -78
- data/lib/sequel/plugins/prepared_statements_associations.rb +0 -117
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -59
- data/lib/sequel/plugins/schema.rb +0 -80
- data/lib/sequel/plugins/scissors.rb +0 -33
- data/spec/adapters/db2_spec.rb +0 -160
- data/spec/adapters/firebird_spec.rb +0 -411
- data/spec/adapters/informix_spec.rb +0 -100
- data/spec/adapters/mssql_spec.rb +0 -706
- data/spec/adapters/mysql_spec.rb +0 -1287
- data/spec/adapters/oracle_spec.rb +0 -313
- data/spec/adapters/postgres_spec.rb +0 -3725
- data/spec/adapters/spec_helper.rb +0 -43
- data/spec/adapters/sqlanywhere_spec.rb +0 -170
- data/spec/adapters/sqlite_spec.rb +0 -653
- data/spec/bin_spec.rb +0 -254
- data/spec/core/connection_pool_spec.rb +0 -1016
- data/spec/core/database_spec.rb +0 -2531
- data/spec/core/dataset_spec.rb +0 -5098
- data/spec/core/deprecated_spec.rb +0 -70
- data/spec/core/expression_filters_spec.rb +0 -1243
- data/spec/core/mock_adapter_spec.rb +0 -462
- data/spec/core/object_graph_spec.rb +0 -303
- data/spec/core/placeholder_literalizer_spec.rb +0 -163
- data/spec/core/schema_generator_spec.rb +0 -179
- data/spec/core/schema_spec.rb +0 -1659
- data/spec/core/spec_helper.rb +0 -34
- data/spec/core/version_spec.rb +0 -7
- data/spec/core_extensions_spec.rb +0 -699
- data/spec/extensions/accessed_columns_spec.rb +0 -51
- data/spec/extensions/active_model_spec.rb +0 -123
- data/spec/extensions/after_initialize_spec.rb +0 -24
- data/spec/extensions/arbitrary_servers_spec.rb +0 -109
- data/spec/extensions/association_dependencies_spec.rb +0 -117
- data/spec/extensions/association_pks_spec.rb +0 -365
- data/spec/extensions/association_proxies_spec.rb +0 -86
- data/spec/extensions/auto_validations_spec.rb +0 -192
- data/spec/extensions/blacklist_security_spec.rb +0 -88
- data/spec/extensions/blank_spec.rb +0 -69
- data/spec/extensions/boolean_readers_spec.rb +0 -93
- data/spec/extensions/caching_spec.rb +0 -270
- data/spec/extensions/class_table_inheritance_spec.rb +0 -420
- data/spec/extensions/column_conflicts_spec.rb +0 -60
- data/spec/extensions/column_select_spec.rb +0 -108
- data/spec/extensions/columns_introspection_spec.rb +0 -91
- data/spec/extensions/composition_spec.rb +0 -242
- data/spec/extensions/connection_validator_spec.rb +0 -120
- data/spec/extensions/constraint_validations_plugin_spec.rb +0 -274
- data/spec/extensions/constraint_validations_spec.rb +0 -325
- data/spec/extensions/core_refinements_spec.rb +0 -519
- data/spec/extensions/csv_serializer_spec.rb +0 -173
- data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
- data/spec/extensions/dataset_associations_spec.rb +0 -311
- data/spec/extensions/dataset_source_alias_spec.rb +0 -51
- data/spec/extensions/date_arithmetic_spec.rb +0 -150
- data/spec/extensions/defaults_setter_spec.rb +0 -101
- data/spec/extensions/delay_add_association_spec.rb +0 -52
- data/spec/extensions/dirty_spec.rb +0 -180
- data/spec/extensions/eager_each_spec.rb +0 -42
- data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
- data/spec/extensions/error_splitter_spec.rb +0 -18
- data/spec/extensions/error_sql_spec.rb +0 -20
- data/spec/extensions/eval_inspect_spec.rb +0 -73
- data/spec/extensions/filter_having_spec.rb +0 -40
- data/spec/extensions/force_encoding_spec.rb +0 -114
- data/spec/extensions/from_block_spec.rb +0 -21
- data/spec/extensions/graph_each_spec.rb +0 -109
- data/spec/extensions/hash_aliases_spec.rb +0 -24
- data/spec/extensions/hook_class_methods_spec.rb +0 -429
- data/spec/extensions/inflector_spec.rb +0 -183
- data/spec/extensions/input_transformer_spec.rb +0 -54
- data/spec/extensions/insert_returning_select_spec.rb +0 -46
- data/spec/extensions/instance_filters_spec.rb +0 -79
- data/spec/extensions/instance_hooks_spec.rb +0 -276
- data/spec/extensions/inverted_subsets_spec.rb +0 -33
- data/spec/extensions/json_serializer_spec.rb +0 -291
- data/spec/extensions/lazy_attributes_spec.rb +0 -170
- data/spec/extensions/list_spec.rb +0 -267
- data/spec/extensions/looser_typecasting_spec.rb +0 -43
- data/spec/extensions/many_through_many_spec.rb +0 -2172
- data/spec/extensions/meta_def_spec.rb +0 -21
- data/spec/extensions/migration_spec.rb +0 -712
- data/spec/extensions/modification_detection_spec.rb +0 -80
- data/spec/extensions/mssql_optimistic_locking_spec.rb +0 -91
- data/spec/extensions/named_timezones_spec.rb +0 -108
- data/spec/extensions/nested_attributes_spec.rb +0 -697
- data/spec/extensions/null_dataset_spec.rb +0 -85
- data/spec/extensions/optimistic_locking_spec.rb +0 -128
- data/spec/extensions/pagination_spec.rb +0 -118
- data/spec/extensions/pg_array_associations_spec.rb +0 -736
- data/spec/extensions/pg_array_ops_spec.rb +0 -143
- data/spec/extensions/pg_array_spec.rb +0 -395
- data/spec/extensions/pg_enum_spec.rb +0 -92
- data/spec/extensions/pg_hstore_ops_spec.rb +0 -236
- data/spec/extensions/pg_hstore_spec.rb +0 -206
- data/spec/extensions/pg_inet_ops_spec.rb +0 -101
- data/spec/extensions/pg_inet_spec.rb +0 -52
- data/spec/extensions/pg_interval_spec.rb +0 -76
- data/spec/extensions/pg_json_ops_spec.rb +0 -229
- data/spec/extensions/pg_json_spec.rb +0 -218
- data/spec/extensions/pg_loose_count_spec.rb +0 -17
- data/spec/extensions/pg_range_ops_spec.rb +0 -58
- data/spec/extensions/pg_range_spec.rb +0 -404
- data/spec/extensions/pg_row_ops_spec.rb +0 -60
- data/spec/extensions/pg_row_plugin_spec.rb +0 -62
- data/spec/extensions/pg_row_spec.rb +0 -360
- data/spec/extensions/pg_static_cache_updater_spec.rb +0 -92
- data/spec/extensions/pg_typecast_on_load_spec.rb +0 -63
- data/spec/extensions/prepared_statements_associations_spec.rb +0 -159
- data/spec/extensions/prepared_statements_safe_spec.rb +0 -61
- data/spec/extensions/prepared_statements_spec.rb +0 -103
- data/spec/extensions/prepared_statements_with_pk_spec.rb +0 -31
- data/spec/extensions/pretty_table_spec.rb +0 -92
- data/spec/extensions/query_literals_spec.rb +0 -183
- data/spec/extensions/query_spec.rb +0 -102
- data/spec/extensions/rcte_tree_spec.rb +0 -392
- data/spec/extensions/round_timestamps_spec.rb +0 -43
- data/spec/extensions/schema_caching_spec.rb +0 -41
- data/spec/extensions/schema_dumper_spec.rb +0 -789
- data/spec/extensions/schema_spec.rb +0 -117
- data/spec/extensions/scissors_spec.rb +0 -26
- data/spec/extensions/select_remove_spec.rb +0 -38
- data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -101
- data/spec/extensions/serialization_modification_detection_spec.rb +0 -98
- data/spec/extensions/serialization_spec.rb +0 -362
- data/spec/extensions/server_block_spec.rb +0 -90
- data/spec/extensions/set_overrides_spec.rb +0 -61
- data/spec/extensions/sharding_spec.rb +0 -198
- data/spec/extensions/shared_caching_spec.rb +0 -175
- data/spec/extensions/single_table_inheritance_spec.rb +0 -297
- data/spec/extensions/singular_table_names_spec.rb +0 -22
- data/spec/extensions/skip_create_refresh_spec.rb +0 -17
- data/spec/extensions/spec_helper.rb +0 -71
- data/spec/extensions/split_array_nil_spec.rb +0 -24
- data/spec/extensions/split_values_spec.rb +0 -22
- data/spec/extensions/sql_expr_spec.rb +0 -60
- data/spec/extensions/static_cache_spec.rb +0 -361
- data/spec/extensions/string_date_time_spec.rb +0 -95
- data/spec/extensions/string_stripper_spec.rb +0 -68
- data/spec/extensions/subclasses_spec.rb +0 -66
- data/spec/extensions/table_select_spec.rb +0 -71
- data/spec/extensions/tactical_eager_loading_spec.rb +0 -82
- data/spec/extensions/thread_local_timezones_spec.rb +0 -67
- data/spec/extensions/timestamps_spec.rb +0 -175
- data/spec/extensions/to_dot_spec.rb +0 -154
- data/spec/extensions/touch_spec.rb +0 -203
- data/spec/extensions/tree_spec.rb +0 -274
- data/spec/extensions/typecast_on_load_spec.rb +0 -80
- data/spec/extensions/unlimited_update_spec.rb +0 -20
- data/spec/extensions/update_or_create_spec.rb +0 -87
- data/spec/extensions/update_primary_key_spec.rb +0 -100
- data/spec/extensions/update_refresh_spec.rb +0 -53
- data/spec/extensions/validate_associated_spec.rb +0 -52
- data/spec/extensions/validation_class_methods_spec.rb +0 -1027
- data/spec/extensions/validation_helpers_spec.rb +0 -541
- data/spec/extensions/xml_serializer_spec.rb +0 -207
- data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
- data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
- data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
- data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
- data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
- data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
- data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
- data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
- data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
- data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
- data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
- data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
- data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
- data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
- data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
- data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
- data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
- data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
- data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
- data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
- data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
- data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
- data/spec/files/reversible_migrations/001_reversible.rb +0 -5
- data/spec/files/reversible_migrations/002_reversible.rb +0 -5
- data/spec/files/reversible_migrations/003_reversible.rb +0 -5
- data/spec/files/reversible_migrations/004_reversible.rb +0 -5
- data/spec/files/reversible_migrations/005_reversible.rb +0 -10
- data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
- data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
- data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
- data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
- data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
- data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
- data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
- data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
- data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
- data/spec/guards_helper.rb +0 -55
- data/spec/integration/associations_test.rb +0 -2454
- data/spec/integration/database_test.rb +0 -113
- data/spec/integration/dataset_test.rb +0 -1808
- data/spec/integration/eager_loader_test.rb +0 -687
- data/spec/integration/migrator_test.rb +0 -240
- data/spec/integration/model_test.rb +0 -226
- data/spec/integration/plugin_test.rb +0 -2240
- data/spec/integration/prepared_statement_test.rb +0 -467
- data/spec/integration/schema_test.rb +0 -817
- data/spec/integration/spec_helper.rb +0 -48
- data/spec/integration/timezone_test.rb +0 -86
- data/spec/integration/transaction_test.rb +0 -374
- data/spec/integration/type_test.rb +0 -133
- data/spec/model/association_reflection_spec.rb +0 -525
- data/spec/model/associations_spec.rb +0 -4426
- data/spec/model/base_spec.rb +0 -759
- data/spec/model/class_dataset_methods_spec.rb +0 -146
- data/spec/model/dataset_methods_spec.rb +0 -149
- data/spec/model/eager_loading_spec.rb +0 -2137
- data/spec/model/hooks_spec.rb +0 -604
- data/spec/model/inflector_spec.rb +0 -26
- data/spec/model/model_spec.rb +0 -982
- data/spec/model/plugins_spec.rb +0 -299
- data/spec/model/record_spec.rb +0 -2147
- data/spec/model/spec_helper.rb +0 -46
- data/spec/model/validations_spec.rb +0 -193
- data/spec/sequel_coverage.rb +0 -15
- data/spec/spec_config.rb +0 -10
|
@@ -1,52 +1,26 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
1
3
|
module Sequel
|
|
2
4
|
module SqlAnywhere
|
|
3
|
-
|
|
4
|
-
@convert_smallint_to_bool = true
|
|
5
|
-
|
|
6
|
-
class << self
|
|
7
|
-
# Whether to convert smallint values to bool, false by default.
|
|
8
|
-
# Can also be overridden per dataset.
|
|
9
|
-
attr_accessor :convert_smallint_to_bool
|
|
10
|
-
end
|
|
5
|
+
Sequel::Database.set_shared_adapter_scheme(:sqlanywhere, self)
|
|
11
6
|
|
|
12
7
|
module DatabaseMethods
|
|
13
|
-
extend Sequel::Database::ResetIdentifierMangling
|
|
14
|
-
|
|
15
8
|
attr_reader :conversion_procs
|
|
16
9
|
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
AUTO_INCREMENT = 'IDENTITY'.freeze
|
|
21
|
-
SQL_BEGIN = "BEGIN TRANSACTION".freeze
|
|
22
|
-
SQL_COMMIT = "COMMIT TRANSACTION".freeze
|
|
23
|
-
SQL_ROLLBACK = "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION".freeze
|
|
24
|
-
TEMPORARY = "GLOBAL TEMPORARY ".freeze
|
|
25
|
-
SMALLINT_RE = /smallint/i.freeze
|
|
26
|
-
DECIMAL_TYPE_RE = /numeric/io
|
|
27
|
-
|
|
28
|
-
# Whether to convert smallint to boolean arguments for this dataset.
|
|
29
|
-
# Defaults to the SqlAnywhere module setting.
|
|
30
|
-
def convert_smallint_to_bool
|
|
31
|
-
defined?(@convert_smallint_to_bool) ? @convert_smallint_to_bool : (@convert_smallint_to_bool = ::Sequel::SqlAnywhere.convert_smallint_to_bool)
|
|
32
|
-
end
|
|
10
|
+
# Set whether to convert smallint type to boolean for this Database instance
|
|
11
|
+
attr_accessor :convert_smallint_to_bool
|
|
33
12
|
|
|
34
|
-
# Sysbase Server uses the :sqlanywhere type.
|
|
35
13
|
def database_type
|
|
36
14
|
:sqlanywhere
|
|
37
15
|
end
|
|
38
16
|
|
|
39
|
-
def
|
|
40
|
-
|
|
17
|
+
def freeze
|
|
18
|
+
@conversion_procs.freeze
|
|
19
|
+
super
|
|
41
20
|
end
|
|
42
21
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if convert_smallint_to_bool && db_type =~ SMALLINT_RE
|
|
46
|
-
:boolean
|
|
47
|
-
else
|
|
48
|
-
super
|
|
49
|
-
end
|
|
22
|
+
def to_application_timestamp_sa(v)
|
|
23
|
+
to_application_timestamp(v.to_s) if v
|
|
50
24
|
end
|
|
51
25
|
|
|
52
26
|
def schema_parse_table(table, opts)
|
|
@@ -54,15 +28,15 @@ module Sequel
|
|
|
54
28
|
im = input_identifier_meth(opts[:dataset])
|
|
55
29
|
metadata_dataset.
|
|
56
30
|
from{sa_describe_query("select * from #{im.call(table)}").as(:a)}.
|
|
57
|
-
join(:
|
|
58
|
-
order
|
|
31
|
+
join(Sequel[:syscolumn].as(:b), :table_id=>:base_table_id, :column_id=>:base_column_id).
|
|
32
|
+
order{a[:column_number]}.
|
|
59
33
|
map do |row|
|
|
60
34
|
auto_increment = row.delete(:is_autoincrement)
|
|
61
35
|
row[:auto_increment] = auto_increment == 1 || auto_increment == true
|
|
62
36
|
row[:primary_key] = row.delete(:pkey) == 'Y'
|
|
63
|
-
row[:allow_null] = row[:nulls_allowed].is_a?(
|
|
37
|
+
row[:allow_null] = row[:nulls_allowed].is_a?(Integer) ? row.delete(:nulls_allowed) == 1 : row.delete(:nulls_allowed)
|
|
64
38
|
row[:db_type] = row.delete(:domain_name)
|
|
65
|
-
row[:type] = if row[:db_type] =~
|
|
39
|
+
row[:type] = if row[:db_type] =~ /numeric/i and (row[:scale].is_a?(Integer) ? row[:scale] == 0 : !row[:scale])
|
|
66
40
|
:integer
|
|
67
41
|
else
|
|
68
42
|
schema_column_type(row[:db_type])
|
|
@@ -75,13 +49,18 @@ module Sequel
|
|
|
75
49
|
def indexes(table, opts = OPTS)
|
|
76
50
|
m = output_identifier_meth
|
|
77
51
|
im = input_identifier_meth
|
|
52
|
+
table = table.value if table.is_a?(Sequel::SQL::Identifier)
|
|
78
53
|
indexes = {}
|
|
79
54
|
metadata_dataset.
|
|
80
|
-
from(:
|
|
81
|
-
select
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
55
|
+
from(Sequel[:dbo][:sysobjects].as(:z)).
|
|
56
|
+
select{[
|
|
57
|
+
z[:name].as(:table_name),
|
|
58
|
+
i[:name].as(:index_name),
|
|
59
|
+
si[:indextype].as(:type),
|
|
60
|
+
si[:colnames].as(:columns)]}.
|
|
61
|
+
join(Sequel[:dbo][:sysindexes].as(:i), :id=>:id).
|
|
62
|
+
join(Sequel[:sys][:sysindexes].as(:si), :iname=> :name).
|
|
63
|
+
where{{z[:type] => 'U', :table_name=>im.call(table)}}.
|
|
85
64
|
each do |r|
|
|
86
65
|
indexes[m.call(r[:index_name])] =
|
|
87
66
|
{:unique=>(r[:type].downcase=='unique'),
|
|
@@ -95,11 +74,16 @@ module Sequel
|
|
|
95
74
|
im = input_identifier_meth
|
|
96
75
|
fk_indexes = {}
|
|
97
76
|
metadata_dataset.
|
|
98
|
-
from(:
|
|
99
|
-
select
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
77
|
+
from{sys[:sysforeignkey].as(:fk)}.
|
|
78
|
+
select{[
|
|
79
|
+
fk[:role].as(:name),
|
|
80
|
+
fks[:columns].as(:column_map),
|
|
81
|
+
si[:indextype].as(:type),
|
|
82
|
+
si[:colnames].as(:columns),
|
|
83
|
+
fks[:primary_tname].as(:table_name)]}.
|
|
84
|
+
join(Sequel[:sys][:sysforeignkeys].as(:fks), :role => :role).
|
|
85
|
+
join(Sequel[:sys][:sysindexes].as(:si), {:iname => Sequel[:fk][:role]}, {:implicit_qualifier => :fk}).
|
|
86
|
+
where{{fks[:foreign_tname]=>im.call(table)}}.
|
|
103
87
|
each do |r|
|
|
104
88
|
unless r[:type].downcase == 'primary key'
|
|
105
89
|
fk_indexes[r[:name]] =
|
|
@@ -136,27 +120,28 @@ module Sequel
|
|
|
136
120
|
|
|
137
121
|
# Sybase uses the IDENTITY column for autoincrementing columns.
|
|
138
122
|
def auto_increment_sql
|
|
139
|
-
|
|
123
|
+
'IDENTITY'
|
|
140
124
|
end
|
|
141
125
|
|
|
142
|
-
#
|
|
126
|
+
# Sybase does not allow adding primary key constraints to NULLable columns.
|
|
127
|
+
def can_add_primary_key_constraint_on_nullable_columns?
|
|
128
|
+
false
|
|
129
|
+
end
|
|
130
|
+
|
|
143
131
|
def temporary_table_sql
|
|
144
|
-
TEMPORARY
|
|
132
|
+
"GLOBAL TEMPORARY "
|
|
145
133
|
end
|
|
146
134
|
|
|
147
|
-
# SQL to BEGIN a transaction.
|
|
148
135
|
def begin_transaction_sql
|
|
149
|
-
|
|
136
|
+
"BEGIN TRANSACTION"
|
|
150
137
|
end
|
|
151
138
|
|
|
152
|
-
# SQL to ROLLBACK a transaction.
|
|
153
139
|
def rollback_transaction_sql
|
|
154
|
-
|
|
140
|
+
"IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION"
|
|
155
141
|
end
|
|
156
142
|
|
|
157
|
-
# SQL to COMMIT a transaction.
|
|
158
143
|
def commit_transaction_sql
|
|
159
|
-
|
|
144
|
+
"COMMIT TRANSACTION"
|
|
160
145
|
end
|
|
161
146
|
|
|
162
147
|
# Sybase has both datetime and timestamp classes, most people are going
|
|
@@ -165,12 +150,6 @@ module Sequel
|
|
|
165
150
|
:datetime
|
|
166
151
|
end
|
|
167
152
|
|
|
168
|
-
# Sybase has both datetime and timestamp classes, most people are going
|
|
169
|
-
# to want datetime
|
|
170
|
-
def type_literal_generic_time(column)
|
|
171
|
-
column[:only_time] ? :time : :datetime
|
|
172
|
-
end
|
|
173
|
-
|
|
174
153
|
# Sybase doesn't have a true boolean class, so it uses integer
|
|
175
154
|
def type_literal_generic_trueclass(column)
|
|
176
155
|
:smallint
|
|
@@ -181,7 +160,6 @@ module Sequel
|
|
|
181
160
|
:image
|
|
182
161
|
end
|
|
183
162
|
|
|
184
|
-
# Sybase specific syntax for altering tables.
|
|
185
163
|
def alter_table_sql(table, op)
|
|
186
164
|
case op[:op]
|
|
187
165
|
when :add_column
|
|
@@ -229,12 +207,21 @@ module Sequel
|
|
|
229
207
|
"ALTER TABLE #{quote_schema_table(name)} RENAME #{quote_schema_table(new_name)}"
|
|
230
208
|
end
|
|
231
209
|
|
|
210
|
+
# Convert smallint type to boolean if convert_smallint_to_bool is true
|
|
211
|
+
def schema_column_type(db_type)
|
|
212
|
+
if convert_smallint_to_bool && db_type =~ /smallint/i
|
|
213
|
+
:boolean
|
|
214
|
+
else
|
|
215
|
+
super
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
232
219
|
def tables_and_views(type, opts=OPTS)
|
|
233
220
|
m = output_identifier_meth
|
|
234
221
|
metadata_dataset.
|
|
235
|
-
from(:
|
|
236
|
-
where
|
|
237
|
-
select_map
|
|
222
|
+
from{sysobjects.as(:a)}.
|
|
223
|
+
where{{a[:type]=>type}}.
|
|
224
|
+
select_map{a[:name]}.
|
|
238
225
|
map{|n| m.call(n)}
|
|
239
226
|
end
|
|
240
227
|
|
|
@@ -245,42 +232,22 @@ module Sequel
|
|
|
245
232
|
end
|
|
246
233
|
|
|
247
234
|
module DatasetMethods
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
WILDCARD = LiteralString.new('%').freeze
|
|
251
|
-
TOP = " TOP ".freeze
|
|
252
|
-
START_AT = " START AT ".freeze
|
|
253
|
-
SQL_WITH_RECURSIVE = "WITH RECURSIVE ".freeze
|
|
254
|
-
DATE_FUNCTION = 'today()'.freeze
|
|
255
|
-
NOW_FUNCTION = 'now()'.freeze
|
|
256
|
-
DATEPART = 'datepart'.freeze
|
|
257
|
-
REGEXP = 'REGEXP'.freeze
|
|
258
|
-
NOT_REGEXP = 'NOT REGEXP'.freeze
|
|
259
|
-
APOS = Dataset::APOS
|
|
260
|
-
APOS_RE = Dataset::APOS_RE
|
|
261
|
-
DOUBLE_APOS = Dataset::DOUBLE_APOS
|
|
262
|
-
BACKSLASH_RE = /\\/.freeze
|
|
263
|
-
QUAD_BACKSLASH = "\\\\\\\\".freeze
|
|
264
|
-
BLOB_START = "0x".freeze
|
|
265
|
-
HSTAR = "H*".freeze
|
|
266
|
-
CROSS_APPLY = 'CROSS APPLY'.freeze
|
|
267
|
-
OUTER_APPLY = 'OUTER APPLY'.freeze
|
|
268
|
-
ONLY_OFFSET = " TOP 2147483647".freeze
|
|
269
|
-
|
|
270
|
-
Dataset.def_sql_method(self, :insert, %w'with insert into columns values')
|
|
271
|
-
Dataset.def_sql_method(self, :select, %w'with select distinct limit columns into from join where group having order compounds lock')
|
|
235
|
+
Dataset.def_sql_method(self, :insert, %w'insert into columns values')
|
|
236
|
+
Dataset.def_sql_method(self, :select, %w'with select distinct limit columns into from join where group having window compounds order lock')
|
|
272
237
|
|
|
273
238
|
# Whether to convert smallint to boolean arguments for this dataset.
|
|
274
|
-
# Defaults to the
|
|
239
|
+
# Defaults to the IBMDB module setting.
|
|
275
240
|
def convert_smallint_to_bool
|
|
276
|
-
|
|
241
|
+
opts.has_key?(:convert_smallint_to_bool) ? opts[:convert_smallint_to_bool] : db.convert_smallint_to_bool
|
|
277
242
|
end
|
|
278
243
|
|
|
279
|
-
#
|
|
280
|
-
|
|
244
|
+
# Return a cloned dataset with the convert_smallint_to_bool option set.
|
|
245
|
+
def with_convert_smallint_to_bool(v)
|
|
246
|
+
clone(:convert_smallint_to_bool=>v)
|
|
247
|
+
end
|
|
281
248
|
|
|
282
249
|
def supports_cte?(type=:select)
|
|
283
|
-
type == :select
|
|
250
|
+
type == :select
|
|
284
251
|
end
|
|
285
252
|
|
|
286
253
|
# SQLAnywhere supports GROUPING SETS
|
|
@@ -308,6 +275,14 @@ module Sequel
|
|
|
308
275
|
false
|
|
309
276
|
end
|
|
310
277
|
|
|
278
|
+
def supports_window_clause?
|
|
279
|
+
true
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def supports_window_functions?
|
|
283
|
+
true
|
|
284
|
+
end
|
|
285
|
+
|
|
311
286
|
# Uses CROSS APPLY to join the given table into the current dataset.
|
|
312
287
|
def cross_apply(table)
|
|
313
288
|
join_table(:cross_apply, table)
|
|
@@ -318,7 +293,6 @@ module Sequel
|
|
|
318
293
|
true
|
|
319
294
|
end
|
|
320
295
|
|
|
321
|
-
# SQLAnywhere uses + for string concatenation, and LIKE is case insensitive by default.
|
|
322
296
|
def complex_expression_sql_append(sql, op, args)
|
|
323
297
|
case op
|
|
324
298
|
when :'||'
|
|
@@ -326,12 +300,12 @@ module Sequel
|
|
|
326
300
|
when :<<, :>>
|
|
327
301
|
complex_expression_emulate_append(sql, op, args)
|
|
328
302
|
when :LIKE, :"NOT LIKE"
|
|
329
|
-
sql <<
|
|
330
|
-
literal_append(sql, args
|
|
331
|
-
sql <<
|
|
332
|
-
pattern =
|
|
303
|
+
sql << '('
|
|
304
|
+
literal_append(sql, args[0])
|
|
305
|
+
sql << (op == :LIKE ? ' REGEXP ' : ' NOT REGEXP ')
|
|
306
|
+
pattern = String.new
|
|
333
307
|
last_c = ''
|
|
334
|
-
args
|
|
308
|
+
args[1].each_char do |c|
|
|
335
309
|
if c == '_' and not pattern.end_with?('\\') and last_c != '\\'
|
|
336
310
|
pattern << '.'
|
|
337
311
|
elsif c == '%' and not pattern.end_with?('\\') and last_c != '\\'
|
|
@@ -354,17 +328,17 @@ module Sequel
|
|
|
354
328
|
end
|
|
355
329
|
end
|
|
356
330
|
literal_append(sql, pattern)
|
|
357
|
-
sql <<
|
|
358
|
-
literal_append(sql,
|
|
359
|
-
sql <<
|
|
331
|
+
sql << " ESCAPE "
|
|
332
|
+
literal_append(sql, "\\")
|
|
333
|
+
sql << ')'
|
|
360
334
|
when :ILIKE, :"NOT ILIKE"
|
|
361
335
|
super(sql, (op == :ILIKE ? :LIKE : :"NOT LIKE"), args)
|
|
362
336
|
when :extract
|
|
363
|
-
sql <<
|
|
364
|
-
literal_append(sql, args
|
|
337
|
+
sql << 'datepart('
|
|
338
|
+
literal_append(sql, args[0])
|
|
365
339
|
sql << ','
|
|
366
|
-
literal_append(sql, args
|
|
367
|
-
sql <<
|
|
340
|
+
literal_append(sql, args[1])
|
|
341
|
+
sql << ')'
|
|
368
342
|
else
|
|
369
343
|
super
|
|
370
344
|
end
|
|
@@ -375,13 +349,13 @@ module Sequel
|
|
|
375
349
|
string.gsub(/[\\%_\[]/){|m| "\\#{m}"}
|
|
376
350
|
end
|
|
377
351
|
|
|
378
|
-
# Use
|
|
352
|
+
# Use today() for CURRENT_DATE and now() for CURRENT_TIMESTAMP and CURRENT_TIME
|
|
379
353
|
def constant_sql_append(sql, constant)
|
|
380
354
|
case constant
|
|
381
355
|
when :CURRENT_DATE
|
|
382
|
-
sql <<
|
|
356
|
+
sql << 'today()'
|
|
383
357
|
when :CURRENT_TIMESTAMP, :CURRENT_TIME
|
|
384
|
-
sql <<
|
|
358
|
+
sql << 'now()'
|
|
385
359
|
else
|
|
386
360
|
super
|
|
387
361
|
end
|
|
@@ -396,17 +370,17 @@ module Sequel
|
|
|
396
370
|
|
|
397
371
|
# Use 1 for true on Sybase
|
|
398
372
|
def literal_true
|
|
399
|
-
|
|
373
|
+
'1'
|
|
400
374
|
end
|
|
401
375
|
|
|
402
376
|
# Use 0 for false on Sybase
|
|
403
377
|
def literal_false
|
|
404
|
-
|
|
378
|
+
'0'
|
|
405
379
|
end
|
|
406
380
|
|
|
407
381
|
# SQL fragment for String. Doubles \ and ' by default.
|
|
408
382
|
def literal_string_append(sql, v)
|
|
409
|
-
sql <<
|
|
383
|
+
sql << "'" << v.gsub("\\", "\\\\\\\\").gsub("'", "''") << "'"
|
|
410
384
|
end
|
|
411
385
|
|
|
412
386
|
# SqlAnywhere uses a preceding X for hex escaping strings
|
|
@@ -414,7 +388,7 @@ module Sequel
|
|
|
414
388
|
if v.empty?
|
|
415
389
|
literal_append(sql, "")
|
|
416
390
|
else
|
|
417
|
-
sql <<
|
|
391
|
+
sql << "0x" << v.unpack("H*").first
|
|
418
392
|
end
|
|
419
393
|
end
|
|
420
394
|
|
|
@@ -423,28 +397,32 @@ module Sequel
|
|
|
423
397
|
:values
|
|
424
398
|
end
|
|
425
399
|
|
|
400
|
+
# SQLAnywhere does not natively support NULLS FIRST/LAST.
|
|
401
|
+
def requires_emulating_nulls_first?
|
|
402
|
+
true
|
|
403
|
+
end
|
|
404
|
+
|
|
426
405
|
def select_into_sql(sql)
|
|
427
406
|
if i = @opts[:into]
|
|
428
|
-
sql <<
|
|
407
|
+
sql << " INTO "
|
|
429
408
|
identifier_append(sql, i)
|
|
430
409
|
end
|
|
431
410
|
end
|
|
432
411
|
|
|
433
|
-
# Sybase uses TOP N for limit.
|
|
434
|
-
# to allow the limit to be a bound variable.
|
|
412
|
+
# Sybase uses TOP N for limit.
|
|
435
413
|
def select_limit_sql(sql)
|
|
436
414
|
l = @opts[:limit]
|
|
437
415
|
o = @opts[:offset]
|
|
438
416
|
if l || o
|
|
439
417
|
if l
|
|
440
|
-
sql << TOP
|
|
418
|
+
sql << " TOP "
|
|
441
419
|
literal_append(sql, l)
|
|
442
420
|
else
|
|
443
|
-
sql <<
|
|
421
|
+
sql << " TOP 2147483647"
|
|
444
422
|
end
|
|
445
423
|
|
|
446
424
|
if o
|
|
447
|
-
sql <<
|
|
425
|
+
sql << " START AT ("
|
|
448
426
|
literal_append(sql, o)
|
|
449
427
|
sql << " + 1)"
|
|
450
428
|
end
|
|
@@ -453,15 +431,15 @@ module Sequel
|
|
|
453
431
|
|
|
454
432
|
# Use WITH RECURSIVE instead of WITH if any of the CTEs is recursive
|
|
455
433
|
def select_with_sql_base
|
|
456
|
-
opts[:with].any?{|w| w[:recursive]} ?
|
|
434
|
+
opts[:with].any?{|w| w[:recursive]} ? "WITH RECURSIVE " : super
|
|
457
435
|
end
|
|
458
436
|
|
|
459
437
|
def join_type_sql(join_type)
|
|
460
438
|
case join_type
|
|
461
439
|
when :cross_apply
|
|
462
|
-
|
|
440
|
+
'CROSS APPLY'
|
|
463
441
|
when :outer_apply
|
|
464
|
-
|
|
442
|
+
'OUTER APPLY'
|
|
465
443
|
else
|
|
466
444
|
super
|
|
467
445
|
end
|
|
@@ -1,49 +1,46 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../utils/replace'
|
|
4
|
+
require_relative '../utils/unmodified_identifiers'
|
|
2
5
|
|
|
3
6
|
module Sequel
|
|
4
7
|
module SQLite
|
|
8
|
+
Sequel::Database.set_shared_adapter_scheme(:sqlite, self)
|
|
9
|
+
|
|
10
|
+
def self.mock_adapter_setup(db)
|
|
11
|
+
db.instance_exec do
|
|
12
|
+
@sqlite_version = 30903
|
|
13
|
+
|
|
14
|
+
def schema_parse_table(*)
|
|
15
|
+
[]
|
|
16
|
+
end
|
|
17
|
+
singleton_class.send(:private, :schema_parse_table)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
5
21
|
# No matter how you connect to SQLite, the following Database options
|
|
6
22
|
# can be used to set PRAGMAs on connections in a thread-safe manner:
|
|
7
23
|
# :auto_vacuum, :foreign_keys, :synchronous, and :temp_store.
|
|
8
24
|
module DatabaseMethods
|
|
9
|
-
|
|
25
|
+
include UnmodifiedIdentifiers::DatabaseMethods
|
|
10
26
|
|
|
11
27
|
AUTO_VACUUM = [:none, :full, :incremental].freeze
|
|
12
|
-
PRIMARY_KEY_INDEX_RE = /\Asqlite_autoindex_/.freeze
|
|
13
28
|
SYNCHRONOUS = [:off, :normal, :full].freeze
|
|
14
|
-
TABLES_FILTER = "type = 'table' AND NOT name = 'sqlite_sequence'".freeze
|
|
15
29
|
TEMP_STORE = [:default, :file, :memory].freeze
|
|
16
|
-
VIEWS_FILTER = "type = 'view'".freeze
|
|
17
30
|
TRANSACTION_MODE = {
|
|
18
31
|
:deferred => "BEGIN DEFERRED TRANSACTION".freeze,
|
|
19
32
|
:immediate => "BEGIN IMMEDIATE TRANSACTION".freeze,
|
|
20
33
|
:exclusive => "BEGIN EXCLUSIVE TRANSACTION".freeze,
|
|
21
|
-
nil =>
|
|
34
|
+
nil => "BEGIN".freeze
|
|
22
35
|
}.freeze
|
|
23
36
|
|
|
24
37
|
# Whether to use integers for booleans in the database. SQLite recommends
|
|
25
38
|
# booleans be stored as integers, but historically Sequel has used 't'/'f'.
|
|
26
39
|
attr_accessor :integer_booleans
|
|
27
40
|
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Set the auto_vacuum PRAGMA using the given symbol (:none, :full, or
|
|
34
|
-
# :incremental). See pragma_set. Consider using the :auto_vacuum
|
|
35
|
-
# Database option instead.
|
|
36
|
-
def auto_vacuum=(value)
|
|
37
|
-
value = AUTO_VACUUM.index(value) || (raise Error, "Invalid value for auto_vacuum option. Please specify one of :none, :full, :incremental.")
|
|
38
|
-
pragma_set(:auto_vacuum, value)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# Set the case_sensitive_like PRAGMA using the given boolean value, if using
|
|
42
|
-
# SQLite 3.2.3+. If not using 3.2.3+, no error is raised. See pragma_set.
|
|
43
|
-
# Consider using the :case_sensitive_like Database option instead.
|
|
44
|
-
def case_sensitive_like=(value)
|
|
45
|
-
pragma_set(:case_sensitive_like, !!value ? 'on' : 'off') if sqlite_version >= 30203
|
|
46
|
-
end
|
|
41
|
+
# Whether to keep CURRENT_TIMESTAMP and similar expressions in UTC. By
|
|
42
|
+
# default, the expressions are converted to localtime.
|
|
43
|
+
attr_accessor :current_timestamp_utc
|
|
47
44
|
|
|
48
45
|
# A symbol signifying the value of the default transaction mode
|
|
49
46
|
attr_reader :transaction_mode
|
|
@@ -62,17 +59,9 @@ module Sequel
|
|
|
62
59
|
:sqlite
|
|
63
60
|
end
|
|
64
61
|
|
|
65
|
-
#
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
pragma_get(:foreign_keys).to_i == 1 if sqlite_version >= 30619
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# Set the foreign_keys PRAGMA using the given boolean value, if using
|
|
72
|
-
# SQLite 3.6.19+. If not using 3.6.19+, no error is raised. See pragma_set.
|
|
73
|
-
# Consider using the :foreign_keys Database option instead.
|
|
74
|
-
def foreign_keys=(value)
|
|
75
|
-
pragma_set(:foreign_keys, !!value ? 'on' : 'off') if sqlite_version >= 30619
|
|
62
|
+
# Set the integer_booleans option using the passed in :integer_boolean option.
|
|
63
|
+
def set_integer_booleans
|
|
64
|
+
@integer_booleans = @opts.has_key?(:integer_booleans) ? typecast_value_boolean(@opts[:integer_booleans]) : true
|
|
76
65
|
end
|
|
77
66
|
|
|
78
67
|
# Return the array of foreign key info hashes using the foreign_key_list PRAGMA,
|
|
@@ -80,7 +69,7 @@ module Sequel
|
|
|
80
69
|
def foreign_key_list(table, opts=OPTS)
|
|
81
70
|
m = output_identifier_meth
|
|
82
71
|
h = {}
|
|
83
|
-
|
|
72
|
+
_foreign_key_list_ds(table).each do |row|
|
|
84
73
|
if r = h[row[:id]]
|
|
85
74
|
r[:columns] << m.call(row[:from])
|
|
86
75
|
r[:key] << m.call(row[:to]) if r[:key]
|
|
@@ -91,14 +80,31 @@ module Sequel
|
|
|
91
80
|
h.values
|
|
92
81
|
end
|
|
93
82
|
|
|
83
|
+
def freeze
|
|
84
|
+
sqlite_version
|
|
85
|
+
use_timestamp_timezones?
|
|
86
|
+
super
|
|
87
|
+
end
|
|
88
|
+
|
|
94
89
|
# Use the index_list and index_info PRAGMAs to determine the indexes on the table.
|
|
95
90
|
def indexes(table, opts=OPTS)
|
|
96
91
|
m = output_identifier_meth
|
|
97
92
|
im = input_identifier_meth
|
|
98
93
|
indexes = {}
|
|
94
|
+
table = table.value if table.is_a?(Sequel::SQL::Identifier)
|
|
99
95
|
metadata_dataset.with_sql("PRAGMA index_list(?)", im.call(table)).each do |r|
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
if opts[:only_autocreated]
|
|
97
|
+
# If specifically asked for only autocreated indexes, then return those an only those
|
|
98
|
+
next unless r[:name] =~ /\Asqlite_autoindex_/
|
|
99
|
+
elsif r.has_key?(:origin)
|
|
100
|
+
# If origin is set, then only exclude primary key indexes and partial indexes
|
|
101
|
+
next if r[:origin] == 'pk'
|
|
102
|
+
next if r[:partial].to_i == 1
|
|
103
|
+
else
|
|
104
|
+
# When :origin key not present, assume any autoindex could be a primary key one and exclude it
|
|
105
|
+
next if r[:name] =~ /\Asqlite_autoindex_/
|
|
106
|
+
end
|
|
107
|
+
|
|
102
108
|
indexes[m.call(r[:name])] = {:unique=>r[:unique].to_i==1}
|
|
103
109
|
end
|
|
104
110
|
indexes.each do |k, v|
|
|
@@ -107,26 +113,6 @@ module Sequel
|
|
|
107
113
|
indexes
|
|
108
114
|
end
|
|
109
115
|
|
|
110
|
-
# Get the value of the given PRAGMA.
|
|
111
|
-
def pragma_get(name)
|
|
112
|
-
self["PRAGMA #{name}"].single_value
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
# Set the value of the given PRAGMA to value.
|
|
116
|
-
#
|
|
117
|
-
# This method is not thread safe, and will not work correctly if there
|
|
118
|
-
# are multiple connections in the Database's connection pool. PRAGMA
|
|
119
|
-
# modifications should be done when the connection is created, using
|
|
120
|
-
# an option provided when creating the Database object.
|
|
121
|
-
def pragma_set(name, value)
|
|
122
|
-
execute_ddl("PRAGMA #{name} = #{value}")
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
# Set the integer_booleans option using the passed in :integer_boolean option.
|
|
126
|
-
def set_integer_booleans
|
|
127
|
-
@integer_booleans = @opts.has_key?(:integer_booleans) ? typecast_value_boolean(@opts[:integer_booleans]) : true
|
|
128
|
-
end
|
|
129
|
-
|
|
130
116
|
# The version of the server as an integer, where 3.6.19 = 30619.
|
|
131
117
|
# If the server version can't be determined, 0 is used.
|
|
132
118
|
def sqlite_version
|
|
@@ -170,55 +156,57 @@ module Sequel
|
|
|
170
156
|
defined?(@use_timestamp_timezones) ? @use_timestamp_timezones : (@use_timestamp_timezones = false)
|
|
171
157
|
end
|
|
172
158
|
|
|
173
|
-
# A symbol signifying the value of the synchronous PRAGMA.
|
|
174
|
-
def synchronous
|
|
175
|
-
SYNCHRONOUS[pragma_get(:synchronous).to_i]
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
# Set the synchronous PRAGMA using the given symbol (:off, :normal, or :full). See pragma_set.
|
|
179
|
-
# Consider using the :synchronous Database option instead.
|
|
180
|
-
def synchronous=(value)
|
|
181
|
-
value = SYNCHRONOUS.index(value) || (raise Error, "Invalid value for synchronous option. Please specify one of :off, :normal, :full.")
|
|
182
|
-
pragma_set(:synchronous, value)
|
|
183
|
-
end
|
|
184
|
-
|
|
185
159
|
# Array of symbols specifying the table names in the current database.
|
|
186
160
|
#
|
|
187
161
|
# Options:
|
|
188
162
|
# :server :: Set the server to use.
|
|
189
163
|
def tables(opts=OPTS)
|
|
190
|
-
tables_and_views(
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
# A symbol signifying the value of the temp_store PRAGMA.
|
|
194
|
-
def temp_store
|
|
195
|
-
TEMP_STORE[pragma_get(:temp_store).to_i]
|
|
164
|
+
tables_and_views(Sequel.~(:name=>'sqlite_sequence') & {:type => 'table'}, opts)
|
|
196
165
|
end
|
|
197
166
|
|
|
198
|
-
#
|
|
199
|
-
#
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
167
|
+
# Creates a dataset that uses the VALUES clause:
|
|
168
|
+
#
|
|
169
|
+
# DB.values([[1, 2], [3, 4]])
|
|
170
|
+
# # VALUES ((1, 2), (3, 4))
|
|
171
|
+
def values(v)
|
|
172
|
+
@default_dataset.clone(:values=>v)
|
|
203
173
|
end
|
|
204
|
-
|
|
174
|
+
|
|
205
175
|
# Array of symbols specifying the view names in the current database.
|
|
206
176
|
#
|
|
207
177
|
# Options:
|
|
208
178
|
# :server :: Set the server to use.
|
|
209
179
|
def views(opts=OPTS)
|
|
210
|
-
tables_and_views(
|
|
180
|
+
tables_and_views({:type => 'view'}, opts)
|
|
211
181
|
end
|
|
212
182
|
|
|
213
183
|
private
|
|
214
184
|
|
|
185
|
+
# Dataset used for parsing foreign key lists
|
|
186
|
+
def _foreign_key_list_ds(table)
|
|
187
|
+
metadata_dataset.with_sql("PRAGMA foreign_key_list(?)", input_identifier_meth.call(table))
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Dataset used for parsing schema
|
|
191
|
+
def _parse_pragma_ds(table_name, opts)
|
|
192
|
+
metadata_dataset.with_sql("PRAGMA table_#{'x' if sqlite_version > 33100}info(?)", input_identifier_meth(opts[:dataset]).call(table_name))
|
|
193
|
+
end
|
|
194
|
+
|
|
215
195
|
# Run all alter_table commands in a transaction. This is technically only
|
|
216
196
|
# needed for drop column.
|
|
217
197
|
def apply_alter_table(table, ops)
|
|
218
|
-
fks = foreign_keys
|
|
219
|
-
|
|
198
|
+
fks = fetch("PRAGMA foreign_keys")
|
|
199
|
+
if fks
|
|
200
|
+
run "PRAGMA foreign_keys = 0"
|
|
201
|
+
run "PRAGMA legacy_alter_table = 1" if sqlite_version >= 32600
|
|
202
|
+
end
|
|
220
203
|
transaction do
|
|
221
|
-
if ops.length > 1 && ops.all?{|op| op[:op] == :add_constraint}
|
|
204
|
+
if ops.length > 1 && ops.all?{|op| op[:op] == :add_constraint || op[:op] == :set_column_null}
|
|
205
|
+
null_ops, ops = ops.partition{|op| op[:op] == :set_column_null}
|
|
206
|
+
|
|
207
|
+
# Apply NULL/NOT NULL ops first, since those should be purely idependent of the constraints.
|
|
208
|
+
null_ops.each{|op| alter_table_sql_list(table, [op]).flatten.each{|sql| execute_ddl(sql)}}
|
|
209
|
+
|
|
222
210
|
# If you are just doing constraints, apply all of them at the same time,
|
|
223
211
|
# as otherwise all but the last one get lost.
|
|
224
212
|
alter_table_sql_list(table, [{:op=>:add_constraints, :ops=>ops}]).flatten.each{|sql| execute_ddl(sql)}
|
|
@@ -228,8 +216,12 @@ module Sequel
|
|
|
228
216
|
ops.each{|op| alter_table_sql_list(table, [op]).flatten.each{|sql| execute_ddl(sql)}}
|
|
229
217
|
end
|
|
230
218
|
end
|
|
219
|
+
remove_cached_schema(table)
|
|
231
220
|
ensure
|
|
232
|
-
|
|
221
|
+
if fks
|
|
222
|
+
run "PRAGMA foreign_keys = 1"
|
|
223
|
+
run "PRAGMA legacy_alter_table = 0" if sqlite_version >= 32600
|
|
224
|
+
end
|
|
233
225
|
end
|
|
234
226
|
|
|
235
227
|
# SQLite supports limited table modification. You can add a column
|
|
@@ -250,8 +242,12 @@ module Sequel
|
|
|
250
242
|
ocp = lambda{|oc| oc.delete_if{|c| c.to_s == op[:name].to_s}}
|
|
251
243
|
duplicate_table(table, :old_columns_proc=>ocp){|columns| columns.delete_if{|s| s[:name].to_s == op[:name].to_s}}
|
|
252
244
|
when :rename_column
|
|
253
|
-
|
|
254
|
-
|
|
245
|
+
if sqlite_version >= 32500
|
|
246
|
+
super
|
|
247
|
+
else
|
|
248
|
+
ncp = lambda{|nc| nc.map!{|c| c.to_s == op[:name].to_s ? op[:new_name] : c}}
|
|
249
|
+
duplicate_table(table, :new_columns_proc=>ncp){|columns| columns.each{|s| s[:name] = op[:new_name] if s[:name].to_s == op[:name].to_s}}
|
|
250
|
+
end
|
|
255
251
|
when :set_column_default
|
|
256
252
|
duplicate_table(table){|columns| columns.each{|s| s[:default] = op[:default] if s[:name].to_s == op[:name].to_s}}
|
|
257
253
|
when :set_column_null
|
|
@@ -261,13 +257,20 @@ module Sequel
|
|
|
261
257
|
when :drop_constraint
|
|
262
258
|
case op[:type]
|
|
263
259
|
when :primary_key
|
|
264
|
-
duplicate_table(table)
|
|
260
|
+
duplicate_table(table) do |columns|
|
|
261
|
+
columns.each do |s|
|
|
262
|
+
s[:unique] = false if s[:primary_key]
|
|
263
|
+
s[:primary_key] = s[:auto_increment] = nil
|
|
264
|
+
end
|
|
265
|
+
end
|
|
265
266
|
when :foreign_key
|
|
266
267
|
if op[:columns]
|
|
267
268
|
duplicate_table(table, :skip_foreign_key_columns=>op[:columns])
|
|
268
269
|
else
|
|
269
270
|
duplicate_table(table, :no_foreign_keys=>true)
|
|
270
271
|
end
|
|
272
|
+
when :unique
|
|
273
|
+
duplicate_table(table, :no_unique=>true)
|
|
271
274
|
else
|
|
272
275
|
duplicate_table(table)
|
|
273
276
|
end
|
|
@@ -296,15 +299,21 @@ module Sequel
|
|
|
296
299
|
end
|
|
297
300
|
end
|
|
298
301
|
|
|
299
|
-
#
|
|
302
|
+
# SQLite allows adding primary key constraints on NULLABLE columns, but then
|
|
303
|
+
# does not enforce NOT NULL for such columns, so force setting the columns NOT NULL.
|
|
304
|
+
def can_add_primary_key_constraint_on_nullable_columns?
|
|
305
|
+
false
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# Surround default with parens to appease SQLite. Add support for GENERATED ALWAYS AS.
|
|
300
309
|
def column_definition_default_sql(sql, column)
|
|
301
310
|
sql << " DEFAULT (#{literal(column[:default])})" if column.include?(:default)
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
311
|
+
if (generated = column[:generated_always_as])
|
|
312
|
+
if (generated_type = column[:generated_type]) && (generated_type == :stored || generated_type == :virtual)
|
|
313
|
+
generated_type = generated_type.to_s.upcase
|
|
314
|
+
end
|
|
315
|
+
sql << " GENERATED ALWAYS AS (#{literal(generated)}) #{generated_type}"
|
|
316
|
+
end
|
|
308
317
|
end
|
|
309
318
|
|
|
310
319
|
# Array of PRAGMA SQL statements based on the Database options that should be applied to
|
|
@@ -326,13 +335,13 @@ module Sequel
|
|
|
326
335
|
|
|
327
336
|
# SQLite support creating temporary views.
|
|
328
337
|
def create_view_prefix_sql(name, options)
|
|
329
|
-
"CREATE #{'TEMPORARY 'if options[:temp]}VIEW #{quote_schema_table(name)}"
|
|
338
|
+
create_view_sql_append_columns("CREATE #{'TEMPORARY 'if options[:temp]}VIEW #{quote_schema_table(name)}", options[:columns])
|
|
330
339
|
end
|
|
331
340
|
|
|
332
341
|
DATABASE_ERROR_REGEXPS = {
|
|
333
342
|
/(is|are) not unique\z|PRIMARY KEY must be unique\z|UNIQUE constraint failed: .+\z/ => UniqueConstraintViolation,
|
|
334
343
|
/foreign key constraint failed\z/i => ForeignKeyConstraintViolation,
|
|
335
|
-
/\
|
|
344
|
+
/\A(SQLITE ERROR 275 \(CONSTRAINT_CHECK\) : )?CHECK constraint failed/ => CheckConstraintViolation,
|
|
336
345
|
/\A(SQLITE ERROR 19 \(CONSTRAINT\) : )?constraint failed\z/ => ConstraintViolation,
|
|
337
346
|
/may not be NULL\z|NOT NULL constraint failed: .+\z/ => NotNullConstraintViolation,
|
|
338
347
|
/\ASQLITE ERROR \d+ \(\) : CHECK constraint failed: / => CheckConstraintViolation
|
|
@@ -341,13 +350,32 @@ module Sequel
|
|
|
341
350
|
DATABASE_ERROR_REGEXPS
|
|
342
351
|
end
|
|
343
352
|
|
|
353
|
+
# Recognize SQLite error codes if the exception provides access to them.
|
|
354
|
+
def database_specific_error_class(exception, opts)
|
|
355
|
+
case sqlite_error_code(exception)
|
|
356
|
+
when 1299
|
|
357
|
+
NotNullConstraintViolation
|
|
358
|
+
when 1555, 2067, 2579
|
|
359
|
+
UniqueConstraintViolation
|
|
360
|
+
when 787
|
|
361
|
+
ForeignKeyConstraintViolation
|
|
362
|
+
when 275
|
|
363
|
+
CheckConstraintViolation
|
|
364
|
+
when 19
|
|
365
|
+
ConstraintViolation
|
|
366
|
+
when 517
|
|
367
|
+
SerializationFailure
|
|
368
|
+
else
|
|
369
|
+
super
|
|
370
|
+
end
|
|
371
|
+
end
|
|
372
|
+
|
|
344
373
|
# The array of column schema hashes for the current columns in the table
|
|
345
374
|
def defined_columns_for(table)
|
|
346
|
-
cols = parse_pragma(table,
|
|
375
|
+
cols = parse_pragma(table, OPTS)
|
|
347
376
|
cols.each do |c|
|
|
348
377
|
c[:default] = LiteralString.new(c[:default]) if c[:default]
|
|
349
378
|
c[:type] = c[:db_type]
|
|
350
|
-
c.delete(:auto_increment)
|
|
351
379
|
end
|
|
352
380
|
cols
|
|
353
381
|
end
|
|
@@ -393,14 +421,22 @@ module Sequel
|
|
|
393
421
|
|
|
394
422
|
# Determine unique constraints and make sure the new columns have them
|
|
395
423
|
unique_columns = []
|
|
396
|
-
|
|
397
|
-
|
|
424
|
+
skip_indexes = []
|
|
425
|
+
indexes(table, :only_autocreated=>true).each do |name, h|
|
|
426
|
+
skip_indexes << name
|
|
427
|
+
if h[:unique]
|
|
428
|
+
if h[:columns].length == 1
|
|
429
|
+
unique_columns.concat(h[:columns])
|
|
430
|
+
elsif h[:columns].map(&:to_s) != pks && !opts[:no_unique]
|
|
431
|
+
constraints << {:type=>:unique, :columns=>h[:columns]}
|
|
432
|
+
end
|
|
433
|
+
end
|
|
398
434
|
end
|
|
399
435
|
unique_columns -= pks
|
|
400
436
|
unless unique_columns.empty?
|
|
401
437
|
unique_columns.map!{|c| quote_identifier(c)}
|
|
402
438
|
def_columns.each do |c|
|
|
403
|
-
c[:unique] = true if unique_columns.include?(quote_identifier(c[:name]))
|
|
439
|
+
c[:unique] = true if unique_columns.include?(quote_identifier(c[:name])) && c[:unique] != false
|
|
404
440
|
end
|
|
405
441
|
end
|
|
406
442
|
|
|
@@ -417,6 +453,7 @@ module Sequel
|
|
|
417
453
|
"DROP TABLE #{bt}"
|
|
418
454
|
]
|
|
419
455
|
indexes(table).each do |name, h|
|
|
456
|
+
next if skip_indexes.include?(name)
|
|
420
457
|
if (h[:columns].map(&:to_s) - new_columns).empty?
|
|
421
458
|
a << alter_table_sql(table, h.merge(:op=>:add_index, :name=>name))
|
|
422
459
|
end
|
|
@@ -424,19 +461,9 @@ module Sequel
|
|
|
424
461
|
a
|
|
425
462
|
end
|
|
426
463
|
|
|
427
|
-
# SQLite folds unquoted identifiers to lowercase, so it shouldn't need to upcase identifiers on input.
|
|
428
|
-
def identifier_input_method_default
|
|
429
|
-
nil
|
|
430
|
-
end
|
|
431
|
-
|
|
432
|
-
# SQLite folds unquoted identifiers to lowercase, so it shouldn't need to upcase identifiers on output.
|
|
433
|
-
def identifier_output_method_default
|
|
434
|
-
nil
|
|
435
|
-
end
|
|
436
|
-
|
|
437
464
|
# Does the reverse of on_delete_clause, eg. converts strings like +'SET NULL'+
|
|
438
465
|
# to symbols +:set_null+.
|
|
439
|
-
def on_delete_sql_to_sym
|
|
466
|
+
def on_delete_sql_to_sym(str)
|
|
440
467
|
case str
|
|
441
468
|
when 'RESTRICT'
|
|
442
469
|
:restrict
|
|
@@ -453,18 +480,43 @@ module Sequel
|
|
|
453
480
|
|
|
454
481
|
# Parse the output of the table_info pragma
|
|
455
482
|
def parse_pragma(table_name, opts)
|
|
456
|
-
|
|
483
|
+
pks = 0
|
|
484
|
+
sch = _parse_pragma_ds(table_name, opts).map do |row|
|
|
485
|
+
if sqlite_version > 33100
|
|
486
|
+
# table_xinfo PRAGMA used, remove hidden columns
|
|
487
|
+
# that are not generated columns
|
|
488
|
+
if row[:generated] = (row.delete(:hidden) != 0)
|
|
489
|
+
next unless row[:type].end_with?(' GENERATED ALWAYS')
|
|
490
|
+
row[:type] = row[:type].sub(' GENERATED ALWAYS', '')
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
|
|
457
494
|
row.delete(:cid)
|
|
458
495
|
row[:allow_null] = row.delete(:notnull).to_i == 0
|
|
459
496
|
row[:default] = row.delete(:dflt_value)
|
|
460
497
|
row[:default] = nil if blank_object?(row[:default]) || row[:default] == 'NULL'
|
|
461
498
|
row[:db_type] = row.delete(:type)
|
|
462
499
|
if row[:primary_key] = row.delete(:pk).to_i > 0
|
|
500
|
+
pks += 1
|
|
501
|
+
# Guess that an integer primary key uses auto increment,
|
|
502
|
+
# since that is Sequel's default and SQLite does not provide
|
|
503
|
+
# a way to introspect whether it is actually autoincrementing.
|
|
463
504
|
row[:auto_increment] = row[:db_type].downcase == 'integer'
|
|
464
505
|
end
|
|
465
506
|
row[:type] = schema_column_type(row[:db_type])
|
|
466
507
|
row
|
|
467
508
|
end
|
|
509
|
+
|
|
510
|
+
sch.compact!
|
|
511
|
+
|
|
512
|
+
if pks > 1
|
|
513
|
+
# SQLite does not allow use of auto increment for tables
|
|
514
|
+
# with composite primary keys, so remove auto_increment
|
|
515
|
+
# if composite primary keys are detected.
|
|
516
|
+
sch.each{|r| r.delete(:auto_increment)}
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
sch
|
|
468
520
|
end
|
|
469
521
|
|
|
470
522
|
# SQLite supports schema parsing using the table_info PRAGMA, so
|
|
@@ -476,78 +528,95 @@ module Sequel
|
|
|
476
528
|
end
|
|
477
529
|
end
|
|
478
530
|
|
|
531
|
+
# Don't support SQLite error codes for exceptions by default.
|
|
532
|
+
def sqlite_error_code(exception)
|
|
533
|
+
nil
|
|
534
|
+
end
|
|
535
|
+
|
|
479
536
|
# Backbone of the tables and views support.
|
|
480
537
|
def tables_and_views(filter, opts)
|
|
481
538
|
m = output_identifier_meth
|
|
482
|
-
metadata_dataset.from(:sqlite_master).server(opts[:server]).
|
|
539
|
+
metadata_dataset.from(:sqlite_master).server(opts[:server]).where(filter).map{|r| m.call(r[:name])}
|
|
483
540
|
end
|
|
484
541
|
|
|
485
542
|
# SQLite only supports AUTOINCREMENT on integer columns, not
|
|
486
543
|
# bigint columns, so use integer instead of bigint for those
|
|
487
544
|
# columns.
|
|
488
|
-
def
|
|
545
|
+
def type_literal_generic_bignum_symbol(column)
|
|
489
546
|
column[:auto_increment] ? :integer : super
|
|
490
547
|
end
|
|
491
548
|
end
|
|
492
549
|
|
|
493
|
-
# Instance methods for datasets that connect to an SQLite database
|
|
494
550
|
module DatasetMethods
|
|
495
551
|
include Dataset::Replace
|
|
552
|
+
include UnmodifiedIdentifiers::DatasetMethods
|
|
553
|
+
|
|
554
|
+
# The allowed values for insert_conflict
|
|
555
|
+
INSERT_CONFLICT_RESOLUTIONS = %w'ROLLBACK ABORT FAIL IGNORE REPLACE'.each(&:freeze).freeze
|
|
496
556
|
|
|
497
|
-
CONSTANT_MAP = {:CURRENT_DATE=>"date(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIMESTAMP=>"datetime(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIME=>"time(CURRENT_TIMESTAMP, 'localtime')".freeze}
|
|
498
|
-
|
|
499
|
-
EXTRACT_MAP
|
|
500
|
-
NOT_SPACE = Dataset::NOT_SPACE
|
|
501
|
-
COMMA = Dataset::COMMA
|
|
502
|
-
PAREN_CLOSE = Dataset::PAREN_CLOSE
|
|
503
|
-
AS = Dataset::AS
|
|
504
|
-
APOS = Dataset::APOS
|
|
505
|
-
EXTRACT_OPEN = "CAST(strftime(".freeze
|
|
506
|
-
EXTRACT_CLOSE = ') AS '.freeze
|
|
507
|
-
NUMERIC = 'NUMERIC'.freeze
|
|
508
|
-
INTEGER = 'INTEGER'.freeze
|
|
509
|
-
BACKTICK = '`'.freeze
|
|
510
|
-
BACKTICK_RE = /`/.freeze
|
|
511
|
-
DOUBLE_BACKTICK = '``'.freeze
|
|
512
|
-
BLOB_START = "X'".freeze
|
|
513
|
-
HSTAR = "H*".freeze
|
|
514
|
-
DATE_OPEN = "date(".freeze
|
|
515
|
-
DATETIME_OPEN = "datetime(".freeze
|
|
516
|
-
ONLY_OFFSET = " LIMIT -1 OFFSET ".freeze
|
|
557
|
+
CONSTANT_MAP = {:CURRENT_DATE=>"date(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIMESTAMP=>"datetime(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIME=>"time(CURRENT_TIMESTAMP, 'localtime')".freeze}.freeze
|
|
558
|
+
EXTRACT_MAP = {:year=>"'%Y'", :month=>"'%m'", :day=>"'%d'", :hour=>"'%H'", :minute=>"'%M'", :second=>"'%f'"}.freeze
|
|
559
|
+
EXTRACT_MAP.each_value(&:freeze)
|
|
517
560
|
|
|
518
561
|
Dataset.def_sql_method(self, :delete, [['if db.sqlite_version >= 30803', %w'with delete from where'], ["else", %w'delete from where']])
|
|
519
|
-
Dataset.def_sql_method(self, :insert, [['if db.sqlite_version >= 30803', %w'with insert into columns values'], ["else", %w'insert into columns values']])
|
|
562
|
+
Dataset.def_sql_method(self, :insert, [['if db.sqlite_version >= 30803', %w'with insert conflict into columns values on_conflict'], ["else", %w'insert conflict into columns values']])
|
|
563
|
+
Dataset.def_sql_method(self, :select, [['if opts[:values]', %w'with values compounds'], ['else', %w'with select distinct columns from join where group having window compounds order limit lock']])
|
|
520
564
|
Dataset.def_sql_method(self, :update, [['if db.sqlite_version >= 30803', %w'with update table set where'], ["else", %w'update table set where']])
|
|
521
565
|
|
|
522
566
|
def cast_sql_append(sql, expr, type)
|
|
523
567
|
if type == Time or type == DateTime
|
|
524
|
-
sql <<
|
|
568
|
+
sql << "datetime("
|
|
525
569
|
literal_append(sql, expr)
|
|
526
|
-
sql <<
|
|
570
|
+
sql << ')'
|
|
527
571
|
elsif type == Date
|
|
528
|
-
sql <<
|
|
572
|
+
sql << "date("
|
|
529
573
|
literal_append(sql, expr)
|
|
530
|
-
sql <<
|
|
574
|
+
sql << ')'
|
|
531
575
|
else
|
|
532
576
|
super
|
|
533
577
|
end
|
|
534
578
|
end
|
|
535
579
|
|
|
536
580
|
# SQLite doesn't support a NOT LIKE b, you need to use NOT (a LIKE b).
|
|
537
|
-
# It doesn't support xor or the extract function natively, so those have to be emulated.
|
|
581
|
+
# It doesn't support xor, power, or the extract function natively, so those have to be emulated.
|
|
538
582
|
def complex_expression_sql_append(sql, op, args)
|
|
539
583
|
case op
|
|
540
584
|
when :"NOT LIKE", :"NOT ILIKE"
|
|
541
|
-
sql <<
|
|
585
|
+
sql << 'NOT '
|
|
542
586
|
complex_expression_sql_append(sql, (op == :"NOT ILIKE" ? :ILIKE : :LIKE), args)
|
|
543
587
|
when :^
|
|
544
588
|
complex_expression_arg_pairs_append(sql, args){|a, b| Sequel.lit(["((~(", " & ", ")) & (", " | ", "))"], a, b, a, b)}
|
|
589
|
+
when :**
|
|
590
|
+
unless (exp = args[1]).is_a?(Integer)
|
|
591
|
+
raise(Sequel::Error, "can only emulate exponentiation on SQLite if exponent is an integer, given #{exp.inspect}")
|
|
592
|
+
end
|
|
593
|
+
case exp
|
|
594
|
+
when 0
|
|
595
|
+
sql << '1'
|
|
596
|
+
else
|
|
597
|
+
sql << '('
|
|
598
|
+
arg = args[0]
|
|
599
|
+
if exp < 0
|
|
600
|
+
invert = true
|
|
601
|
+
exp = exp.abs
|
|
602
|
+
sql << '(1.0 / ('
|
|
603
|
+
end
|
|
604
|
+
(exp - 1).times do
|
|
605
|
+
literal_append(sql, arg)
|
|
606
|
+
sql << " * "
|
|
607
|
+
end
|
|
608
|
+
literal_append(sql, arg)
|
|
609
|
+
sql << ')'
|
|
610
|
+
if invert
|
|
611
|
+
sql << "))"
|
|
612
|
+
end
|
|
613
|
+
end
|
|
545
614
|
when :extract
|
|
546
|
-
part = args
|
|
615
|
+
part = args[0]
|
|
547
616
|
raise(Sequel::Error, "unsupported extract argument: #{part.inspect}") unless format = EXTRACT_MAP[part]
|
|
548
|
-
sql <<
|
|
549
|
-
literal_append(sql, args
|
|
550
|
-
sql <<
|
|
617
|
+
sql << "CAST(strftime(" << format << ', '
|
|
618
|
+
literal_append(sql, args[1])
|
|
619
|
+
sql << ') AS ' << (part == :second ? 'NUMERIC' : 'INTEGER') << ')'
|
|
551
620
|
else
|
|
552
621
|
super
|
|
553
622
|
end
|
|
@@ -556,7 +625,7 @@ module Sequel
|
|
|
556
625
|
# SQLite has CURRENT_TIMESTAMP and related constants in UTC instead
|
|
557
626
|
# of in localtime, so convert those constants to local time.
|
|
558
627
|
def constant_sql_append(sql, constant)
|
|
559
|
-
if c = CONSTANT_MAP[constant]
|
|
628
|
+
if (c = CONSTANT_MAP[constant]) && !db.current_timestamp_utc
|
|
560
629
|
sql << c
|
|
561
630
|
else
|
|
562
631
|
super
|
|
@@ -571,7 +640,7 @@ module Sequel
|
|
|
571
640
|
end
|
|
572
641
|
|
|
573
642
|
# Return an array of strings specifying a query explanation for a SELECT of the
|
|
574
|
-
# current dataset. Currently, the options are
|
|
643
|
+
# current dataset. Currently, the options are ignored, but it accepts options
|
|
575
644
|
# to be compatible with other adapters.
|
|
576
645
|
def explain(opts=nil)
|
|
577
646
|
# Load the PrettyTable class, needed for explain output
|
|
@@ -590,7 +659,7 @@ module Sequel
|
|
|
590
659
|
|
|
591
660
|
# SQLite uses the nonstandard ` (backtick) for quoting identifiers.
|
|
592
661
|
def quoted_identifier_append(sql, c)
|
|
593
|
-
sql <<
|
|
662
|
+
sql << '`' << c.to_s.gsub('`', '``') << '`'
|
|
594
663
|
end
|
|
595
664
|
|
|
596
665
|
# When a qualified column is selected on SQLite and the qualifier
|
|
@@ -604,12 +673,81 @@ module Sequel
|
|
|
604
673
|
super
|
|
605
674
|
end
|
|
606
675
|
end
|
|
607
|
-
|
|
676
|
+
|
|
677
|
+
# Handle uniqueness violations when inserting, by using a specified
|
|
678
|
+
# resolution algorithm. With no options, uses INSERT OR REPLACE. SQLite
|
|
679
|
+
# supports the following conflict resolution algoriths: ROLLBACK, ABORT,
|
|
680
|
+
# FAIL, IGNORE and REPLACE.
|
|
681
|
+
#
|
|
682
|
+
# On SQLite 3.24.0+, you can pass a hash to use an ON CONFLICT clause.
|
|
683
|
+
# With out :update option, uses ON CONFLICT DO NOTHING. Options:
|
|
684
|
+
#
|
|
685
|
+
# :conflict_where :: The index filter, when using a partial index to determine uniqueness.
|
|
686
|
+
# :target :: The column name or expression to handle uniqueness violations on.
|
|
687
|
+
# :update :: A hash of columns and values to set. Uses ON CONFLICT DO UPDATE.
|
|
688
|
+
# :update_where :: A WHERE condition to use for the update.
|
|
689
|
+
#
|
|
690
|
+
# Examples:
|
|
691
|
+
#
|
|
692
|
+
# DB[:table].insert_conflict.insert(a: 1, b: 2)
|
|
693
|
+
# # INSERT OR IGNORE INTO TABLE (a, b) VALUES (1, 2)
|
|
694
|
+
#
|
|
695
|
+
# DB[:table].insert_conflict(:replace).insert(a: 1, b: 2)
|
|
696
|
+
# # INSERT OR REPLACE INTO TABLE (a, b) VALUES (1, 2)
|
|
697
|
+
#
|
|
698
|
+
# DB[:table].insert_conflict({}).insert(a: 1, b: 2)
|
|
699
|
+
# # INSERT INTO TABLE (a, b) VALUES (1, 2)
|
|
700
|
+
# # ON CONFLICT DO NOTHING
|
|
701
|
+
#
|
|
702
|
+
# DB[:table].insert_conflict(target: :a).insert(a: 1, b: 2)
|
|
703
|
+
# # INSERT INTO TABLE (a, b) VALUES (1, 2)
|
|
704
|
+
# # ON CONFLICT (a) DO NOTHING
|
|
705
|
+
#
|
|
706
|
+
# DB[:table].insert_conflict(target: :a, conflict_where: {c: true}).insert(a: 1, b: 2)
|
|
707
|
+
# # INSERT INTO TABLE (a, b) VALUES (1, 2)
|
|
708
|
+
# # ON CONFLICT (a) WHERE (c IS TRUE) DO NOTHING
|
|
709
|
+
#
|
|
710
|
+
# DB[:table].insert_conflict(target: :a, update: {b: Sequel[:excluded][:b]}).insert(a: 1, b: 2)
|
|
711
|
+
# # INSERT INTO TABLE (a, b) VALUES (1, 2)
|
|
712
|
+
# # ON CONFLICT (a) DO UPDATE SET b = excluded.b
|
|
713
|
+
#
|
|
714
|
+
# DB[:table].insert_conflict(target: :a,
|
|
715
|
+
# update: {b: Sequel[:excluded][:b]}, update_where: {Sequel[:table][:status_id] => 1}).insert(a: 1, b: 2)
|
|
716
|
+
# # INSERT INTO TABLE (a, b) VALUES (1, 2)
|
|
717
|
+
# # ON CONFLICT (a) DO UPDATE SET b = excluded.b WHERE (table.status_id = 1)
|
|
718
|
+
def insert_conflict(opts = :ignore)
|
|
719
|
+
case opts
|
|
720
|
+
when Symbol, String
|
|
721
|
+
unless INSERT_CONFLICT_RESOLUTIONS.include?(opts.to_s.upcase)
|
|
722
|
+
raise Error, "Invalid symbol or string passed to Dataset#insert_conflict: #{opts.inspect}. The allowed values are: :rollback, :abort, :fail, :ignore, or :replace"
|
|
723
|
+
end
|
|
724
|
+
clone(:insert_conflict => opts)
|
|
725
|
+
when Hash
|
|
726
|
+
clone(:insert_on_conflict => opts)
|
|
727
|
+
else
|
|
728
|
+
raise Error, "Invalid value passed to Dataset#insert_conflict: #{opts.inspect}, should use a symbol or a hash"
|
|
729
|
+
end
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
# Ignore uniqueness/exclusion violations when inserting, using INSERT OR IGNORE.
|
|
733
|
+
# Exists mostly for compatibility to MySQL's insert_ignore. Example:
|
|
734
|
+
#
|
|
735
|
+
# DB[:table].insert_ignore.insert(a: 1, b: 2)
|
|
736
|
+
# # INSERT OR IGNORE INTO TABLE (a, b) VALUES (1, 2)
|
|
737
|
+
def insert_ignore
|
|
738
|
+
insert_conflict(:ignore)
|
|
739
|
+
end
|
|
740
|
+
|
|
608
741
|
# SQLite 3.8.3+ supports common table expressions.
|
|
609
742
|
def supports_cte?(type=:select)
|
|
610
743
|
db.sqlite_version >= 30803
|
|
611
744
|
end
|
|
612
745
|
|
|
746
|
+
# SQLite supports CTEs in subqueries if it supports CTEs.
|
|
747
|
+
def supports_cte_in_subqueries?
|
|
748
|
+
supports_cte?
|
|
749
|
+
end
|
|
750
|
+
|
|
613
751
|
# SQLite does not support table aliases with column aliases
|
|
614
752
|
def supports_derived_column_lists?
|
|
615
753
|
false
|
|
@@ -641,14 +779,32 @@ module Sequel
|
|
|
641
779
|
def supports_where_true?
|
|
642
780
|
false
|
|
643
781
|
end
|
|
782
|
+
|
|
783
|
+
# SQLite 3.28+ supports the WINDOW clause.
|
|
784
|
+
def supports_window_clause?
|
|
785
|
+
db.sqlite_version >= 32800
|
|
786
|
+
end
|
|
644
787
|
|
|
788
|
+
# SQLite 3.25+ supports window functions. However, support is only enabled
|
|
789
|
+
# on SQLite 3.26.0+ because internal Sequel usage of window functions
|
|
790
|
+
# to implement eager loading of limited associations triggers
|
|
791
|
+
# an SQLite crash bug in versions 3.25.0-3.25.3.
|
|
792
|
+
def supports_window_functions?
|
|
793
|
+
db.sqlite_version >= 32600
|
|
794
|
+
end
|
|
795
|
+
|
|
796
|
+
# SQLite 3.28.0+ supports all window frame options that Sequel supports
|
|
797
|
+
def supports_window_function_frame_option?(option)
|
|
798
|
+
db.sqlite_version >= 32800 ? true : super
|
|
799
|
+
end
|
|
800
|
+
|
|
645
801
|
private
|
|
646
802
|
|
|
647
803
|
# SQLite uses string literals instead of identifiers in AS clauses.
|
|
648
804
|
def as_sql_append(sql, aliaz, column_aliases=nil)
|
|
649
805
|
raise Error, "sqlite does not support derived column lists" if column_aliases
|
|
650
806
|
aliaz = aliaz.value if aliaz.is_a?(SQL::Identifier)
|
|
651
|
-
sql << AS
|
|
807
|
+
sql << ' AS '
|
|
652
808
|
literal_append(sql, aliaz.to_s)
|
|
653
809
|
end
|
|
654
810
|
|
|
@@ -676,12 +832,49 @@ module Sequel
|
|
|
676
832
|
|
|
677
833
|
# SQL fragment specifying a list of identifiers
|
|
678
834
|
def identifier_list(columns)
|
|
679
|
-
columns.map{|i| quote_identifier(i)}.join(
|
|
835
|
+
columns.map{|i| quote_identifier(i)}.join(', ')
|
|
680
836
|
end
|
|
681
837
|
|
|
838
|
+
# Add OR clauses to SQLite INSERT statements
|
|
839
|
+
def insert_conflict_sql(sql)
|
|
840
|
+
if resolution = @opts[:insert_conflict]
|
|
841
|
+
sql << " OR " << resolution.to_s.upcase
|
|
842
|
+
end
|
|
843
|
+
end
|
|
844
|
+
|
|
845
|
+
# Add ON CONFLICT clause if it should be used
|
|
846
|
+
def insert_on_conflict_sql(sql)
|
|
847
|
+
if opts = @opts[:insert_on_conflict]
|
|
848
|
+
sql << " ON CONFLICT"
|
|
849
|
+
|
|
850
|
+
if target = opts[:constraint]
|
|
851
|
+
sql << " ON CONSTRAINT "
|
|
852
|
+
identifier_append(sql, target)
|
|
853
|
+
elsif target = opts[:target]
|
|
854
|
+
sql << ' '
|
|
855
|
+
identifier_append(sql, Array(target))
|
|
856
|
+
if conflict_where = opts[:conflict_where]
|
|
857
|
+
sql << " WHERE "
|
|
858
|
+
literal_append(sql, conflict_where)
|
|
859
|
+
end
|
|
860
|
+
end
|
|
861
|
+
|
|
862
|
+
if values = opts[:update]
|
|
863
|
+
sql << " DO UPDATE SET "
|
|
864
|
+
update_sql_values_hash(sql, values)
|
|
865
|
+
if update_where = opts[:update_where]
|
|
866
|
+
sql << " WHERE "
|
|
867
|
+
literal_append(sql, update_where)
|
|
868
|
+
end
|
|
869
|
+
else
|
|
870
|
+
sql << " DO NOTHING"
|
|
871
|
+
end
|
|
872
|
+
end
|
|
873
|
+
end
|
|
874
|
+
|
|
682
875
|
# SQLite uses a preceding X for hex escaping strings
|
|
683
876
|
def literal_blob_append(sql, v)
|
|
684
|
-
sql <<
|
|
877
|
+
sql << "X'" << v.unpack("H*").first << "'"
|
|
685
878
|
end
|
|
686
879
|
|
|
687
880
|
# Respect the database integer_booleans setting, using 0 or 'f'.
|
|
@@ -700,6 +893,20 @@ module Sequel
|
|
|
700
893
|
db.sqlite_version >= 30711 ? :values : :union
|
|
701
894
|
end
|
|
702
895
|
|
|
896
|
+
# Emulate the char_length function with length
|
|
897
|
+
def native_function_name(emulated_function)
|
|
898
|
+
if emulated_function == :char_length
|
|
899
|
+
'length'
|
|
900
|
+
else
|
|
901
|
+
super
|
|
902
|
+
end
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
# SQLite supports NULLS FIRST/LAST natively in 3.30+.
|
|
906
|
+
def requires_emulating_nulls_first?
|
|
907
|
+
db.sqlite_version < 33000
|
|
908
|
+
end
|
|
909
|
+
|
|
703
910
|
# SQLite does not support FOR UPDATE, but silently ignore it
|
|
704
911
|
# instead of raising an error for compatibility with other
|
|
705
912
|
# databases.
|
|
@@ -708,10 +915,26 @@ module Sequel
|
|
|
708
915
|
end
|
|
709
916
|
|
|
710
917
|
def select_only_offset_sql(sql)
|
|
711
|
-
sql <<
|
|
918
|
+
sql << " LIMIT -1 OFFSET "
|
|
712
919
|
literal_append(sql, @opts[:offset])
|
|
713
920
|
end
|
|
714
921
|
|
|
922
|
+
# Support VALUES clause instead of the SELECT clause to return rows.
|
|
923
|
+
def select_values_sql(sql)
|
|
924
|
+
sql << "VALUES "
|
|
925
|
+
expression_list_append(sql, opts[:values])
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
# SQLite does not support CTEs directly inside UNION/INTERSECT/EXCEPT.
|
|
929
|
+
def supports_cte_in_compounds?
|
|
930
|
+
false
|
|
931
|
+
end
|
|
932
|
+
|
|
933
|
+
# SQLite 3.30 supports the FILTER clause for aggregate functions.
|
|
934
|
+
def supports_filtered_aggregates?
|
|
935
|
+
db.sqlite_version >= 33000
|
|
936
|
+
end
|
|
937
|
+
|
|
715
938
|
# SQLite supports quoted function names.
|
|
716
939
|
def supports_quoted_function_names?
|
|
717
940
|
true
|