From 6c418c98cfe63f8780a7abb61f5aefcef33e58a3 Mon Sep 17 00:00:00 2001
From: jkee <jkee@yandex-team.ru>
Date: Mon, 16 Mar 2015 19:14:44 +0300
Subject: [PATCH] METR-15511: refactor 1

---
 .../metrika/clickhouse/CHException.java       |  22 +++
 .../metrika/clickhouse/CHStatement.java       |  21 ++-
 .../{HttpResult.java => CHResultSet.java}     | 137 +-----------------
 .../copypaste/CHResultSetMetaData.java        | 134 +++++++++++++++++
 .../copypaste/ThrowingFunction.java           |   5 +
 5 files changed, 182 insertions(+), 137 deletions(-)
 create mode 100644 src/main/java/ru/yandex/metrika/clickhouse/CHException.java
 rename src/main/java/ru/yandex/metrika/clickhouse/copypaste/{HttpResult.java => CHResultSet.java} (63%)
 create mode 100644 src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultSetMetaData.java
 create mode 100644 src/main/java/ru/yandex/metrika/clickhouse/copypaste/ThrowingFunction.java

diff --git a/src/main/java/ru/yandex/metrika/clickhouse/CHException.java b/src/main/java/ru/yandex/metrika/clickhouse/CHException.java
new file mode 100644
index 00000000..c5fc9730
--- /dev/null
+++ b/src/main/java/ru/yandex/metrika/clickhouse/CHException.java
@@ -0,0 +1,22 @@
+package ru.yandex.metrika.clickhouse;
+
+import java.sql.SQLException;
+
+/**
+ * Created by jkee on 16.03.15.
+ */
+public class CHException extends SQLException {
+
+
+    public CHException(String reason) {
+        super(reason);
+    }
+
+    public CHException(String reason, int vendorCode) {
+        super(reason, null, vendorCode);
+    }
+
+    public CHException(String reason, Throwable cause) {
+        super(reason, cause);
+    }
+}
diff --git a/src/main/java/ru/yandex/metrika/clickhouse/CHStatement.java b/src/main/java/ru/yandex/metrika/clickhouse/CHStatement.java
index 2be88235..dc58be44 100644
--- a/src/main/java/ru/yandex/metrika/clickhouse/CHStatement.java
+++ b/src/main/java/ru/yandex/metrika/clickhouse/CHStatement.java
@@ -1,12 +1,12 @@
 package ru.yandex.metrika.clickhouse;
 
-import ru.yandex.metrika.clickhouse.copypaste.*;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.util.EntityUtils;
+import ru.yandex.metrika.clickhouse.copypaste.*;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -30,6 +30,10 @@ public class CHStatement implements Statement {
         this.url = url;
     }
 
