sequel 5.80.0 → 5.92.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.
Files changed (205) hide show
  1. checksums.yaml +4 -4
  2. data/bin/sequel +9 -4
  3. data/lib/sequel/adapters/ado.rb +1 -1
  4. data/lib/sequel/adapters/ibmdb.rb +1 -0
  5. data/lib/sequel/adapters/jdbc/db2.rb +2 -2
  6. data/lib/sequel/adapters/jdbc/derby.rb +3 -3
  7. data/lib/sequel/adapters/jdbc/h2.rb +2 -2
  8. data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -2
  9. data/lib/sequel/adapters/jdbc/jtds.rb +2 -2
  10. data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
  11. data/lib/sequel/adapters/jdbc/oracle.rb +5 -5
  12. data/lib/sequel/adapters/jdbc/postgresql.rb +5 -5
  13. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +6 -6
  14. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -2
  15. data/lib/sequel/adapters/jdbc/sqlserver.rb +2 -2
  16. data/lib/sequel/adapters/jdbc.rb +8 -8
  17. data/lib/sequel/adapters/mysql2.rb +8 -1
  18. data/lib/sequel/adapters/shared/access.rb +1 -0
  19. data/lib/sequel/adapters/shared/db2.rb +1 -1
  20. data/lib/sequel/adapters/shared/mssql.rb +18 -5
  21. data/lib/sequel/adapters/shared/mysql.rb +8 -4
  22. data/lib/sequel/adapters/shared/oracle.rb +1 -0
  23. data/lib/sequel/adapters/shared/postgres.rb +106 -13
  24. data/lib/sequel/adapters/shared/sqlite.rb +4 -2
  25. data/lib/sequel/adapters/sqlite.rb +4 -0
  26. data/lib/sequel/adapters/trilogy.rb +1 -2
  27. data/lib/sequel/connection_pool/sharded_threaded.rb +26 -10
  28. data/lib/sequel/connection_pool/threaded.rb +26 -10
  29. data/lib/sequel/connection_pool.rb +2 -2
  30. data/lib/sequel/core.rb +15 -0
  31. data/lib/sequel/database/connecting.rb +20 -26
  32. data/lib/sequel/database/dataset_defaults.rb +3 -3
  33. data/lib/sequel/database/misc.rb +46 -10
  34. data/lib/sequel/database/query.rb +11 -11
  35. data/lib/sequel/database/schema_generator.rb +8 -0
  36. data/lib/sequel/database/schema_methods.rb +17 -1
  37. data/lib/sequel/dataset/actions.rb +9 -1
  38. data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +1 -1
  39. data/lib/sequel/dataset/prepared_statements.rb +2 -1
  40. data/lib/sequel/dataset/query.rb +9 -5
  41. data/lib/sequel/dataset/sql.rb +25 -5
  42. data/lib/sequel/extensions/caller_logging.rb +2 -0
  43. data/lib/sequel/extensions/connection_validator.rb +15 -10
  44. data/lib/sequel/extensions/dataset_run.rb +41 -0
  45. data/lib/sequel/extensions/migration.rb +23 -3
  46. data/lib/sequel/extensions/null_dataset.rb +2 -2
  47. data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -1
  48. data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +93 -10
  49. data/lib/sequel/extensions/pg_enum.rb +3 -3
  50. data/lib/sequel/extensions/pg_json_ops.rb +642 -9
  51. data/lib/sequel/extensions/pg_row.rb +3 -1
  52. data/lib/sequel/extensions/pg_schema_caching.rb +90 -0
  53. data/lib/sequel/extensions/provenance.rb +2 -0
  54. data/lib/sequel/extensions/query_blocker.rb +172 -0
  55. data/lib/sequel/extensions/schema_caching.rb +24 -9
  56. data/lib/sequel/extensions/schema_dumper.rb +16 -4
  57. data/lib/sequel/extensions/sqlite_json_ops.rb +1 -1
  58. data/lib/sequel/extensions/stdio_logger.rb +48 -0
  59. data/lib/sequel/extensions/string_agg.rb +17 -4
  60. data/lib/sequel/extensions/temporarily_release_connection.rb +178 -0
  61. data/lib/sequel/extensions/virtual_row_method_block.rb +1 -0
  62. data/lib/sequel/model/associations.rb +28 -3
  63. data/lib/sequel/model/base.rb +67 -18
  64. data/lib/sequel/plugins/association_pks.rb +1 -1
  65. data/lib/sequel/plugins/column_encryption.rb +1 -1
  66. data/lib/sequel/plugins/composition.rb +1 -1
  67. data/lib/sequel/plugins/defaults_setter.rb +16 -4
  68. data/lib/sequel/plugins/enum.rb +1 -1
  69. data/lib/sequel/plugins/forbid_lazy_load.rb +14 -1
  70. data/lib/sequel/plugins/input_transformer.rb +1 -1
  71. data/lib/sequel/plugins/inspect_pk.rb +44 -0
  72. data/lib/sequel/plugins/instance_filters.rb +4 -1
  73. data/lib/sequel/plugins/inverted_subsets.rb +1 -0
  74. data/lib/sequel/plugins/lazy_attributes.rb +1 -1
  75. data/lib/sequel/plugins/nested_attributes.rb +10 -5
  76. data/lib/sequel/plugins/optimistic_locking.rb +2 -0
  77. data/lib/sequel/plugins/paged_operations.rb +5 -2
  78. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +6 -1
  79. data/lib/sequel/plugins/pg_auto_validate_enums.rb +88 -0
  80. data/lib/sequel/plugins/pg_eager_any_typed_array.rb +95 -0
  81. data/lib/sequel/plugins/rcte_tree.rb +1 -1
  82. data/lib/sequel/plugins/serialization.rb +11 -5
  83. data/lib/sequel/plugins/sql_comments.rb +7 -2
  84. data/lib/sequel/plugins/static_cache_cache.rb +50 -13
  85. data/lib/sequel/plugins/subset_conditions.rb +85 -5
  86. data/lib/sequel/plugins/subset_static_cache.rb +263 -0
  87. data/lib/sequel/plugins/tactical_eager_loading.rb +6 -2
  88. data/lib/sequel/plugins/validate_associated.rb +1 -1
  89. data/lib/sequel/sql.rb +16 -6
  90. data/lib/sequel/version.rb +1 -1
  91. metadata +12 -234
  92. data/CHANGELOG +0 -1355
  93. data/README.rdoc +0 -936
  94. data/doc/advanced_associations.rdoc +0 -884
  95. data/doc/association_basics.rdoc +0 -1859
  96. data/doc/bin_sequel.rdoc +0 -146
  97. data/doc/cheat_sheet.rdoc +0 -255
  98. data/doc/code_order.rdoc +0 -102
  99. data/doc/core_extensions.rdoc +0 -405
  100. data/doc/dataset_basics.rdoc +0 -96
  101. data/doc/dataset_filtering.rdoc +0 -222
  102. data/doc/extensions.rdoc +0 -77
  103. data/doc/fork_safety.rdoc +0 -84
  104. data/doc/mass_assignment.rdoc +0 -98
  105. data/doc/migration.rdoc +0 -660
  106. data/doc/model_dataset_method_design.rdoc +0 -129
  107. data/doc/model_hooks.rdoc +0 -254
  108. data/doc/model_plugins.rdoc +0 -270
  109. data/doc/mssql_stored_procedures.rdoc +0 -43
  110. data/doc/object_model.rdoc +0 -563
  111. data/doc/opening_databases.rdoc +0 -436
  112. data/doc/postgresql.rdoc +0 -611
  113. data/doc/prepared_statements.rdoc +0 -144
  114. data/doc/querying.rdoc +0 -1070
  115. data/doc/reflection.rdoc +0 -120
  116. data/doc/release_notes/5.0.0.txt +0 -159
  117. data/doc/release_notes/5.1.0.txt +0 -31
  118. data/doc/release_notes/5.10.0.txt +0 -84
  119. data/doc/release_notes/5.11.0.txt +0 -83
  120. data/doc/release_notes/5.12.0.txt +0 -141
  121. data/doc/release_notes/5.13.0.txt +0 -27
  122. data/doc/release_notes/5.14.0.txt +0 -63
  123. data/doc/release_notes/5.15.0.txt +0 -39
  124. data/doc/release_notes/5.16.0.txt +0 -110
  125. data/doc/release_notes/5.17.0.txt +0 -31
  126. data/doc/release_notes/5.18.0.txt +0 -69
  127. data/doc/release_notes/5.19.0.txt +0 -28
  128. data/doc/release_notes/5.2.0.txt +0 -33
  129. data/doc/release_notes/5.20.0.txt +0 -89
  130. data/doc/release_notes/5.21.0.txt +0 -87
  131. data/doc/release_notes/5.22.0.txt +0 -48
  132. data/doc/release_notes/5.23.0.txt +0 -56
  133. data/doc/release_notes/5.24.0.txt +0 -56
  134. data/doc/release_notes/5.25.0.txt +0 -32
  135. data/doc/release_notes/5.26.0.txt +0 -35
  136. data/doc/release_notes/5.27.0.txt +0 -21
  137. data/doc/release_notes/5.28.0.txt +0 -16
  138. data/doc/release_notes/5.29.0.txt +0 -22
  139. data/doc/release_notes/5.3.0.txt +0 -121
  140. data/doc/release_notes/5.30.0.txt +0 -20
  141. data/doc/release_notes/5.31.0.txt +0 -148
  142. data/doc/release_notes/5.32.0.txt +0 -46
  143. data/doc/release_notes/5.33.0.txt +0 -24
  144. data/doc/release_notes/5.34.0.txt +0 -40
  145. data/doc/release_notes/5.35.0.txt +0 -56
  146. data/doc/release_notes/5.36.0.txt +0 -60
  147. data/doc/release_notes/5.37.0.txt +0 -30
  148. data/doc/release_notes/5.38.0.txt +0 -28
  149. data/doc/release_notes/5.39.0.txt +0 -19
  150. data/doc/release_notes/5.4.0.txt +0 -80
  151. data/doc/release_notes/5.40.0.txt +0 -40
  152. data/doc/release_notes/5.41.0.txt +0 -25
  153. data/doc/release_notes/5.42.0.txt +0 -136
  154. data/doc/release_notes/5.43.0.txt +0 -98
  155. data/doc/release_notes/5.44.0.txt +0 -32
  156. data/doc/release_notes/5.45.0.txt +0 -34
  157. data/doc/release_notes/5.46.0.txt +0 -87
  158. data/doc/release_notes/5.47.0.txt +0 -59
  159. data/doc/release_notes/5.48.0.txt +0 -14
  160. data/doc/release_notes/5.49.0.txt +0 -59
  161. data/doc/release_notes/5.5.0.txt +0 -61
  162. data/doc/release_notes/5.50.0.txt +0 -78
  163. data/doc/release_notes/5.51.0.txt +0 -47
  164. data/doc/release_notes/5.52.0.txt +0 -87
  165. data/doc/release_notes/5.53.0.txt +0 -23
  166. data/doc/release_notes/5.54.0.txt +0 -27
  167. data/doc/release_notes/5.55.0.txt +0 -21
  168. data/doc/release_notes/5.56.0.txt +0 -51
  169. data/doc/release_notes/5.57.0.txt +0 -23
  170. data/doc/release_notes/5.58.0.txt +0 -31
  171. data/doc/release_notes/5.59.0.txt +0 -73
  172. data/doc/release_notes/5.6.0.txt +0 -31
  173. data/doc/release_notes/5.60.0.txt +0 -22
  174. data/doc/release_notes/5.61.0.txt +0 -43
  175. data/doc/release_notes/5.62.0.txt +0 -132
  176. data/doc/release_notes/5.63.0.txt +0 -33
  177. data/doc/release_notes/5.64.0.txt +0 -50
  178. data/doc/release_notes/5.65.0.txt +0 -21
  179. data/doc/release_notes/5.66.0.txt +0 -24
  180. data/doc/release_notes/5.67.0.txt +0 -32
  181. data/doc/release_notes/5.68.0.txt +0 -61
  182. data/doc/release_notes/5.69.0.txt +0 -26
  183. data/doc/release_notes/5.7.0.txt +0 -108
  184. data/doc/release_notes/5.70.0.txt +0 -35
  185. data/doc/release_notes/5.71.0.txt +0 -21
  186. data/doc/release_notes/5.72.0.txt +0 -33
  187. data/doc/release_notes/5.73.0.txt +0 -66
  188. data/doc/release_notes/5.74.0.txt +0 -45
  189. data/doc/release_notes/5.75.0.txt +0 -35
  190. data/doc/release_notes/5.76.0.txt +0 -86
  191. data/doc/release_notes/5.77.0.txt +0 -63
  192. data/doc/release_notes/5.78.0.txt +0 -67
  193. data/doc/release_notes/5.79.0.txt +0 -28
  194. data/doc/release_notes/5.8.0.txt +0 -170
  195. data/doc/release_notes/5.80.0.txt +0 -40
  196. data/doc/release_notes/5.9.0.txt +0 -99
  197. data/doc/schema_modification.rdoc +0 -679
  198. data/doc/security.rdoc +0 -443
  199. data/doc/sharding.rdoc +0 -286
  200. data/doc/sql.rdoc +0 -648
  201. data/doc/testing.rdoc +0 -190
  202. data/doc/thread_safety.rdoc +0 -15
  203. data/doc/transactions.rdoc +0 -250
  204. data/doc/validations.rdoc +0 -558
  205. data/doc/virtual_rows.rdoc +0 -265
