From 33f651bb05449f36b2ca0181a388bb2eeb451cbc Mon Sep 17 00:00:00 2001 From: jkee <jkee@yandex-team.ru> Date: Tue, 24 Mar 2015 14:24:33 +0300 Subject: [PATCH] METR-15511: catalogs, schemas --- .../metrika/clickhouse/CHConnection.java | 9 +- .../clickhouse/CHDatabaseMetadata.java | 110 +++++++++++------- .../yandex/metrika/clickhouse/CHDriver.java | 4 +- .../clickhouse/copypaste/CHResultBuilder.java | 12 +- .../clickhouse/copypaste/CHResultSet.java | 3 +- .../clickhouse/util/CopypasteUtils.java | 34 ++++++ 6 files changed, 123 insertions(+), 49 deletions(-) diff --git a/src/main/java/ru/yandex/metrika/clickhouse/CHConnection.java b/src/main/java/ru/yandex/metrika/clickhouse/CHConnection.java index c9f986c0..9fdf2d6c 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/CHConnection.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/CHConnection.java @@ -106,7 +106,7 @@ public class CHConnection implements Connection { @Override public DatabaseMetaData getMetaData() throws SQLException { - return new CHDatabaseMetadata(url, this); + return LogProxy.wrap(DatabaseMetaData.class, new CHDatabaseMetadata(url, this)); } @Override @@ -247,7 +247,12 @@ public class CHConnection implements Connection { @Override public boolean isValid(int timeout) throws SQLException { - return false; + // todo timeout + Statement statement = createStatement(); + statement.execute("SELECT 1"); + statement.close(); + // no exception - fine + return true; } @Override diff --git a/src/main/java/ru/yandex/metrika/clickhouse/CHDatabaseMetadata.java b/src/main/java/ru/yandex/metrika/clickhouse/CHDatabaseMetadata.java index 3d609e70..b229e7e1 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/CHDatabaseMetadata.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/CHDatabaseMetadata.java @@ -2,6 +2,7 @@ package ru.yandex.metrika.clickhouse; import ru.yandex.metrika.clickhouse.copypaste.CHResultBuilder; import ru.yandex.metrika.clickhouse.copypaste.CHResultSet; +import ru.yandex.metrika.clickhouse.util.CopypasteUtils; import ru.yandex.metrika.clickhouse.util.Logger; import java.sql.*; @@ -13,6 +14,8 @@ import java.util.List; */ public class CHDatabaseMetadata implements DatabaseMetaData { + private static final String DEFAULT_CAT = "default"; + private static final Logger log = Logger.of(CHDatabaseMetadata.class); private String url; @@ -325,17 +328,17 @@ public class CHDatabaseMetadata implements DatabaseMetaData { @Override public String getSchemaTerm() throws SQLException { - return "schema"; + return "database"; } @Override public String getProcedureTerm() throws SQLException { - return "some bullshit"; + return "procedure"; } @Override public String getCatalogTerm() throws SQLException { - return "database"; + return "catalog"; } @Override @@ -350,32 +353,32 @@ public class CHDatabaseMetadata implements DatabaseMetaData { @Override public boolean supportsSchemasInDataManipulation() throws SQLException { - return false; + return true; } @Override public boolean supportsSchemasInProcedureCalls() throws SQLException { - return false; + return true; } @Override public boolean supportsSchemasInTableDefinitions() throws SQLException { - return false; + return true; } @Override public boolean supportsSchemasInIndexDefinitions() throws SQLException { - return false; + return true; } @Override public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { - return false; + return true; } @Override public boolean supportsCatalogsInDataManipulation() throws SQLException { - return true; + return false; } @Override @@ -385,12 +388,12 @@ public class CHDatabaseMetadata implements DatabaseMetaData { @Override public boolean supportsCatalogsInTableDefinitions() throws SQLException { - return true; + return false; } @Override public boolean supportsCatalogsInIndexDefinitions() throws SQLException { - return true; + return false; } @Override @@ -672,14 +675,18 @@ public class CHDatabaseMetadata implements DatabaseMetaData { SELF_REFERENCING_COL_NAME String => name of the designated "identifier" column of a typed table (may be null) REF_GENERATION String => specifies how values in SELF_REFERENCING_COL_NAME are created. Values are "SYSTEM", "USER", "DERIVED". (may be null) */ - if (catalog == null || catalog.isEmpty()) { - catalog = "default"; - } String sql = "select " + - "database, name, name " + - "from system.tables " + - "where database = '" + catalog + "' " + - "order by name"; + "database, name " + + "from system.tables"; + if (schemaPattern != null) { + sql += " where database like '" + schemaPattern + "'"; + } + if (tableNamePattern != null) { + if (schemaPattern != null) sql += " and"; + else sql += " where"; + sql += " name like '" + tableNamePattern + "'"; + } + sql += " order by database, name"; ResultSet result = request(sql); CHResultBuilder builder = CHResultBuilder.builder(10); @@ -688,15 +695,16 @@ public class CHDatabaseMetadata implements DatabaseMetaData { while(result.next()) { List<String> row = new ArrayList<String>(); + row.add(DEFAULT_CAT); row.add(result.getString(1)); row.add(result.getString(2)); - row.add(result.getString(3)); row.add("TABLE"); // можно Ñделать точнее - for (int i = 4; i < 10; i++) { + for (int i = 3; i < 9; i++) { row.add(null); } builder.addRow(row); } + result.close(); return builder.build(); } @@ -707,19 +715,27 @@ public class CHDatabaseMetadata implements DatabaseMetaData { @Override public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { - String sql = "select name, database from system.tables"; - if (catalog != null) sql += " where database = '" + catalog + '\''; + // Ñто Ð·Ð°Ð¿Ñ€Ð¾Ñ Ðº system.tables, который теоретичеÑки не нужен. Однако, system.databases отÑутÑтвует, + // а по show databases Ð½ÐµÐ»ÑŒÐ·Ñ Ñделать LIKE. + String sql = "select distinct database as TABLE_SCHEM, '" + + DEFAULT_CAT + "' as TABLE_CATALOG from system.tables"; + if (catalog != null) sql += " where TABLE_CATALOG = '" + catalog + '\''; if (schemaPattern != null) { if (catalog != null) sql += " and "; else sql += " where "; - sql += "name = '" + schemaPattern + '\''; + sql += "name LIKE '" + schemaPattern + '\''; } return request(sql); } @Override public ResultSet getCatalogs() throws SQLException { - return request("show databases"); + CHResultBuilder builder = CHResultBuilder.builder(1); + builder.names("TABLE_CAT"); + builder.types("String"); + + builder.addRow(DEFAULT_CAT); + return builder.build(); } @Override @@ -783,9 +799,10 @@ public class CHDatabaseMetadata implements DatabaseMetaData { "Int32", "String" ); + // todo Ñто вÑÑ‘ брехнÑ, ждем https://st.yandex-team.ru/METR-15619 String sql = "desc table "; - if (catalog != null) sql += catalog + '.'; - sql += tableNamePattern; + if (schemaPattern != null) sql += CopypasteUtils.unEscapeString(schemaPattern) + '.'; + sql += CopypasteUtils.unEscapeString(tableNamePattern); ResultSet descTable = request(sql); int colNum = 1; while (descTable.next()) { @@ -795,8 +812,8 @@ public class CHDatabaseMetadata implements DatabaseMetaData { continue; } List<String> row = new ArrayList<String>(); - row.add(catalog); - row.add(tableNamePattern); + row.add(DEFAULT_CAT); + row.add(schemaPattern); row.add(tableNamePattern); row.add(descTable.getString(1)); String type = descTable.getString(2); @@ -842,48 +859,53 @@ public class CHDatabaseMetadata implements DatabaseMetaData { builder.addRow(row); } + descTable.close(); return builder.build(); } + private ResultSet getEmptyResultSet() { + return CHResultBuilder.builder(1).names("bullshit").types("String").build(); + } + @Override public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException { - return null; + return getEmptyResultSet(); } @Override public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { - return null; + return getEmptyResultSet(); } @Override public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException { - return null; + return getEmptyResultSet(); } @Override public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException { - return null; + return getEmptyResultSet(); } @Override public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { - return null; + return getEmptyResultSet(); } @Override public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException { - return null; + return getEmptyResultSet(); } @Override public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException { - return null; + return getEmptyResultSet(); } @Override public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { - return null; + return getEmptyResultSet(); } @Override @@ -1010,7 +1032,7 @@ public class CHDatabaseMetadata implements DatabaseMetaData { @Override public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException { - return null; + return getEmptyResultSet(); } @Override @@ -1079,7 +1101,7 @@ public class CHDatabaseMetadata implements DatabaseMetaData { @Override public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException { - return null; + return getEmptyResultSet(); } @Override @@ -1109,17 +1131,17 @@ public class CHDatabaseMetadata implements DatabaseMetaData { @Override public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException { - return null; + return getEmptyResultSet(); } @Override public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { - return null; + return getEmptyResultSet(); } @Override public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException { - return null; + return getEmptyResultSet(); } @Override @@ -1184,17 +1206,17 @@ public class CHDatabaseMetadata implements DatabaseMetaData { @Override public ResultSet getClientInfoProperties() throws SQLException { - return null; + return getEmptyResultSet(); } @Override public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException { - return null; + return getEmptyResultSet(); } @Override public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) throws SQLException { - return null; + return getEmptyResultSet(); } @Override diff --git a/src/main/java/ru/yandex/metrika/clickhouse/CHDriver.java b/src/main/java/ru/yandex/metrika/clickhouse/CHDriver.java index abc2b374..f82ecc94 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/CHDriver.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/CHDriver.java @@ -1,5 +1,6 @@ package ru.yandex.metrika.clickhouse; +import ru.yandex.metrika.clickhouse.util.LogProxy; import ru.yandex.metrika.clickhouse.util.Logger; import java.sql.*; @@ -33,7 +34,8 @@ public class CHDriver implements Driver { @Override public Connection connect(String url, Properties info) throws SQLException { - return new CHConnection(url); + logger.info("Creating connection"); + return LogProxy.wrap(Connection.class, new CHConnection(url)); } @Override diff --git a/src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultBuilder.java b/src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultBuilder.java index 5f340e79..565ff48d 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultBuilder.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultBuilder.java @@ -89,7 +89,17 @@ public class CHResultBuilder { baos.write('\\'); baos.write('N'); } else { - ByteFragment.escape(o.toString().getBytes(), baos); + String value; + if (o instanceof Boolean) { + if ((Boolean) o) { + value = "1"; + } else { + value = "0"; + } + } else { + value = o.toString(); + } + ByteFragment.escape(value.getBytes(), baos); } } diff --git a/src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultSet.java b/src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultSet.java index ea0c0ff1..613288d9 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultSet.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultSet.java @@ -90,12 +90,13 @@ public class CHResultSet extends AbstractResultSet { nextLine = bis.next(); if (nextLine == null || nextLine.length() == 0 || (maxRows != 0 && rowNumber >= maxRows)) { bis.close(); + nextLine = null; } } catch (IOException e) { throw new SQLException(e); } } - return nextLine != null && nextLine.length() > 0; + return nextLine != null; } @Override public boolean next() throws SQLException { diff --git a/src/main/java/ru/yandex/metrika/clickhouse/util/CopypasteUtils.java b/src/main/java/ru/yandex/metrika/clickhouse/util/CopypasteUtils.java index 77a5ae71..69d1753c 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/util/CopypasteUtils.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/util/CopypasteUtils.java @@ -75,6 +75,40 @@ public class CopypasteUtils { return list.toArray(new String[list.size()]); } + /** + * раÑкукоживатель + */ + public static String unEscapeString(String string) { + if (isBlank(string)) return string; + + char current = 0; + int length = string.length(); + StringBuilder sb = new StringBuilder(length + 4); + for (int i = 0; i < length; i += 1) { + current = string.charAt(i); + if (current == '\\') { + if (i + 1 >= length) { + return sb.toString(); + } + if (string.charAt(i + 1) == 'u') { + if (i + 5 >= length) { + return sb.toString(); + } + sb.append((char) Integer.parseInt(string.substring(i + 2, i + 6), 16)); + //noinspection AssignmentToForLoopParameter + i += 4; + } else { + sb.append(string.charAt(i + 1)); + } + //noinspection AssignmentToForLoopParameter + i++; + } else { + sb.append(current); + } + } + + return sb.toString(); + } /////// Apache StringUtils //////// -- GitLab