From cf12d83fa383daa837f7e51dc5750dc840bfa1d3 Mon Sep 17 00:00:00 2001 From: Jesse Chavez Date: Sun, 28 Sep 2025 12:50:37 +0900 Subject: [PATCH 1/3] Postgres, pass type casted binds for select queries --- lib/arjdbc/abstract/database_statements.rb | 7 +++++-- .../postgresql/PostgreSQLRubyJdbcConnection.java | 2 +- test/simple.rb | 10 ++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/arjdbc/abstract/database_statements.rb b/lib/arjdbc/abstract/database_statements.rb index d86a4b12d..885a092a3 100644 --- a/lib/arjdbc/abstract/database_statements.rb +++ b/lib/arjdbc/abstract/database_statements.rb @@ -44,14 +44,17 @@ def internal_exec_query(sql, name = nil, binds = NO_BINDS, prepare: false, async binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array) + # puts "internal----->sql: #{sql}, binds: #{binds}" + type_casted_binds = type_casted_binds(binds) + with_raw_connection do |conn| if without_prepared_statement?(binds) log(sql, name, async: async) { conn.execute_query(sql) } else - log(sql, name, binds, async: async) do + log(sql, name, type_casted_binds, async: async) do # this is different from normal AR that always caches cached_statement = fetch_cached_statement(sql) if prepare && @jdbc_statement_cache_enabled - conn.execute_prepared_query(sql, binds, cached_statement) + conn.execute_prepared_query(sql, type_casted_binds, cached_statement) end end end diff --git a/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java b/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java index ded69a537..8e754aaf3 100644 --- a/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +++ b/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java @@ -678,7 +678,7 @@ protected void setStringParameter(final ThreadContext context, } } - super.setStringParameter(context, connection, statement, index, value, attribute, type); + statement.setObject(index, value.asString().toString(), Types.OTHER); } diff --git a/test/simple.rb b/test/simple.rb index 2e6610d71..535a7545c 100644 --- a/test/simple.rb +++ b/test/simple.rb @@ -891,6 +891,16 @@ def test_string_id assert_equal "some_string", f.id end + def test_time_bind_param + with_timezone_config default: :utc, zone: 'Australia/Melbourne' do + time = Time.zone.local(2000, 1, 1, 16) + entry = Entry.create!(updated_on: time + 1.hour) + sql = 'updated_on >= ?' + entries = Entry.where(sql, time) + assert_equal 1, entries.size + end + end + def test_handles_quotes_inside_of_strings content_json = { "comments" => [ From aad30c3e4be23b0a63f533f56ae536d4e5f55ee2 Mon Sep 17 00:00:00 2001 From: Jesse Chavez Date: Fri, 17 Oct 2025 22:40:46 +0900 Subject: [PATCH 2/3] Comment out code setting uuid type for plain varchar field --- .../PostgreSQLRubyJdbcConnection.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java b/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java index 8e754aaf3..8730811b9 100644 --- a/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +++ b/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java @@ -661,22 +661,22 @@ protected void setStringParameter(final ThreadContext context, final int index, final IRubyObject value, final IRubyObject attribute, final int type) throws SQLException { - if ( attributeSQLType(context, attribute) == context.nil ) { - /* - We have to check for a uuid here because in some cases - (for example, when doing "exists?" checks, or with legacy binds) - ActiveRecord doesn't send us the actual type of the attribute - and Postgres won't compare a uuid column with a string - */ - final String uuid = value.toString(); - int length = uuid.length(); - - // Checking the length so we don't have the overhead of the regex unless it "looks" like a UUID - if (length >= 32 && length < 40 && uuidPattern.matcher(uuid).matches()) { - setUUIDParameter(statement, index, uuid); - return; - } - } + // if ( attributeSQLType(context, attribute) == context.nil ) { + // /* + // We have to check for a uuid here because in some cases + // (for example, when doing "exists?" checks, or with legacy binds) + // ActiveRecord doesn't send us the actual type of the attribute + // and Postgres won't compare a uuid column with a string + // */ + // final String uuid = value.toString(); + // int length = uuid.length(); + + // // Checking the length so we don't have the overhead of the regex unless it "looks" like a UUID + // if (length >= 32 && length < 40 && uuidPattern.matcher(uuid).matches()) { + // setUUIDParameter(statement, index, uuid); + // return; + // } + // } statement.setObject(index, value.asString().toString(), Types.OTHER); } From 8fca8db0990cd2f3fbf7a161b609aafdc2ed8f80 Mon Sep 17 00:00:00 2001 From: Jesse Chavez Date: Sat, 13 Dec 2025 11:39:18 +0900 Subject: [PATCH 3/3] Fix queries like where(field: [""]) to match CRuby behaviour --- lib/arjdbc/abstract/database_statements.rb | 3 ++- src/java/arjdbc/jdbc/RubyJdbcConnection.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/arjdbc/abstract/database_statements.rb b/lib/arjdbc/abstract/database_statements.rb index 885a092a3..87ba60770 100644 --- a/lib/arjdbc/abstract/database_statements.rb +++ b/lib/arjdbc/abstract/database_statements.rb @@ -44,8 +44,9 @@ def internal_exec_query(sql, name = nil, binds = NO_BINDS, prepare: false, async binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array) - # puts "internal----->sql: #{sql}, binds: #{binds}" + # puts "[1]internal----->sql: #{sql}, binds: #{binds}" type_casted_binds = type_casted_binds(binds) + # puts "[2]internal----->sql: #{type_casted_binds.size}, binds: #{type_casted_binds}" with_raw_connection do |conn| if without_prepared_statement?(binds) diff --git a/src/java/arjdbc/jdbc/RubyJdbcConnection.java b/src/java/arjdbc/jdbc/RubyJdbcConnection.java index 07bee76a6..7dc489bbc 100644 --- a/src/java/arjdbc/jdbc/RubyJdbcConnection.java +++ b/src/java/arjdbc/jdbc/RubyJdbcConnection.java @@ -2453,7 +2453,8 @@ protected void setStatementParameter(final ThreadContext context, // All the set methods were calling this first so save a method call in the nil case if ( value == context.nil ) { - statement.setNull(index, type); + // statement.setNull(index, type); + statement.setObject(index, null); return; }