sequel 5.48.0 → 5.52.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +80 -0
- data/README.rdoc +12 -5
- data/doc/migration.rdoc +1 -1
- data/doc/opening_databases.rdoc +1 -1
- data/doc/postgresql.rdoc +8 -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/testing.rdoc +3 -1
- data/lib/sequel/adapters/ado/access.rb +1 -1
- data/lib/sequel/adapters/ado.rb +1 -1
- data/lib/sequel/adapters/amalgalite.rb +3 -5
- data/lib/sequel/adapters/ibmdb.rb +2 -2
- data/lib/sequel/adapters/jdbc/derby.rb +3 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +4 -4
- data/lib/sequel/adapters/jdbc.rb +9 -11
- data/lib/sequel/adapters/mysql.rb +80 -67
- data/lib/sequel/adapters/mysql2.rb +42 -44
- data/lib/sequel/adapters/odbc.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +3 -3
- data/lib/sequel/adapters/postgres.rb +27 -29
- data/lib/sequel/adapters/shared/access.rb +2 -0
- data/lib/sequel/adapters/shared/db2.rb +2 -0
- data/lib/sequel/adapters/shared/mysql.rb +4 -2
- data/lib/sequel/adapters/shared/postgres.rb +59 -6
- data/lib/sequel/adapters/shared/sqlanywhere.rb +3 -0
- data/lib/sequel/adapters/shared/sqlite.rb +1 -1
- data/lib/sequel/adapters/sqlanywhere.rb +1 -1
- data/lib/sequel/adapters/sqlite.rb +16 -18
- data/lib/sequel/adapters/tinytds.rb +1 -1
- data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
- data/lib/sequel/ast_transformer.rb +6 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -7
- data/lib/sequel/connection_pool/single.rb +6 -8
- data/lib/sequel/core.rb +17 -18
- data/lib/sequel/database/connecting.rb +2 -2
- data/lib/sequel/database/misc.rb +6 -0
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/dataset/actions.rb +2 -2
- data/lib/sequel/dataset/query.rb +45 -3
- data/lib/sequel/dataset/sql.rb +18 -9
- data/lib/sequel/extensions/any_not_empty.rb +1 -1
- data/lib/sequel/extensions/core_refinements.rb +36 -11
- 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 +1 -1
- data/lib/sequel/extensions/inflector.rb +1 -1
- data/lib/sequel/extensions/migration.rb +4 -1
- data/lib/sequel/extensions/pagination.rb +1 -1
- data/lib/sequel/extensions/pg_array_ops.rb +1 -1
- data/lib/sequel/extensions/pg_extended_date_support.rb +1 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +53 -3
- data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
- data/lib/sequel/extensions/pg_interval.rb +1 -0
- data/lib/sequel/extensions/pg_json.rb +3 -5
- data/lib/sequel/extensions/pg_json_ops.rb +71 -1
- data/lib/sequel/extensions/pg_multirange.rb +372 -0
- data/lib/sequel/extensions/pg_range.rb +4 -12
- data/lib/sequel/extensions/pg_range_ops.rb +37 -9
- data/lib/sequel/extensions/pg_row_ops.rb +1 -1
- data/lib/sequel/extensions/s.rb +2 -1
- data/lib/sequel/extensions/server_block.rb +8 -12
- data/lib/sequel/extensions/sql_comments.rb +108 -3
- data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
- data/lib/sequel/extensions/string_agg.rb +1 -1
- data/lib/sequel/extensions/string_date_time.rb +19 -23
- data/lib/sequel/model/associations.rb +3 -1
- data/lib/sequel/model/base.rb +9 -13
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/plugins/auto_validations.rb +25 -5
- data/lib/sequel/plugins/column_encryption.rb +1 -1
- data/lib/sequel/plugins/composition.rb +1 -0
- data/lib/sequel/plugins/json_serializer.rb +2 -2
- data/lib/sequel/plugins/lazy_attributes.rb +3 -0
- data/lib/sequel/plugins/serialization.rb +1 -0
- data/lib/sequel/plugins/serialization_modification_detection.rb +1 -0
- data/lib/sequel/plugins/sql_comments.rb +189 -0
- data/lib/sequel/plugins/static_cache.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/unused_associations.rb +2 -2
- data/lib/sequel/plugins/update_or_create.rb +1 -1
- data/lib/sequel/plugins/validation_helpers.rb +7 -1
- data/lib/sequel/plugins/xml_serializer.rb +1 -1
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/timezones.rb +12 -14
- data/lib/sequel/version.rb +1 -1
- metadata +17 -4
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
require 'mysql'
|
4
|
-
raise(LoadError, "require 'mysql' did not define Mysql::CLIENT_MULTI_RESULTS
|
4
|
+
raise(LoadError, "require 'mysql' did not define Mysql::CLIENT_MULTI_RESULTS!, so it not supported. Please install the mysql or ruby-mysql gem.\n") unless defined?(Mysql::CLIENT_MULTI_RESULTS)
|
5
5
|
|
6
6
|
require_relative 'utils/mysql_mysql2'
|
7
7
|
require_relative 'utils/mysql_prepared_statements'
|
@@ -71,21 +71,43 @@ module Sequel
|
|
71
71
|
# disconnect this connection (a.k.a @@wait_timeout).
|
72
72
|
def connect(server)
|
73
73
|
opts = server_opts(server)
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
74
|
+
|
75
|
+
if Mysql.respond_to?(:init)
|
76
|
+
conn = Mysql.init
|
77
|
+
conn.options(Mysql::READ_DEFAULT_GROUP, opts[:config_default_group] || "client")
|
78
|
+
conn.options(Mysql::OPT_LOCAL_INFILE, opts[:config_local_infile]) if opts.has_key?(:config_local_infile)
|
79
|
+
if encoding = opts[:encoding] || opts[:charset]
|
80
|
+
# Set encoding before connecting so that the mysql driver knows what
|
81
|
+
# encoding we want to use, but this can be overridden by READ_DEFAULT_GROUP.
|
82
|
+
conn.options(Mysql::SET_CHARSET_NAME, encoding)
|
83
|
+
end
|
84
|
+
if read_timeout = opts[:read_timeout] and defined? Mysql::OPT_READ_TIMEOUT
|
85
|
+
conn.options(Mysql::OPT_READ_TIMEOUT, read_timeout)
|
86
|
+
end
|
87
|
+
if connect_timeout = opts[:connect_timeout] and defined? Mysql::OPT_CONNECT_TIMEOUT
|
88
|
+
conn.options(Mysql::OPT_CONNECT_TIMEOUT, connect_timeout)
|
89
|
+
end
|
90
|
+
else
|
91
|
+
# ruby-mysql 3 API
|
92
|
+
conn = Mysql.new
|
93
|
+
# no support for default group
|
94
|
+
conn.local_infile = opts[:config_local_infile] if opts.has_key?(:config_local_infile)
|
95
|
+
if encoding = opts[:encoding] || opts[:charset]
|
96
|
+
conn.charset = encoding
|
97
|
+
end
|
98
|
+
if read_timeout = opts[:read_timeout]
|
99
|
+
conn.read_timeout = read_timeout
|
100
|
+
end
|
101
|
+
if connect_timeout = opts[:connect_timeout]
|
102
|
+
conn.connect_timeout = connect_timeout
|
103
|
+
end
|
104
|
+
conn.singleton_class.class_eval do
|
105
|
+
alias real_connect connect
|
106
|
+
alias use_result store_result
|
107
|
+
end
|
88
108
|
end
|
109
|
+
|
110
|
+
conn.ssl_set(opts[:sslkey], opts[:sslcert], opts[:sslca], opts[:sslcapath], opts[:sslcipher]) if opts[:sslca] || opts[:sslkey]
|
89
111
|
conn.real_connect(
|
90
112
|
opts[:host] || 'localhost',
|
91
113
|
opts[:user],
|
@@ -152,56 +174,49 @@ module Sequel
|
|
152
174
|
super
|
153
175
|
end
|
154
176
|
|
155
|
-
# Return the version of the MySQL server to which we are connecting.
|
156
|
-
def server_version(server=nil)
|
157
|
-
@server_version ||= (synchronize(server){|conn| conn.server_version if conn.respond_to?(:server_version)} || super)
|
158
|
-
end
|
159
|
-
|
160
177
|
private
|
161
178
|
|
162
179
|
# Execute the given SQL on the given connection. If the :type
|
163
180
|
# option is :select, yield the result of the query, otherwise
|
164
181
|
# yield the connection if a block is given.
|
165
182
|
def _execute(conn, sql, opts)
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
break
|
185
|
-
end
|
186
|
-
yield r if opts[:type] == :select
|
183
|
+
r = log_connection_yield((log_sql = opts[:log_sql]) ? sql + log_sql : sql, conn){conn.query(sql)}
|
184
|
+
if opts[:type] == :select
|
185
|
+
yield r if r
|
186
|
+
elsif defined?(yield)
|
187
|
+
yield conn
|
188
|
+
end
|
189
|
+
if conn.respond_to?(:more_results?)
|
190
|
+
while conn.more_results? do
|
191
|
+
if r
|
192
|
+
r.free
|
193
|
+
r = nil
|
194
|
+
end
|
195
|
+
begin
|
196
|
+
conn.next_result
|
197
|
+
r = conn.use_result
|
198
|
+
rescue Mysql::Error => e
|
199
|
+
raise_error(e, :disconnect=>true) if MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message)
|
200
|
+
break
|
187
201
|
end
|
202
|
+
yield r if opts[:type] == :select
|
188
203
|
end
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
r.free if r
|
204
|
+
end
|
205
|
+
rescue Mysql::Error => e
|
206
|
+
raise_error(e)
|
207
|
+
ensure
|
208
|
+
r.free if r
|
209
|
+
# Use up all results to avoid a commands out of sync message.
|
210
|
+
if conn.respond_to?(:more_results?)
|
211
|
+
while conn.more_results? do
|
212
|
+
begin
|
213
|
+
conn.next_result
|
214
|
+
r = conn.use_result
|
215
|
+
rescue Mysql::Error => e
|
216
|
+
raise_error(e, :disconnect=>true) if MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message)
|
217
|
+
break
|
204
218
|
end
|
219
|
+
r.free if r
|
205
220
|
end
|
206
221
|
end
|
207
222
|
end
|
@@ -233,17 +248,15 @@ module Sequel
|
|
233
248
|
# the conversion raises an InvalidValue exception, return v
|
234
249
|
# if :string and nil otherwise.
|
235
250
|
def convert_date_time(v)
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
raise
|
246
|
-
end
|
251
|
+
yield v
|
252
|
+
rescue InvalidValue
|
253
|
+
case @convert_invalid_date_time
|
254
|
+
when nil, :nil
|
255
|
+
nil
|
256
|
+
when :string
|
257
|
+
v
|
258
|
+
else
|
259
|
+
raise
|
247
260
|
end
|
248
261
|
end
|
249
262
|
|
@@ -111,56 +111,54 @@ module Sequel
|
|
111
111
|
# option is :select, yield the result of the query, otherwise
|
112
112
|
# yield the connection if a block is given.
|
113
113
|
def _execute(conn, sql, opts)
|
114
|
-
|
115
|
-
|
116
|
-
if
|
117
|
-
|
118
|
-
|
119
|
-
end
|
114
|
+
stream = opts[:stream]
|
115
|
+
if NativePreparedStatements
|
116
|
+
if args = opts[:arguments]
|
117
|
+
args = args.map{|arg| bound_variable_value(arg)}
|
118
|
+
end
|
120
119
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
end
|
120
|
+
case sql
|
121
|
+
when ::Mysql2::Statement
|
122
|
+
stmt = sql
|
123
|
+
when Dataset
|
124
|
+
sql = sql.sql
|
125
|
+
close_stmt = true
|
126
|
+
stmt = conn.prepare(sql)
|
129
127
|
end
|
128
|
+
end
|
130
129
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
end
|
130
|
+
r = log_connection_yield((log_sql = opts[:log_sql]) ? sql + log_sql : sql, conn, args) do
|
131
|
+
if stmt
|
132
|
+
conn.query_options.merge!(:cache_rows=>true, :database_timezone => timezone, :application_timezone => Sequel.application_timezone, :stream=>stream, :cast_booleans=>convert_tinyint_to_bool)
|
133
|
+
stmt.execute(*args)
|
134
|
+
else
|
135
|
+
conn.query(sql, :database_timezone => timezone, :application_timezone => Sequel.application_timezone, :stream=>stream)
|
138
136
|
end
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
else
|
151
|
-
yield r
|
137
|
+
end
|
138
|
+
if opts[:type] == :select
|
139
|
+
if r
|
140
|
+
if stream
|
141
|
+
begin
|
142
|
+
r2 = yield r
|
143
|
+
ensure
|
144
|
+
# If r2 is nil, it means the block did not exit normally,
|
145
|
+
# so the rest of the results must be drained to prevent
|
146
|
+
# "commands out of sync" errors.
|
147
|
+
r.each{} unless r2
|
152
148
|
end
|
149
|
+
else
|
150
|
+
yield r
|
153
151
|
end
|
154
|
-
elsif block_given?
|
155
|
-
yield conn
|
156
|
-
end
|
157
|
-
rescue ::Mysql2::Error => e
|
158
|
-
raise_error(e)
|
159
|
-
ensure
|
160
|
-
if stmt
|
161
|
-
conn.query_options.replace(conn.instance_variable_get(:@sequel_default_query_options))
|
162
|
-
stmt.close if close_stmt
|
163
152
|
end
|
153
|
+
elsif defined?(yield)
|
154
|
+
yield conn
|
155
|
+
end
|
156
|
+
rescue ::Mysql2::Error => e
|
157
|
+
raise_error(e)
|
158
|
+
ensure
|
159
|
+
if stmt
|
160
|
+
conn.query_options.replace(conn.instance_variable_get(:@sequel_default_query_options))
|
161
|
+
stmt.close if close_stmt
|
164
162
|
end
|
165
163
|
end
|
166
164
|
|
@@ -244,7 +242,7 @@ module Sequel
|
|
244
242
|
# it hasn't been disabled.
|
245
243
|
def paged_each(opts=OPTS, &block)
|
246
244
|
if STREAMING_SUPPORTED && opts[:stream] != false
|
247
|
-
unless
|
245
|
+
unless defined?(yield)
|
248
246
|
return enum_for(:paged_each, opts)
|
249
247
|
end
|
250
248
|
stream.each(&block)
|
data/lib/sequel/adapters/odbc.rb
CHANGED
@@ -88,11 +88,11 @@ module Sequel
|
|
88
88
|
r = conn.parse(sql)
|
89
89
|
args = cursor_bind_params(conn, r, args)
|
90
90
|
nr = log_connection_yield(sql, conn, args){r.exec}
|
91
|
-
r = nr unless
|
91
|
+
r = nr unless defined?(yield)
|
92
92
|
else
|
93
93
|
r = log_connection_yield(sql, conn){conn.exec(sql)}
|
94
94
|
end
|
95
|
-
if
|
95
|
+
if defined?(yield)
|
96
96
|
yield(r)
|
97
97
|
elsif type == :insert
|
98
98
|
last_insert_id(conn, opts)
|
@@ -192,7 +192,7 @@ module Sequel
|
|
192
192
|
log_sql << ")"
|
193
193
|
end
|
194
194
|
r = log_connection_yield(log_sql, conn, args){cursor.exec}
|
195
|
-
if
|
195
|
+
if defined?(yield)
|
196
196
|
yield(cursor)
|
197
197
|
elsif type == :insert
|
198
198
|
last_insert_id(conn, opts)
|
@@ -116,25 +116,23 @@ module Sequel
|
|
116
116
|
# error classes is raised, or a PGError is raised and the connection
|
117
117
|
# status cannot be determined or it is not OK.
|
118
118
|
def check_disconnect_errors
|
119
|
+
yield
|
120
|
+
rescue *DISCONNECT_ERROR_CLASSES => e
|
121
|
+
disconnect = true
|
122
|
+
raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError))
|
123
|
+
rescue PGError => e
|
124
|
+
disconnect = false
|
119
125
|
begin
|
120
|
-
|
121
|
-
rescue
|
126
|
+
s = status
|
127
|
+
rescue PGError
|
122
128
|
disconnect = true
|
123
|
-
raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError))
|
124
|
-
rescue PGError => e
|
125
|
-
disconnect = false
|
126
|
-
begin
|
127
|
-
s = status
|
128
|
-
rescue PGError
|
129
|
-
disconnect = true
|
130
|
-
end
|
131
|
-
status_ok = (s == Adapter::CONNECTION_OK)
|
132
|
-
disconnect ||= !status_ok
|
133
|
-
disconnect ||= e.message =~ DISCONNECT_ERROR_RE
|
134
|
-
disconnect ? raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError)) : raise
|
135
|
-
ensure
|
136
|
-
block if status_ok && !disconnect
|
137
129
|
end
|
130
|
+
status_ok = (s == Adapter::CONNECTION_OK)
|
131
|
+
disconnect ||= !status_ok
|
132
|
+
disconnect ||= e.message =~ DISCONNECT_ERROR_RE
|
133
|
+
disconnect ? raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError)) : raise
|
134
|
+
ensure
|
135
|
+
block if status_ok && !disconnect
|
138
136
|
end
|
139
137
|
|
140
138
|
# Execute the given SQL with this connection. If a block is given,
|
@@ -143,7 +141,7 @@ module Sequel
|
|
143
141
|
args = args.map{|v| @db.bound_variable_arg(v, self)} if args
|
144
142
|
q = check_disconnect_errors{execute_query(sql, args)}
|
145
143
|
begin
|
146
|
-
|
144
|
+
defined?(yield) ? yield(q) : q.cmd_tuples
|
147
145
|
ensure
|
148
146
|
q.clear if q && q.respond_to?(:clear)
|
149
147
|
end
|
@@ -350,7 +348,7 @@ module Sequel
|
|
350
348
|
synchronize(opts[:server]) do |conn|
|
351
349
|
conn.execute(copy_table_sql(table, opts))
|
352
350
|
begin
|
353
|
-
if
|
351
|
+
if defined?(yield)
|
354
352
|
while buf = conn.get_copy_data
|
355
353
|
yield buf
|
356
354
|
end
|
@@ -400,16 +398,16 @@ module Sequel
|
|
400
398
|
data = opts[:data]
|
401
399
|
data = Array(data) if data.is_a?(String)
|
402
400
|
|
403
|
-
if
|
401
|
+
if defined?(yield) && data
|
404
402
|
raise Error, "Cannot provide both a :data option and a block to copy_into"
|
405
|
-
elsif !
|
403
|
+
elsif !defined?(yield) && !data
|
406
404
|
raise Error, "Must provide either a :data option or a block to copy_into"
|
407
405
|
end
|
408
406
|
|
409
407
|
synchronize(opts[:server]) do |conn|
|
410
408
|
conn.execute(copy_into_sql(table, opts))
|
411
409
|
begin
|
412
|
-
if
|
410
|
+
if defined?(yield)
|
413
411
|
while buf = yield
|
414
412
|
conn.put_copy_data(buf)
|
415
413
|
end
|
@@ -518,11 +516,9 @@ module Sequel
|
|
518
516
|
|
519
517
|
# Convert exceptions raised from the block into DatabaseErrors.
|
520
518
|
def check_database_errors
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
raise_error(e, :classes=>database_error_classes)
|
525
|
-
end
|
519
|
+
yield
|
520
|
+
rescue => e
|
521
|
+
raise_error(e, :classes=>database_error_classes)
|
526
522
|
end
|
527
523
|
|
528
524
|
# Set the DateStyle to ISO if configured, for faster date parsing.
|
@@ -590,7 +586,7 @@ module Sequel
|
|
590
586
|
|
591
587
|
q = conn.check_disconnect_errors{log_connection_yield(log_sql, conn, args){_execute_prepared_statement(conn, ps_name, args, opts)}}
|
592
588
|
begin
|
593
|
-
|
589
|
+
defined?(yield) ? yield(q) : q.cmd_tuples
|
594
590
|
ensure
|
595
591
|
q.clear if q && q.respond_to?(:clear)
|
596
592
|
end
|
@@ -616,7 +612,7 @@ module Sequel
|
|
616
612
|
|
617
613
|
# Use a cursor for paging.
|
618
614
|
def paged_each(opts=OPTS, &block)
|
619
|
-
unless
|
615
|
+
unless defined?(yield)
|
620
616
|
return enum_for(:paged_each, opts)
|
621
617
|
end
|
622
618
|
use_cursor(opts).each(&block)
|
@@ -717,7 +713,9 @@ module Sequel
|
|
717
713
|
sql = String.new
|
718
714
|
sql << "CALL "
|
719
715
|
identifier_append(sql, name)
|
720
|
-
|
716
|
+
sql << "("
|
717
|
+
expression_list_append(sql, args)
|
718
|
+
sql << ")"
|
721
719
|
with_sql_first(sql)
|
722
720
|
end
|
723
721
|
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative '../utils/emulate_offset_with_reverse_and_count'
|
4
4
|
require_relative '../utils/unmodified_identifiers'
|
5
|
+
require_relative '../utils/columns_limit_1'
|
5
6
|
|
6
7
|
module Sequel
|
7
8
|
module Access
|
@@ -83,6 +84,7 @@ module Sequel
|
|
83
84
|
end)
|
84
85
|
include EmulateOffsetWithReverseAndCount
|
85
86
|
include UnmodifiedIdentifiers::DatasetMethods
|
87
|
+
include ::Sequel::Dataset::ColumnsLimit1
|
86
88
|
|
87
89
|
EXTRACT_MAP = {:year=>"'yyyy'", :month=>"'m'", :day=>"'d'", :hour=>"'h'", :minute=>"'n'", :second=>"'s'"}.freeze
|
88
90
|
EXTRACT_MAP.each_value(&:freeze)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
require_relative '../utils/emulate_offset_with_row_number'
|
4
|
+
require_relative '../utils/columns_limit_1'
|
4
5
|
|
5
6
|
module Sequel
|
6
7
|
module DB2
|
@@ -273,6 +274,7 @@ module Sequel
|
|
273
274
|
|
274
275
|
module DatasetMethods
|
275
276
|
include EmulateOffsetWithRowNumber
|
277
|
+
include ::Sequel::Dataset::ColumnsLimit1
|
276
278
|
|
277
279
|
BITWISE_METHOD_MAP = {:& =>:BITAND, :| => :BITOR, :^ => :BITXOR, :'B~'=>:BITNOT}.freeze
|
278
280
|
|
@@ -533,6 +533,7 @@ module Sequel
|
|
533
533
|
row[:default] = row.delete(:Default)
|
534
534
|
row[:db_type] = row.delete(:Type)
|
535
535
|
row[:type] = schema_column_type(row[:db_type])
|
536
|
+
row[:extra] = extra
|
536
537
|
[m.call(row.delete(:Field)), row]
|
537
538
|
end
|
538
539
|
end
|
@@ -543,9 +544,10 @@ module Sequel
|
|
543
544
|
server_version >= 50600 && (op[:op] == :drop_index || (op[:op] == :drop_constraint && op[:type] == :unique))
|
544
545
|
end
|
545
546
|
|
546
|
-
#
|
547
|
+
# CHECK constraints only supported on MariaDB 10.2+ and MySQL 8.0.19+
|
548
|
+
# (at least MySQL documents DROP CONSTRAINT was supported in 8.0.19+).
|
547
549
|
def supports_check_constraints?
|
548
|
-
mariadb?
|
550
|
+
server_version >= (mariadb? ? 100200 : 80019)
|
549
551
|
end
|
550
552
|
|
551
553
|
# MySQL can combine multiple alter table ops into a single query.
|
@@ -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
|
@@ -479,6 +479,7 @@ module Sequel
|
|
479
479
|
# :each_row :: Calls the trigger for each row instead of for each statement.
|
480
480
|
# :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
481
|
# the trigger is called for insert, update, or delete.
|
482
|
+
# :replace :: Replace the trigger with the same name if it already exists (PostgreSQL 14+).
|
482
483
|
# :when :: A filter to use for the trigger
|
483
484
|
def create_trigger(table, name, function, opts=OPTS)
|
484
485
|
self << create_trigger_sql(table, name, function, opts)
|
@@ -1237,7 +1238,7 @@ module Sequel
|
|
1237
1238
|
raise Error, "Trigger conditions are not supported for this database" unless supports_trigger_conditions?
|
1238
1239
|
filter = " WHEN #{filter_expr(filter)}"
|
1239
1240
|
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(', ')})"
|
1241
|
+
"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
1242
|
end
|
1242
1243
|
|
1243
1244
|
# DDL fragment for initial part of CREATE VIEW statement
|
@@ -1335,7 +1336,7 @@ module Sequel
|
|
1335
1336
|
ds = metadata_dataset.from(:pg_class).where(:relkind=>type).select(:relname).server(opts[:server]).join(:pg_namespace, :oid=>:relnamespace)
|
1336
1337
|
ds = filter_schema(ds, opts)
|
1337
1338
|
m = output_identifier_meth
|
1338
|
-
if
|
1339
|
+
if defined?(yield)
|
1339
1340
|
yield(ds)
|
1340
1341
|
elsif opts[:qualify]
|
1341
1342
|
ds.select_append{pg_namespace[:nspname]}.map{|r| Sequel.qualify(m.call(r[:nspname]).to_s, m.call(r[:relname]).to_s)}
|
@@ -1503,9 +1504,9 @@ module Sequel
|
|
1503
1504
|
if column[:text]
|
1504
1505
|
:text
|
1505
1506
|
elsif column[:fixed]
|
1506
|
-
"char(#{column[:size]||
|
1507
|
+
"char(#{column[:size]||default_string_column_size})"
|
1507
1508
|
elsif column[:text] == false || column[:size]
|
1508
|
-
"varchar(#{column[:size]||
|
1509
|
+
"varchar(#{column[:size]||default_string_column_size})"
|
1509
1510
|
else
|
1510
1511
|
:text
|
1511
1512
|
end
|
@@ -1727,13 +1728,22 @@ module Sequel
|
|
1727
1728
|
ds.insert_sql(*values)
|
1728
1729
|
end
|
1729
1730
|
|
1731
|
+
# Support SQL::AliasedExpression as expr to setup a USING join with a table alias for the
|
1732
|
+
# USING columns.
|
1733
|
+
def join_table(type, table, expr=nil, options=OPTS, &block)
|
1734
|
+
if expr.is_a?(SQL::AliasedExpression) && expr.expression.is_a?(Array) && !expr.expression.empty? && expr.expression.all?
|
1735
|
+
options = options.merge(:join_using=>true)
|
1736
|
+
end
|
1737
|
+
super
|
1738
|
+
end
|
1739
|
+
|
1730
1740
|
# Locks all tables in the dataset's FROM clause (but not in JOINs) with
|
1731
1741
|
# the specified mode (e.g. 'EXCLUSIVE'). If a block is given, starts
|
1732
1742
|
# a new transaction, locks the table, and yields. If a block is not given,
|
1733
1743
|
# just locks the tables. Note that PostgreSQL will probably raise an error
|
1734
1744
|
# if you lock the table outside of an existing transaction. Returns nil.
|
1735
1745
|
def lock(mode, opts=OPTS)
|
1736
|
-
if
|
1746
|
+
if defined?(yield) # perform locking inside a transaction and yield to block
|
1737
1747
|
@db.transaction(opts){lock(mode, opts); yield}
|
1738
1748
|
else
|
1739
1749
|
sql = 'LOCK TABLE '.dup
|
@@ -2023,6 +2033,17 @@ module Sequel
|
|
2023
2033
|
end
|
2024
2034
|
end
|
2025
2035
|
|
2036
|
+
# Support table aliases for USING columns
|
2037
|
+
def join_using_clause_using_sql_append(sql, using_columns)
|
2038
|
+
if using_columns.is_a?(SQL::AliasedExpression)
|
2039
|
+
super(sql, using_columns.expression)
|
2040
|
+
sql << ' AS '
|
2041
|
+
identifier_append(sql, using_columns.alias)
|
2042
|
+
else
|
2043
|
+
super
|
2044
|
+
end
|
2045
|
+
end
|
2046
|
+
|
2026
2047
|
# Use a generic blob quoting method, hopefully overridden in one of the subadapter methods
|
2027
2048
|
def literal_blob_append(sql, v)
|
2028
2049
|
sql << "'" << v.gsub(/[\000-\037\047\134\177-\377]/n){|b| "\\#{("%o" % b[0..1].unpack("C")[0]).rjust(3, '0')}"} << "'"
|
@@ -2141,6 +2162,38 @@ module Sequel
|
|
2141
2162
|
opts[:with].any?{|w| w[:recursive]} ? "WITH RECURSIVE " : super
|
2142
2163
|
end
|
2143
2164
|
|
2165
|
+
# Support PostgreSQL 14+ CTE SEARCH/CYCLE clauses
|
2166
|
+
def select_with_sql_cte(sql, cte)
|
2167
|
+
super
|
2168
|
+
|
2169
|
+
if search_opts = cte[:search]
|
2170
|
+
sql << if search_opts[:type] == :breadth
|
2171
|
+
" SEARCH BREADTH FIRST BY "
|
2172
|
+
else
|
2173
|
+
" SEARCH DEPTH FIRST BY "
|
2174
|
+
end
|
2175
|
+
|
2176
|
+
identifier_list_append(sql, Array(search_opts[:by]))
|
2177
|
+
sql << " SET "
|
2178
|
+
identifier_append(sql, search_opts[:set] || :ordercol)
|
2179
|
+
end
|
2180
|
+
|
2181
|
+
if cycle_opts = cte[:cycle]
|
2182
|
+
sql << " CYCLE "
|
2183
|
+
identifier_list_append(sql, Array(cycle_opts[:columns]))
|
2184
|
+
sql << " SET "
|
2185
|
+
identifier_append(sql, cycle_opts[:cycle_column] || :is_cycle)
|
2186
|
+
if cycle_opts.has_key?(:cycle_value)
|
2187
|
+
sql << " TO "
|
2188
|
+
literal_append(sql, cycle_opts[:cycle_value])
|
2189
|
+
sql << " DEFAULT "
|
2190
|
+
literal_append(sql, cycle_opts.fetch(:noncycle_value, false))
|
2191
|
+
end
|
2192
|
+
sql << " USING "
|
2193
|
+
identifier_append(sql, cycle_opts[:path_column] || :path)
|
2194
|
+
end
|
2195
|
+
end
|
2196
|
+
|
2144
2197
|
# The version of the database server
|
2145
2198
|
def server_version
|
2146
2199
|
db.server_version(@opts[:server])
|
@@ -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.
|
@@ -393,7 +393,7 @@ module Sequel
|
|
393
393
|
old_columns = def_columns.map{|c| c[:name]}
|
394
394
|
opts[:old_columns_proc].call(old_columns) if opts[:old_columns_proc]
|
395
395
|
|
396
|
-
yield def_columns if
|
396
|
+
yield def_columns if defined?(yield)
|
397
397
|
|
398
398
|
constraints = (opts[:constraints] || []).dup
|
399
399
|
pks = []
|