@@ -113,6 +113,7 @@ module Sequel
113
113
  # automatically casted to the database type when literalizing.
114
114
  def self.subclass(db_type)
115
115
  Class.new(self) do
116
+ Sequel.set_temp_name(self){"Sequel::Postgres::PGRow::ArrayRow::_Subclass(#{db_type})"}
116
117
  @db_type = db_type
117
118
  end
118
119
  end
@@ -170,6 +171,7 @@ module Sequel
170
171
  # type and columns.
171
172
  def self.subclass(db_type, columns)
172
173
  Class.new(self) do
174
+ Sequel.set_temp_name(self){"Sequel::Postgres::PGRow::HashRow::_Subclass(#{db_type})"}
173
175
  @db_type = db_type
174
176
  @columns = columns
175
177
  end
@@ -391,7 +393,7 @@ module Sequel
391
393
  db.instance_exec do
392
394
  @row_types = {}
393
395
  @row_schema_types = {}
394
- extend(@row_type_method_module = Module.new)
396
+ extend(@row_type_method_module = Sequel.set_temp_name(Module.new){"Sequel::Postgres::PGRow::DatabaseMethods::_RowTypeMethodModule"})
395
397
  add_conversion_proc(2249, PGRow::Parser.new(:converter=>PGRow::ArrayRow))
