From 1b4b703fc05d5ce23acdaf6c7b50fc6fc9873cc7 Mon Sep 17 00:00:00 2001
From: jkee <jkee@yandex-team.ru>
Date: Sat, 21 Mar 2015 17:52:13 +0300
Subject: [PATCH] METR-15511: queries from squirrel

---
 .../metrika/clickhouse/CHConnection.java      |  3 +-
 .../clickhouse/CHDatabaseMetadata.java        |  5 +-
 .../metrika/clickhouse/CHStatement.java       | 19 +++++---
 .../clickhouse/copypaste/ByteFragment.java    | 18 +++++--
 .../clickhouse/copypaste/CHResultSet.java     | 24 ++++++----
 .../metrika/clickhouse/util/LogProxy.java     | 47 +++++++++++++++++++
 6 files changed, 91 insertions(+), 25 deletions(-)
 create mode 100644 src/main/java/ru/yandex/metrika/clickhouse/util/LogProxy.java

diff --git a/src/main/java/ru/yandex/metrika/clickhouse/CHConnection.java b/src/main/java/ru/yandex/metrika/clickhouse/CHConnection.java
index 6fcd399c..a1f78cc5 100644
--- a/src/main/java/ru/yandex/metrika/clickhouse/CHConnection.java
+++ b/src/main/java/ru/yandex/metrika/clickhouse/CHConnection.java
@@ -4,6 +4,7 @@ import org.apache.http.impl.client.CloseableHttpClient;
 import ru.yandex.metrika.clickhouse.config.ClickHouseSource;
 import ru.yandex.metrika.clickhouse.copypaste.HttpConnectionProperties;
 import ru.yandex.metrika.clickhouse.util.CHHttpClientBuilder;
+import ru.yandex.metrika.clickhouse.util.LogProxy;
 
 import java.io.IOException;
 import java.sql.*;
@@ -37,7 +38,7 @@ public class CHConnection implements Connection {
 
         ClickHouseSource source = new ClickHouseSource(host, portNum, "default");
 
-        return new CHStatement(httpclient, source, properties);
+        return LogProxy.wrap(Statement.class, new CHStatement(httpclient, source, properties));
     }
 
     @Override
