sequel 5.33.0 → 5.58.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 +4 -4
- data/CHANGELOG +318 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +40 -9
- data/doc/association_basics.rdoc +77 -13
- data/doc/cheat_sheet.rdoc +13 -5
- data/doc/code_order.rdoc +0 -12
- data/doc/dataset_filtering.rdoc +2 -2
- data/doc/fork_safety.rdoc +84 -0
- data/doc/migration.rdoc +12 -6
- data/doc/model_plugins.rdoc +1 -1
- data/doc/opening_databases.rdoc +15 -3
- data/doc/postgresql.rdoc +9 -1
- data/doc/querying.rdoc +7 -5
- 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.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.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/sql.rdoc +14 -2
- data/doc/testing.rdoc +10 -1
- data/doc/transactions.rdoc +0 -8
- data/doc/validations.rdoc +1 -1
- data/doc/virtual_rows.rdoc +1 -1
- data/lib/sequel/adapters/ado/access.rb +1 -1
- data/lib/sequel/adapters/ado.rb +17 -17
- data/lib/sequel/adapters/amalgalite.rb +3 -5
- data/lib/sequel/adapters/ibmdb.rb +2 -2
- data/lib/sequel/adapters/jdbc/derby.rb +8 -0
- data/lib/sequel/adapters/jdbc/h2.rb +60 -10
- data/lib/sequel/adapters/jdbc/hsqldb.rb +6 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +4 -4
- data/lib/sequel/adapters/jdbc/postgresql.rb +4 -4
- data/lib/sequel/adapters/jdbc.rb +29 -19
- data/lib/sequel/adapters/mysql.rb +80 -67
- data/lib/sequel/adapters/mysql2.rb +54 -49
- data/lib/sequel/adapters/odbc.rb +8 -6
- data/lib/sequel/adapters/oracle.rb +5 -4
- data/lib/sequel/adapters/postgres.rb +27 -29
- data/lib/sequel/adapters/shared/access.rb +2 -0
- data/lib/sequel/adapters/shared/db2.rb +30 -0
- data/lib/sequel/adapters/shared/mssql.rb +84 -7
- data/lib/sequel/adapters/shared/mysql.rb +33 -2
- data/lib/sequel/adapters/shared/oracle.rb +82 -7
- data/lib/sequel/adapters/shared/postgres.rb +158 -20
- data/lib/sequel/adapters/shared/sqlanywhere.rb +3 -0
- data/lib/sequel/adapters/shared/sqlite.rb +102 -10
- data/lib/sequel/adapters/sqlanywhere.rb +1 -1
- data/lib/sequel/adapters/sqlite.rb +60 -18
- data/lib/sequel/adapters/tinytds.rb +2 -1
- data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -1
- data/lib/sequel/ast_transformer.rb +6 -0
- data/lib/sequel/connection_pool/sharded_single.rb +9 -8
- data/lib/sequel/connection_pool/sharded_threaded.rb +10 -10
- data/lib/sequel/connection_pool/single.rb +7 -9
- data/lib/sequel/connection_pool/threaded.rb +1 -1
- data/lib/sequel/core.rb +33 -24
- data/lib/sequel/database/connecting.rb +3 -4
- data/lib/sequel/database/misc.rb +37 -12
- data/lib/sequel/database/query.rb +3 -1
- data/lib/sequel/database/schema_generator.rb +50 -53
- data/lib/sequel/database/schema_methods.rb +45 -23
- data/lib/sequel/database/transactions.rb +9 -6
- data/lib/sequel/dataset/actions.rb +61 -8
- data/lib/sequel/dataset/features.rb +15 -0
- data/lib/sequel/dataset/placeholder_literalizer.rb +3 -7
- data/lib/sequel/dataset/prepared_statements.rb +2 -0
- data/lib/sequel/dataset/query.rb +114 -11
- data/lib/sequel/dataset/sql.rb +172 -46
- data/lib/sequel/deprecated.rb +3 -1
- data/lib/sequel/exceptions.rb +2 -0
- data/lib/sequel/extensions/_pretty_table.rb +1 -2
- data/lib/sequel/extensions/any_not_empty.rb +1 -1
- data/lib/sequel/extensions/async_thread_pool.rb +438 -0
- data/lib/sequel/extensions/blank.rb +8 -0
- data/lib/sequel/extensions/columns_introspection.rb +1 -2
- data/lib/sequel/extensions/core_refinements.rb +38 -11
- data/lib/sequel/extensions/date_arithmetic.rb +36 -24
- data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
- data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
- data/lib/sequel/extensions/duplicate_columns_handler.rb +3 -1
- data/lib/sequel/extensions/eval_inspect.rb +2 -0
- data/lib/sequel/extensions/inflector.rb +9 -1
- data/lib/sequel/extensions/is_distinct_from.rb +139 -0
- data/lib/sequel/extensions/migration.rb +13 -2
- data/lib/sequel/extensions/named_timezones.rb +5 -1
- data/lib/sequel/extensions/pagination.rb +1 -1
- data/lib/sequel/extensions/pg_array.rb +1 -0
- data/lib/sequel/extensions/pg_array_ops.rb +6 -2
- data/lib/sequel/extensions/pg_enum.rb +3 -1
- data/lib/sequel/extensions/pg_extended_date_support.rb +2 -2
- data/lib/sequel/extensions/pg_hstore.rb +1 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +55 -3
- data/lib/sequel/extensions/pg_inet.rb +2 -0
- data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
- data/lib/sequel/extensions/pg_interval.rb +35 -8
- data/lib/sequel/extensions/pg_json.rb +3 -5
- data/lib/sequel/extensions/pg_json_ops.rb +119 -4
- data/lib/sequel/extensions/pg_loose_count.rb +3 -1
- data/lib/sequel/extensions/pg_multirange.rb +372 -0
- data/lib/sequel/extensions/pg_range.rb +7 -19
- data/lib/sequel/extensions/pg_range_ops.rb +39 -9
- data/lib/sequel/extensions/pg_row.rb +1 -1
- data/lib/sequel/extensions/pg_row_ops.rb +25 -1
- data/lib/sequel/extensions/query.rb +3 -0
- data/lib/sequel/extensions/run_transaction_hooks.rb +1 -1
- data/lib/sequel/extensions/s.rb +4 -1
- data/lib/sequel/extensions/schema_dumper.rb +16 -5
- data/lib/sequel/extensions/server_block.rb +8 -12
- data/lib/sequel/extensions/sql_comments.rb +110 -3
- 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 +1 -1
- data/lib/sequel/extensions/string_date_time.rb +19 -23
- data/lib/sequel/extensions/symbol_aref_refinement.rb +2 -0
- data/lib/sequel/extensions/symbol_as_refinement.rb +2 -0
- data/lib/sequel/extensions/to_dot.rb +9 -3
- data/lib/sequel/model/associations.rb +342 -114
- data/lib/sequel/model/base.rb +45 -24
- data/lib/sequel/model/errors.rb +10 -1
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model/plugins.rb +8 -3
- data/lib/sequel/model.rb +3 -1
- data/lib/sequel/plugins/association_pks.rb +60 -18
- data/lib/sequel/plugins/association_proxies.rb +3 -0
- 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 +39 -5
- data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
- data/lib/sequel/plugins/blacklist_security.rb +1 -2
- data/lib/sequel/plugins/class_table_inheritance.rb +3 -8
- data/lib/sequel/plugins/column_encryption.rb +728 -0
- data/lib/sequel/plugins/composition.rb +8 -2
- data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
- data/lib/sequel/plugins/constraint_validations.rb +2 -1
- data/lib/sequel/plugins/csv_serializer.rb +2 -0
- data/lib/sequel/plugins/dataset_associations.rb +4 -1
- data/lib/sequel/plugins/dirty.rb +44 -0
- data/lib/sequel/plugins/enum.rb +124 -0
- data/lib/sequel/plugins/forbid_lazy_load.rb +2 -0
- data/lib/sequel/plugins/insert_conflict.rb +4 -0
- data/lib/sequel/plugins/instance_specific_default.rb +113 -0
- data/lib/sequel/plugins/json_serializer.rb +39 -24
- data/lib/sequel/plugins/lazy_attributes.rb +4 -1
- data/lib/sequel/plugins/many_through_many.rb +108 -9
- data/lib/sequel/plugins/nested_attributes.rb +8 -3
- data/lib/sequel/plugins/pg_array_associations.rb +58 -41
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +2 -0
- data/lib/sequel/plugins/prepared_statements.rb +15 -12
- data/lib/sequel/plugins/prepared_statements_safe.rb +1 -3
- data/lib/sequel/plugins/rcte_tree.rb +37 -35
- data/lib/sequel/plugins/serialization.rb +9 -3
- data/lib/sequel/plugins/serialization_modification_detection.rb +2 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +7 -0
- data/lib/sequel/plugins/sql_comments.rb +189 -0
- data/lib/sequel/plugins/static_cache.rb +1 -1
- data/lib/sequel/plugins/string_stripper.rb +1 -1
- data/lib/sequel/plugins/subclasses.rb +28 -11
- data/lib/sequel/plugins/tactical_eager_loading.rb +8 -2
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/tree.rb +9 -4
- data/lib/sequel/plugins/unused_associations.rb +521 -0
- data/lib/sequel/plugins/update_or_create.rb +1 -1
- data/lib/sequel/plugins/validation_class_methods.rb +5 -1
- data/lib/sequel/plugins/validation_helpers.rb +18 -11
- data/lib/sequel/plugins/xml_serializer.rb +1 -1
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/timezones.rb +20 -17
- data/lib/sequel/version.rb +1 -1
- metadata +93 -39
|
@@ -87,7 +87,7 @@ module Sequel
|
|
|
87
87
|
|
|
88
88
|
def self.mock_adapter_setup(db)
|
|
89
89
|
db.instance_exec do
|
|
90
|
-
@server_version =
|
|
90
|
+
@server_version = 140000
|
|
91
91
|
initialize_postgres_adapter
|
|
92
92
|
extend(MockAdapterDatabaseMethods)
|
|
93
93
|
end
|
|
@@ -414,6 +414,7 @@ module Sequel
|
|
|
414
414
|
# 2 :: argument name
|
|
415
415
|
# 3 :: argument mode (e.g. in, out, inout)
|
|
416
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.
|
|
417
418
|
# :cost :: The estimated cost of the function, used by the query planner.
|
|
418
419
|
# :language :: The language the function uses. SQL is the default.
|
|
419
420
|
# :link_symbol :: For a dynamically loaded see function, the function's link symbol if different from the definition argument.
|
|
@@ -479,6 +480,7 @@ module Sequel
|
|
|
479
480
|
# :each_row :: Calls the trigger for each row instead of for each statement.
|
|
480
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,
|
|
481
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+).
|
|
482
484
|
# :when :: A filter to use for the trigger
|
|
483
485
|
def create_trigger(table, name, function, opts=OPTS)
|
|
484
486
|
self << create_trigger_sql(table, name, function, opts)
|
|
@@ -781,7 +783,7 @@ module Sequel
|
|
|
781
783
|
return @server_version if @server_version
|
|
782
784
|
ds = dataset
|
|
783
785
|
ds = ds.server(server) if server
|
|
784
|
-
@server_version
|
|
786
|
+
@server_version = swallow_database_error{ds.with_sql("SELECT CAST(current_setting('server_version_num') AS integer) AS v").single_value} || 0
|
|
785
787
|
end
|
|
786
788
|
|
|
787
789
|
# PostgreSQL supports CREATE TABLE IF NOT EXISTS on 9.1+
|
|
@@ -846,7 +848,7 @@ module Sequel
|
|
|
846
848
|
# :schema :: The schema to search
|
|
847
849
|
# :server :: The server to use
|
|
848
850
|
def tables(opts=OPTS, &block)
|
|
849
|
-
pg_class_relname('r', opts, &block)
|
|
851
|
+
pg_class_relname(['r', 'p'], opts, &block)
|
|
850
852
|
end
|
|
851
853
|
|
|
852
854
|
# Check whether the given type name string/symbol (e.g. :hstore) is supported by
|
|
@@ -1116,6 +1118,7 @@ module Sequel
|
|
|
1116
1118
|
#{opts[:behavior].to_s.upcase if opts[:behavior]}
|
|
1117
1119
|
#{'STRICT' if opts[:strict]}
|
|
1118
1120
|
#{'SECURITY DEFINER' if opts[:security_definer]}
|
|
1121
|
+
#{"PARALLEL #{opts[:parallel].to_s.upcase}" if opts[:parallel]}
|
|
1119
1122
|
#{"COST #{opts[:cost]}" if opts[:cost]}
|
|
1120
1123
|
#{"ROWS #{opts[:rows]}" if opts[:rows]}
|
|
1121
1124
|
#{opts[:set].map{|k,v| " SET #{k} = #{v}"}.join("\n") if opts[:set]}
|
|
@@ -1237,7 +1240,7 @@ module Sequel
|
|
|
1237
1240
|
raise Error, "Trigger conditions are not supported for this database" unless supports_trigger_conditions?
|
|
1238
1241
|
filter = " WHEN #{filter_expr(filter)}"
|
|
1239
1242
|
end
|
|
1240
|
-
"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(', ')})"
|
|
1243
|
+
"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(', ')})"
|
|
1241
1244
|
end
|
|
1242
1245
|
|
|
1243
1246
|
# DDL fragment for initial part of CREATE VIEW statement
|
|
@@ -1335,7 +1338,7 @@ module Sequel
|
|
|
1335
1338
|
ds = metadata_dataset.from(:pg_class).where(:relkind=>type).select(:relname).server(opts[:server]).join(:pg_namespace, :oid=>:relnamespace)
|
|
1336
1339
|
ds = filter_schema(ds, opts)
|
|
1337
1340
|
m = output_identifier_meth
|
|
1338
|
-
if
|
|
1341
|
+
if defined?(yield)
|
|
1339
1342
|
yield(ds)
|
|
1340
1343
|
elsif opts[:qualify]
|
|
1341
1344
|
ds.select_append{pg_namespace[:nspname]}.map{|r| Sequel.qualify(m.call(r[:nspname]).to_s, m.call(r[:relname]).to_s)}
|
|
@@ -1500,10 +1503,12 @@ module Sequel
|
|
|
1500
1503
|
# disallowed or there is a size specified, use the varchar type.
|
|
1501
1504
|
# Otherwise use the text type.
|
|
1502
1505
|
def type_literal_generic_string(column)
|
|
1503
|
-
if column[:
|
|
1504
|
-
|
|
1505
|
-
elsif column[:
|
|
1506
|
-
"
|
|
1506
|
+
if column[:text]
|
|
1507
|
+
:text
|
|
1508
|
+
elsif column[:fixed]
|
|
1509
|
+
"char(#{column[:size]||default_string_column_size})"
|
|
1510
|
+
elsif column[:text] == false || column[:size]
|
|
1511
|
+
"varchar(#{column[:size]||default_string_column_size})"
|
|
1507
1512
|
else
|
|
1508
1513
|
:text
|
|
1509
1514
|
end
|
|
@@ -1522,7 +1527,7 @@ module Sequel
|
|
|
1522
1527
|
LOCK_MODES = ['ACCESS SHARE', 'ROW SHARE', 'ROW EXCLUSIVE', 'SHARE UPDATE EXCLUSIVE', 'SHARE', 'SHARE ROW EXCLUSIVE', 'EXCLUSIVE', 'ACCESS EXCLUSIVE'].each(&:freeze).freeze
|
|
1523
1528
|
|
|
1524
1529
|
Dataset.def_sql_method(self, :delete, [['if server_version >= 90100', %w'with delete from using where returning'], ['else', %w'delete from using where returning']])
|
|
1525
|
-
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']])
|
|
1530
|
+
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']])
|
|
1526
1531
|
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']])
|
|
1527
1532
|
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']])
|
|
1528
1533
|
|
|
@@ -1725,13 +1730,22 @@ module Sequel
|
|
|
1725
1730
|
ds.insert_sql(*values)
|
|
1726
1731
|
end
|
|
1727
1732
|
|
|
1733
|
+
# Support SQL::AliasedExpression as expr to setup a USING join with a table alias for the
|
|
1734
|
+
# USING columns.
|
|
1735
|
+
def join_table(type, table, expr=nil, options=OPTS, &block)
|
|
1736
|
+
if expr.is_a?(SQL::AliasedExpression) && expr.expression.is_a?(Array) && !expr.expression.empty? && expr.expression.all?
|
|
1737
|
+
options = options.merge(:join_using=>true)
|
|
1738
|
+
end
|
|
1739
|
+
super
|
|
1740
|
+
end
|
|
1741
|
+
|
|
1728
1742
|
# Locks all tables in the dataset's FROM clause (but not in JOINs) with
|
|
1729
1743
|
# the specified mode (e.g. 'EXCLUSIVE'). If a block is given, starts
|
|
1730
1744
|
# a new transaction, locks the table, and yields. If a block is not given,
|
|
1731
1745
|
# just locks the tables. Note that PostgreSQL will probably raise an error
|
|
1732
1746
|
# if you lock the table outside of an existing transaction. Returns nil.
|
|
1733
1747
|
def lock(mode, opts=OPTS)
|
|
1734
|
-
if
|
|
1748
|
+
if defined?(yield) # perform locking inside a transaction and yield to block
|
|
1735
1749
|
@db.transaction(opts){lock(mode, opts); yield}
|
|
1736
1750
|
else
|
|
1737
1751
|
sql = 'LOCK TABLE '.dup
|
|
@@ -1746,6 +1760,41 @@ module Sequel
|
|
|
1746
1760
|
nil
|
|
1747
1761
|
end
|
|
1748
1762
|
|
|
1763
|
+
# Return a dataset with a WHEN MATCHED THEN DO NOTHING clause added to the
|
|
1764
|
+
# MERGE statement. If a block is passed, treat it as a virtual row and
|
|
1765
|
+
# use it as additional conditions for the match.
|
|
1766
|
+
#
|
|
1767
|
+
# merge_do_nothing_when_matched
|
|
1768
|
+
# # WHEN MATCHED THEN DO NOTHING
|
|
1769
|
+
#
|
|
1770
|
+
# merge_do_nothing_when_matched{a > 30}
|
|
1771
|
+
# # WHEN MATCHED AND (a > 30) THEN DO NOTHING
|
|
1772
|
+
def merge_do_nothing_when_matched(&block)
|
|
1773
|
+
_merge_when(:type=>:matched, &block)
|
|
1774
|
+
end
|
|
1775
|
+
|
|
1776
|
+
# Return a dataset with a WHEN NOT MATCHED THEN DO NOTHING clause added to the
|
|
1777
|
+
# MERGE statement. If a block is passed, treat it as a virtual row and
|
|
1778
|
+
# use it as additional conditions for the match.
|
|
1779
|
+
#
|
|
1780
|
+
# merge_do_nothing_when_not_matched
|
|
1781
|
+
# # WHEN NOT MATCHED THEN DO NOTHING
|
|
1782
|
+
#
|
|
1783
|
+
# merge_do_nothing_when_not_matched{a > 30}
|
|
1784
|
+
# # WHEN NOT MATCHED AND (a > 30) THEN DO NOTHING
|
|
1785
|
+
def merge_do_nothing_when_not_matched(&block)
|
|
1786
|
+
_merge_when(:type=>:not_matched, &block)
|
|
1787
|
+
end
|
|
1788
|
+
|
|
1789
|
+
# Support OVERRIDING USER|SYSTEM VALUE for MERGE INSERT.
|
|
1790
|
+
def merge_insert(*values, &block)
|
|
1791
|
+
h = {:type=>:insert, :values=>values}
|
|
1792
|
+
if override = @opts[:override]
|
|
1793
|
+
h[:override] = insert_override_sql(String.new)
|
|
1794
|
+
end
|
|
1795
|
+
_merge_when(h, &block)
|
|
1796
|
+
end
|
|
1797
|
+
|
|
1749
1798
|
# Use OVERRIDING USER VALUE for INSERT statements, so that identity columns
|
|
1750
1799
|
# always use the user supplied value, and an error is not raised for identity
|
|
1751
1800
|
# columns that are GENERATED ALWAYS.
|
|
@@ -1813,6 +1862,11 @@ module Sequel
|
|
|
1813
1862
|
true
|
|
1814
1863
|
end
|
|
1815
1864
|
|
|
1865
|
+
# PostgreSQL 15+ supports MERGE.
|
|
1866
|
+
def supports_merge?
|
|
1867
|
+
server_version >= 150000
|
|
1868
|
+
end
|
|
1869
|
+
|
|
1816
1870
|
# PostgreSQL supports NOWAIT.
|
|
1817
1871
|
def supports_nowait?
|
|
1818
1872
|
true
|
|
@@ -1885,6 +1939,13 @@ module Sequel
|
|
|
1885
1939
|
end
|
|
1886
1940
|
end
|
|
1887
1941
|
|
|
1942
|
+
# Use WITH TIES when limiting the result set to also include additional
|
|
1943
|
+
# rules that have the same results for the order column as the final row.
|
|
1944
|
+
# Requires PostgreSQL 13.
|
|
1945
|
+
def with_ties
|
|
1946
|
+
clone(:limit_with_ties=>true)
|
|
1947
|
+
end
|
|
1948
|
+
|
|
1888
1949
|
protected
|
|
1889
1950
|
|
|
1890
1951
|
# If returned primary keys are requested, use RETURNING unless already set on the
|
|
@@ -1916,6 +1977,22 @@ module Sequel
|
|
|
1916
1977
|
|
|
1917
1978
|
private
|
|
1918
1979
|
|
|
1980
|
+
# Append the INSERT sql used in a MERGE
|
|
1981
|
+
def _merge_insert_sql(sql, data)
|
|
1982
|
+
sql << " THEN INSERT "
|
|
1983
|
+
columns, values = _parse_insert_sql_args(data[:values])
|
|
1984
|
+
_insert_columns_sql(sql, columns)
|
|
1985
|
+
if override = data[:override]
|
|
1986
|
+
sql << override
|
|
1987
|
+
end
|
|
1988
|
+
_insert_values_sql(sql, values)
|
|
1989
|
+
end
|
|
1990
|
+
|
|
1991
|
+
def _merge_matched_sql(sql, data)
|
|
1992
|
+
sql << " THEN DO NOTHING"
|
|
1993
|
+
end
|
|
1994
|
+
alias _merge_not_matched_sql _merge_matched_sql
|
|
1995
|
+
|
|
1919
1996
|
# Format TRUNCATE statement with PostgreSQL specific options.
|
|
1920
1997
|
def _truncate_sql(table)
|
|
1921
1998
|
to = @opts[:truncate_opts] || OPTS
|
|
@@ -1992,14 +2069,13 @@ module Sequel
|
|
|
1992
2069
|
end
|
|
1993
2070
|
|
|
1994
2071
|
# Support OVERRIDING SYSTEM|USER VALUE in insert statements
|
|
1995
|
-
def
|
|
2072
|
+
def insert_override_sql(sql)
|
|
1996
2073
|
case opts[:override]
|
|
1997
2074
|
when :system
|
|
1998
2075
|
sql << " OVERRIDING SYSTEM VALUE"
|
|
1999
2076
|
when :user
|
|
2000
2077
|
sql << " OVERRIDING USER VALUE"
|
|
2001
2078
|
end
|
|
2002
|
-
super
|
|
2003
2079
|
end
|
|
2004
2080
|
|
|
2005
2081
|
# For multiple table support, PostgreSQL requires at least
|
|
@@ -2014,6 +2090,17 @@ module Sequel
|
|
|
2014
2090
|
end
|
|
2015
2091
|
end
|
|
2016
2092
|
|
|
2093
|
+
# Support table aliases for USING columns
|
|
2094
|
+
def join_using_clause_using_sql_append(sql, using_columns)
|
|
2095
|
+
if using_columns.is_a?(SQL::AliasedExpression)
|
|
2096
|
+
super(sql, using_columns.expression)
|
|
2097
|
+
sql << ' AS '
|
|
2098
|
+
identifier_append(sql, using_columns.alias)
|
|
2099
|
+
else
|
|
2100
|
+
super
|
|
2101
|
+
end
|
|
2102
|
+
end
|
|
2103
|
+
|
|
2017
2104
|
# Use a generic blob quoting method, hopefully overridden in one of the subadapter methods
|
|
2018
2105
|
def literal_blob_append(sql, v)
|
|
2019
2106
|
sql << "'" << v.gsub(/[\000-\037\047\134\177-\377]/n){|b| "\\#{("%o" % b[0..1].unpack("C")[0]).rjust(3, '0')}"} << "'"
|
|
@@ -2071,6 +2158,37 @@ module Sequel
|
|
|
2071
2158
|
false
|
|
2072
2159
|
end
|
|
2073
2160
|
|
|
2161
|
+
# Support FETCH FIRST WITH TIES on PostgreSQL 13+.
|
|
2162
|
+
def select_limit_sql(sql)
|
|
2163
|
+
l = @opts[:limit]
|
|
2164
|
+
o = @opts[:offset]
|
|
2165
|
+
|
|
2166
|
+
return unless l || o
|
|
2167
|
+
|
|
2168
|
+
if @opts[:limit_with_ties]
|
|
2169
|
+
if o
|
|
2170
|
+
sql << " OFFSET "
|
|
2171
|
+
literal_append(sql, o)
|
|
2172
|
+
end
|
|
2173
|
+
|
|
2174
|
+
if l
|
|
2175
|
+
sql << " FETCH FIRST "
|
|
2176
|
+
literal_append(sql, l)
|
|
2177
|
+
sql << " ROWS WITH TIES"
|
|
2178
|
+
end
|
|
2179
|
+
else
|
|
2180
|
+
if l
|
|
2181
|
+
sql << " LIMIT "
|
|
2182
|
+
literal_append(sql, l)
|
|
2183
|
+
end
|
|
2184
|
+
|
|
2185
|
+
if o
|
|
2186
|
+
sql << " OFFSET "
|
|
2187
|
+
literal_append(sql, o)
|
|
2188
|
+
end
|
|
2189
|
+
end
|
|
2190
|
+
end
|
|
2191
|
+
|
|
2074
2192
|
# Support FOR SHARE locking when using the :share lock style.
|
|
2075
2193
|
# Use SKIP LOCKED if skipping locked rows.
|
|
2076
2194
|
def select_lock_sql(sql)
|
|
@@ -2101,15 +2219,35 @@ module Sequel
|
|
|
2101
2219
|
opts[:with].any?{|w| w[:recursive]} ? "WITH RECURSIVE " : super
|
|
2102
2220
|
end
|
|
2103
2221
|
|
|
2104
|
-
# Support
|
|
2105
|
-
def
|
|
2222
|
+
# Support PostgreSQL 14+ CTE SEARCH/CYCLE clauses
|
|
2223
|
+
def select_with_sql_cte(sql, cte)
|
|
2106
2224
|
super
|
|
2107
2225
|
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2226
|
+
if search_opts = cte[:search]
|
|
2227
|
+
sql << if search_opts[:type] == :breadth
|
|
2228
|
+
" SEARCH BREADTH FIRST BY "
|
|
2229
|
+
else
|
|
2230
|
+
" SEARCH DEPTH FIRST BY "
|
|
2231
|
+
end
|
|
2232
|
+
|
|
2233
|
+
identifier_list_append(sql, Array(search_opts[:by]))
|
|
2234
|
+
sql << " SET "
|
|
2235
|
+
identifier_append(sql, search_opts[:set] || :ordercol)
|
|
2236
|
+
end
|
|
2237
|
+
|
|
2238
|
+
if cycle_opts = cte[:cycle]
|
|
2239
|
+
sql << " CYCLE "
|
|
2240
|
+
identifier_list_append(sql, Array(cycle_opts[:columns]))
|
|
2241
|
+
sql << " SET "
|
|
2242
|
+
identifier_append(sql, cycle_opts[:cycle_column] || :is_cycle)
|
|
2243
|
+
if cycle_opts.has_key?(:cycle_value)
|
|
2244
|
+
sql << " TO "
|
|
2245
|
+
literal_append(sql, cycle_opts[:cycle_value])
|
|
2246
|
+
sql << " DEFAULT "
|
|
2247
|
+
literal_append(sql, cycle_opts.fetch(:noncycle_value, false))
|
|
2248
|
+
end
|
|
2249
|
+
sql << " USING "
|
|
2250
|
+
identifier_append(sql, cycle_opts[:path_column] || :path)
|
|
2113
2251
|
end
|
|
2114
2252
|
end
|
|
2115
2253
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen-string-literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../utils/columns_limit_1'
|
|
4
|
+
|
|
3
5
|
module Sequel
|
|
4
6
|
module SqlAnywhere
|
|
5
7
|
Sequel::Database.set_shared_adapter_scheme(:sqlanywhere, self)
|
|
@@ -234,6 +236,7 @@ module Sequel
|
|
|
234
236
|
module DatasetMethods
|
|
235
237
|
Dataset.def_sql_method(self, :insert, %w'insert into columns values')
|
|
236
238
|
Dataset.def_sql_method(self, :select, %w'with select distinct limit columns into from join where group having window compounds order lock')
|
|
239
|
+
include ::Sequel::Dataset::ColumnsLimit1
|
|
237
240
|
|
|
238
241
|
# Whether to convert smallint to boolean arguments for this dataset.
|
|
239
242
|
# Defaults to the IBMDB module setting.
|
|
@@ -239,8 +239,12 @@ module Sequel
|
|
|
239
239
|
super
|
|
240
240
|
end
|
|
241
241
|
when :drop_column
|
|
242
|
-
|
|
243
|
-
|
|
242
|
+
if sqlite_version >= 33500
|
|
243
|
+
super
|
|
244
|
+
else
|
|
245
|
+
ocp = lambda{|oc| oc.delete_if{|c| c.to_s == op[:name].to_s}}
|
|
246
|
+
duplicate_table(table, :old_columns_proc=>ocp){|columns| columns.delete_if{|s| s[:name].to_s == op[:name].to_s}}
|
|
247
|
+
end
|
|
244
248
|
when :rename_column
|
|
245
249
|
if sqlite_version >= 32500
|
|
246
250
|
super
|
|
@@ -269,6 +273,8 @@ module Sequel
|
|
|
269
273
|
else
|
|
270
274
|
duplicate_table(table, :no_foreign_keys=>true)
|
|
271
275
|
end
|
|
276
|
+
when :unique
|
|
277
|
+
duplicate_table(table, :no_unique=>true)
|
|
272
278
|
else
|
|
273
279
|
duplicate_table(table)
|
|
274
280
|
end
|
|
@@ -331,6 +337,11 @@ module Sequel
|
|
|
331
337
|
ps
|
|
332
338
|
end
|
|
333
339
|
|
|
340
|
+
# Support creating STRICT tables via :strict option
|
|
341
|
+
def create_table_sql(name, generator, options)
|
|
342
|
+
"#{super}#{' STRICT' if options[:strict]}"
|
|
343
|
+
end
|
|
344
|
+
|
|
334
345
|
# SQLite support creating temporary views.
|
|
335
346
|
def create_view_prefix_sql(name, options)
|
|
336
347
|
create_view_sql_append_columns("CREATE #{'TEMPORARY 'if options[:temp]}VIEW #{quote_schema_table(name)}", options[:columns])
|
|
@@ -341,6 +352,7 @@ module Sequel
|
|
|
341
352
|
/foreign key constraint failed\z/i => ForeignKeyConstraintViolation,
|
|
342
353
|
/\A(SQLITE ERROR 275 \(CONSTRAINT_CHECK\) : )?CHECK constraint failed/ => CheckConstraintViolation,
|
|
343
354
|
/\A(SQLITE ERROR 19 \(CONSTRAINT\) : )?constraint failed\z/ => ConstraintViolation,
|
|
355
|
+
/\Acannot store [A-Z]+ value in [A-Z]+ column / => ConstraintViolation,
|
|
344
356
|
/may not be NULL\z|NOT NULL constraint failed: .+\z/ => NotNullConstraintViolation,
|
|
345
357
|
/\ASQLITE ERROR \d+ \(\) : CHECK constraint failed: / => CheckConstraintViolation
|
|
346
358
|
}.freeze
|
|
@@ -387,7 +399,7 @@ module Sequel
|
|
|
387
399
|
old_columns = def_columns.map{|c| c[:name]}
|
|
388
400
|
opts[:old_columns_proc].call(old_columns) if opts[:old_columns_proc]
|
|
389
401
|
|
|
390
|
-
yield def_columns if
|
|
402
|
+
yield def_columns if defined?(yield)
|
|
391
403
|
|
|
392
404
|
constraints = (opts[:constraints] || []).dup
|
|
393
405
|
pks = []
|
|
@@ -422,8 +434,12 @@ module Sequel
|
|
|
422
434
|
skip_indexes = []
|
|
423
435
|
indexes(table, :only_autocreated=>true).each do |name, h|
|
|
424
436
|
skip_indexes << name
|
|
425
|
-
if h[:
|
|
426
|
-
|
|
437
|
+
if h[:unique] && !opts[:no_unique]
|
|
438
|
+
if h[:columns].length == 1
|
|
439
|
+
unique_columns.concat(h[:columns])
|
|
440
|
+
elsif h[:columns].map(&:to_s) != pks
|
|
441
|
+
constraints << {:type=>:unique, :columns=>h[:columns]}
|
|
442
|
+
end
|
|
427
443
|
end
|
|
428
444
|
end
|
|
429
445
|
unique_columns -= pks
|
|
@@ -552,10 +568,10 @@ module Sequel
|
|
|
552
568
|
EXTRACT_MAP = {:year=>"'%Y'", :month=>"'%m'", :day=>"'%d'", :hour=>"'%H'", :minute=>"'%M'", :second=>"'%f'"}.freeze
|
|
553
569
|
EXTRACT_MAP.each_value(&:freeze)
|
|
554
570
|
|
|
555
|
-
Dataset.def_sql_method(self, :delete, [['if db.sqlite_version >= 30803', %w'with delete from where'], ["else", %w'delete from where']])
|
|
556
|
-
Dataset.def_sql_method(self, :insert, [['if db.sqlite_version >= 30803', %w'with insert conflict into columns values on_conflict'], ["else", %w'insert conflict into columns values']])
|
|
571
|
+
Dataset.def_sql_method(self, :delete, [['if db.sqlite_version >= 33500', %w'with delete from where returning'], ['elsif db.sqlite_version >= 30803', %w'with delete from where'], ["else", %w'delete from where']])
|
|
572
|
+
Dataset.def_sql_method(self, :insert, [['if db.sqlite_version >= 33500', %w'with insert conflict into columns values on_conflict returning'], ['elsif db.sqlite_version >= 30803', %w'with insert conflict into columns values on_conflict'], ["else", %w'insert conflict into columns values']])
|
|
557
573
|
Dataset.def_sql_method(self, :select, [['if opts[:values]', %w'with values compounds'], ['else', %w'with select distinct columns from join where group having window compounds order limit lock']])
|
|
558
|
-
Dataset.def_sql_method(self, :update, [['if db.sqlite_version >= 30803', %w'with update table set where'], ["else", %w'update table set where']])
|
|
574
|
+
Dataset.def_sql_method(self, :update, [['if db.sqlite_version >= 33500', %w'with update table set from where returning'], ['elsif db.sqlite_version >= 33300', %w'with update table set from where'], ['elsif db.sqlite_version >= 30803', %w'with update table set where'], ["else", %w'update table set where']])
|
|
559
575
|
|
|
560
576
|
def cast_sql_append(sql, expr, type)
|
|
561
577
|
if type == Time or type == DateTime
|
|
@@ -629,8 +645,8 @@ module Sequel
|
|
|
629
645
|
# SQLite performs a TRUNCATE style DELETE if no filter is specified.
|
|
630
646
|
# Since we want to always return the count of records, add a condition
|
|
631
647
|
# that is always true and then delete.
|
|
632
|
-
def delete
|
|
633
|
-
@opts[:where] ? super : where(1=>1).delete
|
|
648
|
+
def delete(&block)
|
|
649
|
+
@opts[:where] ? super : where(1=>1).delete(&block)
|
|
634
650
|
end
|
|
635
651
|
|
|
636
652
|
# Return an array of strings specifying a query explanation for a SELECT of the
|
|
@@ -651,6 +667,21 @@ module Sequel
|
|
|
651
667
|
super
|
|
652
668
|
end
|
|
653
669
|
|
|
670
|
+
# Support insert select for associations, so that the model code can use
|
|
671
|
+
# returning instead of a separate query.
|
|
672
|
+
def insert_select(*values)
|
|
673
|
+
return unless supports_insert_select?
|
|
674
|
+
# Handle case where query does not return a row
|
|
675
|
+
server?(:default).with_sql_first(insert_select_sql(*values)) || false
|
|
676
|
+
end
|
|
677
|
+
|
|
678
|
+
# The SQL to use for an insert_select, adds a RETURNING clause to the insert
|
|
679
|
+
# unless the RETURNING clause is already present.
|
|
680
|
+
def insert_select_sql(*values)
|
|
681
|
+
ds = opts[:returning] ? self : returning
|
|
682
|
+
ds.insert_sql(*values)
|
|
683
|
+
end
|
|
684
|
+
|
|
654
685
|
# SQLite uses the nonstandard ` (backtick) for quoting identifiers.
|
|
655
686
|
def quoted_identifier_append(sql, c)
|
|
656
687
|
sql << '`' << c.to_s.gsub('`', '``') << '`'
|
|
@@ -732,6 +763,13 @@ module Sequel
|
|
|
732
763
|
insert_conflict(:ignore)
|
|
733
764
|
end
|
|
734
765
|
|
|
766
|
+
# Automatically add aliases to RETURNING values to work around SQLite bug.
|
|
767
|
+
def returning(*values)
|
|
768
|
+
return super if values.empty?
|
|
769
|
+
raise Error, "RETURNING is not supported on #{db.database_type}" unless supports_returning?(:insert)
|
|
770
|
+
clone(:returning=>_returning_values(values).freeze)
|
|
771
|
+
end
|
|
772
|
+
|
|
735
773
|
# SQLite 3.8.3+ supports common table expressions.
|
|
736
774
|
def supports_cte?(type=:select)
|
|
737
775
|
db.sqlite_version >= 30803
|
|
@@ -747,6 +785,11 @@ module Sequel
|
|
|
747
785
|
false
|
|
748
786
|
end
|
|
749
787
|
|
|
788
|
+
# SQLite does not support deleting from a joined dataset
|
|
789
|
+
def supports_deleting_joins?
|
|
790
|
+
false
|
|
791
|
+
end
|
|
792
|
+
|
|
750
793
|
# SQLite does not support INTERSECT ALL or EXCEPT ALL
|
|
751
794
|
def supports_intersect_except_all?
|
|
752
795
|
false
|
|
@@ -757,11 +800,21 @@ module Sequel
|
|
|
757
800
|
false
|
|
758
801
|
end
|
|
759
802
|
|
|
803
|
+
# SQLite 3.33.0 supports modifying joined datasets
|
|
804
|
+
def supports_modifying_joins?
|
|
805
|
+
db.sqlite_version >= 33300
|
|
806
|
+
end
|
|
807
|
+
|
|
760
808
|
# SQLite does not support multiple columns for the IN/NOT IN operators
|
|
761
809
|
def supports_multiple_column_in?
|
|
762
810
|
false
|
|
763
811
|
end
|
|
764
812
|
|
|
813
|
+
# SQLite 3.35.0 supports RETURNING on INSERT/UPDATE/DELETE.
|
|
814
|
+
def supports_returning?(_)
|
|
815
|
+
db.sqlite_version >= 33500
|
|
816
|
+
end
|
|
817
|
+
|
|
765
818
|
# SQLite supports timezones in literal timestamps, since it stores them
|
|
766
819
|
# as text. But using timezones in timestamps breaks SQLite datetime
|
|
767
820
|
# functions, so we allow the user to override the default per database.
|
|
@@ -794,6 +847,21 @@ module Sequel
|
|
|
794
847
|
|
|
795
848
|
private
|
|
796
849
|
|
|
850
|
+
# Add aliases to symbols and identifiers to work around SQLite bug.
|
|
851
|
+
def _returning_values(values)
|
|
852
|
+
values.map do |v|
|
|
853
|
+
case v
|
|
854
|
+
when Symbol
|
|
855
|
+
_, c, a = split_symbol(v)
|
|
856
|
+
a ? v : Sequel.as(v, c)
|
|
857
|
+
when SQL::Identifier, SQL::QualifiedIdentifier
|
|
858
|
+
Sequel.as(v, unqualified_column_for(v))
|
|
859
|
+
else
|
|
860
|
+
v
|
|
861
|
+
end
|
|
862
|
+
end
|
|
863
|
+
end
|
|
864
|
+
|
|
797
865
|
# SQLite uses string literals instead of identifiers in AS clauses.
|
|
798
866
|
def as_sql_append(sql, aliaz, column_aliases=nil)
|
|
799
867
|
raise Error, "sqlite does not support derived column lists" if column_aliases
|
|
@@ -819,6 +887,13 @@ module Sequel
|
|
|
819
887
|
end
|
|
820
888
|
end
|
|
821
889
|
|
|
890
|
+
# Raise an InvalidOperation exception if insert is not allowed for this dataset.
|
|
891
|
+
def check_insert_allowed!
|
|
892
|
+
raise(InvalidOperation, "Grouped datasets cannot be modified") if opts[:group]
|
|
893
|
+
raise(InvalidOperation, "Joined datasets cannot be modified") if joined_dataset?
|
|
894
|
+
end
|
|
895
|
+
alias check_delete_allowed! check_insert_allowed!
|
|
896
|
+
|
|
822
897
|
# SQLite supports a maximum of 500 rows in a VALUES clause.
|
|
823
898
|
def default_import_slice
|
|
824
899
|
500
|
|
@@ -938,6 +1013,23 @@ module Sequel
|
|
|
938
1013
|
def _truncate_sql(table)
|
|
939
1014
|
"DELETE FROM #{table}"
|
|
940
1015
|
end
|
|
1016
|
+
|
|
1017
|
+
# Use FROM to specify additional tables in an update query
|
|
1018
|
+
def update_from_sql(sql)
|
|
1019
|
+
if(from = @opts[:from][1..-1]).empty?
|
|
1020
|
+
raise(Error, 'Need multiple FROM tables if updating/deleting a dataset with JOINs') if @opts[:join]
|
|
1021
|
+
else
|
|
1022
|
+
sql << ' FROM '
|
|
1023
|
+
source_list_append(sql, from)
|
|
1024
|
+
select_join_sql(sql)
|
|
1025
|
+
end
|
|
1026
|
+
end
|
|
1027
|
+
|
|
1028
|
+
# Only include the primary table in the main update clause
|
|
1029
|
+
def update_table_sql(sql)
|
|
1030
|
+
sql << ' '
|
|
1031
|
+
source_list_append(sql, @opts[:from][0..0])
|
|
1032
|
+
end
|
|
941
1033
|
end
|
|
942
1034
|
end
|
|
943
1035
|
end
|