396
398
  if respond_to?(:register_array_type)
397
399
  register_array_type('record', :oid=>2287, :scalar_oid=>2249)
@@ -0,0 +1,90 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # The pg_schema_caching extension builds on top of the schema_caching
4
+ # extension, and allows it to handle custom PostgreSQL types. On
5
+ # PostgreSQL, column schema hashes include an :oid entry for the OID
6
+ # for the column's type. For custom types, this OID is dependent on
7
+ # the PostgreSQL database, so in most cases, test and development
8
+ # versions of the same database, created with the same migrations,
9
+ # will have different OIDs.
10
+ #
11
+ # To fix this case, the pg_schema_caching extension removes custom
12
+ # OIDs from the schema cache when dumping the schema, replacing them
13
+ # with a placeholder. When loading the cached schema, the Database
14
+ # object makes a single query to get the OIDs for all custom types
15
+ # used by the cached schema, and it updates all related column
16
+ # schema hashes to set the correct :oid entry for the current
17
+ # database.
18
+ #
19
+ # Related module: Sequel::Postgres::SchemaCaching
20
+
21
+ require_relative "schema_caching"
22
+
23
+ module Sequel
24
+ module Postgres
25
+ module SchemaCaching
26
+ include Sequel::SchemaCaching
27
+
28
+ private
29
+
30
+ # Load custom oids from database when loading schema cache file.
31
+ def load_schema_cache_file(file)
32
+ set_custom_oids_for_cached_schema(super)
33
+ end
34
+
35
+ # Find all column schema hashes that use custom types.
36
+ # Load the oids for custom types in a single query, and update
37
+ # each related column schema hash with the correct oid.
38
+ def set_custom_oids_for_cached_schema(schemas)
39
+ custom_oid_rows = {}
40
+
41
+ schemas.each_value do |cols|
42
+ cols.each do |_, h|
43
+ if h[:oid] == :custom
44
+ (custom_oid_rows[h[:db_type]] ||= []) << h
45
+ end
46
+ end
47
+ end
48
+
49
+ unless custom_oid_rows.empty?
50
+ from(:pg_type).where(:typname=>custom_oid_rows.keys).select_hash(:typname, :oid).each do |name, oid|
51
+ custom_oid_rows.delete(name).each do |row|
52
+ row[:oid] = oid
53
+ end
54
+ end
55
+ end
56
+
57
+ unless custom_oid_rows.empty?
58
+ warn "Could not load OIDs for the following custom types: #{custom_oid_rows.keys.sort.join(", ")}", uplevel: 3
59
+
60
+ schemas.keys.each do |k|
61
+ if schemas[k].any?{|_,h| h[:oid] == :custom}
62
+ # Remove schema entry for table, so it will be queried at runtime to get the correct oids
63
+ schemas.delete(k)
64
+ end
65
+ end
66
+ end
67
+
68
+ schemas
69
+ end
70
+
71
+ # Replace :oid entries for custom types with :custom.
72
+ def dumpable_schema_cache
73
+ sch = super
74
+
75
+ sch.each_value do |cols|
76
+ cols.each do |_, h|
77
+ if (oid = h[:oid]) && oid >= 10000
78
+ h[:oid] = :custom
79
+ end
80
+ end
81
+ end
82
+
83
+ sch
84
+ end
85
+ end
86
+ end
87
+
88
+ Database.register_extension(:pg_schema_caching, Postgres::SchemaCaching)
89
+ end
90
+
@@ -38,6 +38,7 @@ module Sequel
38
38
  module Provenance
