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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen-string-literal: true
|
|
2
2
|
#
|
|
3
3
|
# The pg_range_ops extension adds support to Sequel's DSL to make
|
|
4
|
-
# it easier to call PostgreSQL range functions and operators.
|
|
4
|
+
# it easier to call PostgreSQL range and multirange functions and operators.
|
|
5
5
|
#
|
|
6
6
|
# To load the extension:
|
|
7
7
|
#
|
|
@@ -11,10 +11,11 @@
|
|
|
11
11
|
#
|
|
12
12
|
# r = Sequel.pg_range_op(:range)
|
|
13
13
|
#
|
|
14
|
-
# If you have also loaded the pg_range
|
|
15
|
-
# Sequel.pg_range as well:
|
|
14
|
+
# If you have also loaded the pg_range or pg_multirange extensions, you can use
|
|
15
|
+
# Sequel.pg_range or Sequel.pg_multirange as well:
|
|
16
16
|
#
|
|
17
17
|
# r = Sequel.pg_range(:range)
|
|
18
|
+
# r = Sequel.pg_multirange(:range)
|
|
18
19
|
#
|
|
19
20
|
# Also, on most Sequel expression objects, you can call the pg_range
|
|
20
21
|
# method:
|
|
@@ -46,13 +47,25 @@
|
|
|
46
47
|
# r.upper_inc # upper_inc(range)
|
|
47
48
|
# r.lower_inf # lower_inf(range)
|
|
48
49
|
# r.upper_inf # upper_inf(range)
|
|
50
|
+
#
|
|
51
|
+
# All of the above methods work for both ranges and multiranges, as long
|
|
52
|
+
# as PostgreSQL supports the operation. The following methods are also
|
|
53
|
+
# supported:
|
|
54
|
+
#
|
|
55
|
+
# r.range_merge # range_merge(range)
|
|
56
|
+
# r.unnest # unnest(range)
|
|
57
|
+
# r.multirange # multirange(range)
|
|
58
|
+
#
|
|
59
|
+
# +range_merge+ and +unnest+ expect the receiver to represent a multirange
|
|
60
|
+
# value, while +multi_range+ expects the receiver to represent a range value.
|
|
49
61
|
#
|
|
50
|
-
# See the PostgreSQL range function and operator documentation for more
|
|
62
|
+
# See the PostgreSQL range and multirange function and operator documentation for more
|
|
51
63
|
# details on what these functions and operators do.
|
|
52
64
|
#
|
|
53
|
-
# If you are also using the pg_range extension, you should
|
|
54
|
-
# loading this extension. Doing so will allow you to use
|
|
55
|
-
#
|
|
65
|
+
# If you are also using the pg_range or pg_multirange extension, you should
|
|
66
|
+
# load them before loading this extension. Doing so will allow you to use
|
|
67
|
+
# PGRange#op and PGMultiRange#op to get a RangeOp, allowing you to perform
|
|
68
|
+
# range operations on range literals.
|
|
56
69
|
#
|
|
57
70
|
# Related module: Sequel::Postgres::RangeOp
|
|
58
71
|
|
|
@@ -77,9 +90,12 @@ module Sequel
|
|
|
77
90
|
:overlaps => ["(".freeze, " && ".freeze, ")".freeze].freeze,
|
|
78
91
|
}.freeze
|
|
79
92
|
|
|
80
|
-
%w'lower upper isempty lower_inc upper_inc lower_inf upper_inf'.each do |f|
|
|
93
|
+
%w'lower upper isempty lower_inc upper_inc lower_inf upper_inf unnest'.each do |f|
|
|
81
94
|
class_eval("def #{f}; function(:#{f}) end", __FILE__, __LINE__)
|
|
82
95
|
end
|
|
96
|
+
%w'range_merge multirange'.each do |f|
|
|
97
|
+
class_eval("def #{f}; RangeOp.new(function(:#{f})) end", __FILE__, __LINE__)
|
|
98
|
+
end
|
|
83
99
|
OPERATORS.each_key do |f|
|
|
84
100
|
class_eval("def #{f}(v); operator(:#{f}, v) end", __FILE__, __LINE__)
|
|
85
101
|
end
|
|
@@ -116,7 +132,9 @@ module Sequel
|
|
|
116
132
|
end
|
|
117
133
|
end
|
|
118
134
|
|
|
135
|
+
# :nocov:
|
|
119
136
|
if defined?(PGRange)
|
|
137
|
+
# :nocov:
|
|
120
138
|
class PGRange
|
|
121
139
|
# Wrap the PGRange instance in an RangeOp, allowing you to easily use
|
|
122
140
|
# the PostgreSQL range functions and operators with literal ranges.
|
|
@@ -125,6 +143,18 @@ module Sequel
|
|
|
125
143
|
end
|
|
126
144
|
end
|
|
127
145
|
end
|
|
146
|
+
|
|
147
|
+
# :nocov:
|
|
148
|
+
if defined?(PGMultiRange)
|
|
149
|
+
# :nocov:
|
|
150
|
+
class PGMultiRange
|
|
151
|
+
# Wrap the PGRange instance in an RangeOp, allowing you to easily use
|
|
152
|
+
# the PostgreSQL range functions and operators with literal ranges.
|
|
153
|
+
def op
|
|
154
|
+
RangeOp.new(self)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
128
158
|
end
|
|
129
159
|
|
|
130
160
|
module SQL::Builders
|
|
@@ -158,7 +188,7 @@ end
|
|
|
158
188
|
if defined?(Sequel::CoreRefinements)
|
|
159
189
|
module Sequel::CoreRefinements
|
|
160
190
|
refine Symbol do
|
|
161
|
-
|
|
191
|
+
send INCLUDE_METH, Sequel::Postgres::RangeOpMethods
|
|
162
192
|
end
|
|
163
193
|
end
|
|
164
194
|
end
|
|
@@ -222,7 +222,6 @@ module Sequel
|
|
|
222
222
|
# Split the stored string into an array of strings, handling
|
|
223
223
|
# the different types of quoting.
|
|
224
224
|
def parse
|
|
225
|
-
return @result if @result
|
|
226
225
|
values = []
|
|
227
226
|
skip(/\(/)
|
|
228
227
|
if skip(/\)/)
|
|
@@ -483,6 +482,7 @@ module Sequel
|
|
|
483
482
|
row_type(db_type, v)
|
|
484
483
|
end
|
|
485
484
|
private meth
|
|
485
|
+
alias_method(meth, meth)
|
|
486
486
|
end
|
|
487
487
|
|
|
488
488
|
nil
|
|
@@ -158,6 +158,30 @@ module Sequel
|
|
|
158
158
|
end
|
|
159
159
|
end
|
|
160
160
|
end
|
|
161
|
+
|
|
162
|
+
# :nocov:
|
|
163
|
+
if defined?(PGRow::ArrayRow)
|
|
164
|
+
# :nocov:
|
|
165
|
+
class PGRow::ArrayRow
|
|
166
|
+
# Wrap the PGRow::ArrayRow instance in an PGRowOp, allowing you to easily use
|
|
167
|
+
# the PostgreSQL row functions and operators with literal rows.
|
|
168
|
+
def op
|
|
169
|
+
Sequel.pg_row_op(self)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# :nocov:
|
|
175
|
+
if defined?(PGRow::HashRow)
|
|
176
|
+
# :nocov:
|
|
177
|
+
class PGRow::HashRow
|
|
178
|
+
# Wrap the PGRow::ArrayRow instance in an PGRowOp, allowing you to easily use
|
|
179
|
+
# the PostgreSQL row functions and operators with literal rows.
|
|
180
|
+
def op
|
|
181
|
+
Sequel.pg_row_op(self)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
161
185
|
end
|
|
162
186
|
|
|
163
187
|
module SQL::Builders
|
|
@@ -186,7 +210,7 @@ end
|
|
|
186
210
|
if defined?(Sequel::CoreRefinements)
|
|
187
211
|
module Sequel::CoreRefinements
|
|
188
212
|
refine Symbol do
|
|
189
|
-
|
|
213
|
+
send INCLUDE_METH, Sequel::Postgres::PGRowOp::ExpressionMethods
|
|
190
214
|
end
|
|
191
215
|
end
|
|
192
216
|
end
|
|
@@ -48,7 +48,7 @@ class Sequel::Database
|
|
|
48
48
|
def _run_transaction_hooks(type, opts)
|
|
49
49
|
synchronize(opts[:server]) do |conn|
|
|
50
50
|
unless h = _trans(conn)
|
|
51
|
-
raise Error, "Cannot call run_#{type}_hooks outside of a transaction"
|
|
51
|
+
raise Sequel::Error, "Cannot call run_#{type}_hooks outside of a transaction"
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
if hooks = h[type]
|
data/lib/sequel/extensions/s.rb
CHANGED
|
@@ -49,9 +49,12 @@ module Sequel::S
|
|
|
49
49
|
Sequel.expr(*a, &block)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
# :nocov:
|
|
52
53
|
if RUBY_VERSION >= '2.0.0'
|
|
54
|
+
include_meth = RUBY_VERSION >= '3.1' ? :import_methods : :include
|
|
55
|
+
# :nocov:
|
|
53
56
|
refine Object do
|
|
54
|
-
|
|
57
|
+
send include_meth, Sequel::S
|
|
55
58
|
end
|
|
56
59
|
end
|
|
57
60
|
end
|
|
@@ -6,6 +6,17 @@
|
|
|
6
6
|
# the current database). The main interface is through
|
|
7
7
|
# Sequel::Database#dump_schema_migration.
|
|
8
8
|
#
|
|
9
|
+
# The schema_dumper extension is quite limited in what types of
|
|
10
|
+
# database objects it supports. In general, it only supports
|
|
11
|
+
# dumping tables, columns, primary key and foreign key constraints,
|
|
12
|
+
# and some indexes. It does not support most table options, CHECK
|
|
13
|
+
# constraints, partial indexes, database functions, triggers,
|
|
14
|
+
# security grants/revokes, and a wide variety of other useful
|
|
15
|
+
# database properties. Be aware of the limitations when using the
|
|
16
|
+
# schema_dumper extension. If you are dumping the schema to restore
|
|
17
|
+
# to the same database type, it is recommended to use your database's
|
|
18
|
+
# dump and restore programs instead of the schema_dumper extension.
|
|
19
|
+
#
|
|
9
20
|
# To load the extension:
|
|
10
21
|
#
|
|
11
22
|
# DB.extension :schema_dumper
|
|
@@ -37,7 +48,7 @@ module Sequel
|
|
|
37
48
|
{:type =>schema[:type] == :boolean ? TrueClass : Integer}
|
|
38
49
|
when /\Abigint(?:\((?:\d+)\))?(?: unsigned)?\z/
|
|
39
50
|
{:type=>:Bignum}
|
|
40
|
-
when /\A(?:real|float
|
|
51
|
+
when /\A(?:real|float|double(?: precision)?|double\(\d+,\d+\))(?: unsigned)?\z/
|
|
41
52
|
{:type=>Float}
|
|
42
53
|
when 'boolean', 'bit', 'bool'
|
|
43
54
|
{:type=>TrueClass}
|
|
@@ -57,7 +68,7 @@ module Sequel
|
|
|
57
68
|
{:type=>String, :size=>($1.to_i if $1)}
|
|
58
69
|
when /\A(?:small)?money\z/
|
|
59
70
|
{:type=>BigDecimal, :size=>[19,2]}
|
|
60
|
-
when /\A(?:decimal|numeric|number)(?:\((\d+)(?:,\s*(\d+))?\))?\z/
|
|
71
|
+
when /\A(?:decimal|numeric|number)(?:\((\d+)(?:,\s*(\d+))?\))?(?: unsigned)?\z/
|
|
61
72
|
s = [($1.to_i if $1), ($2.to_i if $2)].compact
|
|
62
73
|
{:type=>BigDecimal, :size=>(s.empty? ? nil : s)}
|
|
63
74
|
when /\A(?:bytea|(?:tiny|medium|long)?blob|(?:var)?binary)(?:\((\d+)\))?\z/
|
|
@@ -172,7 +183,7 @@ END_MIG
|
|
|
172
183
|
if options[:single_pk] && schema_autoincrementing_primary_key?(schema)
|
|
173
184
|
type_hash = options[:same_db] ? {:type=>schema[:db_type]} : column_schema_to_ruby_type(schema)
|
|
174
185
|
[:table, :key, :on_delete, :on_update, :deferrable].each{|f| type_hash[f] = schema[f] if schema[f]}
|
|
175
|
-
if type_hash == {:type=>Integer} || type_hash == {:type=>"integer"}
|
|
186
|
+
if type_hash == {:type=>Integer} || type_hash == {:type=>"integer"} || type_hash == {:type=>"INTEGER"}
|
|
176
187
|
type_hash.delete(:type)
|
|
177
188
|
elsif options[:same_db] && type_hash == {:type=>type_literal_generic_bignum_symbol(type_hash).to_s}
|
|
178
189
|
type_hash[:type] = :Bignum
|
|
@@ -214,11 +225,11 @@ END_MIG
|
|
|
214
225
|
col_opts[:null] = false if schema[:allow_null] == false
|
|
215
226
|
if table = schema[:table]
|
|
216
227
|
[:key, :on_delete, :on_update, :deferrable].each{|f| col_opts[f] = schema[f] if schema[f]}
|
|
217
|
-
col_opts[:type] = type unless type == Integer || type == 'integer'
|
|
228
|
+
col_opts[:type] = type unless type == Integer || type == 'integer' || type == 'INTEGER'
|
|
218
229
|
gen.foreign_key(name, table, col_opts)
|
|
219
230
|
else
|
|
220
231
|
gen.column(name, type, col_opts)
|
|
221
|
-
if [Integer, :Bignum, Float].include?(type) && schema[:db_type] =~ / unsigned\z/io
|
|
232
|
+
if [Integer, :Bignum, Float, BigDecimal].include?(type) && schema[:db_type] =~ / unsigned\z/io
|
|
222
233
|
gen.check(Sequel::SQL::Identifier.new(name) >= 0)
|
|
223
234
|
end
|
|
224
235
|
end
|
|
@@ -88,12 +88,10 @@ module Sequel
|
|
|
88
88
|
module UnthreadedServerBlock
|
|
89
89
|
# Set a default server/shard to use inside the block.
|
|
90
90
|
def with_server(default_server, read_only_server=default_server)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
clear_default_server
|
|
96
|
-
end
|
|
91
|
+
set_default_server(default_server, read_only_server)
|
|
92
|
+
yield
|
|
93
|
+
ensure
|
|
94
|
+
clear_default_server
|
|
97
95
|
end
|
|
98
96
|
|
|
99
97
|
private
|
|
@@ -131,12 +129,10 @@ module Sequel
|
|
|
131
129
|
# Set a default server/shard to use inside the block for the current
|
|
132
130
|
# thread.
|
|
133
131
|
def with_server(default_server, read_only_server=default_server)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
clear_default_server
|
|
139
|
-
end
|
|
132
|
+
set_default_server(default_server, read_only_server)
|
|
133
|
+
yield
|
|
134
|
+
ensure
|
|
135
|
+
clear_default_server
|
|
140
136
|
end
|
|
141
137
|
|
|
142
138
|
private
|
|
@@ -44,11 +44,51 @@
|
|
|
44
44
|
#
|
|
45
45
|
# DB.extension(:sql_comments)
|
|
46
46
|
#
|
|
47
|
+
# Loading the sql_comments extension into the database also adds
|
|
48
|
+
# support for block-level comment support via Database#with_comments.
|
|
49
|
+
# You call #with_comments with a hash. Queries inside the hash will
|
|
50
|
+
# include a comment based on the hash (assuming they are inside the
|
|
51
|
+
# same thread):
|
|
52
|
+
#
|
|
53
|
+
# DB.with_comments(model: Album, action: :all) do
|
|
54
|
+
# DB[:albums].all
|
|
55
|
+
# # SELECT * FROM albums -- model:Album,action:all
|
|
56
|
+
# end
|
|
57
|
+
#
|
|
58
|
+
# You can nest calls to #with_comments, which will combine the
|
|
59
|
+
# entries from both calls:
|
|
60
|
+
#
|
|
61
|
+
# DB.with_comments(application: App, path: :scrubbed_path) do
|
|
62
|
+
# DB.with_comments(model: Album, action: :all) do
|
|
63
|
+
# ds = DB[:albums].all
|
|
64
|
+
# # SELECT * FROM albums
|
|
65
|
+
# # -- application:App,path:scrubbed_path,model:Album,action:all
|
|
66
|
+
# end
|
|
67
|
+
# end
|
|
68
|
+
#
|
|
69
|
+
# You can override comment entries specified in earlier blocks, or
|
|
70
|
+
# remove entries specified earlier using a nil value:
|
|
71
|
+
#
|
|
72
|
+
# DB.with_comments(application: App, path: :scrubbed_path) do
|
|
73
|
+
# DB.with_comments(application: Foo, path: nil) do
|
|
74
|
+
# ds = DB[:albums].all
|
|
75
|
+
# # SELECT * FROM albums # -- application:Foo
|
|
76
|
+
# end
|
|
77
|
+
# end
|
|
78
|
+
#
|
|
79
|
+
# You can combine block-level comments with dataset-specific
|
|
80
|
+
# comments:
|
|
81
|
+
#
|
|
82
|
+
# DB.with_comments(model: Album, action: :all) do
|
|
83
|
+
# DB[:table].comment("Some Comment").all
|
|
84
|
+
# # SELECT * FROM albums -- model:Album,action:all -- Some Comment
|
|
85
|
+
# end
|
|
86
|
+
#
|
|
47
87
|
# Note that Microsoft Access does not support inline comments,
|
|
48
88
|
# and attempting to use comments on it will result in SQL syntax
|
|
49
89
|
# errors.
|
|
50
90
|
#
|
|
51
|
-
# Related
|
|
91
|
+
# Related modules: Sequel::SQLComments, Sequel::Database::SQLComments
|
|
52
92
|
|
|
53
93
|
#
|
|
54
94
|
module Sequel
|
|
@@ -62,7 +102,7 @@ module Sequel
|
|
|
62
102
|
%w'select insert update delete'.each do |type|
|
|
63
103
|
define_method(:"#{type}_sql") do |*a|
|
|
64
104
|
sql = super(*a)
|
|
65
|
-
if comment =
|
|
105
|
+
if comment = _sql_comment
|
|
66
106
|
# This assumes that the comment stored in the dataset has
|
|
67
107
|
# already been formatted. If not, this could result in SQL
|
|
68
108
|
# injection.
|
|
@@ -74,8 +114,10 @@ module Sequel
|
|
|
74
114
|
if sql.frozen?
|
|
75
115
|
sql += comment
|
|
76
116
|
sql.freeze
|
|
77
|
-
|
|
117
|
+
elsif @opts[:append_sql] || @opts[:placeholder_literalizer]
|
|
78
118
|
sql << comment
|
|
119
|
+
else
|
|
120
|
+
sql += comment
|
|
79
121
|
end
|
|
80
122
|
end
|
|
81
123
|
sql
|
|
@@ -84,6 +126,11 @@ module Sequel
|
|
|
84
126
|
|
|
85
127
|
private
|
|
86
128
|
|
|
129
|
+
# The comment to include in the SQL query, if any.
|
|
130
|
+
def _sql_comment
|
|
131
|
+
@opts[:comment]
|
|
132
|
+
end
|
|
133
|
+
|
|
87
134
|
# Format the comment. For maximum compatibility, this uses a
|
|
88
135
|
# single line SQL comment, and converts all consecutive whitespace
|
|
89
136
|
# in the comment to a single space.
|
|
@@ -92,5 +139,65 @@ module Sequel
|
|
|
92
139
|
end
|
|
93
140
|
end
|
|
94
141
|
|
|
142
|
+
module Database::SQLComments
|
|
143
|
+
def self.extended(db)
|
|
144
|
+
db.instance_variable_set(:@comment_hashes, {})
|
|
145
|
+
db.extend_datasets DatasetSQLComments
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# A map of threads to comment hashes, used for correctly setting
|
|
149
|
+
# comments for all queries inside #with_comments blocks.
|
|
150
|
+
attr_reader :comment_hashes
|
|
151
|
+
|
|
152
|
+
# Store the comment hash and use it to create comments inside the block
|
|
153
|
+
def with_comments(comment_hash)
|
|
154
|
+
hashes = @comment_hashes
|
|
155
|
+
t = Sequel.current
|
|
156
|
+
new_hash = if hash = Sequel.synchronize{hashes[t]}
|
|
157
|
+
hash.merge(comment_hash)
|
|
158
|
+
else
|
|
159
|
+
comment_hash.dup
|
|
160
|
+
end
|
|
161
|
+
yield Sequel.synchronize{hashes[t] = new_hash}
|
|
162
|
+
ensure
|
|
163
|
+
if hash
|
|
164
|
+
Sequel.synchronize{hashes[t] = hash}
|
|
165
|
+
else
|
|
166
|
+
t && Sequel.synchronize{hashes.delete(t)}
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
module DatasetSQLComments
|
|
171
|
+
include Sequel::SQLComments
|
|
172
|
+
|
|
173
|
+
private
|
|
174
|
+
|
|
175
|
+
# Include comments added via Database#with_comments in the output SQL.
|
|
176
|
+
def _sql_comment
|
|
177
|
+
specific_comment = super
|
|
178
|
+
return specific_comment if @opts[:append_sql]
|
|
179
|
+
|
|
180
|
+
t = Sequel.current
|
|
181
|
+
hashes = db.comment_hashes
|
|
182
|
+
block_comment = if comment_hash = Sequel.synchronize{hashes[t]}
|
|
183
|
+
comment_array = comment_hash.map{|k,v| "#{k}:#{v}" unless v.nil?}
|
|
184
|
+
comment_array.compact!
|
|
185
|
+
comment_array.join(",")
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
if block_comment
|
|
189
|
+
if specific_comment
|
|
190
|
+
format_sql_comment(block_comment + specific_comment)
|
|
191
|
+
else
|
|
192
|
+
format_sql_comment(block_comment)
|
|
193
|
+
end
|
|
194
|
+
else
|
|
195
|
+
specific_comment
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
95
201
|
Dataset.register_extension(:sql_comments, SQLComments)
|
|
202
|
+
Database.register_extension(:sql_comments, Database::SQLComments)
|
|
96
203
|
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
#
|
|
3
|
+
# The sql_log_normalizer extension normalizes the SQL that is logged,
|
|
4
|
+
# removing the literal strings and numbers in the SQL, and removing the
|
|
5
|
+
# logging of any bound variables:
|
|
6
|
+
#
|
|
7
|
+
# ds = DB[:table].first(a: 1, b: 'something')
|
|
8
|
+
# # Without sql_log_normalizer extension
|
|
9
|
+
# # SELECT * FROM "table" WHERE (("a" = 1) AND ("b" = 'something')) LIMIT 1
|
|
10
|
+
#
|
|
11
|
+
# # With sql_log_normalizer_extension
|
|
12
|
+
# # SELECT * FROM "table" WHERE (("a" = ?) AND ("b" = ?)) LIMIT ?
|
|
13
|
+
#
|
|
14
|
+
# The normalization is done by scanning the SQL string being executed
|
|
15
|
+
# for literal strings and numbers, and replacing them with question
|
|
16
|
+
# marks. While this should work for all or almost all production queries,
|
|
17
|
+
# there are pathlogical queries that will not be handled correctly, such as
|
|
18
|
+
# the use of apostrophes in identifiers:
|
|
19
|
+
#
|
|
20
|
+
# DB[:"asf'bar"].where(a: 1, b: 'something').first
|
|
21
|
+
# # Logged as:
|
|
22
|
+
# # SELECT * FROM "asf?something')) LIMIT ?
|
|
23
|
+
#
|
|
24
|
+
# The expected use case for this extension is when you want to normalize
|
|
25
|
+
# logs to group similar queries, or when you want to protect sensitive
|
|
26
|
+
# data from being stored in the logs.
|
|
27
|
+
#
|
|
28
|
+
# Related module: Sequel::SQLLogNormalizer
|
|
29
|
+
|
|
30
|
+
#
|
|
31
|
+
module Sequel
|
|
32
|
+
module SQLLogNormalizer
|
|
33
|
+
def self.extended(db)
|
|
34
|
+
type = case db.literal("'")
|
|
35
|
+
when "''''"
|
|
36
|
+
:standard
|
|
37
|
+
when "'\\''"
|
|
38
|
+
:backslash
|
|
39
|
+
when "N''''"
|
|
40
|
+
:n_standard
|
|
41
|
+
else
|
|
42
|
+
raise Error, "SQL log normalization is not supported on this database (' literalized as #{db.literal("'").inspect})"
|
|
43
|
+
end
|
|
44
|
+
db.instance_variable_set(:@sql_string_escape_type, type)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Normalize the SQL before calling super.
|
|
48
|
+
def log_connection_yield(sql, conn, args=nil)
|
|
49
|
+
unless skip_logging?
|
|
50
|
+
sql = normalize_logged_sql(sql)
|
|
51
|
+
args = nil
|
|
52
|
+
end
|
|
53
|
+
super
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Replace literal strings and numbers in SQL with question mark placeholders.
|
|
57
|
+
def normalize_logged_sql(sql)
|
|
58
|
+
sql = sql.dup
|
|
59
|
+
sql.force_encoding('BINARY')
|
|
60
|
+
start_index = 0
|
|
61
|
+
check_n = @sql_string_escape_type == :n_standard
|
|
62
|
+
outside_string = true
|
|
63
|
+
|
|
64
|
+
if @sql_string_escape_type == :backslash
|
|
65
|
+
search_char = /[\\']/
|
|
66
|
+
escape_char_offset = 0
|
|
67
|
+
escape_char_value = 92 # backslash
|
|
68
|
+
else
|
|
69
|
+
search_char = "'"
|
|
70
|
+
escape_char_offset = 1
|
|
71
|
+
escape_char_value = 39 # apostrophe
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# The approach used here goes against Sequel's philosophy of never attempting
|
|
75
|
+
# to parse SQL. However, parsing the SQL is basically the only way to implement
|
|
76
|
+
# this support with Sequel's design, and it's better to be pragmatic and accept
|
|
77
|
+
# this than not be able to support this.
|
|
78
|
+
|
|
79
|
+
# Replace literal strings
|
|
80
|
+
while outside_string && (index = start_index = sql.index("'", start_index))
|
|
81
|
+
if check_n && index != 0 && sql.getbyte(index-1) == 78 # N' start
|
|
82
|
+
start_index -= 1
|
|
83
|
+
end
|
|
84
|
+
index += 1
|
|
85
|
+
outside_string = false
|
|
86
|
+
|
|
87
|
+
while (index = sql.index(search_char, index)) && (sql.getbyte(index + escape_char_offset) == escape_char_value)
|
|
88
|
+
# skip escaped characters inside string literal
|
|
89
|
+
index += 2
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
if index
|
|
93
|
+
# Found end of string
|
|
94
|
+
sql[start_index..index] = '?'
|
|
95
|
+
start_index += 1
|
|
96
|
+
outside_string = true
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Replace integer and decimal floating point numbers
|
|
101
|
+
sql.gsub!(/\b-?\d+(?:\.\d+)?\b/, '?')
|
|
102
|
+
|
|
103
|
+
sql
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
Database.register_extension(:sql_log_normalizer, SQLLogNormalizer)
|
|
108
|
+
end
|