Skip to content

Commit

Permalink
Support H2 version 2+ in the jdbc/h2 adapter (Fixes #1817)
Browse files Browse the repository at this point in the history
This required a few different changes:

* IDENTITY() can no longer be used, so switch to RETURN_GENERATED_KEYS
  approach for getting the inserted primary key values, borrowed from
  the jdbc/mysql adapter. This also works in version 1.

* BIGINT IDENTITY no longer works for 64-bit auto incrementing columns.
  Switch to BIGINT AUTO_INCREMENT, which also works in version 1.

* TRUE and FALSE are now used as the boolean literals, which also works
  in version 1.

* The LIMIT -1 hack no longer works and is no longer needed, so don't
  use it in version 2.

* The special literalization of blobs used in version 1 no longer works
  and is no longer needed, so don't use it in version 2.

This was tested with jdbc-h2 2.0.204, 1.4.197, and 1.3.175.
  • Loading branch information
jeremyevans committed Jan 7, 2022
1 parent 2d7a574 commit ace201d
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
=== master

* Support H2 version 2+ in the jdbc/h2 adapter (jeremyevans) (#1817)

* Work around active_support breaking subclasses plugin on Ruby <3.1 (jeremyevans) (#1816)

* Fix error handling if trying to setup column_encryption plugin without keys (jeremyevans) (#1815)
Expand Down
65 changes: 55 additions & 10 deletions lib/sequel/adapters/jdbc/h2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def database_type

def freeze
h2_version
version2?
super
end

Expand Down Expand Up @@ -140,13 +141,36 @@ def database_error_regexps
DATABASE_ERROR_REGEXPS
end

# Use IDENTITY() to get the last inserted id.
def execute_statement_insert(stmt, sql)
stmt.executeUpdate(sql, JavaSQL::Statement::RETURN_GENERATED_KEYS)
end

def prepare_jdbc_statement(conn, sql, opts)
opts[:type] == :insert ? conn.prepareStatement(sql, JavaSQL::Statement::RETURN_GENERATED_KEYS) : super
end

# Get the last inserted id using getGeneratedKeys, scope_identity, or identity.
def last_insert_id(conn, opts=OPTS)
statement(conn) do |stmt|
sql = 'SELECT IDENTITY();'
rs = log_connection_yield(sql, conn){stmt.executeQuery(sql)}
rs.next
rs.getLong(1)
if stmt = opts[:stmt]
rs = stmt.getGeneratedKeys
begin
if rs.next
begin
rs.getLong(1)
rescue
rs.getObject(1) rescue nil
end
end
ensure
rs.close
end
elsif !version2?
statement(conn) do |stmt|
sql = 'SELECT IDENTITY()'
rs = log_connection_yield(sql, conn){stmt.executeQuery(sql)}
rs.next
rs.getLong(1)
end
end
end

Expand All @@ -161,7 +185,12 @@ def supports_named_column_constraints?

# Use BIGINT IDENTITY for identity columns that use :Bignum type
def type_literal_generic_bignum_symbol(column)
column[:identity] ? 'BIGINT IDENTITY' : super
column[:identity] ? 'BIGINT AUTO_INCREMENT' : super
end

def version2?
return @version2 if defined?(@version2)
@version2 = h2_version.to_i >= 2
end
end

Expand Down Expand Up @@ -209,9 +238,21 @@ def supports_multiple_column_in?

# H2 expects hexadecimal strings for blob values
def literal_blob_append(sql, v)
sql << "'" << v.unpack("H*").first << "'"
if db.send(:version2?)
super
else
sql << "'" << v.unpack("H*").first << "'"
end
end

def literal_false
'FALSE'
end

def literal_true
'TRUE'
end

# H2 handles fractional seconds in timestamps, but not in times
def literal_sqltime(v)
v.strftime("'%H:%M:%S'")
Expand All @@ -223,8 +264,12 @@ def multi_insert_sql_strategy
end

def select_only_offset_sql(sql)
sql << " LIMIT -1 OFFSET "
literal_append(sql, @opts[:offset])
if db.send(:version2?)
super
else
sql << " LIMIT -1 OFFSET "
literal_append(sql, @opts[:offset])
end
end

# H2 supports quoted function names.
Expand Down

1 comment on commit ace201d

@sharkos
Copy link

@sharkos sharkos commented on ace201d Jan 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for quick turnaround!

Please sign in to comment.