39
39
  SEQUEL_LIB_PATH = (File.expand_path('../../..', __FILE__) + '/').freeze
40
40
  RUBY_STDLIB = RbConfig::CONFIG["rubylibdir"]
41
+ INTERNAL = '<internal'
41
42
 
42
43
  if TRUE_FREEZE
43
44
  # Include provenance information when cloning datasets.
@@ -98,6 +99,7 @@ module Sequel
98
99
  caller.find do |line|
99
100
  !(line.start_with?(SEQUEL_LIB_PATH) ||
100
101
  line.start_with?(RUBY_STDLIB) ||
102
+ line.start_with?(INTERNAL) ||
101
103
  (ignore && line =~ ignore))
102
104
  end
103
105
  end
@@ -0,0 +1,172 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # The query_blocker extension adds Database#block_queries.
4
+ # Inside the block passed to #block_queries, any attempts to
5
+ # execute a query/statement on the database will raise a
6
+ # Sequel::QueryBlocker::BlockedQuery exception.
7
+ #
8
+ # DB.extension :query_blocker
9
+ # DB.block_queries do
10
+ # ds = DB[:table] # No exception
11
+ # ds = ds.where(column: 1) # No exception
12
+ # ds.all # Exception raised
13
+ # end
14
+ #
15
+ # To handle concurrency, you can pass a :scope option:
16
+ #
17
+ # # Current Thread
18
+ # DB.block_queries(scope: :thread){}
19
+ #
20
+ # # Current Fiber
21
+ # DB.block_queries(scope: :fiber){}
22
+ #
23
+ # # Specific Thread
24
+ # DB.block_queries(scope: Thread.current){}
25
+ #
26
+ # # Specific Fiber
27
+ # DB.block_queries(scope: Fiber.current){}
28
+ #
29
+ # Database#block_queries is useful for blocking queries inside
30
+ # the block. However, there may be cases where you want to
31
+ # allow queries in specific places inside a block_queries block.
32
+ # You can use Database#allow_queries for that:
33
+ #
34
+ # DB.block_queries do
35
+ # DB.allow_queries do
36
+ # DB[:table].all # Query allowed
37
+ # end
38
+ #
39
+ # DB[:table].all # Exception raised
40
+ # end
41
+ #
42
+ # When mixing block_queries and allow_queries with scopes, the
43
+ # narrowest scope has priority. So if you are blocking with
44
+ # :thread scope, and allowing with :fiber scope, queries in the
45
+ # current fiber will be allowed, but queries in different fibers of
46
+ # the current thread will be blocked.
47
+ #
48
+ # Note that this should catch all queries executed through the
49
+ # Database instance. Whether it catches queries executed directly
50
+ # on a connection object depends on the adapter in use.
51
+ #
52
+ # Related module: Sequel::QueryBlocker
53
+
54
+ require "fiber"
55
+
56
+ #
57
+ module Sequel
58
+ module QueryBlocker
59
+ # Exception class raised if there is an attempt to execute a
60
+ # query/statement on the database inside a block passed to
61
+ # block_queries.
62
+ class BlockedQuery < Sequel::Error
63
+ end
64
+
65
+ def self.extended(db)
66
+ db.instance_exec do
67
+ @blocked_query_scopes ||= {}
68
+ end
69
+ end
70
+
71
+ # If checking a connection for validity, and a BlockedQuery exception is
72
+ # raised, treat it as a valid connection. You cannot check whether the
73
+ # connection is valid without issuing a query, and if queries are blocked,
74
+ # you need to assume it is valid or assume it is not. Since it most cases
75
+ # it will be valid, this assumes validity.
76
+ def valid_connection?(conn)
77
+ super
78
+ rescue BlockedQuery
79
+ true
80
+ end
81
+
82
+ # Check whether queries are blocked before executing them.
83
+ def log_connection_yield(sql, conn, args=nil)
84
+ # All database adapters should be calling this method around
85
+ # query execution (otherwise the queries would not get logged),
86
+ # ensuring the blocking is checked. Any database adapter issuing
87
+ # a query without calling this method is considered buggy.
88
+ check_blocked_queries!
89
+ super
90
+ end
91
+
92
+ # Whether queries are currently blocked.
93
+ def block_queries?
94
+ b = @blocked_query_scopes
95
+ b.fetch(Fiber.current) do
96
+ b.fetch(Thread.current) do
97
+ b.fetch(:global, false)
98
+ end
99
+ end
100
+ end
101
+
102
+ # Allow queries inside the block. Only useful if they are already blocked
103
+ # for the same scope. Useful for blocking queries generally, and only allowing
104
+ # them in specific places. Takes the same :scope option as #block_queries.
105
+ def allow_queries(opts=OPTS, &block)
106
+ _allow_or_block_queries(false, opts, &block)
107
+ end
108
+
109
+ # Reject (raise an BlockedQuery exception) if there is an attempt to execute
110
+ # a query/statement inside the block.
111
+ #
112
+ # The :scope option indicates which queries are rejected inside the block:
113
+ #
114
+ # :global :: This is the default, and rejects all queries.
115
+ # :thread :: Reject all queries in the current thread.
116
+ # :fiber :: Reject all queries in the current fiber.
117
+ # Thread :: Reject all queries in the given thread.
118
+ # Fiber :: Reject all queries in the given fiber.
119
+ def block_queries(opts=OPTS, &block)
120
+ _allow_or_block_queries(true, opts, &block)
121
+ end
122
+
123
+ private
124
+
125
+ # Internals of block_queries and allow_queries.
126
+ def _allow_or_block_queries(value, opts)
127
+ scope = query_blocker_scope(opts)
128
+ prev_value = nil
129
+ scopes = @blocked_query_scopes
130
+
131
+ begin
132
+ Sequel.synchronize do
133
+ prev_value = scopes[scope]
134
+ scopes[scope] = value
135
+ end
136
+
137
+ yield
138
+ ensure
139
+ Sequel.synchronize do
140
+ if prev_value.nil?
141
+ scopes.delete(scope)
142
+ else
143
+ scopes[scope] = prev_value
144
+ end
145
+ end
146
+ end
147
+ end
148
+
149
+ # The scope for the query block, either :global, or a Thread or Fiber instance.
150
+ def query_blocker_scope(opts)
151
+ case scope = opts[:scope]
152
+ when nil
153
+ :global
154
+ when :global, Thread, Fiber
155
+ scope
156
+ when :thread
157
+ Thread.current
158
+ when :fiber
159
+ Fiber.current
160
+ else
161
+ raise Sequel::Error, "invalid scope given to block_queries: #{scope.inspect}"
162
+ end
163
+ end
164
+
165
+ # Raise a BlockQuery exception if queries are currently blocked.
166
+ def check_blocked_queries!
167
+ raise BlockedQuery, "cannot execute query inside a block_queries block" if block_queries?
168
+ end
169
+ end
170
+
171
+ Database.register_extension(:query_blocker, QueryBlocker)
172
+ end
@@ -51,14 +51,7 @@ module Sequel
51
51
  module SchemaCaching