+    public static String clickhousifySql(String sql) {
+        return clickhousifySql(sql, "TabSeparatedWithNamesAndTypes");
+    }
+
     public static String clickhousifySql(String sql, String format) {
         sql = sql.trim();
         if (!sql.replace(";", "").trim().endsWith(" TabSeparatedWithNamesAndTypes")
@@ -43,11 +47,11 @@ public class CHStatement implements Statement {
 
     @Override
     public ResultSet executeQuery(String sql) throws SQLException {
-        String csql = clickhousifySql(sql, "TabSeparatedWithNamesAndTypes");
+        String csql = clickhousifySql(sql);
         CountingInputStream is = getInputStream(csql);
         try {
-            return new HttpResult(properties.isCompress()
-                    ? new ClickhouseLZ4Stream(is) : is, is, properties.getBufferSize());
+            return new CHResultSet(properties.isCompress()
+                    ? new ClickhouseLZ4Stream(is) : is, properties.getBufferSize());
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
@@ -81,19 +85,22 @@ public class CHStatement implements Statement {
             return new CountingInputStream(is);
         } catch (IOException e) {
             EntityUtils.consumeQuietly(entity);
-            try { if (is != null) is.close(); } catch (IOException ignored) { }
             throw new RuntimeException(e);
         }
     }
 
     @Override
     public int executeUpdate(String sql) throws SQLException {
-        return 0;
+        throw new UnsupportedOperationException();
     }
 
     @Override
     public void close() throws SQLException {
-
+        try {
+            client.close();
+        } catch (IOException e) {
+            throw new CHException("HTTP client close exception", e);
+        }
     }
 
     @Override
diff --git a/src/main/java/ru/yandex/metrika/clickhouse/copypaste/HttpResult.java b/src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultSet.java
similarity index 63%
rename from src/main/java/ru/yandex/metrika/clickhouse/copypaste/HttpResult.java
rename to src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultSet.java
index 3f43b0d6..45366868 100644
--- a/src/main/java/ru/yandex/metrika/clickhouse/copypaste/HttpResult.java
+++ b/src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultSet.java
@@ -25,7 +25,7 @@ import java.util.Map;
  * @version $Id$
  * @since 7/12/12
  */
-public class HttpResult extends AbstractResultSet {
+public class CHResultSet extends AbstractResultSet {
 
     private ByteFragment nextLine;
     private final StreamSplitter bis;
@@ -33,20 +33,16 @@ public class HttpResult extends AbstractResultSet {
     private final Map<String, Integer> col = new HashMap<String, Integer>(); // column name -> 1-based index
     private final String[] columns;
     private final String[] types;
-    // number of characters read from is stream
-    private long bytes = 0;
-    private final CountingInputStream cis;
 
     private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //
 
     private ByteFragment[] values;
 
-    public HttpResult(InputStream is, CountingInputStream cis, int bufferSize) throws IOException {
-        this.cis = cis;
+    public CHResultSet(InputStream is, int bufferSize) throws IOException {
         bis = new StreamSplitter(is, (byte) 0x0A, bufferSize);  ///   \n
         ByteFragment headerFragment = bis.next();
         if (headerFragment == null) {
-            throw new IllegalArgumentException("ru.yandex.metrika.clickhouse response without column names");
+            throw new IllegalArgumentException("clickhouse response without column names");
         }
         String header = headerFragment.asString();
         if (header.startsWith("Code: ") && !header.contains("\t")) {
@@ -56,7 +52,7 @@ public class HttpResult extends AbstractResultSet {
         columns = Patterns.TAB.split(header);
         ByteFragment typesFragment = bis.next();
         if (typesFragment == null) {
-            throw new IllegalArgumentException("ru.yandex.metrika.clickhouse response without column types");
+            throw new IllegalArgumentException("clickhouse response without column types");
         }
         types = Patterns.TAB.split(typesFragment.asString());
 
@@ -72,8 +68,6 @@ public class HttpResult extends AbstractResultSet {
                 nextLine = bis.next();
                 if (nextLine == null || nextLine.length() == 0) {
                     bis.close();
-                } else {
-                    bytes += nextLine.getLen();
                 }
             } catch (IOException e) {
                 throw new SQLException(e);
@@ -115,125 +109,7 @@ public class HttpResult extends AbstractResultSet {
 
     @Override
     public ResultSetMetaData getMetaData() throws SQLException {
-        return new ResultSetMetaData() {
-            @Override
-            public int getColumnCount() throws SQLException {
-                return columns.length;
-            }
-
-            @Override
-            public boolean isAutoIncrement(int column) throws SQLException {
-                return false;
-            }
-
-            @Override
-            public boolean isCaseSensitive(int column) throws SQLException {
-                return true;
-            }
-
-            @Override
-            public boolean isSearchable(int column) throws SQLException {
-                return true;
-            }
-
-            @Override
-            public boolean isCurrency(int column) throws SQLException {
-                return false;
-            }
-
-            @Override
-            public int isNullable(int column) throws SQLException {
-                return columnNoNulls;
-            }
-
-            @Override
-            public boolean isSigned(int column) throws SQLException {
-                return !types[column - 1].startsWith("U");
-            }
-
-            @Override
-            public int getColumnDisplaySize(int column) throws SQLException {
-                return 80;
-            }
-
-            @Override
-            public String getColumnLabel(int column) throws SQLException {
-                return columns[column - 1];
-            }
-
-            @Override
-            public String getColumnName(int column) throws SQLException {
-                return columns[column - 1];
-            }
-
-            @Override
-            public String getSchemaName(int column) throws SQLException {
-                return "";
-            }
-
-            @Override
-            public int getPrecision(int column) throws SQLException {
-                return 0;
-            }
-
-            @Override
-            public int getScale(int column) throws SQLException {
-                return 0;
-            }
-
-            @Override
-            public String getTableName(int column) throws SQLException {
-                throw new UnsupportedOperationException("table name unknown at this stage");
-            }
-
-            @Override
-            public String getCatalogName(int column) throws SQLException {
-                throw new UnsupportedOperationException("catalog name unknown at this stage");
-            }
-
-            @Override
-            public int getColumnType(int column) throws SQLException {
-                return toSqlType(getColumnTypeName(column));
-            }
-
-            @Override
-            public String getColumnTypeName(int column) throws SQLException {
-                if (types.length < column) {
-                    throw new ArrayIndexOutOfBoundsException("Array length: " + types.length + " requested: " + (column - 1));
-                }
-                return types[column - 1];
-            }
-
-            @Override
-            public boolean isReadOnly(int column) throws SQLException {
-                return true;
-            }
-
-            @Override
-            public boolean isWritable(int column) throws SQLException {
-                return false;
-            }
-
-            @Override
-            public boolean isDefinitelyWritable(int column) throws SQLException {
-                return false;
-            }
-
-            @Override
-            public String getColumnClassName(int column) throws SQLException {
-                throw new UnsupportedOperationException("no classes for now");
-            }
-
-            @Override
-            public <T> T unwrap(Class<T> iface) throws SQLException {
-                return null;
-            }
-
-            @Override
-            public boolean isWrapperFor(Class<?> iface) throws SQLException {
-                return false;
-            }
-        };
+        return new CHResultSetMetaData(this);
     }
 
 
@@ -398,7 +274,7 @@ public class HttpResult extends AbstractResultSet {
         }
     }
 
-    private int toSqlType(String type) {
+    int toSqlType(String type) {
 
         if (type.startsWith("Int") || type.startsWith("UInt")) {
             if (type.endsWith("64")) return Types.BIGINT;
@@ -414,4 +290,5 @@ public class HttpResult extends AbstractResultSet {
         return Types.VARCHAR;
 
     }
+
 }
diff --git a/src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultSetMetaData.java b/src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultSetMetaData.java
new file mode 100644
index 00000000..8c827b5e
--- /dev/null
+++ b/src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultSetMetaData.java
@@ -0,0 +1,134 @@
+package ru.yandex.metrika.clickhouse.copypaste;
+
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+
+/**
+* Created by jkee on 16.03.15.
+*/
+public class CHResultSetMetaData implements ResultSetMetaData {
+
+    private final CHResultSet CHResultSet;
+
+    public CHResultSetMetaData(CHResultSet CHResultSet) {
+        this.CHResultSet = CHResultSet;
+    }
+
+    @Override
+    public int getColumnCount() throws SQLException {
+        return CHResultSet.getColumnNames().length;
+    }
+
+    @Override
+    public boolean isAutoIncrement(int column) throws SQLException {
+        return false;
+    }
+
+    @Override
+    public boolean isCaseSensitive(int column) throws SQLException {
+        return true;
+    }
+
+    @Override
+    public boolean isSearchable(int column) throws SQLException {
+        return true;
+    }
+
+    @Override
+    public boolean isCurrency(int column) throws SQLException {
+        return false;
+    }
+
+    @Override
+    public int isNullable(int column) throws SQLException {
+        return columnNoNulls;
+    }
+
+    @Override
+    public boolean isSigned(int column) throws SQLException {
+        return !CHResultSet.getTypes()[column - 1].startsWith("U");
+    }
+
+    @Override
+    public int getColumnDisplaySize(int column) throws SQLException {
+        return 80;
+    }
+
+    @Override
+    public String getColumnLabel(int column) throws SQLException {
+        return CHResultSet.getColumnNames()[column - 1];
+    }
+
+    @Override
+    public String getColumnName(int column) throws SQLException {
+        return CHResultSet.getColumnNames()[column - 1];
+    }
+
+    @Override
+    public String getSchemaName(int column) throws SQLException {
+        return "";
+    }
+
+    @Override
+    public int getPrecision(int column) throws SQLException {
+        return 0;
+    }
+
+    @Override
+    public int getScale(int column) throws SQLException {
+        return 0;
+    }
+
+    @Override
+    public String getTableName(int column) throws SQLException {
+        throw new UnsupportedOperationException("table name unknown at this stage");
+    }
+
+    @Override
+    public String getCatalogName(int column) throws SQLException {
+        throw new UnsupportedOperationException("catalog name unknown at this stage");
+    }
+
+    @Override
+    public int getColumnType(int column) throws SQLException {
+        return CHResultSet.toSqlType(getColumnTypeName(column));
+    }
+
+    @Override
+    public String getColumnTypeName(int column) throws SQLException {
+        if (CHResultSet.getTypes().length < column) {
+            throw new ArrayIndexOutOfBoundsException("Array length: " + CHResultSet.getTypes().length + " requested: " + (column - 1));
+        }
+        return CHResultSet.getTypes()[column - 1];
+    }
+
+    @Override
+    public boolean isReadOnly(int column) throws SQLException {
+        return true;
+    }
+
+    @Override
+    public boolean isWritable(int column) throws SQLException {
+        return false;
+    }
+
+    @Override
+    public boolean isDefinitelyWritable(int column) throws SQLException {
+        return false;
+    }
+
+    @Override
+    public String getColumnClassName(int column) throws SQLException {
+        throw new UnsupportedOperationException("no classes for now");
+    }
+
+    @Override
+    public <T> T unwrap(Class<T> iface) throws SQLException {
+        return null;
+    }
+
+    @Override
+    public boolean isWrapperFor(Class<?> iface) throws SQLException {
+        return false;
+    }
+}
diff --git a/src/main/java/ru/yandex/metrika/clickhouse/copypaste/ThrowingFunction.java b/src/main/java/ru/yandex/metrika/clickhouse/copypaste/ThrowingFunction.java
new file mode 100644
index 00000000..7c4dd4a8
--- /dev/null
+++ b/src/main/java/ru/yandex/metrika/clickhouse/copypaste/ThrowingFunction.java
@@ -0,0 +1,5 @@
+package ru.yandex.metrika.clickhouse.copypaste;
+
+public interface ThrowingFunction<F,R> {
+    R apply(F f) throws Exception;
+}
\ No newline at end of file
-- 
GitLab