-
Notifications
You must be signed in to change notification settings - Fork 655
feat: Add an ability to read metadata for attached databases #829
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 4 commits
e7fe0a9
8ccbf02
24fcc05
6e59227
e5e4f1d
6e6eea8
b0eab66
1313587
79fa812
61f5344
cd76f57
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -915,7 +915,9 @@ public ResultSet getColumns(String c, String s, String tblNamePattern, String co | |
| checkOpen(); | ||
|
|
||
| StringBuilder sql = new StringBuilder(700); | ||
| sql.append("select null as TABLE_CAT, null as TABLE_SCHEM, tblname as TABLE_NAME, ") | ||
| sql.append("select null as TABLE_CAT, ") | ||
| .append(quote(s == null ? "main" : s)) | ||
| .append(" as TABLE_SCHEM, tblname as TABLE_NAME, ") | ||
| .append( | ||
| "cn as COLUMN_NAME, ct as DATA_TYPE, tn as TYPE_NAME, colSize as COLUMN_SIZE, ") | ||
| .append( | ||
|
|
@@ -950,8 +952,9 @@ public ResultSet getColumns(String c, String s, String tblNamePattern, String co | |
| statColAutoinc = conn.createStatement(); | ||
| rsColAutoinc = | ||
| statColAutoinc.executeQuery( | ||
| "SELECT LIKE('%autoincrement%', LOWER(sql)) FROM sqlite_master " | ||
| + "WHERE LOWER(name) = LOWER('" | ||
| "SELECT LIKE('%autoincrement%', LOWER(sql)) FROM " | ||
| + prependSchemaPrefix( | ||
| s, "sqlite_master WHERE LOWER(name) = LOWER('") | ||
| + escape(tableName) | ||
| + "') AND TYPE IN ('table', 'view')"); | ||
| rsColAutoinc.next(); | ||
|
|
@@ -974,7 +977,10 @@ public ResultSet getColumns(String c, String s, String tblNamePattern, String co | |
| } | ||
|
|
||
| // For each table, get the column info and build into overall SQL | ||
| String pragmaStatement = "PRAGMA table_xinfo('" + escape(tableName) + "')"; | ||
| String pragmaStatement = | ||
| "PRAGMA " | ||
| + prependSchemaPrefix( | ||
| s, "table_xinfo('" + escape(tableName) + "')"); | ||
| try (Statement colstat = conn.createStatement(); | ||
| ResultSet rscol = colstat.executeQuery(pragmaStatement)) { | ||
|
|
||
|
|
@@ -1175,7 +1181,7 @@ public ResultSet getSchemas() throws SQLException { | |
| if (getSchemas == null) { | ||
| getSchemas = | ||
| conn.prepareStatement( | ||
| "select null as TABLE_SCHEM, null as TABLE_CATALOG limit 0;"); | ||
| "select name as TABLE_SCHEM, null as TABLE_CATALOG from pragma_database_list;"); | ||
| } | ||
|
|
||
| return getSchemas.executeQuery(); | ||
|
|
@@ -1195,12 +1201,14 @@ public ResultSet getCatalogs() throws SQLException { | |
| * java.lang.String) | ||
| */ | ||
| public ResultSet getPrimaryKeys(String c, String s, String table) throws SQLException { | ||
| PrimaryKeyFinder pkFinder = new PrimaryKeyFinder(table); | ||
| PrimaryKeyFinder pkFinder = new PrimaryKeyFinder(table, s); | ||
| String[] columns = pkFinder.getColumns(); | ||
|
|
||
| Statement stat = conn.createStatement(); | ||
| StringBuilder sql = new StringBuilder(512); | ||
| sql.append("select null as TABLE_CAT, null as TABLE_SCHEM, '") | ||
| sql.append("select null as TABLE_CAT, ") | ||
| .append(quote(s == null ? "main" : s)) | ||
|
||
| .append(" as TABLE_SCHEM, '") | ||
| .append(escape(table)) | ||
| .append("' as TABLE_NAME, cn as COLUMN_NAME, ks as KEY_SEQ, pk as PK_NAME from ("); | ||
|
|
||
|
|
@@ -1245,12 +1253,13 @@ public ResultSet getPrimaryKeys(String c, String s, String table) throws SQLExce | |
| */ | ||
| public ResultSet getExportedKeys(String catalog, String schema, String table) | ||
| throws SQLException { | ||
| PrimaryKeyFinder pkFinder = new PrimaryKeyFinder(table); | ||
| PrimaryKeyFinder pkFinder = new PrimaryKeyFinder(table, schema); | ||
| String[] pkColumns = pkFinder.getColumns(); | ||
| Statement stat = conn.createStatement(); | ||
|
|
||
| catalog = (catalog != null) ? quote(catalog) : null; | ||
| schema = (schema != null) ? quote(schema) : null; | ||
|
|
||
| String quotedSchema = (schema != null) ? quote(schema) : quote("main"); | ||
|
||
|
|
||
| StringBuilder exportedKeysQuery = new StringBuilder(512); | ||
|
|
||
|
|
@@ -1260,7 +1269,10 @@ public ResultSet getExportedKeys(String catalog, String schema, String table) | |
| // retrieve table list | ||
| ArrayList<String> tableList; | ||
| try (ResultSet rs = | ||
| stat.executeQuery("select name from sqlite_master where type = 'table'")) { | ||
| stat.executeQuery( | ||
| "select name from " | ||
| + prependSchemaPrefix( | ||
| schema, "sqlite_master where type = " + "'table'"))) { | ||
| tableList = new ArrayList<>(); | ||
|
|
||
| while (rs.next()) { | ||
|
|
@@ -1276,7 +1288,7 @@ public ResultSet getExportedKeys(String catalog, String schema, String table) | |
|
|
||
| // find imported keys for each table | ||
| for (String tbl : tableList) { | ||
| final ImportedKeyFinder impFkFinder = new ImportedKeyFinder(tbl); | ||
| final ImportedKeyFinder impFkFinder = new ImportedKeyFinder(tbl, schema); | ||
| List<ForeignKey> fkNames = impFkFinder.getFkList(); | ||
|
|
||
| for (ForeignKey foreignKey : fkNames) { | ||
|
|
@@ -1340,15 +1352,15 @@ public ResultSet getExportedKeys(String catalog, String schema, String table) | |
| sql.append("select ") | ||
| .append(catalog) | ||
| .append(" as PKTABLE_CAT, ") | ||
| .append(schema) | ||
| .append(quotedSchema) | ||
| .append(" as PKTABLE_SCHEM, ") | ||
| .append(quote(target)) | ||
| .append(" as PKTABLE_NAME, ") | ||
| .append(hasImportedKey ? "pcn" : "''") | ||
| .append(" as PKCOLUMN_NAME, ") | ||
| .append(catalog) | ||
| .append(" as FKTABLE_CAT, ") | ||
| .append(schema) | ||
| .append(quotedSchema) | ||
| .append(" as FKTABLE_SCHEM, ") | ||
| .append(hasImportedKey ? "fkt" : "''") | ||
| .append(" as FKTABLE_NAME, ") | ||
|
|
@@ -1404,12 +1416,12 @@ public ResultSet getImportedKeys(String catalog, String schema, String table) | |
| sql.append("select ") | ||
| .append(quote(catalog)) | ||
| .append(" as PKTABLE_CAT, ") | ||
| .append(quote(schema)) | ||
| .append(quote(schema == null ? "main" : schema)) | ||
|
||
| .append(" as PKTABLE_SCHEM, ") | ||
| .append("ptn as PKTABLE_NAME, pcn as PKCOLUMN_NAME, ") | ||
| .append(quote(catalog)) | ||
| .append(" as FKTABLE_CAT, ") | ||
| .append(quote(schema)) | ||
| .append(quote(schema == null ? "main" : schema)) | ||
|
||
| .append(" as FKTABLE_SCHEM, ") | ||
| .append(quote(table)) | ||
| .append(" as FKTABLE_NAME, ") | ||
|
|
@@ -1426,7 +1438,7 @@ public ResultSet getImportedKeys(String catalog, String schema, String table) | |
| return ((CoreStatement) stat).executeQuery(sql.toString(), true); | ||
| } | ||
|
|
||
| final ImportedKeyFinder impFkFinder = new ImportedKeyFinder(table); | ||
| final ImportedKeyFinder impFkFinder = new ImportedKeyFinder(table, schema); | ||
| List<ForeignKey> fkNames = impFkFinder.getFkList(); | ||
|
|
||
| int i = 0; | ||
|
|
@@ -1439,7 +1451,7 @@ public ResultSet getImportedKeys(String catalog, String schema, String table) | |
|
|
||
| String pkName = null; | ||
| try { | ||
| PrimaryKeyFinder pkFinder = new PrimaryKeyFinder(PKTabName); | ||
| PrimaryKeyFinder pkFinder = new PrimaryKeyFinder(PKTabName, schema); | ||
| pkName = pkFinder.getName(); | ||
| if (PKColName == null) { | ||
| PKColName = pkFinder.getColumns()[0]; | ||
|
|
@@ -1523,7 +1535,9 @@ public ResultSet getIndexInfo(String c, String s, String table, boolean u, boole | |
|
|
||
| // define the column header | ||
| // this is from the JDBC spec, it is part of the driver protocol | ||
| sql.append("select null as TABLE_CAT, null as TABLE_SCHEM, '") | ||
| sql.append("select null as TABLE_CAT,") | ||
| .append(quote(s == null ? "main" : s)) | ||
|
||
| .append(" as TABLE_SCHEM, '") | ||
| .append(escape(table)) | ||
| .append( | ||
| "' as TABLE_NAME, un as NON_UNIQUE, null as INDEX_QUALIFIER, n as INDEX_NAME, ") | ||
|
|
@@ -1533,7 +1547,9 @@ public ResultSet getIndexInfo(String c, String s, String table, boolean u, boole | |
| "cn as COLUMN_NAME, null as ASC_OR_DESC, 0 as CARDINALITY, 0 as PAGES, null as FILTER_CONDITION from ("); | ||
|
|
||
| // this always returns a result set now, previously threw exception | ||
| rs = stat.executeQuery("pragma index_list('" + escape(table) + "');"); | ||
| rs = | ||
| stat.executeQuery( | ||
| "pragma " + prependSchemaPrefix(s, "index_list('" + escape(table) + "');")); | ||
|
|
||
| ArrayList<ArrayList<Object>> indexList = new ArrayList<>(); | ||
| while (rs.next()) { | ||
|
|
@@ -1557,7 +1573,11 @@ public ResultSet getIndexInfo(String c, String s, String table, boolean u, boole | |
| while (indexIterator.hasNext()) { | ||
| currentIndex = indexIterator.next(); | ||
| String indexName = currentIndex.get(0).toString(); | ||
| rs = stat.executeQuery("pragma index_info('" + escape(indexName) + "');"); | ||
| rs = | ||
| stat.executeQuery( | ||
| "pragma " | ||
| + prependSchemaPrefix( | ||
| s, "index_info('" + escape(indexName) + "');")); | ||
|
|
||
| while (rs.next()) { | ||
|
|
||
|
|
@@ -1685,7 +1705,10 @@ public synchronized ResultSet getTables( | |
| StringBuilder sql = new StringBuilder(); | ||
| sql.append("SELECT").append("\n"); | ||
| sql.append(" NULL AS TABLE_CAT,").append("\n"); | ||
| sql.append(" NULL AS TABLE_SCHEM,").append("\n"); | ||
| sql.append(" ") | ||
| .append(quote(s == null ? "main" : s)) | ||
|
||
| .append(" AS TABLE_SCHEM,") | ||
| .append("\n"); | ||
| sql.append(" NAME AS TABLE_NAME,").append("\n"); | ||
| sql.append(" TYPE AS TABLE_TYPE,").append("\n"); | ||
| sql.append(" NULL AS REMARKS,").append("\n"); | ||
|
|
@@ -1704,7 +1727,8 @@ public synchronized ResultSet getTables( | |
| sql.append(" NAME,").append("\n"); | ||
| sql.append(" UPPER(TYPE) AS TYPE").append("\n"); | ||
| sql.append(" FROM").append("\n"); | ||
| sql.append(" sqlite_master").append("\n"); | ||
| sql.append(" "); | ||
| prependSchemaPrefix(sql, s, "sqlite_master\n"); | ||
| sql.append(" WHERE").append("\n"); | ||
| sql.append(" NAME NOT LIKE 'sqlite\\_%' ESCAPE '\\'").append("\n"); | ||
| sql.append(" AND UPPER(TYPE) IN ('TABLE', 'VIEW')").append("\n"); | ||
|
|
@@ -1719,7 +1743,8 @@ public synchronized ResultSet getTables( | |
| sql.append(" NAME,").append("\n"); | ||
| sql.append(" 'SYSTEM TABLE' AS TYPE").append("\n"); | ||
| sql.append(" FROM").append("\n"); | ||
| sql.append(" sqlite_master").append("\n"); | ||
| sql.append(" "); | ||
| prependSchemaPrefix(sql, s, "sqlite_master\n"); | ||
| sql.append(" WHERE").append("\n"); | ||
| sql.append(" NAME LIKE 'sqlite\\_%' ESCAPE '\\'").append("\n"); | ||
| sql.append(" )").append("\n"); | ||
|
|
@@ -1962,6 +1987,7 @@ public ResultSet getFunctionColumns(String a, String b, String c, String d) | |
|
|
||
| /** Parses the sqlite_master table for a table's primary key */ | ||
| class PrimaryKeyFinder { | ||
| String schema; | ||
| /** The table name. */ | ||
| String table; | ||
|
|
||
|
|
@@ -1971,15 +1997,20 @@ class PrimaryKeyFinder { | |
| /** The column(s) for the primary key. */ | ||
| String[] pkColumns = null; | ||
|
|
||
| public PrimaryKeyFinder(String table) throws SQLException { | ||
| this(table, null); | ||
| } | ||
|
|
||
| /** | ||
| * Constructor. | ||
| * | ||
| * @param table The table for which to get find a primary key. | ||
| * @param schema Schema in which table is located | ||
| * @throws SQLException | ||
| */ | ||
| public PrimaryKeyFinder(String table) throws SQLException { | ||
| public PrimaryKeyFinder(String table, String schema) throws SQLException { | ||
| this.table = table; | ||
|
|
||
| this.schema = schema; | ||
| if (table == null || table.trim().length() == 0) { | ||
| throw new SQLException("Invalid table name: '" + this.table + "'"); | ||
| } | ||
|
|
@@ -1988,10 +2019,13 @@ public PrimaryKeyFinder(String table) throws SQLException { | |
| // read create SQL script for table | ||
| ResultSet rs = | ||
| stat.executeQuery( | ||
| "select sql from sqlite_master where" | ||
| + " lower(name) = lower('" | ||
| + escape(table) | ||
| + "') and type in ('table', 'view')")) { | ||
| "select sql from " | ||
| + prependSchemaPrefix( | ||
| schema, | ||
| "sqlite_master where" | ||
| + " lower(name) = lower('" | ||
| + escape(table) | ||
| + "') and type in ('table', 'view')"))) { | ||
|
|
||
| if (!rs.next()) throw new SQLException("Table not found: '" + table + "'"); | ||
|
|
||
|
|
@@ -2008,7 +2042,11 @@ public PrimaryKeyFinder(String table) throws SQLException { | |
|
|
||
| if (pkColumns == null) { | ||
| try (ResultSet rs2 = | ||
| stat.executeQuery("pragma table_info('" + escape(table) + "');")) { | ||
| stat.executeQuery( | ||
| "pragma " | ||
| + prependSchemaPrefix( | ||
| schema, | ||
| "table_info('" + escape(table) + "');"))) { | ||
| while (rs2.next()) { | ||
| if (rs2.getBoolean(6)) pkColumns = new String[] {rs2.getString(2)}; | ||
| } | ||
|
|
@@ -2046,21 +2084,28 @@ class ImportedKeyFinder { | |
| private final List<ForeignKey> fkList = new ArrayList<>(); | ||
|
|
||
| public ImportedKeyFinder(String table) throws SQLException { | ||
| this(table, null); | ||
| } | ||
|
|
||
| public ImportedKeyFinder(String table, String schema) throws SQLException { | ||
|
|
||
| if (table == null || table.trim().length() == 0) { | ||
| throw new SQLException("Invalid table name: '" + table + "'"); | ||
| } | ||
|
|
||
| this.fkTableName = table; | ||
|
|
||
| List<String> fkNames = getForeignKeyNames(this.fkTableName); | ||
| List<String> fkNames = getForeignKeyNames(this.fkTableName, schema); | ||
|
|
||
| try (Statement stat = conn.createStatement(); | ||
| ResultSet rs = | ||
| stat.executeQuery( | ||
| "pragma foreign_key_list('" | ||
| + escape(this.fkTableName.toLowerCase()) | ||
| + "')")) { | ||
| "pragma " | ||
| + prependSchemaPrefix( | ||
| schema, | ||
| "foreign_key_list('" | ||
| + escape(this.fkTableName.toLowerCase()) | ||
| + "')"))) { | ||
|
|
||
| int prevFkId = -1; | ||
| int count = 0; | ||
|
|
@@ -2097,19 +2142,21 @@ public ImportedKeyFinder(String table) throws SQLException { | |
| } | ||
| } | ||
|
|
||
| private List<String> getForeignKeyNames(String tbl) throws SQLException { | ||
| private List<String> getForeignKeyNames(String tbl, String schema) throws SQLException { | ||
| List<String> fkNames = new ArrayList<>(); | ||
| if (tbl == null) { | ||
| return fkNames; | ||
| } | ||
| try (Statement stat2 = conn.createStatement(); | ||
| ResultSet rs = | ||
| stat2.executeQuery( | ||
| "select sql from sqlite_master where" | ||
| + " lower(name) = lower('" | ||
| + escape(tbl) | ||
| + "')")) { | ||
|
|
||
| "select sql from " | ||
| + prependSchemaPrefix( | ||
| schema, | ||
| "sqlite_master where" | ||
| + " lower(name) = lower('" | ||
| + escape(tbl) | ||
| + "')"))) { | ||
| if (rs.next()) { | ||
| Matcher matcher = FK_NAMED_PATTERN.matcher(rs.getString(1)); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about that.
The function should return the actual schema of the table, no? But it seems we just feed back the parameter that was passed.
If we have 2 tables with the same name in 2 different schemas, and we call this function without specifying the schema
s, then that function should return columns from both tables, but we would need to haveTABLE_SCHEMto differentiate them.