52
52
  # Dump the cached schema to the filename given in Marshal format.
53
53
  def dump_schema_cache(file)
54
- sch = {}
55
- @schemas.sort.each do |k,v|
56
- sch[k] = v.map do |c, h|
57
- h = Hash[h]
58
- h.delete(:callable_default)
59
- [c, h]
60
- end
61
- end
54
+ sch = dumpable_schema_cache
62
55
  File.open(file, 'wb'){|f| f.write(Marshal.dump(sch))}
63
56
  nil
64
57
  end
@@ -72,7 +65,7 @@ module Sequel
72
65
  # Replace the schema cache with the data from the given file, which
73
66
  # should be in Marshal format.
74
67
  def load_schema_cache(file)
75
- @schemas = Marshal.load(File.read(file))
68
+ @schemas = load_schema_cache_file(file)
76
69
  @schemas.each_value{|v| schema_post_process(v)}
77
70
  nil
78
71
  end
@@ -82,6 +75,28 @@ module Sequel
82
75
  def load_schema_cache?(file)
83
76
  load_schema_cache(file) if File.exist?(file)
84
77
  end
78
+
79
+ private
80
+
81
+ # Return the deserialized schema cache file.
82
+ def load_schema_cache_file(file)
83
+ Marshal.load(File.read(file))
84
+ end
85
+
86
+ # A dumpable version of the schema cache.
87
+ def dumpable_schema_cache
88
+ sch = {}
89
+
90
+ @schemas.sort.each do |k,v|
91
+ sch[k] = v.map do |c, h|
92
+ h = Hash[h]
93
+ h.delete(:callable_default)
94
+ [c, h]
95
+ end
96
+ end
97
+
98
+ sch
99
+ end
85
100
  end
86
101
 
87
102
  Database.register_extension(:schema_caching, SchemaCaching)
@@ -27,6 +27,11 @@ Sequel.extension :eval_inspect
27
27
 
28
28
  module Sequel
29
29
  module SchemaDumper
30
+ # :nocov:
31
+ IGNORE_INDEX_ERRORS_KEY = RUBY_VERSION >= '3.4' ? 'ignore_index_errors: ' : ':ignore_index_errors=>'
32
+ # :nocov:
33
+ private_constant :IGNORE_INDEX_ERRORS_KEY
34
+
30
35
  # Convert the column schema information to a hash of column options, one of which must
31
36
  # be :type. The other options added should modify that type (e.g. :size). If a
32
37
  # database type is not recognized, return it as a String type.
@@ -161,7 +166,7 @@ END_MIG
161
166
  def dump_table_schema(table, options=OPTS)
162
167
  gen = dump_table_generator(table, options)
163
168
  commands = [gen.dump_columns, gen.dump_constraints, gen.dump_indexes].reject{|x| x == ''}.join("\n\n")
164
- "create_table(#{table.inspect}#{', :ignore_index_errors=>true' if !options[:same_db] && options[:indexes] != false && !gen.indexes.empty?}) do\n#{commands.gsub(/^/, ' ')}\nend"
169
+ "create_table(#{table.inspect}#{", #{IGNORE_INDEX_ERRORS_KEY}true" if !options[:same_db] && options[:indexes] != false && !gen.indexes.empty?}) do\n#{commands.gsub(/^/, ' ')}\nend"
165
170
  end
166
171
 
167
172
  private
@@ -252,7 +257,7 @@ END_MIG
252
257
  gen.foreign_key(name, table, col_opts)
253
258
  else
254
259
  gen.column(name, type, col_opts)
255
- if [Integer, :Bignum, Float, BigDecimal].include?(type) && schema[:db_type] =~ / unsigned\z/io
260
+ if [Integer, :Bignum, Float, BigDecimal].include?(type) && schema[:db_type] =~ / unsigned\z/i
256
261
  gen.check(Sequel::SQL::Identifier.new(name) >= 0)
257
262
  end
258
263
  end
@@ -425,6 +430,13 @@ END_MIG
425
430
 
426
431
  module Schema
427
432
  class CreateTableGenerator
433
+ # :nocov:
434
+ DEFAULT_KEY = RUBY_VERSION >= '3.4' ? 'default: ' : ':default=>'
435
+ IGNORE_ERRORS_KEY = RUBY_VERSION >= '3.4' ? 'ignore_errors: ' : ':ignore_errors=>'
436
+ # :nocov:
437
+ private_constant :DEFAULT_KEY
438
+ private_constant :IGNORE_ERRORS_KEY
439
+
428
440
  # Dump this generator's columns to a string that could be evaled inside
429
441
  # another instance to represent the same columns
430
442
  def dump_columns
@@ -508,7 +520,7 @@ END_MIG
508
520
  c = c.dup
509
521
  cols = c.delete(:columns)
510
522
  if table = options[:add_index] || options[:drop_index]
511
- "#{options[:drop_index] ? 'drop' : 'add'}_index #{table.inspect}, #{cols.inspect}#{', :ignore_errors=>true' if options[:ignore_errors]}#{opts_inspect(c)}"
523
+ "#{options[:drop_index] ? 'drop' : 'add'}_index #{table.inspect}, #{cols.inspect}#{", #{IGNORE_ERRORS_KEY}true" if options[:ignore_errors]}#{opts_inspect(c)}"
512
524
  else
513
525
  "index #{cols.inspect}#{opts_inspect(c)}"
514
526
  end
@@ -526,7 +538,7 @@ END_MIG
526
538
  if opts[:default]
527
539
  opts = opts.dup
528
540
  de = Sequel.eval_inspect(opts.delete(:default))
529
- ", :default=>#{de}#{", #{opts.inspect[1...-1]}" if opts.length > 0}"
541
+ ", #{DEFAULT_KEY}#{de}#{", #{opts.inspect[1...-1]}" if opts.length > 0}"
530
542
  else
531
543
  ", #{opts.inspect[1...-1]}" if opts.length > 0
532
544
  end
@@ -35,7 +35,7 @@
35
35
  #
36
36
  # j[1] # (json_column ->> 1)
37
37
  # j.get(1) # (json_column ->> 1)
38
- # j.get_text(1) # (json_column -> 1)
38
+ # j.get_json(1) # (json_column -> 1)
39
39
  # j.extract('$.a') # json_extract(json_column, '$.a')
