sequel 4.36.0 → 5.61.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 +548 -5749
- data/MIT-LICENSE +1 -1
- data/README.rdoc +265 -159
- data/bin/sequel +34 -12
- data/doc/advanced_associations.rdoc +228 -187
- data/doc/association_basics.rdoc +281 -291
- data/doc/bin_sequel.rdoc +5 -3
- data/doc/cheat_sheet.rdoc +86 -51
- data/doc/code_order.rdoc +25 -19
- 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/fork_safety.rdoc +84 -0
- data/doc/mass_assignment.rdoc +74 -31
- data/doc/migration.rdoc +59 -51
- 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 +58 -68
- data/doc/opening_databases.rdoc +85 -95
- data/doc/postgresql.rdoc +263 -38
- data/doc/prepared_statements.rdoc +29 -24
- data/doc/querying.rdoc +189 -167
- 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.38.0.txt +28 -0
- data/doc/release_notes/5.39.0.txt +19 -0
- data/doc/release_notes/5.4.0.txt +80 -0
- data/doc/release_notes/5.40.0.txt +40 -0
- data/doc/release_notes/5.41.0.txt +25 -0
- data/doc/release_notes/5.42.0.txt +136 -0
- data/doc/release_notes/5.43.0.txt +98 -0
- data/doc/release_notes/5.44.0.txt +32 -0
- data/doc/release_notes/5.45.0.txt +34 -0
- data/doc/release_notes/5.46.0.txt +87 -0
- data/doc/release_notes/5.47.0.txt +59 -0
- data/doc/release_notes/5.48.0.txt +14 -0
- data/doc/release_notes/5.49.0.txt +59 -0
- data/doc/release_notes/5.5.0.txt +61 -0
- data/doc/release_notes/5.50.0.txt +78 -0
- data/doc/release_notes/5.51.0.txt +47 -0
- data/doc/release_notes/5.52.0.txt +87 -0
- data/doc/release_notes/5.53.0.txt +23 -0
- data/doc/release_notes/5.54.0.txt +27 -0
- data/doc/release_notes/5.55.0.txt +21 -0
- data/doc/release_notes/5.56.0.txt +51 -0
- data/doc/release_notes/5.57.0.txt +23 -0
- data/doc/release_notes/5.58.0.txt +31 -0
- data/doc/release_notes/5.59.0.txt +73 -0
- data/doc/release_notes/5.6.0.txt +31 -0
- data/doc/release_notes/5.60.0.txt +22 -0
- data/doc/release_notes/5.61.0.txt +43 -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 +95 -75
- data/doc/security.rdoc +109 -80
- data/doc/sharding.rdoc +74 -47
- data/doc/sql.rdoc +147 -122
- data/doc/testing.rdoc +43 -20
- data/doc/thread_safety.rdoc +2 -4
- data/doc/transactions.rdoc +97 -18
- data/doc/validations.rdoc +52 -50
- data/doc/virtual_rows.rdoc +90 -109
- data/lib/sequel/adapters/ado/access.rb +15 -17
- data/lib/sequel/adapters/ado/mssql.rb +6 -15
- data/lib/sequel/adapters/ado.rb +150 -20
- data/lib/sequel/adapters/amalgalite.rb +11 -23
- data/lib/sequel/adapters/ibmdb.rb +47 -55
- data/lib/sequel/adapters/jdbc/db2.rb +29 -39
- data/lib/sequel/adapters/jdbc/derby.rb +58 -54
- data/lib/sequel/adapters/jdbc/h2.rb +93 -35
- data/lib/sequel/adapters/jdbc/hsqldb.rb +24 -31
- data/lib/sequel/adapters/jdbc/jtds.rb +2 -10
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -11
- data/lib/sequel/adapters/jdbc/mysql.rb +17 -20
- data/lib/sequel/adapters/jdbc/oracle.rb +22 -18
- data/lib/sequel/adapters/jdbc/postgresql.rb +69 -71
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +11 -23
- data/lib/sequel/adapters/jdbc/sqlite.rb +47 -11
- data/lib/sequel/adapters/jdbc/sqlserver.rb +34 -9
- data/lib/sequel/adapters/jdbc/transactions.rb +22 -38
- data/lib/sequel/adapters/jdbc.rb +145 -130
- data/lib/sequel/adapters/mock.rb +100 -111
- data/lib/sequel/adapters/mysql.rb +114 -122
- data/lib/sequel/adapters/mysql2.rb +147 -63
- data/lib/sequel/adapters/odbc/db2.rb +1 -1
- data/lib/sequel/adapters/odbc/mssql.rb +8 -14
- data/lib/sequel/adapters/odbc/oracle.rb +11 -0
- data/lib/sequel/adapters/odbc.rb +20 -25
- data/lib/sequel/adapters/oracle.rb +50 -56
- data/lib/sequel/adapters/postgres.rb +305 -327
- data/lib/sequel/adapters/postgresql.rb +1 -1
- data/lib/sequel/adapters/shared/access.rb +74 -78
- data/lib/sequel/adapters/shared/db2.rb +118 -71
- data/lib/sequel/adapters/shared/mssql.rb +301 -220
- data/lib/sequel/adapters/shared/mysql.rb +299 -217
- data/lib/sequel/adapters/shared/oracle.rb +226 -65
- data/lib/sequel/adapters/shared/postgres.rb +935 -395
- data/lib/sequel/adapters/shared/sqlanywhere.rb +105 -126
- data/lib/sequel/adapters/shared/sqlite.rb +447 -173
- data/lib/sequel/adapters/sqlanywhere.rb +48 -35
- data/lib/sequel/adapters/sqlite.rb +156 -111
- data/lib/sequel/adapters/tinytds.rb +30 -38
- data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +3 -6
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +2 -2
- 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 +1 -4
- data/lib/sequel/adapters/utils/stored_procedures.rb +7 -22
- data/lib/sequel/adapters/utils/unmodified_identifiers.rb +28 -0
- data/lib/sequel/ast_transformer.rb +17 -89
- data/lib/sequel/connection_pool/sharded_single.rb +18 -15
- data/lib/sequel/connection_pool/sharded_threaded.rb +130 -111
- data/lib/sequel/connection_pool/single.rb +18 -13
- data/lib/sequel/connection_pool/threaded.rb +121 -120
- data/lib/sequel/connection_pool.rb +48 -29
- data/lib/sequel/core.rb +351 -301
- data/lib/sequel/database/connecting.rb +69 -57
- data/lib/sequel/database/dataset.rb +13 -5
- data/lib/sequel/database/dataset_defaults.rb +18 -102
- data/lib/sequel/database/features.rb +18 -4
- data/lib/sequel/database/logging.rb +12 -11
- data/lib/sequel/database/misc.rb +180 -122
- data/lib/sequel/database/query.rb +47 -27
- data/lib/sequel/database/schema_generator.rb +178 -84
- data/lib/sequel/database/schema_methods.rb +172 -97
- data/lib/sequel/database/transactions.rb +205 -44
- data/lib/sequel/database.rb +17 -2
- data/lib/sequel/dataset/actions.rb +339 -155
- data/lib/sequel/dataset/dataset_module.rb +46 -0
- data/lib/sequel/dataset/features.rb +90 -35
- data/lib/sequel/dataset/graph.rb +80 -58
- data/lib/sequel/dataset/misc.rb +137 -47
- data/lib/sequel/dataset/placeholder_literalizer.rb +63 -25
- data/lib/sequel/dataset/prepared_statements.rb +188 -85
- data/lib/sequel/dataset/query.rb +530 -222
- data/lib/sequel/dataset/sql.rb +590 -368
- data/lib/sequel/dataset.rb +26 -16
- data/lib/sequel/deprecated.rb +12 -2
- data/lib/sequel/exceptions.rb +46 -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 +2 -5
- data/lib/sequel/extensions/any_not_empty.rb +45 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +10 -10
- data/lib/sequel/extensions/async_thread_pool.rb +438 -0
- data/lib/sequel/extensions/auto_literal_strings.rb +74 -0
- data/lib/sequel/extensions/blank.rb +8 -0
- data/lib/sequel/extensions/caller_logging.rb +79 -0
- data/lib/sequel/extensions/columns_introspection.rb +4 -3
- data/lib/sequel/extensions/connection_expiration.rb +20 -10
- data/lib/sequel/extensions/connection_validator.rb +11 -10
- data/lib/sequel/extensions/constant_sql_override.rb +65 -0
- data/lib/sequel/extensions/constraint_validations.rb +62 -39
- data/lib/sequel/extensions/core_extensions.rb +42 -48
- data/lib/sequel/extensions/core_refinements.rb +80 -59
- data/lib/sequel/extensions/current_datetime_timestamp.rb +1 -4
- data/lib/sequel/extensions/date_arithmetic.rb +98 -39
- data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
- data/lib/sequel/extensions/datetime_parse_to_time.rb +41 -0
- data/lib/sequel/extensions/duplicate_columns_handler.rb +21 -14
- data/lib/sequel/extensions/empty_array_consider_nulls.rb +2 -2
- data/lib/sequel/extensions/escaped_like.rb +100 -0
- data/lib/sequel/extensions/eval_inspect.rb +12 -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 +1 -34
- data/lib/sequel/extensions/graph_each.rb +4 -4
- 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 +13 -5
- data/lib/sequel/extensions/integer64.rb +32 -0
- data/lib/sequel/extensions/is_distinct_from.rb +141 -0
- data/lib/sequel/extensions/looser_typecasting.rb +17 -8
- data/lib/sequel/extensions/migration.rb +119 -78
- data/lib/sequel/extensions/named_timezones.rb +88 -23
- data/lib/sequel/extensions/no_auto_literal_strings.rb +2 -82
- data/lib/sequel/extensions/null_dataset.rb +8 -8
- data/lib/sequel/extensions/pagination.rb +32 -29
- data/lib/sequel/extensions/pg_array.rb +221 -287
- data/lib/sequel/extensions/pg_array_ops.rb +17 -9
- data/lib/sequel/extensions/pg_enum.rb +63 -23
- data/lib/sequel/extensions/pg_extended_date_support.rb +241 -0
- data/lib/sequel/extensions/pg_hstore.rb +45 -54
- data/lib/sequel/extensions/pg_hstore_ops.rb +58 -6
- data/lib/sequel/extensions/pg_inet.rb +31 -12
- data/lib/sequel/extensions/pg_inet_ops.rb +2 -2
- data/lib/sequel/extensions/pg_interval.rb +56 -29
- data/lib/sequel/extensions/pg_json.rb +417 -140
- data/lib/sequel/extensions/pg_json_ops.rb +270 -18
- data/lib/sequel/extensions/pg_loose_count.rb +4 -2
- data/lib/sequel/extensions/pg_multirange.rb +372 -0
- data/lib/sequel/extensions/pg_range.rb +131 -191
- data/lib/sequel/extensions/pg_range_ops.rb +42 -13
- data/lib/sequel/extensions/pg_row.rb +48 -81
- data/lib/sequel/extensions/pg_row_ops.rb +33 -14
- data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -2
- data/lib/sequel/extensions/pg_timestamptz.rb +28 -0
- data/lib/sequel/extensions/query.rb +9 -7
- data/lib/sequel/extensions/round_timestamps.rb +0 -6
- data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
- data/lib/sequel/extensions/s.rb +60 -0
- data/lib/sequel/extensions/schema_caching.rb +10 -1
- data/lib/sequel/extensions/schema_dumper.rb +71 -48
- data/lib/sequel/extensions/select_remove.rb +4 -4
- data/lib/sequel/extensions/sequel_4_dataset_methods.rb +85 -0
- data/lib/sequel/extensions/server_block.rb +51 -27
- data/lib/sequel/extensions/split_array_nil.rb +4 -4
- data/lib/sequel/extensions/sql_comments.rb +119 -7
- data/lib/sequel/extensions/sql_expr.rb +2 -1
- data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
- data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
- data/lib/sequel/extensions/string_agg.rb +11 -8
- data/lib/sequel/extensions/string_date_time.rb +19 -23
- data/lib/sequel/extensions/symbol_aref.rb +55 -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/to_dot.rb +10 -4
- data/lib/sequel/extensions/virtual_row_method_block.rb +44 -0
- data/lib/sequel/model/associations.rb +1006 -284
- data/lib/sequel/model/base.rb +560 -805
- data/lib/sequel/model/dataset_module.rb +11 -10
- data/lib/sequel/model/default_inflections.rb +1 -1
- data/lib/sequel/model/errors.rb +10 -3
- data/lib/sequel/model/exceptions.rb +8 -10
- data/lib/sequel/model/inflections.rb +7 -20
- data/lib/sequel/model/plugins.rb +114 -0
- data/lib/sequel/model.rb +32 -82
- data/lib/sequel/plugins/active_model.rb +30 -14
- data/lib/sequel/plugins/after_initialize.rb +1 -1
- data/lib/sequel/plugins/association_dependencies.rb +25 -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 +147 -70
- data/lib/sequel/plugins/association_proxies.rb +33 -9
- data/lib/sequel/plugins/async_thread_pool.rb +39 -0
- data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
- data/lib/sequel/plugins/auto_validations.rb +95 -28
- data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
- data/lib/sequel/plugins/before_after_save.rb +0 -42
- data/lib/sequel/plugins/blacklist_security.rb +21 -12
- data/lib/sequel/plugins/boolean_readers.rb +5 -5
- data/lib/sequel/plugins/boolean_subsets.rb +13 -8
- data/lib/sequel/plugins/caching.rb +25 -16
- data/lib/sequel/plugins/class_table_inheritance.rb +179 -100
- data/lib/sequel/plugins/column_conflicts.rb +16 -3
- data/lib/sequel/plugins/column_encryption.rb +728 -0
- data/lib/sequel/plugins/column_select.rb +7 -5
- data/lib/sequel/plugins/columns_updated.rb +42 -0
- data/lib/sequel/plugins/composition.rb +42 -26
- data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
- data/lib/sequel/plugins/constraint_validations.rb +20 -14
- data/lib/sequel/plugins/csv_serializer.rb +56 -35
- data/lib/sequel/plugins/dataset_associations.rb +40 -17
- data/lib/sequel/plugins/def_dataset_method.rb +90 -0
- data/lib/sequel/plugins/defaults_setter.rb +65 -10
- data/lib/sequel/plugins/delay_add_association.rb +1 -1
- data/lib/sequel/plugins/dirty.rb +62 -24
- data/lib/sequel/plugins/eager_each.rb +3 -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/enum.rb +124 -0
- data/lib/sequel/plugins/error_splitter.rb +17 -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 +7 -12
- data/lib/sequel/plugins/hook_class_methods.rb +37 -54
- data/lib/sequel/plugins/input_transformer.rb +18 -10
- data/lib/sequel/plugins/insert_conflict.rb +76 -0
- data/lib/sequel/plugins/insert_returning_select.rb +2 -2
- data/lib/sequel/plugins/instance_filters.rb +10 -8
- data/lib/sequel/plugins/instance_hooks.rb +34 -17
- data/lib/sequel/plugins/instance_specific_default.rb +113 -0
- data/lib/sequel/plugins/inverted_subsets.rb +22 -13
- data/lib/sequel/plugins/json_serializer.rb +124 -64
- data/lib/sequel/plugins/lazy_attributes.rb +21 -14
- data/lib/sequel/plugins/list.rb +35 -21
- data/lib/sequel/plugins/many_through_many.rb +134 -21
- data/lib/sequel/plugins/modification_detection.rb +15 -5
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +6 -5
- data/lib/sequel/plugins/nested_attributes.rb +61 -31
- data/lib/sequel/plugins/optimistic_locking.rb +3 -3
- data/lib/sequel/plugins/pg_array_associations.rb +103 -53
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +350 -0
- data/lib/sequel/plugins/pg_row.rb +5 -51
- data/lib/sequel/plugins/prepared_statements.rb +60 -72
- data/lib/sequel/plugins/prepared_statements_safe.rb +9 -4
- data/lib/sequel/plugins/rcte_tree.rb +68 -82
- data/lib/sequel/plugins/require_valid_schema.rb +67 -0
- data/lib/sequel/plugins/serialization.rb +43 -46
- data/lib/sequel/plugins/serialization_modification_detection.rb +3 -2
- data/lib/sequel/plugins/sharding.rb +15 -10
- data/lib/sequel/plugins/single_table_inheritance.rb +67 -28
- data/lib/sequel/plugins/skip_create_refresh.rb +3 -3
- data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
- data/lib/sequel/plugins/split_values.rb +11 -6
- data/lib/sequel/plugins/sql_comments.rb +189 -0
- data/lib/sequel/plugins/static_cache.rb +77 -53
- data/lib/sequel/plugins/static_cache_cache.rb +53 -0
- data/lib/sequel/plugins/string_stripper.rb +3 -3
- data/lib/sequel/plugins/subclasses.rb +43 -10
- data/lib/sequel/plugins/subset_conditions.rb +15 -5
- data/lib/sequel/plugins/table_select.rb +2 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +96 -12
- data/lib/sequel/plugins/throw_failures.rb +110 -0
- data/lib/sequel/plugins/timestamps.rb +20 -8
- data/lib/sequel/plugins/touch.rb +19 -8
- data/lib/sequel/plugins/tree.rb +62 -32
- data/lib/sequel/plugins/typecast_on_load.rb +12 -4
- data/lib/sequel/plugins/unlimited_update.rb +1 -7
- data/lib/sequel/plugins/unused_associations.rb +521 -0
- data/lib/sequel/plugins/update_or_create.rb +4 -4
- data/lib/sequel/plugins/update_primary_key.rb +1 -1
- data/lib/sequel/plugins/update_refresh.rb +26 -15
- data/lib/sequel/plugins/uuid.rb +7 -11
- data/lib/sequel/plugins/validate_associated.rb +18 -0
- data/lib/sequel/plugins/validation_class_methods.rb +38 -19
- data/lib/sequel/plugins/validation_contexts.rb +49 -0
- data/lib/sequel/plugins/validation_helpers.rb +57 -41
- data/lib/sequel/plugins/whitelist_security.rb +122 -0
- data/lib/sequel/plugins/xml_serializer.rb +30 -31
- data/lib/sequel/sql.rb +471 -331
- data/lib/sequel/timezones.rb +78 -47
- data/lib/sequel/version.rb +7 -2
- data/lib/sequel.rb +1 -1
- metadata +217 -521
- data/Rakefile +0 -164
- data/doc/active_record.rdoc +0 -928
- 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.27.0.txt +0 -78
- data/doc/release_notes/4.28.0.txt +0 -57
- data/doc/release_notes/4.29.0.txt +0 -41
- data/doc/release_notes/4.3.0.txt +0 -40
- data/doc/release_notes/4.30.0.txt +0 -37
- data/doc/release_notes/4.31.0.txt +0 -57
- data/doc/release_notes/4.32.0.txt +0 -132
- data/doc/release_notes/4.33.0.txt +0 -88
- data/doc/release_notes/4.34.0.txt +0 -86
- data/doc/release_notes/4.35.0.txt +0 -130
- data/doc/release_notes/4.36.0.txt +0 -116
- 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 -144
- data/lib/sequel/adapters/do/mysql.rb +0 -66
- data/lib/sequel/adapters/do/postgres.rb +0 -44
- data/lib/sequel/adapters/do/sqlite3.rb +0 -42
- data/lib/sequel/adapters/do.rb +0 -158
- data/lib/sequel/adapters/jdbc/as400.rb +0 -84
- data/lib/sequel/adapters/jdbc/cubrid.rb +0 -64
- data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -36
- data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -33
- data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -33
- data/lib/sequel/adapters/odbc/progress.rb +0 -10
- data/lib/sequel/adapters/shared/cubrid.rb +0 -245
- data/lib/sequel/adapters/shared/firebird.rb +0 -247
- data/lib/sequel/adapters/shared/informix.rb +0 -54
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +0 -152
- data/lib/sequel/adapters/shared/progress.rb +0 -40
- data/lib/sequel/adapters/swift/mysql.rb +0 -49
- data/lib/sequel/adapters/swift/postgres.rb +0 -47
- data/lib/sequel/adapters/swift/sqlite.rb +0 -49
- data/lib/sequel/adapters/swift.rb +0 -160
- data/lib/sequel/adapters/utils/pg_types.rb +0 -70
- data/lib/sequel/dataset/mutation.rb +0 -111
- data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -5
- data/lib/sequel/extensions/filter_having.rb +0 -63
- data/lib/sequel/extensions/hash_aliases.rb +0 -49
- data/lib/sequel/extensions/meta_def.rb +0 -35
- data/lib/sequel/extensions/query_literals.rb +0 -84
- data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -24
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -122
- data/lib/sequel/extensions/set_overrides.rb +0 -76
- data/lib/sequel/no_core_ext.rb +0 -3
- data/lib/sequel/plugins/association_autoreloading.rb +0 -9
- data/lib/sequel/plugins/identifier_columns.rb +0 -47
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -9
- data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -81
- data/lib/sequel/plugins/prepared_statements_associations.rb +0 -119
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -61
- data/lib/sequel/plugins/schema.rb +0 -82
- data/lib/sequel/plugins/scissors.rb +0 -35
- data/spec/adapter_spec.rb +0 -4
- 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 -733
- data/spec/adapters/mysql_spec.rb +0 -1319
- data/spec/adapters/oracle_spec.rb +0 -313
- data/spec/adapters/postgres_spec.rb +0 -3790
- data/spec/adapters/spec_helper.rb +0 -49
- data/spec/adapters/sqlanywhere_spec.rb +0 -170
- data/spec/adapters/sqlite_spec.rb +0 -688
- data/spec/bin_spec.rb +0 -258
- data/spec/core/connection_pool_spec.rb +0 -1045
- data/spec/core/database_spec.rb +0 -2636
- data/spec/core/dataset_spec.rb +0 -5175
- data/spec/core/deprecated_spec.rb +0 -70
- data/spec/core/expression_filters_spec.rb +0 -1247
- data/spec/core/mock_adapter_spec.rb +0 -464
- 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 -203
- data/spec/core/schema_spec.rb +0 -1676
- 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/core_model_spec.rb +0 -2
- data/spec/core_spec.rb +0 -1
- data/spec/extensions/accessed_columns_spec.rb +0 -51
- data/spec/extensions/active_model_spec.rb +0 -85
- 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 -405
- data/spec/extensions/association_proxies_spec.rb +0 -86
- data/spec/extensions/auto_validations_spec.rb +0 -192
- data/spec/extensions/before_after_save_spec.rb +0 -40
- 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/boolean_subsets_spec.rb +0 -47
- data/spec/extensions/caching_spec.rb +0 -270
- data/spec/extensions/class_table_inheritance_spec.rb +0 -444
- 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_expiration_spec.rb +0 -121
- data/spec/extensions/connection_validator_spec.rb +0 -127
- data/spec/extensions/constraint_validations_plugin_spec.rb +0 -288
- data/spec/extensions/constraint_validations_spec.rb +0 -389
- data/spec/extensions/core_refinements_spec.rb +0 -519
- data/spec/extensions/csv_serializer_spec.rb +0 -180
- data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
- data/spec/extensions/dataset_associations_spec.rb +0 -343
- data/spec/extensions/dataset_source_alias_spec.rb +0 -51
- data/spec/extensions/date_arithmetic_spec.rb +0 -167
- data/spec/extensions/defaults_setter_spec.rb +0 -102
- data/spec/extensions/delay_add_association_spec.rb +0 -74
- data/spec/extensions/dirty_spec.rb +0 -180
- data/spec/extensions/duplicate_columns_handler_spec.rb +0 -110
- data/spec/extensions/eager_each_spec.rb +0 -66
- 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 -119
- data/spec/extensions/hash_aliases_spec.rb +0 -24
- data/spec/extensions/hook_class_methods_spec.rb +0 -429
- data/spec/extensions/identifier_columns_spec.rb +0 -17
- 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 -304
- data/spec/extensions/lazy_attributes_spec.rb +0 -170
- data/spec/extensions/list_spec.rb +0 -278
- 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 -728
- 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/no_auto_literal_strings_spec.rb +0 -65
- 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 -390
- 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 -275
- 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 -473
- 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 -814
- 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/server_logging_spec.rb +0 -45
- 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_comments_spec.rb +0 -27
- data/spec/extensions/sql_expr_spec.rb +0 -60
- data/spec/extensions/static_cache_spec.rb +0 -361
- data/spec/extensions/string_agg_spec.rb +0 -85
- 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/subset_conditions_spec.rb +0 -38
- data/spec/extensions/table_select_spec.rb +0 -71
- data/spec/extensions/tactical_eager_loading_spec.rb +0 -136
- 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/uuid_spec.rb +0 -106
- 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 -554
- 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/double_migration/001_create_sessions.rb +0 -9
- data/spec/files/double_migration/002_create_nodes.rb +0 -19
- data/spec/files/double_migration/003_3_create_users.rb +0 -4
- 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/empty_migration/001_create_sessions.rb +0 -9
- data/spec/files/empty_migration/002_create_nodes.rb +0 -0
- data/spec/files/empty_migration/003_3_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/reversible_migrations/006_reversible.rb +0 -10
- data/spec/files/reversible_migrations/007_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 -2506
- data/spec/integration/database_test.rb +0 -113
- data/spec/integration/dataset_test.rb +0 -1858
- data/spec/integration/eager_loader_test.rb +0 -687
- data/spec/integration/migrator_test.rb +0 -262
- data/spec/integration/model_test.rb +0 -230
- data/spec/integration/plugin_test.rb +0 -2297
- data/spec/integration/prepared_statement_test.rb +0 -467
- data/spec/integration/schema_test.rb +0 -815
- data/spec/integration/spec_helper.rb +0 -56
- data/spec/integration/timezone_test.rb +0 -86
- data/spec/integration/transaction_test.rb +0 -406
- data/spec/integration/type_test.rb +0 -133
- data/spec/model/association_reflection_spec.rb +0 -565
- data/spec/model/associations_spec.rb +0 -4589
- data/spec/model/base_spec.rb +0 -759
- data/spec/model/class_dataset_methods_spec.rb +0 -150
- data/spec/model/dataset_methods_spec.rb +0 -149
- data/spec/model/eager_loading_spec.rb +0 -2197
- data/spec/model/hooks_spec.rb +0 -604
- data/spec/model/inflector_spec.rb +0 -26
- data/spec/model/model_spec.rb +0 -1097
- data/spec/model/plugins_spec.rb +0 -299
- data/spec/model/record_spec.rb +0 -2162
- data/spec/model/spec_helper.rb +0 -46
- data/spec/model/validations_spec.rb +0 -193
- data/spec/model_no_assoc_spec.rb +0 -1
- data/spec/model_spec.rb +0 -1
- data/spec/plugin_spec.rb +0 -1
- data/spec/sequel_coverage.rb +0 -15
- data/spec/spec_config.rb +0 -10
|
@@ -1,63 +1,113 @@
|
|
|
1
1
|
# frozen-string-literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require_relative '../utils/unmodified_identifiers'
|
|
4
4
|
|
|
5
5
|
module Sequel
|
|
6
6
|
# Top level module for holding all PostgreSQL-related modules and classes
|
|
7
|
-
# for Sequel.
|
|
8
|
-
# metaprogramming. These are:
|
|
9
|
-
#
|
|
10
|
-
# client_min_messages :: Change the minimum level of messages that PostgreSQL will send to the
|
|
11
|
-
# the client. The PostgreSQL default is NOTICE, the Sequel default is
|
|
12
|
-
# WARNING. Set to nil to not change the server default. Overridable on
|
|
13
|
-
# a per instance basis via the :client_min_messages option.
|
|
14
|
-
# force_standard_strings :: Set to false to not force the use of standard strings. Overridable
|
|
15
|
-
# on a per instance basis via the :force_standard_strings option.
|
|
16
|
-
#
|
|
17
|
-
# It is not recommened you use these module-level accessors. Instead,
|
|
18
|
-
# use the database option to make the setting per-Database.
|
|
19
|
-
#
|
|
20
|
-
# All adapters that connect to PostgreSQL support the following option in
|
|
21
|
-
# addition to those mentioned above:
|
|
7
|
+
# for Sequel. All adapters that connect to PostgreSQL support the following options:
|
|
22
8
|
#
|
|
9
|
+
# :client_min_messages :: Change the minimum level of messages that PostgreSQL will send to the
|
|
10
|
+
# the client. The PostgreSQL default is NOTICE, the Sequel default is
|
|
11
|
+
# WARNING. Set to nil to not change the server default. Overridable on
|
|
12
|
+
# a per instance basis via the :client_min_messages option.
|
|
13
|
+
# :force_standard_strings :: Set to false to not force the use of standard strings. Overridable
|
|
14
|
+
# on a per instance basis via the :force_standard_strings option.
|
|
23
15
|
# :search_path :: Set the schema search_path for this Database's connections.
|
|
24
16
|
# Allows to to set which schemas do not need explicit
|
|
25
17
|
# qualification, and in which order to check the schemas when
|
|
26
18
|
# an unqualified object is referenced.
|
|
27
19
|
module Postgres
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
20
|
+
Sequel::Database.set_shared_adapter_scheme(:postgres, self)
|
|
21
|
+
|
|
22
|
+
NAN = 0.0/0.0
|
|
23
|
+
PLUS_INFINITY = 1.0/0.0
|
|
24
|
+
MINUS_INFINITY = -1.0/0.0
|
|
25
|
+
|
|
26
|
+
boolean = Object.new
|
|
27
|
+
def boolean.call(s) s == 't' end
|
|
28
|
+
integer = Object.new
|
|
29
|
+
def integer.call(s) s.to_i end
|
|
30
|
+
float = Object.new
|
|
31
|
+
def float.call(s)
|
|
32
|
+
case s
|
|
33
|
+
when 'NaN'
|
|
34
|
+
NAN
|
|
35
|
+
when 'Infinity'
|
|
36
|
+
PLUS_INFINITY
|
|
37
|
+
when '-Infinity'
|
|
38
|
+
MINUS_INFINITY
|
|
39
|
+
else
|
|
40
|
+
s.to_f
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
date = Object.new
|
|
44
|
+
def date.call(s) ::Date.new(*s.split('-').map(&:to_i)) end
|
|
45
|
+
TYPE_TRANSLATOR_DATE = date.freeze
|
|
46
|
+
bytea = Object.new
|
|
47
|
+
def bytea.call(str)
|
|
48
|
+
str = if str =~ /\A\\x/
|
|
49
|
+
# PostgreSQL 9.0+ bytea hex format
|
|
50
|
+
str[2..-1].gsub(/(..)/){|s| s.to_i(16).chr}
|
|
51
|
+
else
|
|
52
|
+
# Historical PostgreSQL bytea escape format
|
|
53
|
+
str.gsub(/\\(\\|'|[0-3][0-7][0-7])/) {|s|
|
|
54
|
+
if s.size == 2 then s[1,1] else s[1,3].oct.chr end
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
::Sequel::SQL::Blob.new(str)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
CONVERSION_PROCS = {}
|
|
61
|
+
|
|
62
|
+
{
|
|
63
|
+
[16] => boolean,
|
|
64
|
+
[17] => bytea,
|
|
65
|
+
[20, 21, 23, 26] => integer,
|
|
66
|
+
[700, 701] => float,
|
|
67
|
+
[1700] => ::Kernel.method(:BigDecimal),
|
|
68
|
+
[1083, 1266] => ::Sequel.method(:string_to_time),
|
|
69
|
+
[1082] => ::Sequel.method(:string_to_date),
|
|
70
|
+
[1184, 1114] => ::Sequel.method(:database_to_application_timestamp),
|
|
71
|
+
}.each do |k,v|
|
|
72
|
+
k.each do |n|
|
|
73
|
+
CONVERSION_PROCS[n] = v
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
CONVERSION_PROCS.freeze
|
|
77
|
+
|
|
78
|
+
module MockAdapterDatabaseMethods
|
|
79
|
+
def bound_variable_arg(arg, conn)
|
|
80
|
+
arg
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def primary_key(table)
|
|
84
|
+
:id
|
|
85
|
+
end
|
|
48
86
|
end
|
|
49
87
|
|
|
50
|
-
|
|
88
|
+
def self.mock_adapter_setup(db)
|
|
89
|
+
db.instance_exec do
|
|
90
|
+
@server_version = 140000
|
|
91
|
+
initialize_postgres_adapter
|
|
92
|
+
extend(MockAdapterDatabaseMethods)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
class CreateTableGenerator < Sequel::Schema::CreateTableGenerator
|
|
51
97
|
# Add an exclusion constraint when creating the table. Elements should be
|
|
52
98
|
# an array of 2 element arrays, with the first element being the column or
|
|
53
99
|
# expression the exclusion constraint is applied to, and the second element
|
|
54
|
-
# being the operator to use for the column/expression to check for exclusion
|
|
55
|
-
#
|
|
56
|
-
# Example:
|
|
100
|
+
# being the operator to use for the column/expression to check for exclusion:
|
|
57
101
|
#
|
|
58
102
|
# exclude([[:col1, '&&'], [:col2, '=']])
|
|
59
103
|
# # EXCLUDE USING gist (col1 WITH &&, col2 WITH =)
|
|
60
104
|
#
|
|
105
|
+
# To use a custom operator class, you need to use Sequel.lit with the expression
|
|
106
|
+
# and operator class:
|
|
107
|
+
#
|
|
108
|
+
# exclude([[Sequel.lit('col1 inet_ops'), '&&'], [:col2, '=']])
|
|
109
|
+
# # EXCLUDE USING gist (col1 inet_ops WITH &&, col2 WITH =)
|
|
110
|
+
#
|
|
61
111
|
# Options supported:
|
|
62
112
|
#
|
|
63
113
|
# :name :: Name the constraint with the given name (useful if you may
|
|
@@ -84,21 +134,105 @@ module Sequel
|
|
|
84
134
|
end
|
|
85
135
|
end
|
|
86
136
|
|
|
137
|
+
# Generator used for creating tables that are partitions of other tables.
|
|
138
|
+
class CreatePartitionOfTableGenerator
|
|
139
|
+
MINVALUE = Sequel.lit('MINVALUE').freeze
|
|
140
|
+
MAXVALUE = Sequel.lit('MAXVALUE').freeze
|
|
141
|
+
|
|
142
|
+
def initialize(&block)
|
|
143
|
+
instance_exec(&block)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# The minimum value of the data type used in range partitions, useful
|
|
147
|
+
# as an argument to #from.
|
|
148
|
+
def minvalue
|
|
149
|
+
MINVALUE
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# The minimum value of the data type used in range partitions, useful
|
|
153
|
+
# as an argument to #to.
|
|
154
|
+
def maxvalue
|
|
155
|
+
MAXVALUE
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Assumes range partitioning, sets the inclusive minimum value of the range for
|
|
159
|
+
# this partition.
|
|
160
|
+
def from(*v)
|
|
161
|
+
@from = v
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Assumes range partitioning, sets the exclusive maximum value of the range for
|
|
165
|
+
# this partition.
|
|
166
|
+
def to(*v)
|
|
167
|
+
@to = v
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Assumes list partitioning, sets the values to be included in this partition.
|
|
171
|
+
def values_in(*v)
|
|
172
|
+
@in = v
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Assumes hash partitioning, sets the modulus for this parition.
|
|
176
|
+
def modulus(v)
|
|
177
|
+
@modulus = v
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Assumes hash partitioning, sets the remainder for this parition.
|
|
181
|
+
def remainder(v)
|
|
182
|
+
@remainder = v
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Sets that this is a default partition, where values not in other partitions
|
|
186
|
+
# are stored.
|
|
187
|
+
def default
|
|
188
|
+
@default = true
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# The from and to values of this partition for a range partition.
|
|
192
|
+
def range
|
|
193
|
+
[@from, @to]
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# The values to include in this partition for a list partition.
|
|
197
|
+
def list
|
|
198
|
+
@in
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# The modulus and remainder to use for this partition for a hash partition.
|
|
202
|
+
def hash_values
|
|
203
|
+
[@modulus, @remainder]
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Determine the appropriate partition type for this partition by which methods
|
|
207
|
+
# were called on it.
|
|
208
|
+
def partition_type
|
|
209
|
+
raise Error, "Unable to determine partition type, multiple different partitioning methods called" if [@from || @to, @list, @modulus || @remainder, @default].compact.length > 1
|
|
210
|
+
|
|
211
|
+
if @from || @to
|
|
212
|
+
raise Error, "must call both from and to when creating a partition of a table if calling either" unless @from && @to
|
|
213
|
+
:range
|
|
214
|
+
elsif @in
|
|
215
|
+
:list
|
|
216
|
+
elsif @modulus || @remainder
|
|
217
|
+
raise Error, "must call both modulus and remainder when creating a partition of a table if calling either" unless @modulus && @remainder
|
|
218
|
+
:hash
|
|
219
|
+
elsif @default
|
|
220
|
+
:default
|
|
221
|
+
else
|
|
222
|
+
raise Error, "unable to determine partition type, no partitioning methods called"
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
87
227
|
# Error raised when Sequel determines a PostgreSQL exclusion constraint has been violated.
|
|
88
228
|
class ExclusionConstraintViolation < Sequel::ConstraintViolation; end
|
|
89
229
|
|
|
90
|
-
# Methods shared by Database instances that connect to PostgreSQL.
|
|
91
230
|
module DatabaseMethods
|
|
92
|
-
|
|
231
|
+
include UnmodifiedIdentifiers::DatabaseMethods
|
|
93
232
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
POSTGRES_DEFAULT_RE = /\A(?:B?('.*')::[^']+|\((-?\d+(?:\.\d+)?)\))\z/
|
|
98
|
-
UNLOGGED = 'UNLOGGED '.freeze
|
|
99
|
-
ON_COMMIT = {
|
|
100
|
-
:drop => 'DROP', :delete_rows => 'DELETE ROWS', :preserve_rows => 'PRESERVE ROWS',
|
|
101
|
-
}.freeze
|
|
233
|
+
FOREIGN_KEY_LIST_ON_DELETE_MAP = {'a'=>:no_action, 'r'=>:restrict, 'c'=>:cascade, 'n'=>:set_null, 'd'=>:set_default}.freeze
|
|
234
|
+
ON_COMMIT = {:drop => 'DROP', :delete_rows => 'DELETE ROWS', :preserve_rows => 'PRESERVE ROWS'}.freeze
|
|
235
|
+
ON_COMMIT.each_value(&:freeze)
|
|
102
236
|
|
|
103
237
|
# SQL fragment for custom sequences (ones not created by serial primary key),
|
|
104
238
|
# Returning the schema and literal form of the sequence name, by parsing
|
|
@@ -106,10 +240,10 @@ module Sequel
|
|
|
106
240
|
SELECT_CUSTOM_SEQUENCE_SQL = (<<-end_sql
|
|
107
241
|
SELECT name.nspname AS "schema",
|
|
108
242
|
CASE
|
|
109
|
-
WHEN split_part(def.
|
|
110
|
-
substr(split_part(def.
|
|
111
|
-
strpos(split_part(def.
|
|
112
|
-
ELSE split_part(def.
|
|
243
|
+
WHEN split_part(pg_get_expr(def.adbin, attr.attrelid), '''', 2) ~ '.' THEN
|
|
244
|
+
substr(split_part(pg_get_expr(def.adbin, attr.attrelid), '''', 2),
|
|
245
|
+
strpos(split_part(pg_get_expr(def.adbin, attr.attrelid), '''', 2), '.')+1)
|
|
246
|
+
ELSE split_part(pg_get_expr(def.adbin, attr.attrelid), '''', 2)
|
|
113
247
|
END AS "sequence"
|
|
114
248
|
FROM pg_class t
|
|
115
249
|
JOIN pg_namespace name ON (t.relnamespace = name.oid)
|
|
@@ -117,7 +251,7 @@ module Sequel
|
|
|
117
251
|
JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
|
|
118
252
|
JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
|
|
119
253
|
WHERE cons.contype = 'p'
|
|
120
|
-
AND def.
|
|
254
|
+
AND pg_get_expr(def.adbin, attr.attrelid) ~* 'nextval'
|
|
121
255
|
end_sql
|
|
122
256
|
).strip.gsub(/\s+/, ' ').freeze
|
|
123
257
|
|
|
@@ -156,21 +290,121 @@ module Sequel
|
|
|
156
290
|
# having callable values for the conversion proc for that type.
|
|
157
291
|
attr_reader :conversion_procs
|
|
158
292
|
|
|
159
|
-
#
|
|
160
|
-
#
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
293
|
+
# Set a conversion proc for the given oid. The callable can
|
|
294
|
+
# be passed either as a argument or a block.
|
|
295
|
+
def add_conversion_proc(oid, callable=nil, &block)
|
|
296
|
+
conversion_procs[oid] = callable || block
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
# Add a conversion proc for a named type, using the given block.
|
|
300
|
+
# This should be used for types without fixed OIDs, which includes all types that
|
|
301
|
+
# are not included in a default PostgreSQL installation.
|
|
164
302
|
def add_named_conversion_proc(name, &block)
|
|
165
|
-
|
|
303
|
+
unless oid = from(:pg_type).where(:typtype=>['b', 'e'], :typname=>name.to_s).get(:oid)
|
|
304
|
+
raise Error, "No matching type in pg_type for #{name.inspect}"
|
|
305
|
+
end
|
|
306
|
+
add_conversion_proc(oid, block)
|
|
166
307
|
end
|
|
167
308
|
|
|
168
|
-
# Commit an existing prepared transaction with the given transaction
|
|
169
|
-
# identifier string.
|
|
170
309
|
def commit_prepared_transaction(transaction_id, opts=OPTS)
|
|
171
310
|
run("COMMIT PREPARED #{literal(transaction_id)}", opts)
|
|
172
311
|
end
|
|
173
312
|
|
|
313
|
+
# A hash of metadata for CHECK constraints on the table.
|
|
314
|
+
# Keys are CHECK constraint name symbols. Values are hashes with the following keys:
|
|
315
|
+
# :definition :: An SQL fragment for the definition of the constraint
|
|
316
|
+
# :columns :: An array of column symbols for the columns referenced in the constraint,
|
|
317
|
+
# can be an empty array if the database cannot deteremine the column symbols.
|
|
318
|
+
def check_constraints(table)
|
|
319
|
+
m = output_identifier_meth
|
|
320
|
+
|
|
321
|
+
rows = metadata_dataset.
|
|
322
|
+
from{pg_constraint.as(:co)}.
|
|
323
|
+
left_join(Sequel[:pg_attribute].as(:att), :attrelid=>:conrelid, :attnum=>SQL::Function.new(:ANY, Sequel[:co][:conkey])).
|
|
324
|
+
where(:conrelid=>regclass_oid(table), :contype=>'c').
|
|
325
|
+
select{[co[:conname].as(:constraint), att[:attname].as(:column), pg_get_constraintdef(co[:oid]).as(:definition)]}
|
|
326
|
+
|
|
327
|
+
hash = {}
|
|
328
|
+
rows.each do |row|
|
|
329
|
+
constraint = m.call(row[:constraint])
|
|
330
|
+
entry = hash[constraint] ||= {:definition=>row[:definition], :columns=>[]}
|
|
331
|
+
entry[:columns] << m.call(row[:column]) if row[:column]
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
hash
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# Convert the first primary key column in the +table+ from being a serial column to being an identity column.
|
|
338
|
+
# If the column is already an identity column, assume it was already converted and make no changes.
|
|
339
|
+
#
|
|
340
|
+
# Only supported on PostgreSQL 10.2+, since on those versions Sequel will use identity columns
|
|
341
|
+
# instead of serial columns for auto incrementing primary keys. Only supported when running as
|
|
342
|
+
# a superuser, since regular users cannot modify system tables, and there is no way to keep an
|
|
343
|
+
# existing sequence when changing an existing column to be an identity column.
|
|
344
|
+
#
|
|
345
|
+
# This method can raise an exception in at least the following cases where it may otherwise succeed
|
|
346
|
+
# (there may be additional cases not listed here):
|
|
347
|
+
#
|
|
348
|
+
# * The serial column was added after table creation using PostgreSQL <7.3
|
|
349
|
+
# * A regular index also exists on the column (such an index can probably be dropped as the
|
|
350
|
+
# primary key index should suffice)
|
|
351
|
+
#
|
|
352
|
+
# Options:
|
|
353
|
+
# :column :: Specify the column to convert instead of using the first primary key column
|
|
354
|
+
# :server :: Run the SQL on the given server
|
|
355
|
+
def convert_serial_to_identity(table, opts=OPTS)
|
|
356
|
+
raise Error, "convert_serial_to_identity is only supported on PostgreSQL 10.2+" unless server_version >= 100002
|
|
357
|
+
|
|
358
|
+
server = opts[:server]
|
|
359
|
+
server_hash = server ? {:server=>server} : OPTS
|
|
360
|
+
ds = dataset
|
|
361
|
+
ds = ds.server(server) if server
|
|
362
|
+
|
|
363
|
+
raise Error, "convert_serial_to_identity requires superuser permissions" unless ds.get{current_setting('is_superuser')} == 'on'
|
|
364
|
+
|
|
365
|
+
table_oid = regclass_oid(table)
|
|
366
|
+
im = input_identifier_meth
|
|
367
|
+
unless column = (opts[:column] || ((sch = schema(table).find{|_, sc| sc[:primary_key] && sc[:auto_increment]}) && sch[0]))
|
|
368
|
+
raise Error, "could not determine column to convert from serial to identity automatically"
|
|
369
|
+
end
|
|
370
|
+
column = im.call(column)
|
|
371
|
+
|
|
372
|
+
column_num = ds.from(:pg_attribute).
|
|
373
|
+
where(:attrelid=>table_oid, :attname=>column).
|
|
374
|
+
get(:attnum)
|
|
375
|
+
|
|
376
|
+
pg_class = Sequel.cast('pg_class', :regclass)
|
|
377
|
+
res = ds.from(:pg_depend).
|
|
378
|
+
where(:refclassid=>pg_class, :refobjid=>table_oid, :refobjsubid=>column_num, :classid=>pg_class, :objsubid=>0, :deptype=>%w'a i').
|
|
379
|
+
select_map([:objid, Sequel.as({:deptype=>'i'}, :v)])
|
|
380
|
+
|
|
381
|
+
case res.length
|
|
382
|
+
when 0
|
|
383
|
+
raise Error, "unable to find related sequence when converting serial to identity"
|
|
384
|
+
when 1
|
|
385
|
+
seq_oid, already_identity = res.first
|
|
386
|
+
else
|
|
387
|
+
raise Error, "more than one linked sequence found when converting serial to identity"
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
return if already_identity
|
|
391
|
+
|
|
392
|
+
transaction(server_hash) do
|
|
393
|
+
run("ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{quote_identifier(column)} DROP DEFAULT", server_hash)
|
|
394
|
+
|
|
395
|
+
ds.from(:pg_depend).
|
|
396
|
+
where(:classid=>pg_class, :objid=>seq_oid, :objsubid=>0, :deptype=>'a').
|
|
397
|
+
update(:deptype=>'i')
|
|
398
|
+
|
|
399
|
+
ds.from(:pg_attribute).
|
|
400
|
+
where(:attrelid=>table_oid, :attname=>column).
|
|
401
|
+
update(:attidentity=>'d')
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
remove_cached_schema(table)
|
|
405
|
+
nil
|
|
406
|
+
end
|
|
407
|
+
|
|
174
408
|
# Creates the function in the database. Arguments:
|
|
175
409
|
# name :: name of the function to create
|
|
176
410
|
# definition :: string definition of the function, or object file for a dynamically loaded C function.
|
|
@@ -180,6 +414,7 @@ module Sequel
|
|
|
180
414
|
# 2 :: argument name
|
|
181
415
|
# 3 :: argument mode (e.g. in, out, inout)
|
|
182
416
|
# :behavior :: Should be IMMUTABLE, STABLE, or VOLATILE. PostgreSQL assumes VOLATILE by default.
|
|
417
|
+
# :parallel :: The thread safety attribute of the function. Should be SAFE, UNSAFE, RESTRICTED. PostgreSQL assumes UNSAFE by default.
|
|
183
418
|
# :cost :: The estimated cost of the function, used by the query planner.
|
|
184
419
|
# :language :: The language the function uses. SQL is the default.
|
|
185
420
|
# :link_symbol :: For a dynamically loaded see function, the function's link symbol if different from the definition argument.
|
|
@@ -215,6 +450,26 @@ module Sequel
|
|
|
215
450
|
self << create_schema_sql(name, opts)
|
|
216
451
|
end
|
|
217
452
|
|
|
453
|
+
# Support partitions of tables using the :partition_of option.
|
|
454
|
+
def create_table(name, options=OPTS, &block)
|
|
455
|
+
if options[:partition_of]
|
|
456
|
+
create_partition_of_table_from_generator(name, CreatePartitionOfTableGenerator.new(&block), options)
|
|
457
|
+
return
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
super
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
# Support partitions of tables using the :partition_of option.
|
|
464
|
+
def create_table?(name, options=OPTS, &block)
|
|
465
|
+
if options[:partition_of]
|
|
466
|
+
create_table(name, options.merge!(:if_not_exists=>true), &block)
|
|
467
|
+
return
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
super
|
|
471
|
+
end
|
|
472
|
+
|
|
218
473
|
# Create a trigger in the database. Arguments:
|
|
219
474
|
# table :: the table on which this trigger operates
|
|
220
475
|
# name :: the name of this trigger
|
|
@@ -225,12 +480,12 @@ module Sequel
|
|
|
225
480
|
# :each_row :: Calls the trigger for each row instead of for each statement.
|
|
226
481
|
# :events :: Can be :insert, :update, :delete, or an array of any of those. Calls the trigger whenever that type of statement is used. By default,
|
|
227
482
|
# the trigger is called for insert, update, or delete.
|
|
483
|
+
# :replace :: Replace the trigger with the same name if it already exists (PostgreSQL 14+).
|
|
228
484
|
# :when :: A filter to use for the trigger
|
|
229
485
|
def create_trigger(table, name, function, opts=OPTS)
|
|
230
486
|
self << create_trigger_sql(table, name, function, opts)
|
|
231
487
|
end
|
|
232
488
|
|
|
233
|
-
# PostgreSQL uses the :postgres database type.
|
|
234
489
|
def database_type
|
|
235
490
|
:postgres
|
|
236
491
|
end
|
|
@@ -285,75 +540,150 @@ module Sequel
|
|
|
285
540
|
|
|
286
541
|
# Return full foreign key information using the pg system tables, including
|
|
287
542
|
# :name, :on_delete, :on_update, and :deferrable entries in the hashes.
|
|
543
|
+
#
|
|
544
|
+
# Supports additional options:
|
|
545
|
+
# :reverse :: Instead of returning foreign keys in the current table, return
|
|
546
|
+
# foreign keys in other tables that reference the current table.
|
|
547
|
+
# :schema :: Set to true to have the :table value in the hashes be a qualified
|
|
548
|
+
# identifier. Set to false to use a separate :schema value with
|
|
549
|
+
# the related schema. Defaults to whether the given table argument
|
|
550
|
+
# is a qualified identifier.
|
|
288
551
|
def foreign_key_list(table, opts=OPTS)
|
|
289
552
|
m = output_identifier_meth
|
|
290
553
|
schema, _ = opts.fetch(:schema, schema_and_table(table))
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
554
|
+
oid = regclass_oid(table)
|
|
555
|
+
reverse = opts[:reverse]
|
|
556
|
+
|
|
557
|
+
if reverse
|
|
558
|
+
ctable = Sequel[:att2]
|
|
559
|
+
cclass = Sequel[:cl2]
|
|
560
|
+
rtable = Sequel[:att]
|
|
561
|
+
rclass = Sequel[:cl]
|
|
562
|
+
else
|
|
563
|
+
ctable = Sequel[:att]
|
|
564
|
+
cclass = Sequel[:cl]
|
|
565
|
+
rtable = Sequel[:att2]
|
|
566
|
+
rclass = Sequel[:cl2]
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
if server_version >= 90500
|
|
570
|
+
cpos = Sequel.expr{array_position(co[:conkey], ctable[:attnum])}
|
|
571
|
+
rpos = Sequel.expr{array_position(co[:confkey], rtable[:attnum])}
|
|
572
|
+
# :nocov:
|
|
573
|
+
else
|
|
574
|
+
range = 0...32
|
|
575
|
+
cpos = Sequel.expr{SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(co[:conkey], [x]), x]}, 32, ctable[:attnum])}
|
|
576
|
+
rpos = Sequel.expr{SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(co[:confkey], [x]), x]}, 32, rtable[:attnum])}
|
|
577
|
+
# :nocov:
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
ds = metadata_dataset.
|
|
581
|
+
from{pg_constraint.as(:co)}.
|
|
582
|
+
join(Sequel[:pg_class].as(cclass), :oid=>:conrelid).
|
|
583
|
+
join(Sequel[:pg_attribute].as(ctable), :attrelid=>:oid, :attnum=>SQL::Function.new(:ANY, Sequel[:co][:conkey])).
|
|
584
|
+
join(Sequel[:pg_class].as(rclass), :oid=>Sequel[:co][:confrelid]).
|
|
585
|
+
join(Sequel[:pg_attribute].as(rtable), :attrelid=>:oid, :attnum=>SQL::Function.new(:ANY, Sequel[:co][:confkey])).
|
|
586
|
+
join(Sequel[:pg_namespace].as(:nsp), :oid=>Sequel[:cl2][:relnamespace]).
|
|
587
|
+
order{[co[:conname], cpos]}.
|
|
588
|
+
where{{
|
|
589
|
+
cl[:relkind]=>%w'r p',
|
|
590
|
+
co[:contype]=>'f',
|
|
591
|
+
cl[:oid]=>oid,
|
|
592
|
+
cpos=>rpos
|
|
593
|
+
}}.
|
|
594
|
+
select{[
|
|
595
|
+
co[:conname].as(:name),
|
|
596
|
+
ctable[:attname].as(:column),
|
|
597
|
+
co[:confupdtype].as(:on_update),
|
|
598
|
+
co[:confdeltype].as(:on_delete),
|
|
599
|
+
cl2[:relname].as(:table),
|
|
600
|
+
rtable[:attname].as(:refcolumn),
|
|
601
|
+
SQL::BooleanExpression.new(:AND, co[:condeferrable], co[:condeferred]).as(:deferrable),
|
|
602
|
+
nsp[:nspname].as(:schema)
|
|
603
|
+
]}
|
|
604
|
+
|
|
605
|
+
if reverse
|
|
606
|
+
ds = ds.order_append(Sequel[:nsp][:nspname], Sequel[:cl2][:relname])
|
|
321
607
|
end
|
|
322
608
|
|
|
323
609
|
h = {}
|
|
324
610
|
fklod_map = FOREIGN_KEY_LIST_ON_DELETE_MAP
|
|
611
|
+
|
|
325
612
|
ds.each do |row|
|
|
326
|
-
if
|
|
613
|
+
if reverse
|
|
614
|
+
key = [row[:schema], row[:table], row[:name]]
|
|
615
|
+
else
|
|
616
|
+
key = row[:name]
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
if r = h[key]
|
|
327
620
|
r[:columns] << m.call(row[:column])
|
|
621
|
+
r[:key] << m.call(row[:refcolumn])
|
|
328
622
|
else
|
|
329
|
-
h[
|
|
623
|
+
entry = h[key] = {
|
|
624
|
+
:name=>m.call(row[:name]),
|
|
625
|
+
:columns=>[m.call(row[:column])],
|
|
626
|
+
:key=>[m.call(row[:refcolumn])],
|
|
627
|
+
:on_update=>fklod_map[row[:on_update]],
|
|
628
|
+
:on_delete=>fklod_map[row[:on_delete]],
|
|
629
|
+
:deferrable=>row[:deferrable],
|
|
630
|
+
:table=>schema ? SQL::QualifiedIdentifier.new(m.call(row[:schema]), m.call(row[:table])) : m.call(row[:table]),
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
unless schema
|
|
634
|
+
# If not combining schema information into the :table entry
|
|
635
|
+
# include it as a separate entry.
|
|
636
|
+
entry[:schema] = m.call(row[:schema])
|
|
637
|
+
end
|
|
330
638
|
end
|
|
331
639
|
end
|
|
332
|
-
|
|
333
|
-
r = h[row[:name]]
|
|
334
|
-
r[:table] ||= schema ? SQL::QualifiedIdentifier.new(m.call(row[:schema]), m.call(row[:table])) : m.call(row[:table])
|
|
335
|
-
r[:key] ||= []
|
|
336
|
-
r[:key] << m.call(row[:refcolumn])
|
|
337
|
-
end
|
|
640
|
+
|
|
338
641
|
h.values
|
|
339
642
|
end
|
|
340
643
|
|
|
644
|
+
def freeze
|
|
645
|
+
server_version
|
|
646
|
+
supports_prepared_transactions?
|
|
647
|
+
@conversion_procs.freeze
|
|
648
|
+
super
|
|
649
|
+
end
|
|
650
|
+
|
|
341
651
|
# Use the pg_* system tables to determine indexes on a table
|
|
342
652
|
def indexes(table, opts=OPTS)
|
|
343
653
|
m = output_identifier_meth
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
select(:indc__relname___name, :ind__indisunique___unique, :att__attname___column, :con__condeferrable___deferrable)
|
|
654
|
+
oid = regclass_oid(table, opts)
|
|
655
|
+
|
|
656
|
+
if server_version >= 90500
|
|
657
|
+
order = [Sequel[:indc][:relname], Sequel.function(:array_position, Sequel[:ind][:indkey], Sequel[:att][:attnum])]
|
|
658
|
+
# :nocov:
|
|
659
|
+
else
|
|
660
|
+
range = 0...32
|
|
661
|
+
order = [Sequel[:indc][:relname], SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(Sequel[:ind][:indkey], [x]), x]}, 32, Sequel[:att][:attnum])]
|
|
662
|
+
# :nocov:
|
|
663
|
+
end
|
|
355
664
|
|
|
356
|
-
|
|
665
|
+
attnums = SQL::Function.new(:ANY, Sequel[:ind][:indkey])
|
|
666
|
+
|
|
667
|
+
ds = metadata_dataset.
|
|
668
|
+
from{pg_class.as(:tab)}.
|
|
669
|
+
join(Sequel[:pg_index].as(:ind), :indrelid=>:oid).
|
|
670
|
+
join(Sequel[:pg_class].as(:indc), :oid=>:indexrelid).
|
|
671
|
+
join(Sequel[:pg_attribute].as(:att), :attrelid=>Sequel[:tab][:oid], :attnum=>attnums).
|
|
672
|
+
left_join(Sequel[:pg_constraint].as(:con), :conname=>Sequel[:indc][:relname]).
|
|
673
|
+
where{{
|
|
674
|
+
indc[:relkind]=>'i',
|
|
675
|
+
ind[:indisprimary]=>false,
|
|
676
|
+
:indexprs=>nil,
|
|
677
|
+
:indisvalid=>true,
|
|
678
|
+
tab[:oid]=>oid}}.
|
|
679
|
+
order(*order).
|
|
680
|
+
select{[indc[:relname].as(:name), ind[:indisunique].as(:unique), att[:attname].as(:column), con[:condeferrable].as(:deferrable)]}
|
|
681
|
+
|
|
682
|
+
ds = ds.where(:indpred=>nil) unless opts[:include_partial]
|
|
683
|
+
# :nocov:
|
|
684
|
+
ds = ds.where(:indisready=>true) if server_version >= 80300
|
|
685
|
+
ds = ds.where(:indislive=>true) if server_version >= 90300
|
|
686
|
+
# :nocov:
|
|
357
687
|
|
|
358
688
|
indexes = {}
|
|
359
689
|
ds.each do |r|
|
|
@@ -365,7 +695,7 @@ module Sequel
|
|
|
365
695
|
|
|
366
696
|
# Dataset containing all current database locks
|
|
367
697
|
def locks
|
|
368
|
-
dataset.from(:pg_class).join(:pg_locks, :relation=>:relfilenode).select
|
|
698
|
+
dataset.from(:pg_class).join(:pg_locks, :relation=>:relfilenode).select{[pg_class[:relname], Sequel::SQL::ColumnAll.new(:pg_locks)]}
|
|
369
699
|
end
|
|
370
700
|
|
|
371
701
|
# Notifies the given channel. See the PostgreSQL NOTIFY documentation. Options:
|
|
@@ -421,28 +751,30 @@ module Sequel
|
|
|
421
751
|
run "REFRESH MATERIALIZED VIEW#{' CONCURRENTLY' if opts[:concurrently]} #{quote_schema_table(name)}"
|
|
422
752
|
end
|
|
423
753
|
|
|
424
|
-
# Reset the database's conversion procs, requires a server query if there
|
|
425
|
-
# any named types.
|
|
426
|
-
def reset_conversion_procs
|
|
427
|
-
@conversion_procs = get_conversion_procs
|
|
428
|
-
conversion_procs_updated
|
|
429
|
-
@conversion_procs
|
|
430
|
-
end
|
|
431
|
-
|
|
432
754
|
# Reset the primary key sequence for the given table, basing it on the
|
|
433
755
|
# maximum current value of the table's primary key.
|
|
434
756
|
def reset_primary_key_sequence(table)
|
|
435
757
|
return unless seq = primary_key_sequence(table)
|
|
436
758
|
pk = SQL::Identifier.new(primary_key(table))
|
|
437
759
|
db = self
|
|
438
|
-
seq_ds = db.from(LiteralString.new(seq))
|
|
439
760
|
s, t = schema_and_table(table)
|
|
440
761
|
table = Sequel.qualify(s, t) if s
|
|
441
|
-
|
|
762
|
+
|
|
763
|
+
if server_version >= 100000
|
|
764
|
+
seq_ds = metadata_dataset.from(:pg_sequence).where(:seqrelid=>regclass_oid(LiteralString.new(seq)))
|
|
765
|
+
increment_by = :seqincrement
|
|
766
|
+
min_value = :seqmin
|
|
767
|
+
# :nocov:
|
|
768
|
+
else
|
|
769
|
+
seq_ds = metadata_dataset.from(LiteralString.new(seq))
|
|
770
|
+
increment_by = :increment_by
|
|
771
|
+
min_value = :min_value
|
|
772
|
+
# :nocov:
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
get{setval(seq, db[table].select(coalesce(max(pk)+seq_ds.select(increment_by), seq_ds.select(min_value))), false)}
|
|
442
776
|
end
|
|
443
777
|
|
|
444
|
-
# Rollback an existing prepared transaction with the given transaction
|
|
445
|
-
# identifier string.
|
|
446
778
|
def rollback_prepared_transaction(transaction_id, opts=OPTS)
|
|
447
779
|
run("ROLLBACK PREPARED #{literal(transaction_id)}", opts)
|
|
448
780
|
end
|
|
@@ -450,24 +782,18 @@ module Sequel
|
|
|
450
782
|
# PostgreSQL uses SERIAL psuedo-type instead of AUTOINCREMENT for
|
|
451
783
|
# managing incrementing primary keys.
|
|
452
784
|
def serial_primary_key_options
|
|
453
|
-
|
|
785
|
+
# :nocov:
|
|
786
|
+
auto_increment_key = server_version >= 100002 ? :identity : :serial
|
|
787
|
+
# :nocov:
|
|
788
|
+
{:primary_key => true, auto_increment_key => true, :type=>Integer}
|
|
454
789
|
end
|
|
455
790
|
|
|
456
791
|
# The version of the PostgreSQL server, used for determining capability.
|
|
457
792
|
def server_version(server=nil)
|
|
458
793
|
return @server_version if @server_version
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
unless @server_version
|
|
463
|
-
@server_version = if m = /PostgreSQL (\d+)\.(\d+)(?:(?:rc\d+)|\.(\d+))?/.match(fetch('SELECT version()').single_value)
|
|
464
|
-
(m[1].to_i * 10000) + (m[2].to_i * 100) + m[3].to_i
|
|
465
|
-
else
|
|
466
|
-
0
|
|
467
|
-
end
|
|
468
|
-
end
|
|
469
|
-
warn 'Sequel no longer supports PostgreSQL <8.2, some things may not work' if @server_version < 80200
|
|
470
|
-
@server_version
|
|
794
|
+
ds = dataset
|
|
795
|
+
ds = ds.server(server) if server
|
|
796
|
+
@server_version = swallow_database_error{ds.with_sql("SELECT CAST(current_setting('server_version_num') AS integer) AS v").single_value} || 0
|
|
471
797
|
end
|
|
472
798
|
|
|
473
799
|
# PostgreSQL supports CREATE TABLE IF NOT EXISTS on 9.1+
|
|
@@ -532,23 +858,24 @@ module Sequel
|
|
|
532
858
|
# :schema :: The schema to search
|
|
533
859
|
# :server :: The server to use
|
|
534
860
|
def tables(opts=OPTS, &block)
|
|
535
|
-
pg_class_relname('r', opts, &block)
|
|
861
|
+
pg_class_relname(['r', 'p'], opts, &block)
|
|
536
862
|
end
|
|
537
863
|
|
|
538
864
|
# Check whether the given type name string/symbol (e.g. :hstore) is supported by
|
|
539
865
|
# the database.
|
|
540
866
|
def type_supported?(type)
|
|
541
|
-
@supported_types
|
|
542
|
-
|
|
867
|
+
Sequel.synchronize{return @supported_types[type] if @supported_types.has_key?(type)}
|
|
868
|
+
supported = from(:pg_type).where(:typtype=>'b', :typname=>type.to_s).count > 0
|
|
869
|
+
Sequel.synchronize{return @supported_types[type] = supported}
|
|
543
870
|
end
|
|
544
871
|
|
|
545
872
|
# Creates a dataset that uses the VALUES clause:
|
|
546
873
|
#
|
|
547
874
|
# DB.values([[1, 2], [3, 4]])
|
|
548
|
-
# VALUES ((1, 2), (3, 4))
|
|
875
|
+
# # VALUES ((1, 2), (3, 4))
|
|
549
876
|
#
|
|
550
877
|
# DB.values([[1, 2], [3, 4]]).order(:column2).limit(1, 1)
|
|
551
|
-
# VALUES ((1, 2), (3, 4)) ORDER BY column2 LIMIT 1 OFFSET 1
|
|
878
|
+
# # VALUES ((1, 2), (3, 4)) ORDER BY column2 LIMIT 1 OFFSET 1
|
|
552
879
|
def values(v)
|
|
553
880
|
@default_dataset.clone(:values=>v)
|
|
554
881
|
end
|
|
@@ -556,28 +883,22 @@ module Sequel
|
|
|
556
883
|
# Array of symbols specifying view names in the current database.
|
|
557
884
|
#
|
|
558
885
|
# Options:
|
|
886
|
+
# :materialized :: Return materialized views
|
|
559
887
|
# :qualify :: Return the views as Sequel::SQL::QualifiedIdentifier instances,
|
|
560
888
|
# using the schema the view is located in as the qualifier.
|
|
561
889
|
# :schema :: The schema to search
|
|
562
890
|
# :server :: The server to use
|
|
563
891
|
def views(opts=OPTS)
|
|
564
|
-
|
|
892
|
+
relkind = opts[:materialized] ? 'm' : 'v'
|
|
893
|
+
pg_class_relname(relkind, opts)
|
|
565
894
|
end
|
|
566
895
|
|
|
567
896
|
private
|
|
568
897
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
def add_named_conversion_procs(procs, named_procs)
|
|
572
|
-
unless (named_procs).empty?
|
|
573
|
-
convert_named_procs_to_procs(named_procs).each do |oid, pr|
|
|
574
|
-
procs[oid] ||= pr
|
|
575
|
-
end
|
|
576
|
-
conversion_procs_updated
|
|
577
|
-
end
|
|
898
|
+
def alter_table_add_column_sql(table, op)
|
|
899
|
+
"ADD COLUMN#{' IF NOT EXISTS' if op[:if_not_exists]} #{column_definition_sql(op)}"
|
|
578
900
|
end
|
|
579
901
|
|
|
580
|
-
# Use a PostgreSQL-specific alter table generator
|
|
581
902
|
def alter_table_generator_class
|
|
582
903
|
Postgres::AlterTableGenerator
|
|
583
904
|
end
|
|
@@ -637,9 +958,24 @@ module Sequel
|
|
|
637
958
|
end
|
|
638
959
|
end
|
|
639
960
|
|
|
961
|
+
# Support identity columns, but only use the identity SQL syntax if no
|
|
962
|
+
# default value is given.
|
|
963
|
+
def column_definition_default_sql(sql, column)
|
|
964
|
+
super
|
|
965
|
+
if !column[:serial] && !['smallserial', 'serial', 'bigserial'].include?(column[:type].to_s) && !column[:default]
|
|
966
|
+
if (identity = column[:identity])
|
|
967
|
+
sql << " GENERATED "
|
|
968
|
+
sql << (identity == :always ? "ALWAYS" : "BY DEFAULT")
|
|
969
|
+
sql << " AS IDENTITY"
|
|
970
|
+
elsif (generated = column[:generated_always_as])
|
|
971
|
+
sql << " GENERATED ALWAYS AS (#{literal(generated)}) STORED"
|
|
972
|
+
end
|
|
973
|
+
end
|
|
974
|
+
end
|
|
975
|
+
|
|
640
976
|
# Handle PostgreSQL specific default format.
|
|
641
977
|
def column_schema_normalize_default(default, type)
|
|
642
|
-
if m =
|
|
978
|
+
if m = /\A(?:B?('.*')::[^']+|\((-?\d+(?:\.\d+)?)\))\z/.match(default)
|
|
643
979
|
default = m[1] || m[2]
|
|
644
980
|
end
|
|
645
981
|
super(default, type)
|
|
@@ -661,14 +997,15 @@ module Sequel
|
|
|
661
997
|
(super || op[:op] == :validate_constraint) && op[:op] != :rename_column
|
|
662
998
|
end
|
|
663
999
|
|
|
664
|
-
VALID_CLIENT_MIN_MESSAGES = %w'DEBUG5 DEBUG4 DEBUG3 DEBUG2 DEBUG1 LOG NOTICE WARNING ERROR FATAL PANIC'.freeze
|
|
1000
|
+
VALID_CLIENT_MIN_MESSAGES = %w'DEBUG5 DEBUG4 DEBUG3 DEBUG2 DEBUG1 LOG NOTICE WARNING ERROR FATAL PANIC'.freeze.each(&:freeze)
|
|
665
1001
|
# The SQL queries to execute when starting a new connection.
|
|
666
|
-
def connection_configuration_sqls
|
|
1002
|
+
def connection_configuration_sqls(opts=@opts)
|
|
667
1003
|
sqls = []
|
|
668
1004
|
|
|
669
|
-
sqls << "SET standard_conforming_strings = ON" if typecast_value_boolean(
|
|
1005
|
+
sqls << "SET standard_conforming_strings = ON" if typecast_value_boolean(opts.fetch(:force_standard_strings, true))
|
|
670
1006
|
|
|
671
|
-
|
|
1007
|
+
cmm = opts.fetch(:client_min_messages, :warning)
|
|
1008
|
+
if cmm && !cmm.to_s.empty?
|
|
672
1009
|
cmm = cmm.to_s.upcase.strip
|
|
673
1010
|
unless VALID_CLIENT_MIN_MESSAGES.include?(cmm)
|
|
674
1011
|
raise Error, "Unsupported client_min_messages setting: #{cmm}"
|
|
@@ -676,7 +1013,7 @@ module Sequel
|
|
|
676
1013
|
sqls << "SET client_min_messages = '#{cmm.to_s.upcase}'"
|
|
677
1014
|
end
|
|
678
1015
|
|
|
679
|
-
if search_path =
|
|
1016
|
+
if search_path = opts[:search_path]
|
|
680
1017
|
case search_path
|
|
681
1018
|
when String
|
|
682
1019
|
search_path = search_path.split(",").map(&:strip)
|
|
@@ -711,37 +1048,13 @@ module Sequel
|
|
|
711
1048
|
end
|
|
712
1049
|
end
|
|
713
1050
|
|
|
714
|
-
# Callback used when conversion procs are updated.
|
|
715
|
-
def conversion_procs_updated
|
|
716
|
-
nil
|
|
717
|
-
end
|
|
718
|
-
|
|
719
|
-
# Convert the hash of named conversion procs into a hash a oid conversion procs.
|
|
720
|
-
def convert_named_procs_to_procs(named_procs)
|
|
721
|
-
h = {}
|
|
722
|
-
from(:pg_type).where(:typtype=>['b', 'e'], :typname=>named_procs.keys.map(&:to_s)).select_map([:oid, :typname]).each do |oid, name|
|
|
723
|
-
h[oid.to_i] = named_procs[name.untaint.to_sym]
|
|
724
|
-
end
|
|
725
|
-
h
|
|
726
|
-
end
|
|
727
|
-
|
|
728
|
-
# Copy the conversion procs related to the given oids from PG_TYPES into
|
|
729
|
-
# the conversion procs for this instance.
|
|
730
|
-
def copy_conversion_procs(oids)
|
|
731
|
-
procs = conversion_procs
|
|
732
|
-
oids.each do |oid|
|
|
733
|
-
procs[oid] = PG_TYPES[oid]
|
|
734
|
-
end
|
|
735
|
-
conversion_procs_updated
|
|
736
|
-
end
|
|
737
|
-
|
|
738
|
-
EXCLUSION_CONSTRAINT_SQL_STATE = '23P01'.freeze
|
|
739
|
-
DEADLOCK_SQL_STATE = '40P01'.freeze
|
|
740
1051
|
def database_specific_error_class_from_sqlstate(sqlstate)
|
|
741
|
-
if sqlstate ==
|
|
1052
|
+
if sqlstate == '23P01'
|
|
742
1053
|
ExclusionConstraintViolation
|
|
743
|
-
elsif sqlstate ==
|
|
1054
|
+
elsif sqlstate == '40P01'
|
|
744
1055
|
SerializationFailure
|
|
1056
|
+
elsif sqlstate == '55P03'
|
|
1057
|
+
DatabaseLockTimeout
|
|
745
1058
|
else
|
|
746
1059
|
super
|
|
747
1060
|
end
|
|
@@ -757,6 +1070,7 @@ module Sequel
|
|
|
757
1070
|
[/violates not-null constraint/, NotNullConstraintViolation],
|
|
758
1071
|
[/conflicting key value violates exclusion constraint/, ExclusionConstraintViolation],
|
|
759
1072
|
[/could not serialize access/, SerializationFailure],
|
|
1073
|
+
[/could not obtain lock on row in relation/, DatabaseLockTimeout],
|
|
760
1074
|
].freeze
|
|
761
1075
|
def database_error_regexps
|
|
762
1076
|
DATABASE_ERROR_REGEXPS
|
|
@@ -814,6 +1128,7 @@ module Sequel
|
|
|
814
1128
|
#{opts[:behavior].to_s.upcase if opts[:behavior]}
|
|
815
1129
|
#{'STRICT' if opts[:strict]}
|
|
816
1130
|
#{'SECURITY DEFINER' if opts[:security_definer]}
|
|
1131
|
+
#{"PARALLEL #{opts[:parallel].to_s.upcase}" if opts[:parallel]}
|
|
817
1132
|
#{"COST #{opts[:cost]}" if opts[:cost]}
|
|
818
1133
|
#{"ROWS #{opts[:rows]}" if opts[:rows]}
|
|
819
1134
|
#{opts[:set].map{|k,v| " SET #{k} = #{v}"}.join("\n") if opts[:set]}
|
|
@@ -826,6 +1141,36 @@ module Sequel
|
|
|
826
1141
|
"CREATE#{' OR REPLACE' if opts[:replace] && server_version >= 90000}#{' TRUSTED' if opts[:trusted]} LANGUAGE #{name}#{" HANDLER #{opts[:handler]}" if opts[:handler]}#{" VALIDATOR #{opts[:validator]}" if opts[:validator]}"
|
|
827
1142
|
end
|
|
828
1143
|
|
|
1144
|
+
# Create a partition of another table, used when the create_table with
|
|
1145
|
+
# the :partition_of option is given.
|
|
1146
|
+
def create_partition_of_table_from_generator(name, generator, options)
|
|
1147
|
+
execute_ddl(create_partition_of_table_sql(name, generator, options))
|
|
1148
|
+
end
|
|
1149
|
+
|
|
1150
|
+
# SQL for creating a partition of another table.
|
|
1151
|
+
def create_partition_of_table_sql(name, generator, options)
|
|
1152
|
+
sql = create_table_prefix_sql(name, options).dup
|
|
1153
|
+
|
|
1154
|
+
sql << " PARTITION OF #{quote_schema_table(options[:partition_of])}"
|
|
1155
|
+
|
|
1156
|
+
case generator.partition_type
|
|
1157
|
+
when :range
|
|
1158
|
+
from, to = generator.range
|
|
1159
|
+
sql << " FOR VALUES FROM #{literal(from)} TO #{literal(to)}"
|
|
1160
|
+
when :list
|
|
1161
|
+
sql << " FOR VALUES IN #{literal(generator.list)}"
|
|
1162
|
+
when :hash
|
|
1163
|
+
mod, remainder = generator.hash_values
|
|
1164
|
+
sql << " FOR VALUES WITH (MODULUS #{literal(mod)}, REMAINDER #{literal(remainder)})"
|
|
1165
|
+
else # when :default
|
|
1166
|
+
sql << " DEFAULT"
|
|
1167
|
+
end
|
|
1168
|
+
|
|
1169
|
+
sql << create_table_suffix_sql(name, options)
|
|
1170
|
+
|
|
1171
|
+
sql
|
|
1172
|
+
end
|
|
1173
|
+
|
|
829
1174
|
# SQL for creating a schema.
|
|
830
1175
|
def create_schema_sql(name, opts=OPTS)
|
|
831
1176
|
"CREATE SCHEMA #{'IF NOT EXISTS ' if opts[:if_not_exists]}#{quote_identifier(name)}#{" AUTHORIZATION #{literal(opts[:owner])}" if opts[:owner]}"
|
|
@@ -841,27 +1186,42 @@ module Sequel
|
|
|
841
1186
|
raise(Error, "can't provide both :foreign and :unlogged to create_table") if options[:unlogged]
|
|
842
1187
|
'FOREIGN '
|
|
843
1188
|
elsif options[:unlogged]
|
|
844
|
-
UNLOGGED
|
|
1189
|
+
'UNLOGGED '
|
|
845
1190
|
end
|
|
846
1191
|
|
|
847
1192
|
"CREATE #{prefix_sql}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{options[:temp] ? quote_identifier(name) : quote_schema_table(name)}"
|
|
848
1193
|
end
|
|
849
1194
|
|
|
1195
|
+
# SQL for creating a table with PostgreSQL specific options
|
|
850
1196
|
def create_table_sql(name, generator, options)
|
|
851
|
-
|
|
1197
|
+
"#{super}#{create_table_suffix_sql(name, options)}"
|
|
1198
|
+
end
|
|
1199
|
+
|
|
1200
|
+
# Handle various PostgreSQl specific table extensions such as inheritance,
|
|
1201
|
+
# partitioning, tablespaces, and foreign tables.
|
|
1202
|
+
def create_table_suffix_sql(name, options)
|
|
1203
|
+
sql = String.new
|
|
852
1204
|
|
|
853
1205
|
if inherits = options[:inherits]
|
|
854
|
-
sql
|
|
1206
|
+
sql << " INHERITS (#{Array(inherits).map{|t| quote_schema_table(t)}.join(', ')})"
|
|
1207
|
+
end
|
|
1208
|
+
|
|
1209
|
+
if partition_by = options[:partition_by]
|
|
1210
|
+
sql << " PARTITION BY #{options[:partition_type]||'RANGE'} #{literal(Array(partition_by))}"
|
|
855
1211
|
end
|
|
856
1212
|
|
|
857
1213
|
if on_commit = options[:on_commit]
|
|
858
1214
|
raise(Error, "can't provide :on_commit without :temp to create_table") unless options[:temp]
|
|
859
1215
|
raise(Error, "unsupported on_commit option: #{on_commit.inspect}") unless ON_COMMIT.has_key?(on_commit)
|
|
860
|
-
sql
|
|
1216
|
+
sql << " ON COMMIT #{ON_COMMIT[on_commit]}"
|
|
1217
|
+
end
|
|
1218
|
+
|
|
1219
|
+
if tablespace = options[:tablespace]
|
|
1220
|
+
sql << " TABLESPACE #{quote_identifier(tablespace)}"
|
|
861
1221
|
end
|
|
862
1222
|
|
|
863
1223
|
if server = options[:foreign]
|
|
864
|
-
sql
|
|
1224
|
+
sql << " SERVER #{quote_identifier(server)}"
|
|
865
1225
|
if foreign_opts = options[:options]
|
|
866
1226
|
sql << " OPTIONS (#{foreign_opts.map{|k, v| "#{k} #{literal(v.to_s)}"}.join(', ')})"
|
|
867
1227
|
end
|
|
@@ -878,7 +1238,6 @@ module Sequel
|
|
|
878
1238
|
result += " AS #{sql}"
|
|
879
1239
|
end
|
|
880
1240
|
|
|
881
|
-
# Use a PostgreSQL-specific create table generator
|
|
882
1241
|
def create_table_generator_class
|
|
883
1242
|
Postgres::CreateTableGenerator
|
|
884
1243
|
end
|
|
@@ -891,17 +1250,22 @@ module Sequel
|
|
|
891
1250
|
raise Error, "Trigger conditions are not supported for this database" unless supports_trigger_conditions?
|
|
892
1251
|
filter = " WHEN #{filter_expr(filter)}"
|
|
893
1252
|
end
|
|
894
|
-
"CREATE TRIGGER #{name} #{whence} #{events.map{|e| e.to_s.upcase}.join(' OR ')} ON #{quote_schema_table(table)}#{' FOR EACH ROW' if opts[:each_row]}#{filter} EXECUTE PROCEDURE #{function}(#{Array(opts[:args]).map{|a| literal(a)}.join(', ')})"
|
|
1253
|
+
"CREATE #{'OR REPLACE ' if opts[:replace]}TRIGGER #{name} #{whence} #{events.map{|e| e.to_s.upcase}.join(' OR ')} ON #{quote_schema_table(table)}#{' FOR EACH ROW' if opts[:each_row]}#{filter} EXECUTE PROCEDURE #{function}(#{Array(opts[:args]).map{|a| literal(a)}.join(', ')})"
|
|
895
1254
|
end
|
|
896
1255
|
|
|
897
1256
|
# DDL fragment for initial part of CREATE VIEW statement
|
|
898
1257
|
def create_view_prefix_sql(name, options)
|
|
899
|
-
create_view_sql_append_columns("CREATE #{'OR REPLACE 'if options[:replace]}#{'TEMPORARY 'if options[:temp]}#{'RECURSIVE ' if options[:recursive]}#{'MATERIALIZED ' if options[:materialized]}VIEW #{quote_schema_table(name)}", options[:columns] || options[:recursive])
|
|
900
|
-
end
|
|
1258
|
+
sql = create_view_sql_append_columns("CREATE #{'OR REPLACE 'if options[:replace]}#{'TEMPORARY 'if options[:temp]}#{'RECURSIVE ' if options[:recursive]}#{'MATERIALIZED ' if options[:materialized]}VIEW #{quote_schema_table(name)}", options[:columns] || options[:recursive])
|
|
901
1259
|
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
1260
|
+
if options[:security_invoker]
|
|
1261
|
+
sql += " WITH (security_invoker)"
|
|
1262
|
+
end
|
|
1263
|
+
|
|
1264
|
+
if tablespace = options[:tablespace]
|
|
1265
|
+
sql += " TABLESPACE #{quote_identifier(tablespace)}"
|
|
1266
|
+
end
|
|
1267
|
+
|
|
1268
|
+
sql
|
|
905
1269
|
end
|
|
906
1270
|
|
|
907
1271
|
# SQL for dropping a function from the database.
|
|
@@ -940,48 +1304,34 @@ module Sequel
|
|
|
940
1304
|
"DROP #{'MATERIALIZED ' if opts[:materialized]}VIEW#{' IF EXISTS' if opts[:if_exists]} #{quote_schema_table(name)}#{' CASCADE' if opts[:cascade]}"
|
|
941
1305
|
end
|
|
942
1306
|
|
|
943
|
-
# If opts includes a :schema option,
|
|
944
|
-
#
|
|
1307
|
+
# If opts includes a :schema option, use it, otherwise restrict the filter to only the
|
|
1308
|
+
# currently visible schemas.
|
|
945
1309
|
def filter_schema(ds, opts)
|
|
946
1310
|
expr = if schema = opts[:schema]
|
|
947
1311
|
schema.to_s
|
|
948
1312
|
else
|
|
949
1313
|
Sequel.function(:any, Sequel.function(:current_schemas, false))
|
|
950
1314
|
end
|
|
951
|
-
ds.where
|
|
952
|
-
end
|
|
953
|
-
|
|
954
|
-
# Return a hash with oid keys and callable values, used for converting types.
|
|
955
|
-
def get_conversion_procs
|
|
956
|
-
procs = PG_TYPES.dup
|
|
957
|
-
procs[1184] = procs[1114] = method(:to_application_timestamp)
|
|
958
|
-
add_named_conversion_procs(procs, PG_NAMED_TYPES)
|
|
959
|
-
procs
|
|
1315
|
+
ds.where{{pg_namespace[:nspname]=>expr}}
|
|
960
1316
|
end
|
|
961
1317
|
|
|
962
|
-
# PostgreSQL folds unquoted identifiers to lowercase, so it shouldn't need to upcase identifiers on input.
|
|
963
|
-
def identifier_input_method_default
|
|
964
|
-
nil
|
|
965
|
-
end
|
|
966
|
-
|
|
967
|
-
# PostgreSQL folds unquoted identifiers to lowercase, so it shouldn't need to upcase identifiers on output.
|
|
968
|
-
def identifier_output_method_default
|
|
969
|
-
nil
|
|
970
|
-
end
|
|
971
|
-
|
|
972
|
-
# PostgreSQL specific index SQL.
|
|
973
1318
|
def index_definition_sql(table_name, index)
|
|
974
1319
|
cols = index[:columns]
|
|
975
1320
|
index_name = index[:name] || default_index_name(table_name, cols)
|
|
1321
|
+
|
|
976
1322
|
expr = if o = index[:opclass]
|
|
977
1323
|
"(#{Array(cols).map{|c| "#{literal(c)} #{o}"}.join(', ')})"
|
|
978
1324
|
else
|
|
979
1325
|
literal(Array(cols))
|
|
980
1326
|
end
|
|
1327
|
+
|
|
1328
|
+
if_not_exists = " IF NOT EXISTS" if index[:if_not_exists]
|
|
981
1329
|
unique = "UNIQUE " if index[:unique]
|
|
982
1330
|
index_type = index[:type]
|
|
983
1331
|
filter = index[:where] || index[:filter]
|
|
984
1332
|
filter = " WHERE #{filter_expr(filter)}" if filter
|
|
1333
|
+
nulls_distinct = " NULLS#{' NOT' if index[:nulls_distinct] == false} DISTINCT" unless index[:nulls_distinct].nil?
|
|
1334
|
+
|
|
985
1335
|
case index_type
|
|
986
1336
|
when :full_text
|
|
987
1337
|
expr = "(to_tsvector(#{literal(index[:language] || 'simple')}::regconfig, #{literal(dataset.send(:full_text_string_join, cols))}))"
|
|
@@ -989,37 +1339,33 @@ module Sequel
|
|
|
989
1339
|
when :spatial
|
|
990
1340
|
index_type = :gist
|
|
991
1341
|
end
|
|
992
|
-
|
|
1342
|
+
|
|
1343
|
+
"CREATE #{unique}INDEX#{' CONCURRENTLY' if index[:concurrently]}#{if_not_exists} #{quote_identifier(index_name)} ON #{quote_schema_table(table_name)} #{"USING #{index_type} " if index_type}#{expr}#{" INCLUDE #{literal(Array(index[:include]))}" if index[:include]}#{nulls_distinct}#{" TABLESPACE #{quote_identifier(index[:tablespace])}" if index[:tablespace]}#{filter}"
|
|
993
1344
|
end
|
|
994
1345
|
|
|
995
1346
|
# Setup datastructures shared by all postgres adapters.
|
|
996
1347
|
def initialize_postgres_adapter
|
|
997
1348
|
@primary_keys = {}
|
|
998
1349
|
@primary_key_sequences = {}
|
|
999
|
-
@
|
|
1000
|
-
|
|
1350
|
+
@supported_types = {}
|
|
1351
|
+
procs = @conversion_procs = CONVERSION_PROCS.dup
|
|
1352
|
+
procs[1184] = procs[1114] = method(:to_application_timestamp)
|
|
1001
1353
|
end
|
|
1002
1354
|
|
|
1003
1355
|
# Backbone of the tables and views support.
|
|
1004
1356
|
def pg_class_relname(type, opts)
|
|
1005
|
-
ds = metadata_dataset.from(:pg_class).
|
|
1357
|
+
ds = metadata_dataset.from(:pg_class).where(:relkind=>type).select(:relname).server(opts[:server]).join(:pg_namespace, :oid=>:relnamespace)
|
|
1006
1358
|
ds = filter_schema(ds, opts)
|
|
1007
1359
|
m = output_identifier_meth
|
|
1008
|
-
if
|
|
1360
|
+
if defined?(yield)
|
|
1009
1361
|
yield(ds)
|
|
1010
1362
|
elsif opts[:qualify]
|
|
1011
|
-
ds.select_append
|
|
1363
|
+
ds.select_append{pg_namespace[:nspname]}.map{|r| Sequel.qualify(m.call(r[:nspname]).to_s, m.call(r[:relname]).to_s)}
|
|
1012
1364
|
else
|
|
1013
1365
|
ds.map{|r| m.call(r[:relname])}
|
|
1014
1366
|
end
|
|
1015
1367
|
end
|
|
1016
1368
|
|
|
1017
|
-
# Use a dollar sign instead of question mark for the argument
|
|
1018
|
-
# placeholder.
|
|
1019
|
-
def prepared_arg_placeholder
|
|
1020
|
-
PREPARED_ARG_PLACEHOLDER
|
|
1021
|
-
end
|
|
1022
|
-
|
|
1023
1369
|
# Return an expression the oid for the table expr. Used by the metadata parsing
|
|
1024
1370
|
# code to disambiguate unqualified tables.
|
|
1025
1371
|
def regclass_oid(expr, opts=OPTS)
|
|
@@ -1042,8 +1388,7 @@ module Sequel
|
|
|
1042
1388
|
Sequel.cast(expr.to_s,:regclass).cast(:oid)
|
|
1043
1389
|
end
|
|
1044
1390
|
|
|
1045
|
-
# Remove the cached entries for primary keys and sequences when a table is
|
|
1046
|
-
# changed.
|
|
1391
|
+
# Remove the cached entries for primary keys and sequences when a table is changed.
|
|
1047
1392
|
def remove_cached_schema(table)
|
|
1048
1393
|
tab = quote_schema_table(table)
|
|
1049
1394
|
Sequel.synchronize do
|
|
@@ -1059,7 +1404,6 @@ module Sequel
|
|
|
1059
1404
|
"ALTER TABLE #{quote_schema_table(name)} RENAME TO #{quote_identifier(schema_and_table(new_name).last)}"
|
|
1060
1405
|
end
|
|
1061
1406
|
|
|
1062
|
-
# Recognize PostgreSQL interval type.
|
|
1063
1407
|
def schema_column_type(db_type)
|
|
1064
1408
|
case db_type
|
|
1065
1409
|
when /\Ainterval\z/io
|
|
@@ -1074,24 +1418,39 @@ module Sequel
|
|
|
1074
1418
|
# The dataset used for parsing table schemas, using the pg_* system catalogs.
|
|
1075
1419
|
def schema_parse_table(table_name, opts)
|
|
1076
1420
|
m = output_identifier_meth(opts[:dataset])
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
SQL::
|
|
1081
|
-
SQL::
|
|
1082
|
-
SQL::Function.new(:
|
|
1083
|
-
SQL::
|
|
1084
|
-
SQL::Function.new(:
|
|
1421
|
+
oid = regclass_oid(table_name, opts)
|
|
1422
|
+
ds = metadata_dataset.select{[
|
|
1423
|
+
pg_attribute[:attname].as(:name),
|
|
1424
|
+
SQL::Cast.new(pg_attribute[:atttypid], :integer).as(:oid),
|
|
1425
|
+
SQL::Cast.new(basetype[:oid], :integer).as(:base_oid),
|
|
1426
|
+
SQL::Function.new(:format_type, basetype[:oid], pg_type[:typtypmod]).as(:db_base_type),
|
|
1427
|
+
SQL::Function.new(:format_type, pg_type[:oid], pg_attribute[:atttypmod]).as(:db_type),
|
|
1428
|
+
SQL::Function.new(:pg_get_expr, pg_attrdef[:adbin], pg_class[:oid]).as(:default),
|
|
1429
|
+
SQL::BooleanExpression.new(:NOT, pg_attribute[:attnotnull]).as(:allow_null),
|
|
1430
|
+
SQL::Function.new(:COALESCE, SQL::BooleanExpression.from_value_pairs(pg_attribute[:attnum] => SQL::Function.new(:ANY, pg_index[:indkey])), false).as(:primary_key)]}.
|
|
1085
1431
|
from(:pg_class).
|
|
1086
1432
|
join(:pg_attribute, :attrelid=>:oid).
|
|
1087
1433
|
join(:pg_type, :oid=>:atttypid).
|
|
1088
|
-
left_outer_join(:
|
|
1089
|
-
left_outer_join(:pg_attrdef, :adrelid
|
|
1090
|
-
left_outer_join(:pg_index, :indrelid
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
order
|
|
1434
|
+
left_outer_join(Sequel[:pg_type].as(:basetype), :oid=>:typbasetype).
|
|
1435
|
+
left_outer_join(:pg_attrdef, :adrelid=>Sequel[:pg_class][:oid], :adnum=>Sequel[:pg_attribute][:attnum]).
|
|
1436
|
+
left_outer_join(:pg_index, :indrelid=>Sequel[:pg_class][:oid], :indisprimary=>true).
|
|
1437
|
+
where{{pg_attribute[:attisdropped]=>false}}.
|
|
1438
|
+
where{pg_attribute[:attnum] > 0}.
|
|
1439
|
+
where{{pg_class[:oid]=>oid}}.
|
|
1440
|
+
order{pg_attribute[:attnum]}
|
|
1441
|
+
|
|
1442
|
+
# :nocov:
|
|
1443
|
+
if server_version > 100000
|
|
1444
|
+
# :nocov:
|
|
1445
|
+
ds = ds.select_append{pg_attribute[:attidentity]}
|
|
1446
|
+
|
|
1447
|
+
# :nocov:
|
|
1448
|
+
if server_version > 120000
|
|
1449
|
+
# :nocov:
|
|
1450
|
+
ds = ds.select_append{Sequel.~(pg_attribute[:attgenerated]=>'').as(:generated)}
|
|
1451
|
+
end
|
|
1452
|
+
end
|
|
1453
|
+
|
|
1095
1454
|
ds.map do |row|
|
|
1096
1455
|
row[:default] = nil if blank_object?(row[:default])
|
|
1097
1456
|
if row[:base_oid]
|
|
@@ -1104,8 +1463,9 @@ module Sequel
|
|
|
1104
1463
|
row.delete(:db_base_type)
|
|
1105
1464
|
end
|
|
1106
1465
|
row[:type] = schema_column_type(row[:db_type])
|
|
1466
|
+
identity = row.delete(:attidentity)
|
|
1107
1467
|
if row[:primary_key]
|
|
1108
|
-
row[:auto_increment] = !!(row[:default] =~ /\
|
|
1468
|
+
row[:auto_increment] = !!(row[:default] =~ /\A(?:nextval)/i) || identity == 'a' || identity == 'd'
|
|
1109
1469
|
end
|
|
1110
1470
|
[m.call(row.delete(:name)), row]
|
|
1111
1471
|
end
|
|
@@ -1159,12 +1519,14 @@ module Sequel
|
|
|
1159
1519
|
# PostgreSQL prefers the text datatype. If a fixed size is requested,
|
|
1160
1520
|
# the char type is used. If the text type is specifically
|
|
1161
1521
|
# disallowed or there is a size specified, use the varchar type.
|
|
1162
|
-
# Otherwise use the
|
|
1522
|
+
# Otherwise use the text type.
|
|
1163
1523
|
def type_literal_generic_string(column)
|
|
1164
|
-
if column[:
|
|
1165
|
-
|
|
1166
|
-
elsif column[:
|
|
1167
|
-
"
|
|
1524
|
+
if column[:text]
|
|
1525
|
+
:text
|
|
1526
|
+
elsif column[:fixed]
|
|
1527
|
+
"char(#{column[:size]||default_string_column_size})"
|
|
1528
|
+
elsif column[:text] == false || column[:size]
|
|
1529
|
+
"varchar(#{column[:size]||default_string_column_size})"
|
|
1168
1530
|
else
|
|
1169
1531
|
:text
|
|
1170
1532
|
end
|
|
@@ -1172,77 +1534,23 @@ module Sequel
|
|
|
1172
1534
|
|
|
1173
1535
|
# PostgreSQL 9.4+ supports views with check option.
|
|
1174
1536
|
def view_with_check_option_support
|
|
1537
|
+
# :nocov:
|
|
1175
1538
|
:local if server_version >= 90400
|
|
1539
|
+
# :nocov:
|
|
1176
1540
|
end
|
|
1177
1541
|
end
|
|
1178
1542
|
|
|
1179
|
-
# Instance methods for datasets that connect to a PostgreSQL database.
|
|
1180
1543
|
module DatasetMethods
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
BOOL_FALSE = 'false'.freeze
|
|
1184
|
-
BOOL_TRUE = 'true'.freeze
|
|
1185
|
-
COMMA_SEPARATOR = ', '.freeze
|
|
1186
|
-
EXCLUSIVE = 'EXCLUSIVE'.freeze
|
|
1187
|
-
EXPLAIN = 'EXPLAIN '.freeze
|
|
1188
|
-
EXPLAIN_ANALYZE = 'EXPLAIN ANALYZE '.freeze
|
|
1189
|
-
FOR_SHARE = ' FOR SHARE'.freeze
|
|
1544
|
+
include UnmodifiedIdentifiers::DatasetMethods
|
|
1545
|
+
|
|
1190
1546
|
NULL = LiteralString.new('NULL').freeze
|
|
1191
|
-
|
|
1192
|
-
QUERY_PLAN = 'QUERY PLAN'.to_sym
|
|
1193
|
-
ROW_EXCLUSIVE = 'ROW EXCLUSIVE'.freeze
|
|
1194
|
-
ROW_SHARE = 'ROW SHARE'.freeze
|
|
1195
|
-
SHARE = 'SHARE'.freeze
|
|
1196
|
-
SHARE_ROW_EXCLUSIVE = 'SHARE ROW EXCLUSIVE'.freeze
|
|
1197
|
-
SHARE_UPDATE_EXCLUSIVE = 'SHARE UPDATE EXCLUSIVE'.freeze
|
|
1198
|
-
SQL_WITH_RECURSIVE = "WITH RECURSIVE ".freeze
|
|
1199
|
-
SPACE = Dataset::SPACE
|
|
1200
|
-
FROM = Dataset::FROM
|
|
1201
|
-
APOS = Dataset::APOS
|
|
1202
|
-
APOS_RE = Dataset::APOS_RE
|
|
1203
|
-
DOUBLE_APOS = Dataset::DOUBLE_APOS
|
|
1204
|
-
PAREN_OPEN = Dataset::PAREN_OPEN
|
|
1205
|
-
PAREN_CLOSE = Dataset::PAREN_CLOSE
|
|
1206
|
-
COMMA = Dataset::COMMA
|
|
1207
|
-
ESCAPE = Dataset::ESCAPE
|
|
1208
|
-
BACKSLASH = Dataset::BACKSLASH
|
|
1209
|
-
AS = Dataset::AS
|
|
1210
|
-
XOR_OP = ' # '.freeze
|
|
1211
|
-
CRLF = "\r\n".freeze
|
|
1212
|
-
BLOB_RE = /[\000-\037\047\134\177-\377]/n.freeze
|
|
1213
|
-
WINDOW = " WINDOW ".freeze
|
|
1214
|
-
SELECT_VALUES = "VALUES ".freeze
|
|
1215
|
-
EMPTY_STRING = ''.freeze
|
|
1216
|
-
LOCK_MODES = ['ACCESS SHARE', 'ROW SHARE', 'ROW EXCLUSIVE', 'SHARE UPDATE EXCLUSIVE', 'SHARE', 'SHARE ROW EXCLUSIVE', 'EXCLUSIVE', 'ACCESS EXCLUSIVE'].each(&:freeze)
|
|
1217
|
-
SKIP_LOCKED = " SKIP LOCKED".freeze
|
|
1547
|
+
LOCK_MODES = ['ACCESS SHARE', 'ROW SHARE', 'ROW EXCLUSIVE', 'SHARE UPDATE EXCLUSIVE', 'SHARE', 'SHARE ROW EXCLUSIVE', 'EXCLUSIVE', 'ACCESS EXCLUSIVE'].each(&:freeze).freeze
|
|
1218
1548
|
|
|
1219
1549
|
Dataset.def_sql_method(self, :delete, [['if server_version >= 90100', %w'with delete from using where returning'], ['else', %w'delete from using where returning']])
|
|
1220
|
-
Dataset.def_sql_method(self, :insert, [['if server_version >= 90500', %w'with insert into columns values conflict returning'], ['elsif server_version >= 90100', %w'with insert into columns values returning'], ['else', %w'insert into columns values returning']])
|
|
1550
|
+
Dataset.def_sql_method(self, :insert, [['if server_version >= 90500', %w'with insert into columns override values conflict returning'], ['elsif server_version >= 90100', %w'with insert into columns values returning'], ['else', %w'insert into columns values returning']])
|
|
1221
1551
|
Dataset.def_sql_method(self, :select, [['if opts[:values]', %w'values order limit'], ['elsif server_version >= 80400', %w'with select distinct columns from join where group having window compounds order limit lock'], ['else', %w'select distinct columns from join where group having compounds order limit lock']])
|
|
1222
1552
|
Dataset.def_sql_method(self, :update, [['if server_version >= 90100', %w'with update table set from where returning'], ['else', %w'update table set from where returning']])
|
|
1223
1553
|
|
|
1224
|
-
# Shared methods for prepared statements when used with PostgreSQL databases.
|
|
1225
|
-
module PreparedStatementMethods
|
|
1226
|
-
# Override insert action to use RETURNING if the server supports it.
|
|
1227
|
-
def run
|
|
1228
|
-
if @prepared_type == :insert && (opts[:returning_pk] || !opts[:returning])
|
|
1229
|
-
fetch_rows(prepared_sql){|r| return r.values.first}
|
|
1230
|
-
else
|
|
1231
|
-
super
|
|
1232
|
-
end
|
|
1233
|
-
end
|
|
1234
|
-
|
|
1235
|
-
def prepared_sql
|
|
1236
|
-
return @prepared_sql if @prepared_sql
|
|
1237
|
-
if @prepared_type == :insert && !opts[:returning]
|
|
1238
|
-
@opts[:returning] = insert_pk
|
|
1239
|
-
@opts[:returning_pk] = true
|
|
1240
|
-
end
|
|
1241
|
-
super
|
|
1242
|
-
@prepared_sql
|
|
1243
|
-
end
|
|
1244
|
-
end
|
|
1245
|
-
|
|
1246
1554
|
# Return the results of an EXPLAIN ANALYZE query as a string
|
|
1247
1555
|
def analyze
|
|
1248
1556
|
explain(:analyze=>true)
|
|
@@ -1254,7 +1562,7 @@ module Sequel
|
|
|
1254
1562
|
def complex_expression_sql_append(sql, op, args)
|
|
1255
1563
|
case op
|
|
1256
1564
|
when :^
|
|
1257
|
-
j =
|
|
1565
|
+
j = ' # '
|
|
1258
1566
|
c = false
|
|
1259
1567
|
args.each do |a|
|
|
1260
1568
|
sql << j if c
|
|
@@ -1262,13 +1570,13 @@ module Sequel
|
|
|
1262
1570
|
c ||= true
|
|
1263
1571
|
end
|
|
1264
1572
|
when :ILIKE, :'NOT ILIKE'
|
|
1265
|
-
sql <<
|
|
1266
|
-
literal_append(sql, args
|
|
1267
|
-
sql <<
|
|
1268
|
-
literal_append(sql, args
|
|
1269
|
-
sql << ESCAPE
|
|
1270
|
-
literal_append(sql,
|
|
1271
|
-
sql <<
|
|
1573
|
+
sql << '('
|
|
1574
|
+
literal_append(sql, args[0])
|
|
1575
|
+
sql << ' ' << op.to_s << ' '
|
|
1576
|
+
literal_append(sql, args[1])
|
|
1577
|
+
sql << " ESCAPE "
|
|
1578
|
+
literal_append(sql, "\\")
|
|
1579
|
+
sql << ')'
|
|
1272
1580
|
else
|
|
1273
1581
|
super
|
|
1274
1582
|
end
|
|
@@ -1294,7 +1602,7 @@ module Sequel
|
|
|
1294
1602
|
|
|
1295
1603
|
# Return the results of an EXPLAIN query as a string
|
|
1296
1604
|
def explain(opts=OPTS)
|
|
1297
|
-
with_sql((opts[:analyze] ?
|
|
1605
|
+
with_sql((opts[:analyze] ? 'EXPLAIN ANALYZE ' : 'EXPLAIN ') + select_sql).map(:'QUERY PLAN').join("\r\n")
|
|
1298
1606
|
end
|
|
1299
1607
|
|
|
1300
1608
|
# Return a cloned dataset which will use FOR SHARE to lock returned rows.
|
|
@@ -1315,6 +1623,8 @@ module Sequel
|
|
|
1315
1623
|
# :phrase :: Similar to :plain, but also adding an ILIKE filter to ensure that
|
|
1316
1624
|
# returned rows also include the exact phrase used.
|
|
1317
1625
|
# :rank :: Set to true to order by the rank, so that closer matches are returned first.
|
|
1626
|
+
# :to_tsquery :: Can be set to :plain or :phrase to specify the function to use to
|
|
1627
|
+
# convert the terms to a ts_query.
|
|
1318
1628
|
# :tsquery :: Specifies the terms argument is already a valid SQL expression returning a
|
|
1319
1629
|
# tsquery, and can be used directly in the query.
|
|
1320
1630
|
# :tsvector :: Specifies the cols argument is already a valid SQL expression returning a
|
|
@@ -1329,11 +1639,18 @@ module Sequel
|
|
|
1329
1639
|
|
|
1330
1640
|
unless opts[:tsquery]
|
|
1331
1641
|
phrase_terms = terms.is_a?(Array) ? terms.join(' | ') : terms
|
|
1332
|
-
|
|
1642
|
+
|
|
1643
|
+
query_func = case to_tsquery = opts[:to_tsquery]
|
|
1644
|
+
when :phrase, :plain
|
|
1645
|
+
:"#{to_tsquery}to_tsquery"
|
|
1646
|
+
else
|
|
1647
|
+
(opts[:phrase] || opts[:plain]) ? :plainto_tsquery : :to_tsquery
|
|
1648
|
+
end
|
|
1649
|
+
|
|
1333
1650
|
terms = Sequel.function(query_func, lang, phrase_terms)
|
|
1334
1651
|
end
|
|
1335
1652
|
|
|
1336
|
-
ds = where(Sequel.lit(["
|
|
1653
|
+
ds = where(Sequel.lit(["", " @@ ", ""], cols, terms))
|
|
1337
1654
|
|
|
1338
1655
|
if opts[:phrase]
|
|
1339
1656
|
raise Error, "can't use :phrase with either :tsvector or :tsquery arguments to full_text_search together" if opts[:tsvector] || opts[:tsquery]
|
|
@@ -1370,6 +1687,7 @@ module Sequel
|
|
|
1370
1687
|
|
|
1371
1688
|
# Handle uniqueness violations when inserting, by updating the conflicting row, using
|
|
1372
1689
|
# ON CONFLICT. With no options, uses ON CONFLICT DO NOTHING. Options:
|
|
1690
|
+
# :conflict_where :: The index filter, when using a partial index to determine uniqueness.
|
|
1373
1691
|
# :constraint :: An explicit constraint name, has precendence over :target.
|
|
1374
1692
|
# :target :: The column name or expression to handle uniqueness violations on.
|
|
1375
1693
|
# :update :: A hash of columns and values to set. Uses ON CONFLICT DO UPDATE.
|
|
@@ -1377,24 +1695,28 @@ module Sequel
|
|
|
1377
1695
|
#
|
|
1378
1696
|
# Examples:
|
|
1379
1697
|
#
|
|
1380
|
-
# DB[:table].insert_conflict.insert(:
|
|
1698
|
+
# DB[:table].insert_conflict.insert(a: 1, b: 2)
|
|
1381
1699
|
# # INSERT INTO TABLE (a, b) VALUES (1, 2)
|
|
1382
1700
|
# # ON CONFLICT DO NOTHING
|
|
1383
1701
|
#
|
|
1384
|
-
# DB[:table].insert_conflict(:
|
|
1702
|
+
# DB[:table].insert_conflict(constraint: :table_a_uidx).insert(a: 1, b: 2)
|
|
1385
1703
|
# # INSERT INTO TABLE (a, b) VALUES (1, 2)
|
|
1386
1704
|
# # ON CONFLICT ON CONSTRAINT table_a_uidx DO NOTHING
|
|
1387
1705
|
#
|
|
1388
|
-
# DB[:table].insert_conflict(:
|
|
1706
|
+
# DB[:table].insert_conflict(target: :a).insert(a: 1, b: 2)
|
|
1389
1707
|
# # INSERT INTO TABLE (a, b) VALUES (1, 2)
|
|
1390
1708
|
# # ON CONFLICT (a) DO NOTHING
|
|
1709
|
+
#
|
|
1710
|
+
# DB[:table].insert_conflict(target: :a, conflict_where: {c: true}).insert(a: 1, b: 2)
|
|
1711
|
+
# # INSERT INTO TABLE (a, b) VALUES (1, 2)
|
|
1712
|
+
# # ON CONFLICT (a) WHERE (c IS TRUE) DO NOTHING
|
|
1391
1713
|
#
|
|
1392
|
-
# DB[:table].insert_conflict(:
|
|
1714
|
+
# DB[:table].insert_conflict(target: :a, update: {b: Sequel[:excluded][:b]}).insert(a: 1, b: 2)
|
|
1393
1715
|
# # INSERT INTO TABLE (a, b) VALUES (1, 2)
|
|
1394
1716
|
# # ON CONFLICT (a) DO UPDATE SET b = excluded.b
|
|
1395
1717
|
#
|
|
1396
|
-
# DB[:table].insert_conflict(:
|
|
1397
|
-
# :
|
|
1718
|
+
# DB[:table].insert_conflict(constraint: :table_a_uidx,
|
|
1719
|
+
# update: {b: Sequel[:excluded][:b]}, update_where: {Sequel[:table][:status_id] => 1}).insert(a: 1, b: 2)
|
|
1398
1720
|
# # INSERT INTO TABLE (a, b) VALUES (1, 2)
|
|
1399
1721
|
# # ON CONFLICT ON CONSTRAINT table_a_uidx
|
|
1400
1722
|
# # DO UPDATE SET b = excluded.b WHERE (table.status_id = 1)
|
|
@@ -1405,18 +1727,20 @@ module Sequel
|
|
|
1405
1727
|
# Ignore uniqueness/exclusion violations when inserting, using ON CONFLICT DO NOTHING.
|
|
1406
1728
|
# Exists mostly for compatibility to MySQL's insert_ignore. Example:
|
|
1407
1729
|
#
|
|
1408
|
-
# DB[:table].insert_ignore.insert(:
|
|
1730
|
+
# DB[:table].insert_ignore.insert(a: 1, b: 2)
|
|
1409
1731
|
# # INSERT INTO TABLE (a, b) VALUES (1, 2)
|
|
1410
1732
|
# # ON CONFLICT DO NOTHING
|
|
1411
1733
|
def insert_ignore
|
|
1412
1734
|
insert_conflict
|
|
1413
1735
|
end
|
|
1414
1736
|
|
|
1415
|
-
# Insert a record returning the record inserted. Always returns nil without
|
|
1416
|
-
#
|
|
1737
|
+
# Insert a record, returning the record inserted, using RETURNING. Always returns nil without
|
|
1738
|
+
# running an INSERT statement if disable_insert_returning is used. If the query runs
|
|
1739
|
+
# but returns no values, returns false.
|
|
1417
1740
|
def insert_select(*values)
|
|
1418
1741
|
return unless supports_insert_select?
|
|
1419
|
-
|
|
1742
|
+
# Handle case where query does not return a row
|
|
1743
|
+
server?(:default).with_sql_first(insert_select_sql(*values)) || false
|
|
1420
1744
|
end
|
|
1421
1745
|
|
|
1422
1746
|
# The SQL to use for an insert_select, adds a RETURNING clause to the insert
|
|
@@ -1426,13 +1750,22 @@ module Sequel
|
|
|
1426
1750
|
ds.insert_sql(*values)
|
|
1427
1751
|
end
|
|
1428
1752
|
|
|
1753
|
+
# Support SQL::AliasedExpression as expr to setup a USING join with a table alias for the
|
|
1754
|
+
# USING columns.
|
|
1755
|
+
def join_table(type, table, expr=nil, options=OPTS, &block)
|
|
1756
|
+
if expr.is_a?(SQL::AliasedExpression) && expr.expression.is_a?(Array) && !expr.expression.empty? && expr.expression.all?
|
|
1757
|
+
options = options.merge(:join_using=>true)
|
|
1758
|
+
end
|
|
1759
|
+
super
|
|
1760
|
+
end
|
|
1761
|
+
|
|
1429
1762
|
# Locks all tables in the dataset's FROM clause (but not in JOINs) with
|
|
1430
1763
|
# the specified mode (e.g. 'EXCLUSIVE'). If a block is given, starts
|
|
1431
|
-
# a new transaction, locks the table, and yields. If a block is not given
|
|
1764
|
+
# a new transaction, locks the table, and yields. If a block is not given,
|
|
1432
1765
|
# just locks the tables. Note that PostgreSQL will probably raise an error
|
|
1433
1766
|
# if you lock the table outside of an existing transaction. Returns nil.
|
|
1434
1767
|
def lock(mode, opts=OPTS)
|
|
1435
|
-
if
|
|
1768
|
+
if defined?(yield) # perform locking inside a transaction and yield to block
|
|
1436
1769
|
@db.transaction(opts){lock(mode, opts); yield}
|
|
1437
1770
|
else
|
|
1438
1771
|
sql = 'LOCK TABLE '.dup
|
|
@@ -1447,6 +1780,54 @@ module Sequel
|
|
|
1447
1780
|
nil
|
|
1448
1781
|
end
|
|
1449
1782
|
|
|
1783
|
+
# Return a dataset with a WHEN MATCHED THEN DO NOTHING clause added to the
|
|
1784
|
+
# MERGE statement. If a block is passed, treat it as a virtual row and
|
|
1785
|
+
# use it as additional conditions for the match.
|
|
1786
|
+
#
|
|
1787
|
+
# merge_do_nothing_when_matched
|
|
1788
|
+
# # WHEN MATCHED THEN DO NOTHING
|
|
1789
|
+
#
|
|
1790
|
+
# merge_do_nothing_when_matched{a > 30}
|
|
1791
|
+
# # WHEN MATCHED AND (a > 30) THEN DO NOTHING
|
|
1792
|
+
def merge_do_nothing_when_matched(&block)
|
|
1793
|
+
_merge_when(:type=>:matched, &block)
|
|
1794
|
+
end
|
|
1795
|
+
|
|
1796
|
+
# Return a dataset with a WHEN NOT MATCHED THEN DO NOTHING clause added to the
|
|
1797
|
+
# MERGE statement. If a block is passed, treat it as a virtual row and
|
|
1798
|
+
# use it as additional conditions for the match.
|
|
1799
|
+
#
|
|
1800
|
+
# merge_do_nothing_when_not_matched
|
|
1801
|
+
# # WHEN NOT MATCHED THEN DO NOTHING
|
|
1802
|
+
#
|
|
1803
|
+
# merge_do_nothing_when_not_matched{a > 30}
|
|
1804
|
+
# # WHEN NOT MATCHED AND (a > 30) THEN DO NOTHING
|
|
1805
|
+
def merge_do_nothing_when_not_matched(&block)
|
|
1806
|
+
_merge_when(:type=>:not_matched, &block)
|
|
1807
|
+
end
|
|
1808
|
+
|
|
1809
|
+
# Support OVERRIDING USER|SYSTEM VALUE for MERGE INSERT.
|
|
1810
|
+
def merge_insert(*values, &block)
|
|
1811
|
+
h = {:type=>:insert, :values=>values}
|
|
1812
|
+
if override = @opts[:override]
|
|
1813
|
+
h[:override] = insert_override_sql(String.new)
|
|
1814
|
+
end
|
|
1815
|
+
_merge_when(h, &block)
|
|
1816
|
+
end
|
|
1817
|
+
|
|
1818
|
+
# Use OVERRIDING USER VALUE for INSERT statements, so that identity columns
|
|
1819
|
+
# always use the user supplied value, and an error is not raised for identity
|
|
1820
|
+
# columns that are GENERATED ALWAYS.
|
|
1821
|
+
def overriding_system_value
|
|
1822
|
+
clone(:override=>:system)
|
|
1823
|
+
end
|
|
1824
|
+
|
|
1825
|
+
# Use OVERRIDING USER VALUE for INSERT statements, so that identity columns
|
|
1826
|
+
# always use the sequence value instead of the user supplied value.
|
|
1827
|
+
def overriding_user_value
|
|
1828
|
+
clone(:override=>:user)
|
|
1829
|
+
end
|
|
1830
|
+
|
|
1450
1831
|
def supports_cte?(type=:select)
|
|
1451
1832
|
if type == :select
|
|
1452
1833
|
server_version >= 80400
|
|
@@ -1491,7 +1872,7 @@ module Sequel
|
|
|
1491
1872
|
server_version >= 90500
|
|
1492
1873
|
end
|
|
1493
1874
|
|
|
1494
|
-
# PostgreSQL 9.
|
|
1875
|
+
# PostgreSQL 9.3+ supports lateral subqueries
|
|
1495
1876
|
def supports_lateral_subqueries?
|
|
1496
1877
|
server_version >= 90300
|
|
1497
1878
|
end
|
|
@@ -1501,6 +1882,16 @@ module Sequel
|
|
|
1501
1882
|
true
|
|
1502
1883
|
end
|
|
1503
1884
|
|
|
1885
|
+
# PostgreSQL 15+ supports MERGE.
|
|
1886
|
+
def supports_merge?
|
|
1887
|
+
server_version >= 150000
|
|
1888
|
+
end
|
|
1889
|
+
|
|
1890
|
+
# PostgreSQL supports NOWAIT.
|
|
1891
|
+
def supports_nowait?
|
|
1892
|
+
true
|
|
1893
|
+
end
|
|
1894
|
+
|
|
1504
1895
|
# Returning is always supported.
|
|
1505
1896
|
def supports_returning?(type)
|
|
1506
1897
|
true
|
|
@@ -1521,11 +1912,31 @@ module Sequel
|
|
|
1521
1912
|
true
|
|
1522
1913
|
end
|
|
1523
1914
|
|
|
1915
|
+
# PostgreSQL 8.4+ supports WINDOW clause.
|
|
1916
|
+
def supports_window_clause?
|
|
1917
|
+
server_version >= 80400
|
|
1918
|
+
end
|
|
1919
|
+
|
|
1524
1920
|
# PostgreSQL 8.4+ supports window functions
|
|
1525
1921
|
def supports_window_functions?
|
|
1526
1922
|
server_version >= 80400
|
|
1527
1923
|
end
|
|
1528
1924
|
|
|
1925
|
+
# Base support added in 8.4, offset supported added in 9.0,
|
|
1926
|
+
# GROUPS and EXCLUDE support added in 11.0.
|
|
1927
|
+
def supports_window_function_frame_option?(option)
|
|
1928
|
+
case option
|
|
1929
|
+
when :rows, :range
|
|
1930
|
+
true
|
|
1931
|
+
when :offset
|
|
1932
|
+
server_version >= 90000
|
|
1933
|
+
when :groups, :exclude
|
|
1934
|
+
server_version >= 110000
|
|
1935
|
+
else
|
|
1936
|
+
false
|
|
1937
|
+
end
|
|
1938
|
+
end
|
|
1939
|
+
|
|
1529
1940
|
# Truncates the dataset. Returns nil.
|
|
1530
1941
|
#
|
|
1531
1942
|
# Options:
|
|
@@ -1537,10 +1948,11 @@ module Sequel
|
|
|
1537
1948
|
# :only and :restart only work correctly on PostgreSQL 8.4+.
|
|
1538
1949
|
#
|
|
1539
1950
|
# Usage:
|
|
1540
|
-
# DB[:table].truncate
|
|
1541
|
-
# #
|
|
1542
|
-
#
|
|
1543
|
-
#
|
|
1951
|
+
# DB[:table].truncate
|
|
1952
|
+
# # TRUNCATE TABLE "table"
|
|
1953
|
+
#
|
|
1954
|
+
# DB[:table].truncate(cascade: true, only: true, restart: true)
|
|
1955
|
+
# # TRUNCATE TABLE ONLY "table" RESTART IDENTITY CASCADE
|
|
1544
1956
|
def truncate(opts = OPTS)
|
|
1545
1957
|
if opts.empty?
|
|
1546
1958
|
super()
|
|
@@ -1549,9 +1961,11 @@ module Sequel
|
|
|
1549
1961
|
end
|
|
1550
1962
|
end
|
|
1551
1963
|
|
|
1552
|
-
#
|
|
1553
|
-
|
|
1554
|
-
|
|
1964
|
+
# Use WITH TIES when limiting the result set to also include additional
|
|
1965
|
+
# rules that have the same results for the order column as the final row.
|
|
1966
|
+
# Requires PostgreSQL 13.
|
|
1967
|
+
def with_ties
|
|
1968
|
+
clone(:limit_with_ties=>true)
|
|
1555
1969
|
end
|
|
1556
1970
|
|
|
1557
1971
|
protected
|
|
@@ -1563,7 +1977,9 @@ module Sequel
|
|
|
1563
1977
|
def _import(columns, values, opts=OPTS)
|
|
1564
1978
|
if @opts[:returning]
|
|
1565
1979
|
statements = multi_insert_sql(columns, values)
|
|
1566
|
-
|
|
1980
|
+
trans_opts = Hash[opts]
|
|
1981
|
+
trans_opts[:server] = @opts[:server]
|
|
1982
|
+
@db.transaction(trans_opts) do
|
|
1567
1983
|
statements.map{|st| returning_fetch_rows(st)}
|
|
1568
1984
|
end.first.map{|v| v.length == 1 ? v.values.first : v}
|
|
1569
1985
|
elsif opts[:return] == :primary_key
|
|
@@ -1573,11 +1989,35 @@ module Sequel
|
|
|
1573
1989
|
end
|
|
1574
1990
|
end
|
|
1575
1991
|
|
|
1992
|
+
def to_prepared_statement(type, *a)
|
|
1993
|
+
if type == :insert && !@opts.has_key?(:returning)
|
|
1994
|
+
returning(insert_pk).send(:to_prepared_statement, :insert_pk, *a)
|
|
1995
|
+
else
|
|
1996
|
+
super
|
|
1997
|
+
end
|
|
1998
|
+
end
|
|
1999
|
+
|
|
1576
2000
|
private
|
|
1577
2001
|
|
|
2002
|
+
# Append the INSERT sql used in a MERGE
|
|
2003
|
+
def _merge_insert_sql(sql, data)
|
|
2004
|
+
sql << " THEN INSERT "
|
|
2005
|
+
columns, values = _parse_insert_sql_args(data[:values])
|
|
2006
|
+
_insert_columns_sql(sql, columns)
|
|
2007
|
+
if override = data[:override]
|
|
2008
|
+
sql << override
|
|
2009
|
+
end
|
|
2010
|
+
_insert_values_sql(sql, values)
|
|
2011
|
+
end
|
|
2012
|
+
|
|
2013
|
+
def _merge_matched_sql(sql, data)
|
|
2014
|
+
sql << " THEN DO NOTHING"
|
|
2015
|
+
end
|
|
2016
|
+
alias _merge_not_matched_sql _merge_matched_sql
|
|
2017
|
+
|
|
1578
2018
|
# Format TRUNCATE statement with PostgreSQL specific options.
|
|
1579
2019
|
def _truncate_sql(table)
|
|
1580
|
-
to = @opts[:truncate_opts] ||
|
|
2020
|
+
to = @opts[:truncate_opts] || OPTS
|
|
1581
2021
|
"TRUNCATE TABLE#{' ONLY' if to[:only]} #{table}#{' RESTART IDENTITY' if to[:restart]}#{' CASCADE' if to[:cascade]}"
|
|
1582
2022
|
end
|
|
1583
2023
|
|
|
@@ -1589,7 +2029,7 @@ module Sequel
|
|
|
1589
2029
|
|
|
1590
2030
|
# Only include the primary table in the main delete clause
|
|
1591
2031
|
def delete_from_sql(sql)
|
|
1592
|
-
sql << FROM
|
|
2032
|
+
sql << ' FROM '
|
|
1593
2033
|
source_list_append(sql, @opts[:from][0..0])
|
|
1594
2034
|
end
|
|
1595
2035
|
|
|
@@ -1609,54 +2049,87 @@ module Sequel
|
|
|
1609
2049
|
elsif target = opts[:target]
|
|
1610
2050
|
sql << ' '
|
|
1611
2051
|
identifier_append(sql, Array(target))
|
|
2052
|
+
if conflict_where = opts[:conflict_where]
|
|
2053
|
+
sql << " WHERE "
|
|
2054
|
+
literal_append(sql, conflict_where)
|
|
2055
|
+
end
|
|
1612
2056
|
end
|
|
1613
2057
|
|
|
1614
2058
|
if values = opts[:update]
|
|
1615
2059
|
sql << " DO UPDATE SET "
|
|
1616
2060
|
update_sql_values_hash(sql, values)
|
|
1617
|
-
if
|
|
2061
|
+
if update_where = opts[:update_where]
|
|
1618
2062
|
sql << " WHERE "
|
|
1619
|
-
literal_append(sql,
|
|
2063
|
+
literal_append(sql, update_where)
|
|
1620
2064
|
end
|
|
1621
2065
|
else
|
|
1622
2066
|
sql << " DO NOTHING"
|
|
1623
2067
|
end
|
|
2068
|
+
end
|
|
2069
|
+
end
|
|
1624
2070
|
|
|
2071
|
+
# Include aliases when inserting into a single table on PostgreSQL 9.5+.
|
|
2072
|
+
def insert_into_sql(sql)
|
|
2073
|
+
sql << " INTO "
|
|
2074
|
+
if (f = @opts[:from]) && f.length == 1
|
|
2075
|
+
identifier_append(sql, server_version >= 90500 ? f.first : unaliased_identifier(f.first))
|
|
2076
|
+
else
|
|
2077
|
+
source_list_append(sql, f)
|
|
1625
2078
|
end
|
|
1626
2079
|
end
|
|
1627
2080
|
|
|
1628
2081
|
# Return the primary key to use for RETURNING in an INSERT statement
|
|
1629
2082
|
def insert_pk
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
end
|
|
2083
|
+
(f = opts[:from]) && !f.empty? && (t = f.first)
|
|
2084
|
+
case t
|
|
2085
|
+
when Symbol, String, SQL::Identifier, SQL::QualifiedIdentifier
|
|
2086
|
+
if pk = db.primary_key(t)
|
|
2087
|
+
Sequel::SQL::Identifier.new(pk)
|
|
1636
2088
|
end
|
|
1637
2089
|
end
|
|
1638
2090
|
end
|
|
1639
2091
|
|
|
2092
|
+
# Support OVERRIDING SYSTEM|USER VALUE in insert statements
|
|
2093
|
+
def insert_override_sql(sql)
|
|
2094
|
+
case opts[:override]
|
|
2095
|
+
when :system
|
|
2096
|
+
sql << " OVERRIDING SYSTEM VALUE"
|
|
2097
|
+
when :user
|
|
2098
|
+
sql << " OVERRIDING USER VALUE"
|
|
2099
|
+
end
|
|
2100
|
+
end
|
|
2101
|
+
|
|
1640
2102
|
# For multiple table support, PostgreSQL requires at least
|
|
1641
2103
|
# two from tables, with joins allowed.
|
|
1642
2104
|
def join_from_sql(type, sql)
|
|
1643
2105
|
if(from = @opts[:from][1..-1]).empty?
|
|
1644
2106
|
raise(Error, 'Need multiple FROM tables if updating/deleting a dataset with JOINs') if @opts[:join]
|
|
1645
2107
|
else
|
|
1646
|
-
sql <<
|
|
2108
|
+
sql << ' ' << type.to_s << ' '
|
|
1647
2109
|
source_list_append(sql, from)
|
|
1648
2110
|
select_join_sql(sql)
|
|
1649
2111
|
end
|
|
1650
2112
|
end
|
|
1651
2113
|
|
|
2114
|
+
# Support table aliases for USING columns
|
|
2115
|
+
def join_using_clause_using_sql_append(sql, using_columns)
|
|
2116
|
+
if using_columns.is_a?(SQL::AliasedExpression)
|
|
2117
|
+
super(sql, using_columns.expression)
|
|
2118
|
+
sql << ' AS '
|
|
2119
|
+
identifier_append(sql, using_columns.alias)
|
|
2120
|
+
else
|
|
2121
|
+
super
|
|
2122
|
+
end
|
|
2123
|
+
end
|
|
2124
|
+
|
|
1652
2125
|
# Use a generic blob quoting method, hopefully overridden in one of the subadapter methods
|
|
1653
2126
|
def literal_blob_append(sql, v)
|
|
1654
|
-
sql <<
|
|
2127
|
+
sql << "'" << v.gsub(/[\000-\037\047\134\177-\377]/n){|b| "\\#{("%o" % b[0..1].unpack("C")[0]).rjust(3, '0')}"} << "'"
|
|
1655
2128
|
end
|
|
1656
2129
|
|
|
1657
2130
|
# PostgreSQL uses FALSE for false values
|
|
1658
2131
|
def literal_false
|
|
1659
|
-
|
|
2132
|
+
'false'
|
|
1660
2133
|
end
|
|
1661
2134
|
|
|
1662
2135
|
# PostgreSQL quotes NaN and Infinity.
|
|
@@ -1674,12 +2147,12 @@ module Sequel
|
|
|
1674
2147
|
|
|
1675
2148
|
# Assume that SQL standard quoting is on, per Sequel's defaults
|
|
1676
2149
|
def literal_string_append(sql, v)
|
|
1677
|
-
sql <<
|
|
2150
|
+
sql << "'" << v.gsub("'", "''") << "'"
|
|
1678
2151
|
end
|
|
1679
2152
|
|
|
1680
|
-
# PostgreSQL uses
|
|
2153
|
+
# PostgreSQL uses true for true values
|
|
1681
2154
|
def literal_true
|
|
1682
|
-
|
|
2155
|
+
'true'
|
|
1683
2156
|
end
|
|
1684
2157
|
|
|
1685
2158
|
# PostgreSQL supports multiple rows in INSERT.
|
|
@@ -1687,54 +2160,116 @@ module Sequel
|
|
|
1687
2160
|
:values
|
|
1688
2161
|
end
|
|
1689
2162
|
|
|
2163
|
+
# Dataset options that do not affect the generated SQL.
|
|
2164
|
+
def non_sql_option?(key)
|
|
2165
|
+
super || key == :cursor || key == :insert_conflict
|
|
2166
|
+
end
|
|
2167
|
+
|
|
1690
2168
|
# PostgreSQL requires parentheses around compound datasets if they use
|
|
1691
2169
|
# CTEs, and using them in other places doesn't hurt.
|
|
1692
2170
|
def compound_dataset_sql_append(sql, ds)
|
|
1693
|
-
sql <<
|
|
2171
|
+
sql << '('
|
|
1694
2172
|
super
|
|
1695
|
-
sql <<
|
|
2173
|
+
sql << ')'
|
|
2174
|
+
end
|
|
2175
|
+
|
|
2176
|
+
# Backslash is supported by default as the escape character on PostgreSQL,
|
|
2177
|
+
# and using ESCAPE can break LIKE ANY() usage.
|
|
2178
|
+
def requires_like_escape?
|
|
2179
|
+
false
|
|
2180
|
+
end
|
|
2181
|
+
|
|
2182
|
+
# Support FETCH FIRST WITH TIES on PostgreSQL 13+.
|
|
2183
|
+
def select_limit_sql(sql)
|
|
2184
|
+
l = @opts[:limit]
|
|
2185
|
+
o = @opts[:offset]
|
|
2186
|
+
|
|
2187
|
+
return unless l || o
|
|
2188
|
+
|
|
2189
|
+
if @opts[:limit_with_ties]
|
|
2190
|
+
if o
|
|
2191
|
+
sql << " OFFSET "
|
|
2192
|
+
literal_append(sql, o)
|
|
2193
|
+
end
|
|
2194
|
+
|
|
2195
|
+
if l
|
|
2196
|
+
sql << " FETCH FIRST "
|
|
2197
|
+
literal_append(sql, l)
|
|
2198
|
+
sql << " ROWS WITH TIES"
|
|
2199
|
+
end
|
|
2200
|
+
else
|
|
2201
|
+
if l
|
|
2202
|
+
sql << " LIMIT "
|
|
2203
|
+
literal_append(sql, l)
|
|
2204
|
+
end
|
|
2205
|
+
|
|
2206
|
+
if o
|
|
2207
|
+
sql << " OFFSET "
|
|
2208
|
+
literal_append(sql, o)
|
|
2209
|
+
end
|
|
2210
|
+
end
|
|
1696
2211
|
end
|
|
1697
2212
|
|
|
1698
2213
|
# Support FOR SHARE locking when using the :share lock style.
|
|
1699
2214
|
# Use SKIP LOCKED if skipping locked rows.
|
|
1700
2215
|
def select_lock_sql(sql)
|
|
1701
|
-
|
|
1702
|
-
|
|
2216
|
+
lock = @opts[:lock]
|
|
2217
|
+
if lock == :share
|
|
2218
|
+
sql << ' FOR SHARE'
|
|
1703
2219
|
else
|
|
1704
2220
|
super
|
|
1705
2221
|
end
|
|
1706
2222
|
|
|
1707
|
-
if
|
|
1708
|
-
|
|
2223
|
+
if lock
|
|
2224
|
+
if @opts[:skip_locked]
|
|
2225
|
+
sql << " SKIP LOCKED"
|
|
2226
|
+
elsif @opts[:nowait]
|
|
2227
|
+
sql << " NOWAIT"
|
|
2228
|
+
end
|
|
1709
2229
|
end
|
|
1710
2230
|
end
|
|
1711
2231
|
|
|
1712
2232
|
# Support VALUES clause instead of the SELECT clause to return rows.
|
|
1713
2233
|
def select_values_sql(sql)
|
|
1714
|
-
sql <<
|
|
2234
|
+
sql << "VALUES "
|
|
1715
2235
|
expression_list_append(sql, opts[:values])
|
|
1716
2236
|
end
|
|
1717
2237
|
|
|
1718
|
-
#
|
|
1719
|
-
def
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
2238
|
+
# Use WITH RECURSIVE instead of WITH if any of the CTEs is recursive
|
|
2239
|
+
def select_with_sql_base
|
|
2240
|
+
opts[:with].any?{|w| w[:recursive]} ? "WITH RECURSIVE " : super
|
|
2241
|
+
end
|
|
2242
|
+
|
|
2243
|
+
# Support PostgreSQL 14+ CTE SEARCH/CYCLE clauses
|
|
2244
|
+
def select_with_sql_cte(sql, cte)
|
|
2245
|
+
super
|
|
2246
|
+
|
|
2247
|
+
if search_opts = cte[:search]
|
|
2248
|
+
sql << if search_opts[:type] == :breadth
|
|
2249
|
+
" SEARCH BREADTH FIRST BY "
|
|
2250
|
+
else
|
|
2251
|
+
" SEARCH DEPTH FIRST BY "
|
|
1731
2252
|
end
|
|
2253
|
+
|
|
2254
|
+
identifier_list_append(sql, Array(search_opts[:by]))
|
|
2255
|
+
sql << " SET "
|
|
2256
|
+
identifier_append(sql, search_opts[:set] || :ordercol)
|
|
1732
2257
|
end
|
|
1733
|
-
end
|
|
1734
2258
|
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
2259
|
+
if cycle_opts = cte[:cycle]
|
|
2260
|
+
sql << " CYCLE "
|
|
2261
|
+
identifier_list_append(sql, Array(cycle_opts[:columns]))
|
|
2262
|
+
sql << " SET "
|
|
2263
|
+
identifier_append(sql, cycle_opts[:cycle_column] || :is_cycle)
|
|
2264
|
+
if cycle_opts.has_key?(:cycle_value)
|
|
2265
|
+
sql << " TO "
|
|
2266
|
+
literal_append(sql, cycle_opts[:cycle_value])
|
|
2267
|
+
sql << " DEFAULT "
|
|
2268
|
+
literal_append(sql, cycle_opts.fetch(:noncycle_value, false))
|
|
2269
|
+
end
|
|
2270
|
+
sql << " USING "
|
|
2271
|
+
identifier_append(sql, cycle_opts[:path_column] || :path)
|
|
2272
|
+
end
|
|
1738
2273
|
end
|
|
1739
2274
|
|
|
1740
2275
|
# The version of the database server
|
|
@@ -1742,6 +2277,11 @@ module Sequel
|
|
|
1742
2277
|
db.server_version(@opts[:server])
|
|
1743
2278
|
end
|
|
1744
2279
|
|
|
2280
|
+
# PostgreSQL 9.4+ supports the FILTER clause for aggregate functions.
|
|
2281
|
+
def supports_filtered_aggregates?
|
|
2282
|
+
server_version >= 90400
|
|
2283
|
+
end
|
|
2284
|
+
|
|
1745
2285
|
# PostgreSQL supports quoted function names.
|
|
1746
2286
|
def supports_quoted_function_names?
|
|
1747
2287
|
true
|
|
@@ -1749,8 +2289,8 @@ module Sequel
|
|
|
1749
2289
|
|
|
1750
2290
|
# Concatenate the expressions with a space in between
|
|
1751
2291
|
def full_text_string_join(cols)
|
|
1752
|
-
cols = Array(cols).map{|x| SQL::Function.new(:COALESCE, x,
|
|
1753
|
-
cols = cols.zip([
|
|
2292
|
+
cols = Array(cols).map{|x| SQL::Function.new(:COALESCE, x, '')}
|
|
2293
|
+
cols = cols.zip([' '] * cols.length).flatten
|
|
1754
2294
|
cols.pop
|
|
1755
2295
|
SQL::StringExpression.new(:'||', *cols)
|
|
1756
2296
|
end
|
|
@@ -1762,7 +2302,7 @@ module Sequel
|
|
|
1762
2302
|
|
|
1763
2303
|
# Only include the primary table in the main update clause
|
|
1764
2304
|
def update_table_sql(sql)
|
|
1765
|
-
sql <<
|
|
2305
|
+
sql << ' '
|
|
1766
2306
|
source_list_append(sql, @opts[:from][0..0])
|
|
1767
2307
|
end
|
|
1768
2308
|
end
|