fix(gbase8s): load table metadata details
This commit is contained in:
parent
53f2a4f215
commit
eb3d5e4071
|
|
@ -7,6 +7,7 @@ import com.dbx.agent.DatabaseInfo;
|
|||
import com.dbx.agent.ExecuteQueryOptions;
|
||||
import com.dbx.agent.JdbcAgentProfile;
|
||||
import com.dbx.agent.JsonRpcServer;
|
||||
import com.dbx.agent.IndexInfo;
|
||||
import com.dbx.agent.MetadataListConstraints;
|
||||
import com.dbx.agent.ObjectSource;
|
||||
import com.dbx.agent.QueryResult;
|
||||
|
|
@ -18,9 +19,11 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public final class Gbase8sAgent extends ConfiguredJdbcAgent {
|
||||
|
|
@ -163,9 +166,14 @@ public final class Gbase8sAgent extends ConfiguredJdbcAgent {
|
|||
}
|
||||
List<TableInfo> result = new ArrayList<>();
|
||||
String owner = trim(schema);
|
||||
String sql = "SELECT tabname, tabtype FROM systables WHERE tabid >= 100 AND tabtype IN ('T', 'V')";
|
||||
String sql = """
|
||||
SELECT t.tabname, t.tabtype, c.comments
|
||||
FROM systables t
|
||||
LEFT JOIN syscomms c ON c.tabid = t.tabid
|
||||
WHERE t.tabid >= 100 AND t.tabtype IN ('T', 'V')
|
||||
""".stripIndent().trim();
|
||||
if (!owner.isEmpty()) {
|
||||
sql += " AND owner = ?";
|
||||
sql += " AND t.owner = ?";
|
||||
}
|
||||
sql += " ORDER BY tabname";
|
||||
try (PreparedStatement stmt = requireConnection().prepareStatement(sql)) {
|
||||
|
|
@ -176,7 +184,8 @@ public final class Gbase8sAgent extends ConfiguredJdbcAgent {
|
|||
while (rs.next()) {
|
||||
result.add(new TableInfo(
|
||||
trim(rs.getString("tabname")),
|
||||
tableType(rs.getString("tabtype"))
|
||||
tableType(rs.getString("tabtype")),
|
||||
emptyToNull(trim(rs.getString("comments")))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -207,9 +216,10 @@ public final class Gbase8sAgent extends ConfiguredJdbcAgent {
|
|||
List<Object> args = new ArrayList<>();
|
||||
args.add(table);
|
||||
StringBuilder sql = new StringBuilder("""
|
||||
SELECT c.colname, c.coltype, c.colno, c.collength
|
||||
SELECT c.colname, c.coltype, c.colno, c.collength, cc.comments
|
||||
FROM syscolumns c
|
||||
JOIN systables t ON t.tabid = c.tabid
|
||||
LEFT JOIN syscolcomms cc ON cc.tabid = c.tabid AND cc.colno = c.colno
|
||||
WHERE t.tabid >= 100 AND t.tabname = ?
|
||||
""".stripIndent().trim());
|
||||
if (!owner.isEmpty()) {
|
||||
|
|
@ -234,7 +244,7 @@ public final class Gbase8sAgent extends ConfiguredJdbcAgent {
|
|||
null,
|
||||
primaryKeyColumns.contains(rs.getInt("colno")),
|
||||
null,
|
||||
null,
|
||||
emptyToNull(trim(rs.getString("comments"))),
|
||||
numericPrecision(baseType, length),
|
||||
numericScale(baseType, length),
|
||||
characterMaximumLength(baseType, length)
|
||||
|
|
@ -248,6 +258,60 @@ public final class Gbase8sAgent extends ConfiguredJdbcAgent {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IndexInfo> listIndexes(String schema, String table) {
|
||||
try {
|
||||
String owner = trim(schema);
|
||||
List<Object> args = new ArrayList<>();
|
||||
args.add(table);
|
||||
StringBuilder sql = new StringBuilder("""
|
||||
SELECT i.idxname, i.idxtype, c.constrtype,
|
||||
i.part1, i.part2, i.part3, i.part4, i.part5, i.part6, i.part7, i.part8,
|
||||
i.part9, i.part10, i.part11, i.part12, i.part13, i.part14, i.part15, i.part16
|
||||
FROM sysindexes i
|
||||
JOIN systables t ON t.tabid = i.tabid
|
||||
LEFT JOIN sysconstraints c ON c.tabid = i.tabid AND c.idxname = i.idxname
|
||||
WHERE t.tabid >= 100 AND t.tabname = ?
|
||||
""".stripIndent().trim());
|
||||
if (!owner.isEmpty()) {
|
||||
sql.append(" AND t.owner = ?");
|
||||
args.add(owner);
|
||||
}
|
||||
sql.append(" ORDER BY i.idxname");
|
||||
|
||||
Map<Integer, String> columnNames = loadColumnNamesByNumber(owner, table);
|
||||
List<IndexInfo> result = new ArrayList<>();
|
||||
try (PreparedStatement stmt = requireConnection().prepareStatement(sql.toString())) {
|
||||
bind(stmt, args);
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
String name = trim(rs.getString("idxname"));
|
||||
if (name.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
List<Integer> parts = readIndexParts(rs);
|
||||
List<String> columns = resolveIndexColumns(parts, columnNames);
|
||||
String indexType = trim(rs.getString("idxtype"));
|
||||
String constraintType = trim(rs.getString("constrtype"));
|
||||
result.add(new IndexInfo(
|
||||
name,
|
||||
columns,
|
||||
indexType.toUpperCase(Locale.ROOT).startsWith("U"),
|
||||
"P".equalsIgnoreCase(constraintType),
|
||||
null,
|
||||
indexType,
|
||||
null,
|
||||
null
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectSource getObjectSource(String schema, String name, String objectType) {
|
||||
String normalizedType = objectType == null ? "" : objectType.trim().toUpperCase(Locale.ROOT);
|
||||
|
|
@ -281,24 +345,25 @@ public final class Gbase8sAgent extends ConfiguredJdbcAgent {
|
|||
if (constraints.hasLimit()) {
|
||||
sql.append("FIRST ").append(constraints.getLimit()).append(' ');
|
||||
}
|
||||
sql.append("tabname, tabtype FROM systables WHERE tabid >= 100");
|
||||
sql.append("t.tabname, t.tabtype, c.comments FROM systables t LEFT JOIN syscomms c ON c.tabid = t.tabid WHERE t.tabid >= 100");
|
||||
appendGbase8sTableTypePredicate(sql, constraints);
|
||||
if (!owner.isEmpty()) {
|
||||
sql.append(" AND owner = ?");
|
||||
sql.append(" AND t.owner = ?");
|
||||
args.add(owner);
|
||||
}
|
||||
if (constraints.hasFilter()) {
|
||||
sql.append(" AND UPPER(tabname) LIKE ? ESCAPE '\\\\'");
|
||||
sql.append(" AND UPPER(t.tabname) LIKE ? ESCAPE '\\\\'");
|
||||
args.add(constraints.fuzzyLikePattern().toUpperCase(Locale.ROOT));
|
||||
}
|
||||
sql.append(" ORDER BY tabname");
|
||||
sql.append(" ORDER BY t.tabname");
|
||||
try (PreparedStatement stmt = requireConnection().prepareStatement(sql.toString())) {
|
||||
bind(stmt, args);
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
result.add(new TableInfo(
|
||||
trim(rs.getString("tabname")),
|
||||
tableType(rs.getString("tabtype"))
|
||||
tableType(rs.getString("tabtype")),
|
||||
emptyToNull(trim(rs.getString("comments")))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -554,6 +619,56 @@ public final class Gbase8sAgent extends ConfiguredJdbcAgent {
|
|||
return result;
|
||||
}
|
||||
|
||||
static List<String> resolveIndexColumns(List<Integer> parts, Map<Integer, String> columnNames) {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (Integer part : parts) {
|
||||
if (part == null || part == 0) {
|
||||
continue;
|
||||
}
|
||||
// Informix-compatible catalogs encode descending index columns as negative column numbers.
|
||||
String columnName = columnNames.get(Math.abs(part));
|
||||
if (columnName != null && !columnName.isEmpty()) {
|
||||
result.add(columnName);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<Integer, String> loadColumnNamesByNumber(String owner, String table) throws Exception {
|
||||
List<Object> args = new ArrayList<>();
|
||||
args.add(table);
|
||||
StringBuilder sql = new StringBuilder("""
|
||||
SELECT c.colno, c.colname
|
||||
FROM syscolumns c
|
||||
JOIN systables t ON t.tabid = c.tabid
|
||||
WHERE t.tabid >= 100 AND t.tabname = ?
|
||||
""".stripIndent().trim());
|
||||
if (!owner.isEmpty()) {
|
||||
sql.append(" AND t.owner = ?");
|
||||
args.add(owner);
|
||||
}
|
||||
|
||||
Map<Integer, String> result = new LinkedHashMap<>();
|
||||
try (PreparedStatement stmt = requireConnection().prepareStatement(sql.toString())) {
|
||||
bind(stmt, args);
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
result.put(rs.getInt("colno"), trim(rs.getString("colname")));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<Integer> readIndexParts(ResultSet rs) throws Exception {
|
||||
List<Integer> parts = new ArrayList<>();
|
||||
for (int index = 1; index <= 16; index += 1) {
|
||||
int value = rs.getInt("part" + index);
|
||||
parts.add(rs.wasNull() ? null : value);
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
|
||||
private Set<Integer> getPrimaryKeyColumnNumbers(Connection conn, String owner, String table) throws Exception {
|
||||
List<Object> args = new ArrayList<>();
|
||||
args.add(table);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.dbx.agent.gbase8s;
|
|||
|
||||
import com.dbx.agent.ConnectParams;
|
||||
import com.dbx.agent.ColumnInfo;
|
||||
import com.dbx.agent.IndexInfo;
|
||||
import com.dbx.agent.MetadataListConstraints;
|
||||
import com.dbx.agent.ObjectSource;
|
||||
import com.dbx.agent.TableInfo;
|
||||
|
|
@ -18,6 +19,7 @@ import java.sql.ResultSet;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
class Gbase8sAgentTest {
|
||||
|
|
@ -132,7 +134,25 @@ class Gbase8sAgentTest {
|
|||
Assertions.assertEquals("user_order", tables.get(0).getName());
|
||||
Assertions.assertTrue(sql.get(0).contains("FROM systables"), sql.get(0));
|
||||
Assertions.assertTrue(sql.get(0).contains("SELECT SKIP 1 FIRST 1"), sql.get(0));
|
||||
Assertions.assertTrue(sql.get(0).contains("UPPER(tabname) LIKE ?"), sql.get(0));
|
||||
Assertions.assertTrue(sql.get(0).contains("UPPER(t.tabname) LIKE ?"), sql.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void listTablesLoadsGbase8sTableComments() {
|
||||
List<String> sql = new ArrayList<>();
|
||||
Gbase8sAgent agent = new Gbase8sAgent();
|
||||
TestSupport.setPrivateConnection(agent, preparedConnection(sql, resultSet(
|
||||
new String[]{"tabname", "tabtype", "comments"},
|
||||
new Object[][]{
|
||||
{"products", "T", "Product catalog"}
|
||||
}
|
||||
)));
|
||||
|
||||
List<TableInfo> tables = agent.listTables("root");
|
||||
|
||||
Assertions.assertEquals("Product catalog", tables.get(0).getComment());
|
||||
Assertions.assertTrue(sql.get(0).contains("LEFT JOIN syscomms"), sql.get(0));
|
||||
Assertions.assertTrue(sql.get(0).contains("t.owner = ?"), sql.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -156,11 +176,11 @@ class Gbase8sAgentTest {
|
|||
}
|
||||
),
|
||||
resultSet(
|
||||
new String[]{"colname", "coltype", "colno", "collength"},
|
||||
new String[]{"colname", "coltype", "colno", "collength", "comments"},
|
||||
new Object[][]{
|
||||
{"product_id", 258, 1, 4},
|
||||
{"sku", 13, 2, 40},
|
||||
{"price", 5, 3, 3074}
|
||||
{"product_id", 258, 1, 4, "Product identifier"},
|
||||
{"sku", 13, 2, 40, null},
|
||||
{"price", 5, 3, 3074, "Unit price"}
|
||||
}
|
||||
)
|
||||
));
|
||||
|
|
@ -182,6 +202,54 @@ class Gbase8sAgentTest {
|
|||
Assertions.assertEquals("DECIMAL", columns.get(2).getData_type());
|
||||
Assertions.assertEquals(12, columns.get(2).getNumeric_precision());
|
||||
Assertions.assertEquals(2, columns.get(2).getNumeric_scale());
|
||||
Assertions.assertEquals("Product identifier", columns.get(0).getComment());
|
||||
Assertions.assertEquals("Unit price", columns.get(2).getComment());
|
||||
Assertions.assertTrue(sql.get(1).contains("LEFT JOIN syscolcomms"), sql.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void listIndexesLoadsGbase8sSystemCatalogIndexes() {
|
||||
List<String> sql = new ArrayList<>();
|
||||
Gbase8sAgent agent = new Gbase8sAgent();
|
||||
TestSupport.setPrivateConnection(agent, preparedConnection(
|
||||
sql,
|
||||
resultSet(
|
||||
new String[]{"colno", "colname"},
|
||||
new Object[][]{
|
||||
{1, "product_id"},
|
||||
{2, "sku"},
|
||||
{3, "created_at"}
|
||||
}
|
||||
),
|
||||
resultSet(
|
||||
new String[]{"idxname", "idxtype", "constrtype", "part1", "part2", "part3", "part4", "part5", "part6", "part7", "part8", "part9", "part10", "part11", "part12", "part13", "part14", "part15", "part16"},
|
||||
new Object[][]{
|
||||
{"products_pk", "U", "P", 1, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null},
|
||||
{"products_sku_created", "D", null, 2, -3, 0, null, null, null, null, null, null, null, null, null, null, null, null, null}
|
||||
}
|
||||
)
|
||||
));
|
||||
|
||||
List<IndexInfo> indexes = agent.listIndexes("root", "products");
|
||||
|
||||
Assertions.assertEquals(2, indexes.size());
|
||||
Assertions.assertEquals(List.of("product_id"), indexes.get(0).getColumns());
|
||||
Assertions.assertTrue(indexes.get(0).getIs_unique());
|
||||
Assertions.assertTrue(indexes.get(0).getIs_primary());
|
||||
Assertions.assertEquals(List.of("sku", "created_at"), indexes.get(1).getColumns());
|
||||
Assertions.assertFalse(indexes.get(1).getIs_unique());
|
||||
Assertions.assertFalse(indexes.get(1).getIs_primary());
|
||||
Assertions.assertTrue(sql.get(0).contains("FROM syscolumns"), sql.get(0));
|
||||
Assertions.assertTrue(sql.get(1).contains("FROM sysindexes"), sql.get(1));
|
||||
Assertions.assertTrue(sql.get(1).contains("LEFT JOIN sysconstraints"), sql.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolvesGbase8sIndexPartsInDeclaredOrder() {
|
||||
Assertions.assertEquals(
|
||||
List.of("sku", "created_at"),
|
||||
Gbase8sAgent.resolveIndexColumns(List.of(2, -3, 0), Map.of(2, "sku", 3, "created_at"))
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Loading…
Reference in New Issue