Skip to content

Commit 3bf2452

Browse files
committed
Modify UUID when passing it as a bind variable
When parsing an UUID from a string literal DuckDB modifies it with flipping the most significant bit in `UUID::FromString` for the following reason: "Flip the first bit to make `order by uuid` same as `order by uuid::varchar`" When an UUID is read from a result set, JDBC driver flips the MSB again to get back the original UUID in Java. This bit-flipping logic was missing when an UUID was passed from Java as a bind variable. The proposed change adds the same logic when passing bind variables. Testing: existing test is improved to cover both string literal and a bind variable. Fixes: duckdb#147
1 parent a179e86 commit 3bf2452

File tree

3 files changed

+29
-8
lines changed

3 files changed

+29
-8
lines changed

src/jni/duckdb_java.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
#include "duckdb/parser/parsed_data/create_type_info.hpp"
1414
#include "functions.hpp"
1515

16+
#include <cstdint>
17+
#include <limits>
18+
1619
using namespace duckdb;
1720
using namespace std;
1821

@@ -625,6 +628,9 @@ Value ToValue(JNIEnv *env, jobject param, duckdb::shared_ptr<ClientContext> cont
625628
return (Value::BLOB_RAW(byte_array_to_string(env, (jbyteArray)param)));
626629
} else if (env->IsInstanceOf(param, J_UUID)) {
627630
auto most_significant = (jlong)env->CallObjectMethod(param, J_UUID_getMostSignificantBits);
631+
// Account for the following logic in UUID::FromString:
632+
// Flip the first bit to make `order by uuid` same as `order by uuid::varchar`
633+
most_significant ^= (std::numeric_limits<int64_t>::min)();
628634
auto least_significant = (jlong)env->CallObjectMethod(param, J_UUID_getLeastSignificantBits);
629635
return (Value::UUID(hugeint_t(most_significant, least_significant)));
630636
} else if (env->IsInstanceOf(param, J_DuckMap)) {

src/main/java/org/duckdb/DuckDBVector.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,10 @@ UUID getUuid(int idx) throws SQLException {
228228
if (isType(DuckDBColumnType.UUID)) {
229229
ByteBuffer buffer = getbuf(idx, 16);
230230
long leastSignificantBits = buffer.getLong();
231-
232-
// Account for unsigned
233-
long mostSignificantBits = buffer.getLong() - Long.MAX_VALUE - 1;
231+
long mostSignificantBits = buffer.getLong();
232+
// Account for the following logic in UUID::FromString:
233+
// Flip the first bit to make `order by uuid` same as `order by uuid::varchar`
234+
mostSignificantBits ^= Long.MIN_VALUE;
234235
return new UUID(mostSignificantBits, leastSignificantBits);
235236
}
236237
Object o = getObject(idx);

src/test/java/org/duckdb/TestDuckDBJDBC.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4317,11 +4317,25 @@ public static void test_offset_limit() throws Exception {
43174317
}
43184318

43194319
public static void test_UUID_binding() throws Exception {
4320-
try (Connection conn = DriverManager.getConnection(JDBC_URL);
4321-
PreparedStatement statement = conn.prepareStatement("select '0b17ce61-375c-4ad8-97b3-349d96d35ab1'::UUID");
4322-
ResultSet resultSet = statement.executeQuery()) {
4323-
resultSet.next();
4324-
assertEquals(UUID.fromString("0b17ce61-375c-4ad8-97b3-349d96d35ab1"), resultSet.getObject(1));
4320+
UUID uuid = UUID.fromString("7f649593-934e-4945-9bd6-9a554f25b573");
4321+
try (Connection conn = DriverManager.getConnection(JDBC_URL)) {
4322+
try (Statement stmt = conn.createStatement()) {
4323+
// UUID is parsed from string by UUID::FromString
4324+
try (ResultSet rs = stmt.executeQuery("SELECT '" + uuid + "'::UUID")) {
4325+
rs.next();
4326+
Object obj = rs.getObject(1);
4327+
assertEquals(uuid, obj);
4328+
}
4329+
}
4330+
try (PreparedStatement stmt = conn.prepareStatement("SELECT ?")) {
4331+
// UUID is passed as 2 longs in JDBC ToValue
4332+
stmt.setObject(1, uuid);
4333+
try (ResultSet rs = stmt.executeQuery()) {
4334+
rs.next();
4335+
Object obj = rs.getObject(1);
4336+
assertEquals(uuid, obj);
4337+
}
4338+
}
43254339
}
43264340
}
43274341

0 commit comments

Comments
 (0)