sequel 5.51.0 → 5.56.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 +62 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -0
- data/doc/opening_databases.rdoc +4 -1
- data/doc/querying.rdoc +3 -1
- 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/sql.rdoc +1 -1
- data/doc/testing.rdoc +3 -1
- data/lib/sequel/adapters/amalgalite.rb +3 -5
- data/lib/sequel/adapters/jdbc/h2.rb +55 -10
- data/lib/sequel/adapters/jdbc.rb +12 -14
- data/lib/sequel/adapters/mysql.rb +80 -67
- data/lib/sequel/adapters/mysql2.rb +53 -48
- data/lib/sequel/adapters/postgres.rb +17 -21
- data/lib/sequel/adapters/shared/mysql.rb +3 -2
- data/lib/sequel/adapters/shared/postgres.rb +2 -2
- data/lib/sequel/adapters/shared/sqlite.rb +6 -0
- data/lib/sequel/adapters/sqlite.rb +60 -18
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
- 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/query.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +6 -5
- data/lib/sequel/database/schema_methods.rb +9 -0
- data/lib/sequel/dataset/sql.rb +3 -2
- 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/pg_array_ops.rb +2 -2
- data/lib/sequel/extensions/pg_hstore_ops.rb +1 -1
- 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 +3 -2
- data/lib/sequel/extensions/pg_range_ops.rb +1 -1
- data/lib/sequel/extensions/pg_row_ops.rb +1 -1
- data/lib/sequel/extensions/s.rb +2 -1
- data/lib/sequel/extensions/schema_dumper.rb +2 -2
- data/lib/sequel/extensions/server_block.rb +8 -12
- data/lib/sequel/extensions/sql_comments.rb +110 -3
- data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
- data/lib/sequel/extensions/string_date_time.rb +19 -23
- data/lib/sequel/model/base.rb +8 -12
- data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
- data/lib/sequel/plugins/column_encryption.rb +1 -1
- data/lib/sequel/plugins/enum.rb +124 -0
- data/lib/sequel/plugins/instance_specific_default.rb +1 -1
- data/lib/sequel/plugins/sql_comments.rb +189 -0
- data/lib/sequel/plugins/subclasses.rb +28 -11
- data/lib/sequel/plugins/unused_associations.rb +2 -2
- data/lib/sequel/timezones.rb +12 -14
- data/lib/sequel/version.rb +1 -1
- metadata +21 -6
@@ -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
|
|
@@ -86,20 +86,26 @@ module Sequel
|
|
86
86
|
if NativePreparedStatements
|
87
87
|
# Use a native mysql2 prepared statement to implement prepared statements.
|
88
88
|
def execute_prepared_statement(ps_name, opts, &block)
|
89
|
-
|
89
|
+
if ps_name.is_a?(Sequel::Dataset::ArgumentMapper)
|
90
|
+
ps = ps_name
|
91
|
+
ps_name = ps.prepared_statement_name
|
92
|
+
else
|
93
|
+
ps = prepared_statement(ps_name)
|
94
|
+
end
|
90
95
|
sql = ps.prepared_sql
|
91
96
|
|
92
97
|
synchronize(opts[:server]) do |conn|
|
93
98
|
stmt, ps_sql = conn.prepared_statements[ps_name]
|
94
99
|
unless ps_sql == sql
|
95
100
|
stmt.close if stmt
|
96
|
-
stmt = log_connection_yield(
|
101
|
+
stmt = log_connection_yield("Preparing #{ps_name}: #{sql}", conn){conn.prepare(sql)}
|
97
102
|
conn.prepared_statements[ps_name] = [stmt, sql]
|
98
103
|
end
|
99
104
|
|
100
|
-
|
101
|
-
|
102
|
-
|
105
|
+
opts = Hash[opts]
|
106
|
+
opts[:sql] = "Executing #{ps_name || sql}"
|
107
|
+
if ps_name && ps.log_sql
|
108
|
+
opts[:log_sql] = " (#{sql})"
|
103
109
|
end
|
104
110
|
|
105
111
|
_execute(conn, stmt, opts, &block)
|
@@ -111,56 +117,55 @@ module Sequel
|
|
111
117
|
# option is :select, yield the result of the query, otherwise
|
112
118
|
# yield the connection if a block is given.
|
113
119
|
def _execute(conn, sql, opts)
|
114
|
-
|
115
|
-
|
116
|
-
if
|
117
|
-
|
118
|
-
|
119
|
-
end
|
120
|
+
stream = opts[:stream]
|
121
|
+
if NativePreparedStatements
|
122
|
+
if args = opts[:arguments]
|
123
|
+
args = args.map{|arg| bound_variable_value(arg)}
|
124
|
+
end
|
120
125
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
126
|
+
case sql
|
127
|
+
when ::Mysql2::Statement
|
128
|
+
stmt = sql
|
129
|
+
sql = opts[:sql] || ''
|
130
|
+
when Dataset
|
131
|
+
sql = sql.sql
|
132
|
+
close_stmt = true
|
133
|
+
stmt = conn.prepare(sql)
|
129
134
|
end
|
135
|
+
end
|
130
136
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
end
|
137
|
+
r = log_connection_yield((log_sql = opts[:log_sql]) ? sql + log_sql : sql, conn, args) do
|
138
|
+
if stmt
|
139
|
+
conn.query_options.merge!(:cache_rows=>true, :database_timezone => timezone, :application_timezone => Sequel.application_timezone, :stream=>stream, :cast_booleans=>convert_tinyint_to_bool)
|
140
|
+
stmt.execute(*args)
|
141
|
+
else
|
142
|
+
conn.query(sql, :database_timezone => timezone, :application_timezone => Sequel.application_timezone, :stream=>stream)
|
138
143
|
end
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
else
|
151
|
-
yield r
|
144
|
+
end
|
145
|
+
if opts[:type] == :select
|
146
|
+
if r
|
147
|
+
if stream
|
148
|
+
begin
|
149
|
+
r2 = yield r
|
150
|
+
ensure
|
151
|
+
# If r2 is nil, it means the block did not exit normally,
|
152
|
+
# so the rest of the results must be drained to prevent
|
153
|
+
# "commands out of sync" errors.
|
154
|
+
r.each{} unless r2
|
152
155
|
end
|
156
|
+
else
|
157
|
+
yield r
|
153
158
|
end
|
154
|
-
elsif defined?(yield)
|
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
159
|
end
|
160
|
+
elsif defined?(yield)
|
161
|
+
yield conn
|
162
|
+
end
|
163
|
+
rescue ::Mysql2::Error => e
|
164
|
+
raise_error(e)
|
165
|
+
ensure
|
166
|
+
if stmt
|
167
|
+
conn.query_options.replace(conn.instance_variable_get(:@sequel_default_query_options))
|
168
|
+
stmt.close if close_stmt
|
164
169
|
end
|
165
170
|
end
|
166
171
|
|
@@ -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,
|
@@ -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.
|
@@ -544,9 +544,10 @@ module Sequel
|
|
544
544
|
server_version >= 50600 && (op[:op] == :drop_index || (op[:op] == :drop_constraint && op[:type] == :unique))
|
545
545
|
end
|
546
546
|
|
547
|
-
#
|
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+).
|
548
549
|
def supports_check_constraints?
|
549
|
-
mariadb?
|
550
|
+
server_version >= (mariadb? ? 100200 : 80019)
|
550
551
|
end
|
551
552
|
|
552
553
|
# MySQL can combine multiple alter table ops into a single query.
|
@@ -1504,9 +1504,9 @@ module Sequel
|
|
1504
1504
|
if column[:text]
|
1505
1505
|
:text
|
1506
1506
|
elsif column[:fixed]
|
1507
|
-
"char(#{column[:size]||
|
1507
|
+
"char(#{column[:size]||default_string_column_size})"
|
1508
1508
|
elsif column[:text] == false || column[:size]
|
1509
|
-
"varchar(#{column[:size]||
|
1509
|
+
"varchar(#{column[:size]||default_string_column_size})"
|
1510
1510
|
else
|
1511
1511
|
:text
|
1512
1512
|
end
|
@@ -337,6 +337,11 @@ module Sequel
|
|
337
337
|
ps
|
338
338
|
end
|
339
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
|
+
|
340
345
|
# SQLite support creating temporary views.
|
341
346
|
def create_view_prefix_sql(name, options)
|
342
347
|
create_view_sql_append_columns("CREATE #{'TEMPORARY 'if options[:temp]}VIEW #{quote_schema_table(name)}", options[:columns])
|
@@ -347,6 +352,7 @@ module Sequel
|
|
347
352
|
/foreign key constraint failed\z/i => ForeignKeyConstraintViolation,
|
348
353
|
/\A(SQLITE ERROR 275 \(CONSTRAINT_CHECK\) : )?CHECK constraint failed/ => CheckConstraintViolation,
|
349
354
|
/\A(SQLITE ERROR 19 \(CONSTRAINT\) : )?constraint failed\z/ => ConstraintViolation,
|
355
|
+
/\Acannot store [A-Z]+ value in [A-Z]+ column / => ConstraintViolation,
|
350
356
|
/may not be NULL\z|NOT NULL constraint failed: .+\z/ => NotNullConstraintViolation,
|
351
357
|
/\ASQLITE ERROR \d+ \(\) : CHECK constraint failed: / => CheckConstraintViolation
|
352
358
|
}.freeze
|
@@ -98,6 +98,11 @@ module Sequel
|
|
98
98
|
# The conversion procs to use for this database
|
99
99
|
attr_reader :conversion_procs
|
100
100
|
|
101
|
+
def initialize(opts = OPTS)
|
102
|
+
super
|
103
|
+
@allow_regexp = typecast_value_boolean(opts[:setup_regexp_function])
|
104
|
+
end
|
105
|
+
|
101
106
|
# Connect to the database. Since SQLite is a file based database,
|
102
107
|
# available options are limited:
|
103
108
|
#
|
@@ -119,6 +124,12 @@ module Sequel
|
|
119
124
|
end
|
120
125
|
|
121
126
|
connection_pragmas.each{|s| log_connection_yield(s, db){db.execute_batch(s)}}
|
127
|
+
|
128
|
+
if typecast_value_boolean(opts[:setup_regexp_function])
|
129
|
+
db.create_function("regexp", 2) do |func, regexp_str, string|
|
130
|
+
func.result = Regexp.new(regexp_str).match(string) ? 1 : 0
|
131
|
+
end
|
132
|
+
end
|
122
133
|
|
123
134
|
class << db
|
124
135
|
attr_reader :prepared_statements
|
@@ -128,6 +139,12 @@ module Sequel
|
|
128
139
|
db
|
129
140
|
end
|
130
141
|
|
142
|
+
# Whether this Database instance is setup to allow regexp matching.
|
143
|
+
# True if the :setup_regexp_function option was passed when creating the Database.
|
144
|
+
def allow_regexp?
|
145
|
+
@allow_regexp
|
146
|
+
end
|
147
|
+
|
131
148
|
# Disconnect given connections from the database.
|
132
149
|
def disconnect_connection(c)
|
133
150
|
c.prepared_statements.each_value{|v| v.first.close}
|
@@ -189,26 +206,24 @@ module Sequel
|
|
189
206
|
# Yield an available connection. Rescue
|
190
207
|
# any SQLite3::Exceptions and turn them into DatabaseErrors.
|
191
208
|
def _execute(type, sql, opts, &block)
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
conn.changes
|
207
|
-
end
|
209
|
+
synchronize(opts[:server]) do |conn|
|
210
|
+
return execute_prepared_statement(conn, type, sql, opts, &block) if sql.is_a?(Symbol)
|
211
|
+
log_args = opts[:arguments]
|
212
|
+
args = {}
|
213
|
+
opts.fetch(:arguments, OPTS).each{|k, v| args[k] = prepared_statement_argument(v)}
|
214
|
+
case type
|
215
|
+
when :select
|
216
|
+
log_connection_yield(sql, conn, log_args){conn.query(sql, args, &block)}
|
217
|
+
when :insert
|
218
|
+
log_connection_yield(sql, conn, log_args){conn.execute(sql, args)}
|
219
|
+
conn.last_insert_row_id
|
220
|
+
when :update
|
221
|
+
log_connection_yield(sql, conn, log_args){conn.execute_batch(sql, args)}
|
222
|
+
conn.changes
|
208
223
|
end
|
209
|
-
rescue SQLite3::Exception => e
|
210
|
-
raise_error(e)
|
211
224
|
end
|
225
|
+
rescue SQLite3::Exception => e
|
226
|
+
raise_error(e)
|
212
227
|
end
|
213
228
|
|
214
229
|
# The SQLite adapter does not need the pool to convert exceptions.
|
@@ -323,6 +338,28 @@ module Sequel
|
|
323
338
|
BindArgumentMethods = prepared_statements_module(:bind, ArgumentMapper)
|
324
339
|
PreparedStatementMethods = prepared_statements_module(:prepare, BindArgumentMethods)
|
325
340
|
|
341
|
+
# Support regexp functions if using :setup_regexp_function Database option.
|
342
|
+
def complex_expression_sql_append(sql, op, args)
|
343
|
+
case op
|
344
|
+
when :~, :'!~', :'~*', :'!~*'
|
345
|
+
return super unless supports_regexp?
|
346
|
+
|
347
|
+
case_insensitive = [:'~*', :'!~*'].include?(op)
|
348
|
+
sql << 'NOT ' if [:'!~', :'!~*'].include?(op)
|
349
|
+
sql << '('
|
350
|
+
sql << 'LOWER(' if case_insensitive
|
351
|
+
literal_append(sql, args[0])
|
352
|
+
sql << ')' if case_insensitive
|
353
|
+
sql << ' REGEXP '
|
354
|
+
sql << 'LOWER(' if case_insensitive
|
355
|
+
literal_append(sql, args[1])
|
356
|
+
sql << ')' if case_insensitive
|
357
|
+
sql << ')'
|
358
|
+
else
|
359
|
+
super
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
326
363
|
def fetch_rows(sql)
|
327
364
|
execute(sql) do |result|
|
328
365
|
cps = db.conversion_procs
|
@@ -346,6 +383,11 @@ module Sequel
|
|
346
383
|
end
|
347
384
|
end
|
348
385
|
end
|
386
|
+
|
387
|
+
# Support regexp if using :setup_regexp_function Database option.
|
388
|
+
def supports_regexp?
|
389
|
+
db.allow_regexp?
|
390
|
+
end
|
349
391
|
|
350
392
|
private
|
351
393
|
|
@@ -34,7 +34,7 @@ module Sequel
|
|
34
34
|
def execute(sql, opts=OPTS, &block)
|
35
35
|
if opts[:sproc]
|
36
36
|
call_sproc(sql, opts, &block)
|
37
|
-
elsif sql.is_a?(Symbol)
|
37
|
+
elsif sql.is_a?(Symbol) || sql.is_a?(Sequel::Dataset::ArgumentMapper)
|
38
38
|
execute_prepared_statement(sql, opts, &block)
|
39
39
|
else
|
40
40
|
synchronize(opts[:server]){|conn| _execute(conn, sql, opts, &block)}
|
@@ -55,13 +55,11 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
|
|
55
55
|
# Yields the connection to the supplied block for the given server.
|
56
56
|
# This method simulates the ConnectionPool#hold API.
|
57
57
|
def hold(server=:default)
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
raise
|
64
|
-
end
|
58
|
+
server = pick_server(server)
|
59
|
+
yield(@conns[server] ||= make_new(server))
|
60
|
+
rescue Sequel::DatabaseDisconnectError, *@error_classes => e
|
61
|
+
disconnect_server(server) if disconnect_error?(e)
|
62
|
+
raise
|
65
63
|
end
|
66
64
|
|
67
65
|
# The ShardedSingleConnectionPool always has a maximum size of 1.
|
@@ -24,15 +24,13 @@ class Sequel::SingleConnectionPool < Sequel::ConnectionPool
|
|
24
24
|
|
25
25
|
# Yield the connection to the block.
|
26
26
|
def hold(server=nil)
|
27
|
-
|
28
|
-
|
29
|
-
@conn.replace([c = make_new(:default)])
|
30
|
-
end
|
31
|
-
yield c
|
32
|
-
rescue Sequel::DatabaseDisconnectError, *@error_classes => e
|
33
|
-
disconnect if disconnect_error?(e)
|
34
|
-
raise
|
27
|
+
unless c = @conn.first
|
28
|
+
@conn.replace([c = make_new(:default)])
|
35
29
|
end
|
30
|
+
yield c
|
31
|
+
rescue Sequel::DatabaseDisconnectError, *@error_classes => e
|
32
|
+
disconnect if disconnect_error?(e)
|
33
|
+
raise
|
36
34
|
end
|
37
35
|
|
38
36
|
# The SingleConnectionPool always has a maximum size of 1.
|
data/lib/sequel/core.rb
CHANGED
@@ -278,11 +278,9 @@ module Sequel
|
|
278
278
|
#
|
279
279
|
# Sequel.string_to_date('2010-09-10') # Date.civil(2010, 09, 10)
|
280
280
|
def string_to_date(string)
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
raise convert_exception_class(e, InvalidValue)
|
285
|
-
end
|
281
|
+
Date.parse(string, Sequel.convert_two_digit_years)
|
282
|
+
rescue => e
|
283
|
+
raise convert_exception_class(e, InvalidValue)
|
286
284
|
end
|
287
285
|
|
288
286
|
# Converts the given +string+ into a +Time+ or +DateTime+ object, depending on the
|
@@ -290,15 +288,13 @@ module Sequel
|
|
290
288
|
#
|
291
289
|
# Sequel.string_to_datetime('2010-09-10 10:20:30') # Time.local(2010, 09, 10, 10, 20, 30)
|
292
290
|
def string_to_datetime(string)
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
datetime_class.parse(string)
|
298
|
-
end
|
299
|
-
rescue => e
|
300
|
-
raise convert_exception_class(e, InvalidValue)
|
291
|
+
if datetime_class == DateTime
|
292
|
+
DateTime.parse(string, convert_two_digit_years)
|
293
|
+
else
|
294
|
+
datetime_class.parse(string)
|
301
295
|
end
|
296
|
+
rescue => e
|
297
|
+
raise convert_exception_class(e, InvalidValue)
|
302
298
|
end
|
303
299
|
|
304
300
|
# Converts the given +string+ into a <tt>Sequel::SQLTime</tt> object.
|
@@ -306,11 +302,9 @@ module Sequel
|
|
306
302
|
# v = Sequel.string_to_time('10:20:30') # Sequel::SQLTime.parse('10:20:30')
|
307
303
|
# DB.literal(v) # => '10:20:30'
|
308
304
|
def string_to_time(string)
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
raise convert_exception_class(e, InvalidValue)
|
313
|
-
end
|
305
|
+
SQLTime.parse(string)
|
306
|
+
rescue => e
|
307
|
+
raise convert_exception_class(e, InvalidValue)
|
314
308
|
end
|
315
309
|
|
316
310
|
# Unless in single threaded mode, protects access to any mutable
|
@@ -400,6 +394,11 @@ module Sequel
|
|
400
394
|
|
401
395
|
private
|
402
396
|
|
397
|
+
# Return a hash of date information parsed from the given string.
|
398
|
+
def _date_parse(string)
|
399
|
+
Date._parse(string)
|
400
|
+
end
|
401
|
+
|
403
402
|
# Helper method that the database adapter class methods that are added to Sequel via
|
404
403
|
# metaprogramming use to parse arguments.
|
405
404
|
def adapter_method(adapter, *args, &block)
|