mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-08-04 18:18:03 +00:00
Implement getTables for JDBC4DatabaseMetaData
This commit is contained in:
parent
a00fe6d358
commit
208c6963e0
5 changed files with 322 additions and 124 deletions
|
@ -119,6 +119,18 @@ public final class LimboResultSet {
|
|||
this.open = false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Object get(String columnName) throws SQLException {
|
||||
final int columnsLength = this.columnNames.length;
|
||||
for (int i = 0; i < columnsLength; i++) {
|
||||
if (this.columnNames[i].equals(columnName)) {
|
||||
return get(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
throw new SQLException("column name " + columnName + " not found");
|
||||
}
|
||||
|
||||
// Note that columnIndex starts from 1
|
||||
@Nullable
|
||||
public Object get(int columnIndex) throws SQLException {
|
||||
|
|
|
@ -687,16 +687,85 @@ public final class JDBC4DatabaseMetaData implements DatabaseMetaData {
|
|||
return null;
|
||||
}
|
||||
|
||||
// TODO: make use of getSearchStringEscape
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public ResultSet getTables(
|
||||
@Nullable String catalog,
|
||||
@Nullable String schemaPattern,
|
||||
String tableNamePattern,
|
||||
@Nullable String[] types)
|
||||
throws SQLException {
|
||||
// TODO: after union is supported
|
||||
return null;
|
||||
// SQLite doesn't support catalogs or schemas — reject if non-empty values provided
|
||||
if (catalog != null && !catalog.isEmpty()) {
|
||||
return connection.prepareStatement("SELECT * FROM sqlite_schema WHERE 1=0").executeQuery();
|
||||
}
|
||||
|
||||
if (schemaPattern != null && !schemaPattern.isEmpty()) {
|
||||
return connection.prepareStatement("SELECT * FROM sqlite_schema WHERE 1=0").executeQuery();
|
||||
}
|
||||
|
||||
// Start building query
|
||||
StringBuilder sql = new StringBuilder(
|
||||
"SELECT " +
|
||||
"NULL AS TABLE_CAT, " +
|
||||
"NULL AS TABLE_SCHEM, " +
|
||||
"name AS TABLE_NAME, " +
|
||||
"CASE type " +
|
||||
" WHEN 'table' THEN 'TABLE' " +
|
||||
" WHEN 'view' THEN 'VIEW' " +
|
||||
" ELSE UPPER(type) " +
|
||||
"END AS TABLE_TYPE, " +
|
||||
"NULL AS REMARKS, " +
|
||||
"NULL AS TYPE_CAT, " +
|
||||
"NULL AS TYPE_SCHEM, " +
|
||||
"NULL AS TYPE_NAME, " +
|
||||
"NULL AS SELF_REFERENCING_COL_NAME, " +
|
||||
"NULL AS REF_GENERATION " +
|
||||
"FROM sqlite_schema " +
|
||||
"WHERE 1=1"
|
||||
);
|
||||
|
||||
// Apply type filtering if needed
|
||||
if (types != null && types.length > 0) {
|
||||
sql.append(" AND type IN (");
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (i > 0) sql.append(", ");
|
||||
sql.append("?");
|
||||
}
|
||||
sql.append(")");
|
||||
}
|
||||
|
||||
// Apply table name pattern filtering
|
||||
if (tableNamePattern != null) {
|
||||
sql.append(" AND name LIKE ?");
|
||||
}
|
||||
|
||||
// Comply with spec: sort by TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME
|
||||
sql.append(" ORDER BY TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME");
|
||||
|
||||
// Prepare and bind statement
|
||||
PreparedStatement stmt = connection.prepareStatement(sql.toString());
|
||||
int paramIndex = 1;
|
||||
|
||||
if (types != null && types.length > 0) {
|
||||
for (String type : types) {
|
||||
String sqliteType;
|
||||
if ("TABLE".equalsIgnoreCase(type)) {
|
||||
sqliteType = "table";
|
||||
} else if ("VIEW".equalsIgnoreCase(type)) {
|
||||
sqliteType = "view";
|
||||
} else {
|
||||
sqliteType = type.toLowerCase();
|
||||
}
|
||||
stmt.setString(paramIndex++, sqliteType);
|
||||
}
|
||||
}
|
||||
|
||||
if (tableNamePattern != null) {
|
||||
stmt.setString(paramIndex, tableNamePattern);
|
||||
}
|
||||
|
||||
return stmt.executeQuery();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -190,8 +190,12 @@ public final class JDBC4ResultSet implements ResultSet, ResultSetMetaData {
|
|||
|
||||
@Override
|
||||
public String getString(String columnLabel) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
final Object result = this.resultSet.get(columnLabel);
|
||||
if (result == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return wrapTypeConversion(() -> (String) result);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,150 +2,152 @@ package tech.turso.jdbc4;
|
|||
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import tech.turso.annotations.SkipNullableCheck;
|
||||
|
||||
public class JDBC4ResultSetMetadata implements ResultSetMetaData {
|
||||
|
||||
private final JDBC4ResultSet resultSet;
|
||||
private final JDBC4ResultSet resultSet;
|
||||
|
||||
public JDBC4ResultSetMetadata(JDBC4ResultSet resultSet) {
|
||||
this.resultSet = resultSet;
|
||||
}
|
||||
public JDBC4ResultSetMetadata(JDBC4ResultSet resultSet) {
|
||||
this.resultSet = resultSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int getColumnCount() throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoIncrement(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isAutoIncrement(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCaseSensitive(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isCaseSensitive(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSearchable(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isSearchable(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrency(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isCurrency(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int isNullable(int column) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int isNullable(int column) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSigned(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isSigned(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnDisplaySize(int column) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int getColumnDisplaySize(int column) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnLabel(int column) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
@Override
|
||||
public String getColumnLabel(int column) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int column) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
@Override
|
||||
public String getColumnName(int column) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSchemaName(int column) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
@Override
|
||||
public String getSchemaName(int column) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrecision(int column) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int getPrecision(int column) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScale(int column) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int getScale(int column) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTableName(int column) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
@Override
|
||||
public String getTableName(int column) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCatalogName(int column) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
@Override
|
||||
public String getCatalogName(int column) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnType(int column) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int getColumnType(int column) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnTypeName(int column) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
@Override
|
||||
public String getColumnTypeName(int column) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isReadOnly(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isWritable(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefinitelyWritable(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isDefinitelyWritable(int column) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnClassName(int column) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
@Override
|
||||
public String getColumnClassName(int column) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
package tech.turso.jdbc4;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Properties;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tech.turso.TestUtils;
|
||||
|
||||
|
@ -44,4 +51,108 @@ class JDBC4DatabaseMetaDataTest {
|
|||
void getDriverVersion_should_not_return_empty_string() {
|
||||
assertFalse(metaData.getDriverVersion().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getTables_with_non_empty_catalog_should_return_empty() throws SQLException {
|
||||
ResultSet rs = metaData.getTables("nonexistent", null, null, null);
|
||||
assertNotNull(rs);
|
||||
assertFalse(rs.next());
|
||||
rs.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getTables_with_non_empty_schema_should_return_empty() throws SQLException {
|
||||
ResultSet rs = metaData.getTables(null, "schema", null, null);
|
||||
assertNotNull(rs);
|
||||
assertFalse(rs.next());
|
||||
rs.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getTables_should_return_correct_table_info() throws SQLException {
|
||||
try (Statement stmt = connection.createStatement()) {
|
||||
stmt.execute("CREATE TABLE test_table (id INTEGER PRIMARY KEY)");
|
||||
}
|
||||
|
||||
ResultSet rs = metaData.getTables(null, null, null, null);
|
||||
|
||||
assertNotNull(rs);
|
||||
|
||||
assertTrue(rs.next());
|
||||
|
||||
assertEquals("test_table", rs.getString("TABLE_NAME"));
|
||||
assertEquals("TABLE", rs.getString("TABLE_TYPE"));
|
||||
|
||||
assertFalse(rs.next());
|
||||
|
||||
rs.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getTables_with_pattern_should_filter_results() throws SQLException {
|
||||
// Create test tables
|
||||
try (Statement stmt = connection.createStatement()) {
|
||||
stmt.execute("CREATE TABLE test1 (id INTEGER PRIMARY KEY)");
|
||||
stmt.execute("CREATE TABLE test2 (id INTEGER PRIMARY KEY)");
|
||||
stmt.execute("CREATE TABLE other (id INTEGER PRIMARY KEY)");
|
||||
}
|
||||
|
||||
ResultSet rs = metaData.getTables(null, null, "test%", null);
|
||||
|
||||
assertNotNull(rs);
|
||||
|
||||
int tableCount = 0;
|
||||
while (rs.next()) {
|
||||
String tableName = rs.getString("TABLE_NAME");
|
||||
assertTrue(tableName.startsWith("test"));
|
||||
tableCount++;
|
||||
}
|
||||
|
||||
assertEquals(2, tableCount);
|
||||
|
||||
rs.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled("CREATE VIEW not supported yet")
|
||||
void getTables_with_type_filter_should_return_only_views() throws SQLException {
|
||||
try (Statement stmt = connection.createStatement()) {
|
||||
stmt.execute("CREATE TABLE my_table (id INTEGER PRIMARY KEY)");
|
||||
stmt.execute("CREATE VIEW my_view AS SELECT * FROM my_table");
|
||||
}
|
||||
|
||||
ResultSet rs = metaData.getTables(null, null, null, new String[] {"VIEW"});
|
||||
|
||||
assertNotNull(rs);
|
||||
|
||||
assertTrue(rs.next());
|
||||
assertEquals("my_view", rs.getString("TABLE_NAME"));
|
||||
assertEquals("VIEW", rs.getString("TABLE_TYPE"));
|
||||
|
||||
assertFalse(rs.next());
|
||||
|
||||
rs.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled("CREATE VIEW not supported yet")
|
||||
void getTables_with_pattern_and_type_filter_should_work_together() throws SQLException {
|
||||
try (Statement stmt = connection.createStatement()) {
|
||||
stmt.execute("CREATE TABLE alpha (id INTEGER)");
|
||||
stmt.execute("CREATE TABLE beta (id INTEGER)");
|
||||
stmt.execute("CREATE VIEW alpha_view AS SELECT * FROM alpha");
|
||||
}
|
||||
|
||||
ResultSet rs = metaData.getTables(null, null, "alpha%", new String[] {"VIEW"});
|
||||
|
||||
assertNotNull(rs);
|
||||
|
||||
assertTrue(rs.next());
|
||||
assertEquals("alpha_view", rs.getString("TABLE_NAME"));
|
||||
assertEquals("VIEW", rs.getString("TABLE_TYPE"));
|
||||
|
||||
assertFalse(rs.next());
|
||||
|
||||
rs.close();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue