Skip to content

Commit

Permalink
Support INSERT RETURNING on MariaDB 10.5+, and use it when saving new…
Browse files Browse the repository at this point in the history
… model objects

Do not use this on jdbc/mysql, because the MySQL JDBC driver
raises an exception before sending the query to the server because
it parses the query and because it is INSERT, and MySQL does
not support INSERT returning result sets.

This is probably fixable by using the MariaDB JDBC driver, but
Sequel doesn't yet support that.  The jdbc-mariadb Ruby gem is
old enough that it is unlikely to have support.  If the
jdbc-mariadb gem is updated to a version that supports this,
we can add a jdbc/mariadb adapter and support INSERT RETURNING
when using it.
  • Loading branch information
jeremyevans committed Nov 8, 2023
1 parent 5e5f703 commit 0d509ad
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
=== master

* Support INSERT RETURNING on MariaDB 10.5+, and use it when saving new model objects (jeremyevans)

* Add Database#{defer,immediate}_constraints on PostgreSQL for changing handling of deferrable constraints in a transaction (jeremyevans)

=== 5.74.0 (2023-11-01)
Expand Down
22 changes: 21 additions & 1 deletion lib/sequel/adapters/shared/mysql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ module DatasetMethods
MATCH_AGAINST_BOOLEAN = ["MATCH ".freeze, " AGAINST (".freeze, " IN BOOLEAN MODE)".freeze].freeze

Dataset.def_sql_method(self, :delete, %w'with delete from where order limit')
Dataset.def_sql_method(self, :insert, %w'insert ignore into columns values on_duplicate_key_update')
Dataset.def_sql_method(self, :insert, %w'insert ignore into columns values on_duplicate_key_update returning')
Dataset.def_sql_method(self, :select, %w'with select distinct calc_found_rows columns from join where group having window compounds order limit lock')
Dataset.def_sql_method(self, :update, %w'with update ignore table set where order limit')

Expand Down Expand Up @@ -774,6 +774,21 @@ def insert_ignore
clone(:insert_ignore=>true)
end

# Support insert select for associations, so that the model code can use
# returning instead of a separate query.
def insert_select(*values)
return unless supports_insert_select?
# Handle case where query does not return a row
server?(:default).with_sql_first(insert_select_sql(*values)) || false
end

# The SQL to use for an insert_select, adds a RETURNING clause to the insert
# unless the RETURNING clause is already present.
def insert_select_sql(*values)
ds = opts[:returning] ? self : returning
ds.insert_sql(*values)
end

# Sets up the insert methods to use ON DUPLICATE KEY UPDATE
# If you pass no arguments, ALL fields will be
# updated with the new values. If you pass the fields you
Expand Down Expand Up @@ -871,6 +886,11 @@ def supports_regexp?
true
end

# MariaDB 10.5.0 supports INSERT RETURNING.
def supports_returning?(type)
(type == :insert && db.mariadb? && db.adapter_scheme != :jdbc) ? (db.server_version >= 100500) : false
end

# MySQL 8+ supports SKIP LOCKED.
def supports_skip_locked?
!db.mariadb? && db.server_version >= 80000
Expand Down

0 comments on commit 0d509ad

Please sign in to comment.