40
40
  # jb.extract('$.a') # jsonb_extract(jsonb_column, '$.a')
41
41
  #
@@ -0,0 +1,48 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # The stdio_logger extension exposes a Sequel::StdioLogger class that
4
+ # can be used for logging with Sequel, as a minimal alternative to
5
+ # the logger library. It exposes debug/info/warn/error methods for the
6
+ # different warning levels. The debug method is a no-op, so that setting
7
+ # the Database sql_log_level to debug will result in no output for normal
8
+ # queries. The info/warn/error methods log the current time, log level,
9
+ # and the given message.
10
+ #
11
+ # To use this extension:
12
+ #
13
+ # Sequel.extension :stdio_logger
14
+ #
15
+ # Then you you can use Sequel::StdioLogger to wrap IO objects that you
16
+ # would like Sequel to log to:
17
+ #
18
+ # DB.loggers << Sequel::StdioLogger.new($stdout)
19
+ #
20
+ # log_file = File.open("db_queries.log", 'a')
21
+ # log_file.sync = true
22
+ # DB.loggers << Sequel::StdioLogger.new(log_file)
23
+ #
24
+ # This is implemented as a global extension instead of a Database extension
25
+ # because Database loggers must be set before Database extensions are loaded.
26
+ #
27
+ # Related module: Sequel::StdioLogger
28
+
29
+ #
30
+ module Sequel
31
+ class StdioLogger
32
+ def initialize(device)
33
+ @device = device
34
+ end
35
+
36
+ # Do not log debug messages. This is so setting the Database
37
+ # sql_log_level to debug will result in no output.
38
+ def debug(msg)
39
+ end
40
+
41
+ [:info, :warn, :error].each do |meth|
42
+ define_method(meth) do |msg|
43
+ @device.write("#{Time.now.strftime('%F %T')} #{meth.to_s.upcase}: #{msg}\n")
44
+ nil
45
+ end
46
+ end
47
+ end
48
+ end
@@ -54,6 +54,7 @@
54
54
  # * MySQL
55
55
  # * HSQLDB
56
56
  # * H2
57
+ # * SQLite 3.44+ (distinct only works when separator is ',')
57
58
  #
58
59
  # Related module: Sequel::SQL::StringAgg
59
60
 
@@ -94,6 +95,19 @@ module Sequel
94
95
  distinct = sa.is_distinct?
95
96
 
96
97
  case db_type = db.database_type
98
+ when :sqlite
99
+ raise Error, "string_agg(DISTINCT) is not supported with a non-comma separator on #{db.database_type}" if distinct && separator != ","
100
+
101
+ args = [expr]
102
+ args << separator unless distinct
103
+ f = Function.new(:group_concat, *args)
104
+ if order
105
+ f = f.order(*order)
106
+ end
107
+ if distinct
108
+ f = f.distinct
109
+ end
110
+ literal_append(sql, f)
97
111
  when :postgres, :sqlanywhere
98
112
  f = Function.new(db_type == :postgres ? :string_agg : :list, expr, separator)
99
113
  if order
@@ -151,7 +165,7 @@ module Sequel
151
165
  freeze
152
166
  end
153
167
 
154
- # Whether the current expression uses distinct expressions
168
+ # Whether the current expression uses distinct expressions
155
169
  def is_distinct?
156
170
  @distinct == true
157
171
  end
@@ -159,7 +173,7 @@ module Sequel
159
173
  # Return a modified StringAgg that uses distinct expressions
160
174
  def distinct
161
175
  self.class.new(@expr, @separator) do |sa|
162
- sa.instance_variable_set(:@order_expr, @order_expr) if @order_expr
176
+ sa.instance_variable_set(:@order_expr, @order_expr)
163
177
  sa.instance_variable_set(:@distinct, true)
164
178
  end
165
179
  end
@@ -167,8 +181,8 @@ module Sequel
167
181
  # Return a modified StringAgg with the given order
168
182
  def order(*o)
169
183
  self.class.new(@expr, @separator) do |sa|
170
- sa.instance_variable_set(:@distinct, @distinct) if @distinct
171
184
  sa.instance_variable_set(:@order_expr, o.empty? ? nil : o.freeze)
185
+ sa.instance_variable_set(:@distinct, @distinct)
172
186
  end
173
187
  end
174
188
 
@@ -178,4 +192,3 @@ module Sequel
178
192
 
179
193
  Dataset.register_extension(:string_agg, SQL::StringAgg::DatasetMethods)
180
194
  end
181
-