diff --git a/bindings/java/rs_src/limbo_statement.rs b/bindings/java/rs_src/limbo_statement.rs index 97328a964..c2746dfb9 100644 --- a/bindings/java/rs_src/limbo_statement.rs +++ b/bindings/java/rs_src/limbo_statement.rs @@ -2,7 +2,7 @@ use crate::errors::Result; use crate::errors::{LimboError, LIMBO_ETC}; use crate::limbo_connection::LimboConnection; use crate::utils::set_err_msg_and_throw_exception; -use jni::objects::{JObject, JValue}; +use jni::objects::{JObject, JObjectArray, JValue}; use jni::sys::jlong; use jni::JNIEnv; use limbo_core::{Statement, StepResult}; @@ -125,6 +125,27 @@ fn row_to_obj_array<'local>( Ok(obj_array.into()) } +#[no_mangle] +pub extern "system" fn Java_org_github_tursodatabase_core_LimboStatement_columnNames<'local>( + mut env: JNIEnv<'local>, + _obj: JObject<'local>, + stmt_ptr: jlong, +) -> JObject<'local> { + let stmt = to_limbo_statement(stmt_ptr).unwrap(); + let columns = stmt.stmt.columns(); + let obj_arr: JObjectArray = env + .new_object_array(columns.len() as i32, "java/lang/String", JObject::null()) + .unwrap(); + + for (i, value) in columns.iter().enumerate() { + let str = env.new_string(value).unwrap(); + env.set_object_array_element(&obj_arr, i as i32, str) + .unwrap(); + } + + obj_arr.into() +} + /// Converts an optional `JObject` into Java's `LimboStepResult`. /// /// This function takes an optional `JObject` and converts it into a Java object diff --git a/bindings/java/src/main/java/org/github/tursodatabase/core/LimboResultSet.java b/bindings/java/src/main/java/org/github/tursodatabase/core/LimboResultSet.java index 1884d4786..67bc6b8ee 100644 --- a/bindings/java/src/main/java/org/github/tursodatabase/core/LimboResultSet.java +++ b/bindings/java/src/main/java/org/github/tursodatabase/core/LimboResultSet.java @@ -19,6 +19,8 @@ public class LimboResultSet { private final LimboStatement statement; + // Name of the columns + private String[] columnNames = new String[0]; // Whether the result set does not have any rows. private boolean isEmptyResultSet = false; // If the result set is open. Doesn't mean it has results. @@ -136,6 +138,14 @@ public class LimboResultSet { return resultSet[columnIndex - 1]; } + public String[] getColumnNames() { + return this.columnNames; + } + + public void setColumnNames(String[] columnNames) { + this.columnNames = columnNames; + } + @Override public String toString() { return "LimboResultSet{" diff --git a/bindings/java/src/main/java/org/github/tursodatabase/core/LimboStatement.java b/bindings/java/src/main/java/org/github/tursodatabase/core/LimboStatement.java index fa660b67c..ab55ef1a8 100644 --- a/bindings/java/src/main/java/org/github/tursodatabase/core/LimboStatement.java +++ b/bindings/java/src/main/java/org/github/tursodatabase/core/LimboStatement.java @@ -89,6 +89,23 @@ public class LimboStatement { private native void _close(long statementPointer); + /** + * Initializes the column metadata, such as the names of the columns. Since {@link LimboStatement} + * can only have a single {@link LimboResultSet}, it is appropriate to place the initialization of + * column metadata here. + * + * @throws SQLException if a database access error occurs while retrieving column names + */ + public void initializeColumnMetadata() throws SQLException { + final String[] columnNames = this.columnNames(statementPointer); + if (columnNames != null) { + this.resultSet.setColumnNames(columnNames); + } + } + + @Nullable + private native String[] columnNames(long statementPointer) throws SQLException; + /** * Checks if the statement is closed. * diff --git a/bindings/java/src/test/java/org/github/tursodatabase/core/LimboStatementTest.java b/bindings/java/src/test/java/org/github/tursodatabase/core/LimboStatementTest.java index fe274b07e..a4230d3eb 100644 --- a/bindings/java/src/test/java/org/github/tursodatabase/core/LimboStatementTest.java +++ b/bindings/java/src/test/java/org/github/tursodatabase/core/LimboStatementTest.java @@ -1,6 +1,8 @@ package org.github.tursodatabase.core; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Properties; import org.github.tursodatabase.TestUtils; @@ -28,4 +30,26 @@ class LimboStatementTest { assertTrue(stmt.isClosed()); assertFalse(stmt.getResultSet().isOpen()); } + + @Test + void test_initializeColumnMetadata() throws Exception { + runSql("CREATE TABLE users (name TEXT, age INT, country TEXT);"); + runSql("INSERT INTO users VALUES ('seonwoo', 30, 'KR');"); + + final LimboStatement stmt = connection.prepare("SELECT * FROM users"); + stmt.initializeColumnMetadata(); + final LimboResultSet rs = stmt.getResultSet(); + final String[] columnNames = rs.getColumnNames(); + + assertEquals(columnNames[0], "name"); + assertEquals(columnNames[1], "age"); + assertEquals(columnNames[2], "country"); + } + + private void runSql(String sql) throws Exception { + LimboStatement stmt = connection.prepare(sql); + while (stmt.execute()) { + stmt.execute(); + } + } }