diff --git a/src/main/java/ru/yandex/metrika/clickhouse/CHDatabaseMetadata.java b/src/main/java/ru/yandex/metrika/clickhouse/CHDatabaseMetadata.java
index d78c2968..7a0eb49a 100644
--- a/src/main/java/ru/yandex/metrika/clickhouse/CHDatabaseMetadata.java
+++ b/src/main/java/ru/yandex/metrika/clickhouse/CHDatabaseMetadata.java
@@ -800,7 +800,8 @@ public class CHDatabaseMetadata implements DatabaseMetaData {
             row.add(tableNamePattern);
             row.add(descTable.getString(1));
             String type = descTable.getString(2);
-            row.add(Integer.toString(CHResultSet.toSqlType(type)));
+            int sqlType = CHResultSet.toSqlType(type);
+            row.add(Integer.toString(sqlType));
             row.add(type);
 
             // column size ?
@@ -808,7 +809,7 @@ public class CHDatabaseMetadata implements DatabaseMetaData {
             row.add("0");
 
             // decimal digits
-            if (type.contains("Int")) {
+            if (sqlType == Types.INTEGER || sqlType == Types.BIGINT && type.contains("Int")) {
                 String bits = type.substring(type.indexOf("Int") + "Int".length());
                 row.add(bits); //bullshit
             } else {
diff --git a/src/main/java/ru/yandex/metrika/clickhouse/CHStatement.java b/src/main/java/ru/yandex/metrika/clickhouse/CHStatement.java
index 4f8a1cb3..07f5cf69 100644
--- a/src/main/java/ru/yandex/metrika/clickhouse/CHStatement.java
+++ b/src/main/java/ru/yandex/metrika/clickhouse/CHStatement.java
@@ -72,9 +72,19 @@ public class CHStatement implements Statement {
         return 1;
     }
 
+    @Override
+    public boolean execute(String sql) throws SQLException {
+        executeQuery(sql);
+        return true;
+    }
+
+
+
     @Override
     public void close() throws SQLException {
-        currentResult.close();
+        if (currentResult != null) {
+            currentResult.close();
+        }
     }
 
     @Override
@@ -132,14 +142,9 @@ public class CHStatement implements Statement {
 
     }
 
-    @Override
-    public boolean execute(String sql) throws SQLException {
-        return false;
-    }
-
     @Override
     public ResultSet getResultSet() throws SQLException {
-        return null;
+        return currentResult;
     }
 
     @Override
diff --git a/src/main/java/ru/yandex/metrika/clickhouse/copypaste/ByteFragment.java b/src/main/java/ru/yandex/metrika/clickhouse/copypaste/ByteFragment.java
index bb911f40..0736c89c 100644
--- a/src/main/java/ru/yandex/metrika/clickhouse/copypaste/ByteFragment.java
+++ b/src/main/java/ru/yandex/metrika/clickhouse/copypaste/ByteFragment.java
@@ -5,7 +5,6 @@ import ru.yandex.metrika.clickhouse.util.CopypasteUtils;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.util.Arrays;
 
 /**
  * @author orantius
@@ -45,11 +44,20 @@ public class ByteFragment {
 
     @Override
     public String toString() {
-        return "ByteFragment{" +
-                "buf=" + Arrays.toString(buf) +
-                ", start=" + start +
+        StringBuilder b = new StringBuilder();
+        b.append("ByteFragment{[");
+        for (byte b1 : buf) {
+            if (b1 == '\t') {
+                b.append("<TAB>");
+            } else {
+                b.append((char) b1);
+            }
+        }
+        b.append(']');
+        b.append(", start=" + start +
                 ", len=" + len +
-                '}';
+                '}');
+        return b.toString();
     }
 
     public ByteFragment[] split(byte sep) {
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 d930212f..888602a8 100644
--- a/src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultSet.java
+++ b/src/main/java/ru/yandex/metrika/clickhouse/copypaste/CHResultSet.java
@@ -301,17 +301,21 @@ public class CHResultSet extends AbstractResultSet {
 
     @Override
     public Object getObject(int columnIndex) throws SQLException {
-        int type = toSqlType(types[columnIndex - 1]);
-        switch (type) {
-            case Types.BIGINT:      return getLong(columnIndex);
-            case Types.INTEGER:     return getInt(columnIndex);
-            case Types.VARCHAR:     return getString(columnIndex);
-            case Types.FLOAT:       return getFloat(columnIndex);
-            case Types.DATE:        return getDate(columnIndex);
-            case Types.TIMESTAMP:   return getTime(columnIndex);
-            case Types.BLOB:        return getString(columnIndex);
+        try {
+            int type = toSqlType(types[columnIndex - 1]);
+            switch (type) {
+                case Types.BIGINT:      return getLong(columnIndex);
+                case Types.INTEGER:     return getInt(columnIndex);
+                case Types.VARCHAR:     return getString(columnIndex);
+                case Types.FLOAT:       return getFloat(columnIndex);
+                case Types.DATE:        return getDate(columnIndex);
+                case Types.TIMESTAMP:   return getTime(columnIndex);
+                case Types.BLOB:        return getString(columnIndex);
+            }
+            return getString(columnIndex);
+        } catch (Exception e) {
+            throw new RuntimeException("Parse exception: " + values[columnIndex - 1].toString(), e);
         }
-        return getString(columnIndex);
     }
 
     /////////////////////////////////////////////////////////
diff --git a/src/main/java/ru/yandex/metrika/clickhouse/util/LogProxy.java b/src/main/java/ru/yandex/metrika/clickhouse/util/LogProxy.java
new file mode 100644
index 00000000..69cba1c6
--- /dev/null
+++ b/src/main/java/ru/yandex/metrika/clickhouse/util/LogProxy.java
@@ -0,0 +1,47 @@
+package ru.yandex.metrika.clickhouse.util;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+
+/**
+ * Created by jkee on 21.03.15.
+ */
+public class LogProxy<T> implements InvocationHandler {
+
+    private static final Logger log = Logger.of(LogProxy.class);
+
+    private final T object;
+    private final Class<T> clazz;
+
+    public static <T> T wrap(Class<T> interfaceClass, T object) {
+        LogProxy<T> proxy = new LogProxy<T>(interfaceClass, object);
+        return proxy.getProxy();
+    }
+
+    private LogProxy(Class<T> interfaceClass, T object) {
+        if (!interfaceClass.isInterface()) {
+            throw new IllegalStateException("Class " + interfaceClass.getName() + " is not an interface");
+        }
+        clazz = interfaceClass;
+        this.object = object;
+    }
+
+    public T getProxy() {
+        //noinspection unchecked
+        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[]{clazz}, this);
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        log.info("Call class: " + clazz.getName() + " Method: " + method.getName() +
+        " Args: " + Arrays.toString(args));
+        try {
+            return method.invoke(object, args);
+        } catch (InvocationTargetException e) {
+            throw e.getTargetException();
+        }
+    }
+}
-- 
GitLab