You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tajo.apache.org by hy...@apache.org on 2013/12/30 10:18:02 UTC
[6/6] git commit: TAJO-456: Separate tajo-jdbc and tajo-client from
tajo-core-backend. (hyunsik)
TAJO-456: Separate tajo-jdbc and tajo-client from tajo-core-backend. (hyunsik)
Project: http://git-wip-us.apache.org/repos/asf/incubator-tajo/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tajo/commit/b6a5ff0c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tajo/tree/b6a5ff0c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tajo/diff/b6a5ff0c
Branch: refs/heads/master
Commit: b6a5ff0c39e3fd50fc27c2a3804218fc884135f5
Parents: d39bb99
Author: Hyunsik Choi <hy...@apache.org>
Authored: Mon Dec 30 18:17:07 2013 +0900
Committer: Hyunsik Choi <hy...@apache.org>
Committed: Mon Dec 30 18:17:42 2013 +0900
----------------------------------------------------------------------
CHANGES.txt | 2 +
pom.xml | 2 +
tajo-catalog/tajo-catalog-client/pom.xml | 6 +-
tajo-catalog/tajo-catalog-common/pom.xml | 6 +-
tajo-catalog/tajo-catalog-server/pom.xml | 1 +
tajo-client/pom.xml | 399 ++++++
.../main/java/org/apache/tajo/cli/TajoCli.java | 723 +++++++++++
.../org/apache/tajo/client/QueryStatus.java | 86 ++
.../org/apache/tajo/client/ResultSetUtil.java | 193 +++
.../java/org/apache/tajo/client/TajoClient.java | 462 +++++++
.../java/org/apache/tajo/client/TajoDump.java | 129 ++
.../java/org/apache/tajo/jdbc/SQLStates.java | 33 +
.../org/apache/tajo/jdbc/TajoResultSet.java | 152 +++
.../org/apache/tajo/jdbc/TajoResultSetBase.java | 1129 +++++++++++++++++
.../apache/tajo/jdbc/TajoResultSetMetaData.java | 161 +++
tajo-client/src/main/proto/ClientProtos.proto | 138 ++
.../main/proto/QueryMasterClientProtocol.proto | 35 +
.../main/proto/TajoMasterClientProtocol.proto | 62 +
tajo-client/src/main/resources/log4j.properties | 27 +
tajo-common/pom.xml | 8 +-
.../java/org/apache/tajo/conf/TajoConf.java | 7 +-
.../java/org/apache/tajo/storage/Tuple.java | 80 --
.../main/java/org/apache/tajo/util/TUtil.java | 5 +
tajo-common/src/main/proto/tajo_protos.proto | 46 +
tajo-core/pom.xml | 4 -
tajo-core/tajo-core-backend/pom.xml | 30 +-
.../main/java/org/apache/tajo/cli/TajoCli.java | 724 -----------
.../org/apache/tajo/client/QueryStatus.java | 86 --
.../org/apache/tajo/client/ResultSetUtil.java | 49 -
.../java/org/apache/tajo/client/SQLStates.java | 33 -
.../java/org/apache/tajo/client/TajoClient.java | 461 -------
.../java/org/apache/tajo/client/TajoDump.java | 129 --
.../org/apache/tajo/jdbc/MetaDataTuple.java | 194 ---
.../org/apache/tajo/jdbc/TajoConnection.java | 400 ------
.../apache/tajo/jdbc/TajoDatabaseMetaData.java | 1196 ------------------
.../java/org/apache/tajo/jdbc/TajoDriver.java | 233 ----
.../apache/tajo/jdbc/TajoMetaDataResultSet.java | 77 --
.../apache/tajo/jdbc/TajoPreparedStatement.java | 660 ----------
.../org/apache/tajo/jdbc/TajoResultSet.java | 152 ---
.../org/apache/tajo/jdbc/TajoResultSetBase.java | 1129 -----------------
.../apache/tajo/jdbc/TajoResultSetMetaData.java | 160 ---
.../org/apache/tajo/jdbc/TajoStatement.java | 289 -----
.../src/main/proto/ClientProtos.proto | 139 --
.../main/proto/QueryMasterClientProtocol.proto | 36 -
.../main/proto/TajoMasterClientProtocol.proto | 63 -
.../src/main/proto/tajo_protos.proto | 46 -
tajo-core/tajo-core-pullserver/pom.xml | 4 +-
.../java/org/apache/tajo/storage/Tuple.java | 80 ++
tajo-core/tajo-core-storage/pom.xml | 42 +-
tajo-dist/pom.xml | 6 +
tajo-jdbc/pom.xml | 191 +++
.../org/apache/tajo/jdbc/MetaDataTuple.java | 192 +++
.../org/apache/tajo/jdbc/TajoConnection.java | 398 ++++++
.../apache/tajo/jdbc/TajoDatabaseMetaData.java | 1196 ++++++++++++++++++
.../java/org/apache/tajo/jdbc/TajoDriver.java | 89 ++
.../apache/tajo/jdbc/TajoMetaDataResultSet.java | 75 ++
.../apache/tajo/jdbc/TajoPreparedStatement.java | 658 ++++++++++
.../org/apache/tajo/jdbc/TajoStatement.java | 287 +++++
tajo-jdbc/src/main/resources/log4j.properties | 27 +
tajo-project/pom.xml | 18 +-
tajo-rpc/pom.xml | 56 +-
.../org/apache/tajo/rpc/RpcConnectionPool.java | 4 +-
62 files changed, 7073 insertions(+), 6432 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/b6a5ff0c/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index fae9d1d..76b0acc 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -110,6 +110,8 @@ Release 0.8.0 - unreleased
IMPROVEMENTS
+ TAJO-456: Separate tajo-jdbc and tajo-client from tajo-core-backend. (hyunsik)
+
TAJO-432: Add shuffle phase for column-partitioned table store. (Min Zhou via jihoon)
TAJO-135: Bump up hadoop to 2.2.0. (jihoon)
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/b6a5ff0c/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index c485119..5b0effb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -83,6 +83,8 @@
<module>tajo-core</module>
<module>tajo-rpc</module>
<module>tajo-catalog</module>
+ <module>tajo-client</module>
+ <module>tajo-jdbc</module>
<module>tajo-dist</module>
</modules>
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/b6a5ff0c/tajo-catalog/tajo-catalog-client/pom.xml
----------------------------------------------------------------------
diff --git a/tajo-catalog/tajo-catalog-client/pom.xml b/tajo-catalog/tajo-catalog-client/pom.xml
index 41e7bbe..b511739 100644
--- a/tajo-catalog/tajo-catalog-client/pom.xml
+++ b/tajo-catalog/tajo-catalog-client/pom.xml
@@ -136,6 +136,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
@@ -145,11 +146,6 @@
<groupId>commons-logging</groupId>
<artifactId>commons-logging-api</artifactId>
</dependency>
- <dependency>
- <groupId>org.apache.derby</groupId>
- <artifactId>derby</artifactId>
- <version>10.8.2.2</version>
- </dependency>
</dependencies>
<profiles>
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/b6a5ff0c/tajo-catalog/tajo-catalog-common/pom.xml
----------------------------------------------------------------------
diff --git a/tajo-catalog/tajo-catalog-common/pom.xml b/tajo-catalog/tajo-catalog-common/pom.xml
index f424110..a4db647 100644
--- a/tajo-catalog/tajo-catalog-common/pom.xml
+++ b/tajo-catalog/tajo-catalog-common/pom.xml
@@ -150,6 +150,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
@@ -159,11 +160,6 @@
<groupId>commons-logging</groupId>
<artifactId>commons-logging-api</artifactId>
</dependency>
- <dependency>
- <groupId>org.apache.derby</groupId>
- <artifactId>derby</artifactId>
- <version>10.8.2.2</version>
- </dependency>
</dependencies>
<profiles>
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/b6a5ff0c/tajo-catalog/tajo-catalog-server/pom.xml
----------------------------------------------------------------------
diff --git a/tajo-catalog/tajo-catalog-server/pom.xml b/tajo-catalog/tajo-catalog-server/pom.xml
index ab3139b..03e92ec 100644
--- a/tajo-catalog/tajo-catalog-server/pom.xml
+++ b/tajo-catalog/tajo-catalog-server/pom.xml
@@ -135,6 +135,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/b6a5ff0c/tajo-client/pom.xml
----------------------------------------------------------------------
diff --git a/tajo-client/pom.xml b/tajo-client/pom.xml
new file mode 100644
index 0000000..797ad3a
--- /dev/null
+++ b/tajo-client/pom.xml
@@ -0,0 +1,399 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>tajo-project</artifactId>
+ <groupId>org.apache.tajo</groupId>
+ <version>0.8.0-SNAPSHOT</version>
+ <relativePath>../tajo-project</relativePath>
+ </parent>
+ <artifactId>tajo-client</artifactId>
+ <packaging>jar</packaging>
+ <name>Tajo Client</name>
+ <version>0.8.0-SNAPSHOT</version>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ <metrics.version>3.0.1</metrics.version>
+ </properties>
+
+ <repositories>
+ <repository>
+ <id>repository.jboss.org</id>
+ <url>https://repository.jboss.org/nexus/content/repositories/releases/
+ </url>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ <encoding>${project.build.sourceEncoding}</encoding>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.12.4</version>
+ <configuration>
+ <systemProperties>
+ <tajo.test>TRUE</tajo.test>
+ </systemProperties>
+ <argLine>-Xms512m -Xmx1024m -Dfile.encoding=UTF-8</argLine>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.2</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>create-protobuf-generated-sources-directory</id>
+ <phase>initialize</phase>
+ <configuration>
+ <target>
+ <mkdir dir="target/generated-sources/proto" />
+ </target>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.2</version>
+ <executions>
+ <execution>
+ <id>generate-sources</id>
+ <phase>generate-sources</phase>
+ <configuration>
+ <executable>protoc</executable>
+ <arguments>
+ <argument>-Isrc/main/proto/</argument>
+ <argument>--proto_path=../tajo-common/src/main/proto</argument>
+ <argument>--proto_path=../tajo-catalog/tajo-catalog-common/src/main/proto</argument>
+ <argument>--proto_path=../tajo-core/tajo-core-backend/src/main/proto</argument>
+ <argument>--java_out=target/generated-sources/proto</argument>
+ <argument>src/main/proto/ClientProtos.proto</argument>
+ <argument>src/main/proto/TajoMasterClientProtocol.proto</argument>
+ <argument>src/main/proto/QueryMasterClientProtocol.proto</argument>
+ </arguments>
+ </configuration>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>add-source</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>target/generated-sources/proto</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-dependencies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/lib</outputDirectory>
+ <overWriteReleases>false</overWriteReleases>
+ <overWriteSnapshots>false</overWriteSnapshots>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ <excludeGroupIds>org.apache.hadoop</excludeGroupIds>
+ <excludeScope>provided</excludeScope>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-pmd-plugin</artifactId>
+ <version>2.7.1</version>
+ </plugin>
+ </plugins>
+ </build>
+
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.tajo</groupId>
+ <artifactId>tajo-common</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>joda-time</groupId>
+ <artifactId>joda-time</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.sun.jersey.jersey-test-framework</groupId>
+ <artifactId>jersey-test-framework-grizzly2</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tajo</groupId>
+ <artifactId>tajo-catalog-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tajo</groupId>
+ <artifactId>tajo-core-storage</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tajo</groupId>
+ <artifactId>tajo-rpc</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.hadoop</groupId>
+ <artifactId>hadoop-common</artifactId>
+ <scope>provided</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>commons-el</groupId>
+ <artifactId>commons-el</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>tomcat</groupId>
+ <artifactId>jasper-runtime</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>tomcat</groupId>
+ <artifactId>jasper-compiler</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>joda-time</groupId>
+ <artifactId>joda-time</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jsp-2.1-jetty</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.sun.jersey.jersey-test-framework</groupId>
+ <artifactId>jersey-test-framework-grizzly2</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.hadoop</groupId>
+ <artifactId>hadoop-hdfs</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>jline</groupId>
+ <artifactId>jline</artifactId>
+ <version>2.11</version>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>docs</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <!-- build javadoc jars per jar for publishing to maven -->
+ <id>module-javadocs</id>
+ <phase>package</phase>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ <configuration>
+ <destDir>${project.build.directory}</destDir>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>src</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <executions>
+ <execution>
+ <!-- builds source jars and attaches them to the project for publishing -->
+ <id>tajo-java-sources</id>
+ <phase>package</phase>
+ <goals>
+ <goal>jar-no-fork</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>dist</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>tar|rpm|deb</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>dist</id>
+ <phase>package</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <target>
+ <echo file="${project.build.directory}/dist-layout-stitching.sh">
+ run() {
+ echo "\$ ${@}"
+ "${@}"
+ res=$?
+ if [ $res != 0 ]; then
+ echo
+ echo "Failed!"
+ echo
+ exit $res
+ fi
+ }
+
+ ROOT=`cd ${basedir}/..;pwd`
+ echo
+ echo "Current directory `pwd`"
+ echo
+ run rm -rf ${project.artifactId}-${project.version}
+ run mkdir ${project.artifactId}-${project.version}
+ run cd ${project.artifactId}-${project.version}
+ run cp -r ${basedir}/target/${project.artifactId}-${project.version}*.jar .
+ echo
+ echo "Tajo Client dist layout available at: ${project.build.directory}/${project.artifactId}-${project.version}"
+ echo
+ </echo>
+ <exec executable="sh" dir="${project.build.directory}" failonerror="true">
+ <arg line="./dist-layout-stitching.sh"/>
+ </exec>
+ </target>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-project-info-reports-plugin</artifactId>
+ <version>2.4</version>
+ <configuration>
+ <dependencyLocationsEnabled>false</dependencyLocationsEnabled>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ <version>2.15</version>
+ </plugin>
+ </plugins>
+ </reporting>
+</project>
+
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/b6a5ff0c/tajo-client/src/main/java/org/apache/tajo/cli/TajoCli.java
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/java/org/apache/tajo/cli/TajoCli.java b/tajo-client/src/main/java/org/apache/tajo/cli/TajoCli.java
new file mode 100644
index 0000000..2e7a92c
--- /dev/null
+++ b/tajo-client/src/main/java/org/apache/tajo/cli/TajoCli.java
@@ -0,0 +1,723 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.cli;
+
+import jline.console.ConsoleReader;
+import jline.console.history.FileHistory;
+import jline.console.history.PersistentHistory;
+import org.apache.commons.cli.*;
+import org.apache.commons.lang.StringUtils;
+import org.apache.tajo.QueryId;
+import org.apache.tajo.QueryIdFactory;
+import org.apache.tajo.TajoConstants;
+import org.apache.tajo.TajoProtos.QueryState;
+import org.apache.tajo.catalog.CatalogUtil;
+import org.apache.tajo.catalog.Column;
+import org.apache.tajo.catalog.TableDesc;
+import org.apache.tajo.catalog.partition.Specifier;
+import org.apache.tajo.catalog.statistics.TableStats;
+import org.apache.tajo.client.QueryStatus;
+import org.apache.tajo.client.TajoClient;
+import org.apache.tajo.conf.TajoConf;
+import org.apache.tajo.conf.TajoConf.ConfVars;
+import org.apache.tajo.ipc.ClientProtos;
+import org.apache.tajo.jdbc.TajoResultSet;
+import org.apache.tajo.util.FileUtil;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class TajoCli {
+ private final TajoConf conf;
+ private static final Options options;
+
+ private TajoClient client;
+
+ private final ConsoleReader reader;
+ private final InputStream sin;
+ private final PrintWriter sout;
+
+ private static final int PRINT_LIMIT = 24;
+ private final Map<String, Command> commands = new TreeMap<String, Command>();
+
+ private static final Class [] registeredCommands = {
+ DescTableCommand.class,
+ HelpCommand.class,
+ ExitCommand.class,
+ Copyright.class,
+ Version.class
+ };
+
+ private static final String HOME_DIR = System.getProperty("user.home");
+ private static final String HISTORY_FILE = ".tajo_history";
+
+ static {
+ options = new Options();
+ options.addOption("c", "command", true, "execute only single command, then exit");
+ options.addOption("f", "file", true, "execute commands from file, then exit");
+ options.addOption("h", "host", true, "Tajo server host");
+ options.addOption("p", "port", true, "Tajo server port");
+ }
+
+ public TajoCli(TajoConf c, String [] args,
+ InputStream in, OutputStream out) throws Exception {
+ this.conf = new TajoConf(c);
+ this.sin = in;
+ this.reader = new ConsoleReader(sin, out);
+ this.sout = new PrintWriter(reader.getOutput());
+
+ CommandLineParser parser = new PosixParser();
+ CommandLine cmd = parser.parse(options, args);
+
+ String hostName = null;
+ Integer port = null;
+ if (cmd.hasOption("h")) {
+ hostName = cmd.getOptionValue("h");
+ }
+ if (cmd.hasOption("p")) {
+ port = Integer.parseInt(cmd.getOptionValue("p"));
+ }
+
+ // if there is no "-h" option,
+ if(hostName == null) {
+ if (conf.getVar(ConfVars.TAJO_MASTER_CLIENT_RPC_ADDRESS) != null) {
+ // it checks if the client service address is given in configuration and distributed mode.
+ // if so, it sets entryAddr.
+ hostName = conf.getVar(ConfVars.TAJO_MASTER_CLIENT_RPC_ADDRESS).split(":")[0];
+ }
+ }
+ if (port == null) {
+ if (conf.getVar(ConfVars.TAJO_MASTER_CLIENT_RPC_ADDRESS) != null) {
+ // it checks if the client service address is given in configuration and distributed mode.
+ // if so, it sets entryAddr.
+ port = Integer.parseInt(conf.getVar(ConfVars.TAJO_MASTER_CLIENT_RPC_ADDRESS).split(":")[1]);
+ }
+ }
+
+ if ((hostName == null) ^ (port == null)) {
+ System.err.println("ERROR: cannot find valid Tajo server address");
+ System.exit(-1);
+ } else if (hostName != null && port != null) {
+ conf.setVar(ConfVars.TAJO_MASTER_CLIENT_RPC_ADDRESS, hostName+":"+port);
+ client = new TajoClient(conf);
+ } else if (hostName == null && port == null) {
+ client = new TajoClient(conf);
+ }
+
+ initHistory();
+ initCommands();
+
+ if (cmd.hasOption("c")) {
+ executeStatements(cmd.getOptionValue("c"));
+ sout.flush();
+ System.exit(0);
+ }
+ if (cmd.hasOption("f")) {
+ File sqlFile = new File(cmd.getOptionValue("f"));
+ if (sqlFile.exists()) {
+ String contents = FileUtil.readTextFile(new File(cmd.getOptionValue("f")));
+ executeStatements(contents);
+ sout.flush();
+ System.exit(0);
+ } else {
+ System.err.println("No such a file \"" + cmd.getOptionValue("f") + "\"");
+ System.exit(-1);
+ }
+ }
+ }
+
+ private void initHistory() {
+ try {
+ String historyPath = HOME_DIR + File.separator + HISTORY_FILE;
+ if ((new File(HOME_DIR)).exists()) {
+ reader.setHistory(new FileHistory(new File(historyPath)));
+ } else {
+ System.err.println("ERROR: home directory : '" + HOME_DIR +"' does not exist.");
+ }
+ } catch (Exception e) {
+ System.err.println(e.getMessage());
+ }
+ }
+
+ private void initCommands() {
+ for (Class clazz : registeredCommands) {
+ Command cmd = null;
+ try {
+ Constructor cons = clazz.getConstructor(new Class[] {TajoCli.class});
+ cmd = (Command) cons.newInstance(this);
+ } catch (Exception e) {
+ System.err.println(e.getMessage());
+ System.exit(-1);
+ }
+ commands.put(cmd.getCommand(), cmd);
+ }
+ }
+
+ public int runShell() throws Exception {
+
+ String raw;
+ String line;
+ String accumulatedLine = "";
+ String prompt = "tajo";
+ String curPrompt = prompt;
+ boolean newStatement = true;
+ int code = 0;
+
+ sout.write("Try \\? for help.\n");
+ while((raw = reader.readLine(curPrompt + "> ")) != null) {
+ // each accumulated line has a space delimiter
+ if (!accumulatedLine.equals("")) {
+ accumulatedLine += ' ';
+ }
+
+ line = raw.trim();
+
+ if (line.length() == 0) { // if empty line
+ continue;
+
+ } else if (line.charAt(0) == '/') { // warning for legacy usage
+ printInvalidCommand(line);
+ continue;
+
+ } else if (line.charAt(0) == '\\') { // command mode
+ executeCommand(line);
+ ((PersistentHistory)reader.getHistory()).flush();
+
+ } else if (line.endsWith(";") && !line.endsWith("\\;")) {
+
+ // remove a trailing newline
+ line = StringUtils.chomp(line).trim();
+
+ // get a punctuated statement
+ String punctuated = accumulatedLine + line;
+
+ if (!newStatement) {
+ // why do two lines are removed?
+ // First history line indicates an accumulated line.
+ // Second history line is a just typed line.
+ reader.getHistory().removeLast();
+ reader.getHistory().removeLast();
+ reader.getHistory().add(punctuated);
+ ((PersistentHistory)reader.getHistory()).flush();
+ }
+
+ code = executeStatements(punctuated);
+
+ // reset accumulated lines
+ newStatement = true;
+ accumulatedLine = "";
+ curPrompt = prompt;
+
+ } else {
+ line = StringUtils.chomp(raw).trim();
+
+ // accumulate a line
+ accumulatedLine = accumulatedLine + line;
+
+ // replace the latest line with a accumulated line
+ if (!newStatement) { // if this is not first line, remove one more line.
+ reader.getHistory().removeLast();
+ } else {
+ newStatement = false;
+ }
+ reader.getHistory().removeLast();
+ reader.getHistory().add(accumulatedLine);
+
+ // use an alternative prompt during accumulating lines
+ curPrompt = StringUtils.repeat(" ", prompt.length());
+ continue;
+ }
+ }
+ return code;
+ }
+
+ private void invokeCommand(String [] cmds) {
+ // this command should be moved to GlobalEngine
+ Command invoked;
+ try {
+ invoked = commands.get(cmds[0]);
+ invoked.invoke(cmds);
+ } catch (Throwable t) {
+ sout.println(t.getMessage());
+ }
+ }
+
+ public int executeStatements(String line) throws Exception {
+
+ // TODO - comment handling and multi line queries should be improved
+ // remove comments
+ String filtered = line.replaceAll("--[^\\r\\n]*", "").trim();
+
+ String stripped;
+ for (String statement : filtered.split(";")) {
+ stripped = StringUtils.chomp(statement);
+ if (StringUtils.isBlank(stripped)) {
+ continue;
+ }
+
+ String [] cmds = stripped.split(" ");
+ if (cmds[0].equalsIgnoreCase("exit") || cmds[0].equalsIgnoreCase("quit")) {
+ sout.println("\n\nbye!");
+ sout.flush();
+ ((PersistentHistory)this.reader.getHistory()).flush();
+ System.exit(0);
+ } else if (cmds[0].equalsIgnoreCase("detach") && cmds.length > 1 && cmds[1].equalsIgnoreCase("table")) {
+ // this command should be moved to GlobalEngine
+ invokeCommand(cmds);
+
+ } else { // submit a query to TajoMaster
+ ClientProtos.GetQueryStatusResponse response = client.executeQuery(stripped);
+ if (response == null) {
+ sout.println("response is null");
+ }
+ else if (response.getResultCode() == ClientProtos.ResultCode.OK) {
+ QueryId queryId = null;
+ try {
+ queryId = new QueryId(response.getQueryId());
+ if (queryId.equals(QueryIdFactory.NULL_QUERY_ID)) {
+ sout.println("OK");
+ } else {
+ getQueryResult(queryId);
+ }
+ } finally {
+ if(queryId != null) {
+ client.closeQuery(queryId);
+ }
+ }
+ } else {
+ if (response.hasErrorMessage()) {
+ sout.println(response.getErrorMessage());
+ }
+ }
+ }
+ }
+ return 0;
+ }
+
+ private boolean isFailed(QueryState state) {
+ return state == QueryState.QUERY_ERROR || state == QueryState.QUERY_FAILED;
+ }
+
+ private void getQueryResult(QueryId queryId) {
+ // if query is empty string
+ if (queryId.equals(QueryIdFactory.NULL_QUERY_ID)) {
+ return;
+ }
+
+ // query execute
+ try {
+
+ QueryStatus status;
+ while (true) {
+ // TODO - configurable
+ Thread.sleep(1000);
+ status = client.getQueryStatus(queryId);
+ if(status.getState() == QueryState.QUERY_MASTER_INIT || status.getState() == QueryState.QUERY_MASTER_LAUNCHED) {
+ continue;
+ }
+
+ if (status.getState() == QueryState.QUERY_RUNNING ||
+ status.getState() == QueryState.QUERY_SUCCEEDED) {
+ sout.println("Progress: " + (int)(status.getProgress() * 100.0f)
+ + "%, response time: " + ((float)(status.getFinishTime() - status.getSubmitTime()) / 1000.0) + " sec");
+ sout.flush();
+ }
+
+ if (status.getState() != QueryState.QUERY_RUNNING && status.getState() != QueryState.QUERY_NOT_ASSIGNED) {
+ break;
+ }
+ }
+
+ if (status.getState() == QueryState.QUERY_ERROR) {
+ sout.println("Internal error!");
+ } else if (status.getState() == QueryState.QUERY_FAILED) {
+ sout.println("Query failed!");
+ } else if (status.getState() == QueryState.QUERY_KILLED) {
+ sout.println(queryId + " is killed.");
+ } else {
+ if (status.getState() == QueryState.QUERY_SUCCEEDED) {
+ sout.println("final state: " + status.getState()
+ + ", response time: " + (((float)(status.getFinishTime() - status.getSubmitTime()) / 1000.0)
+ + " sec"));
+ if (status.hasResult()) {
+ ResultSet res = null;
+ TableDesc desc = null;
+ if (queryId.equals(QueryIdFactory.NULL_QUERY_ID)) {
+ res = client.createNullResultSet(queryId);
+ } else {
+ ClientProtos.GetQueryResultResponse response = client.getResultResponse(queryId);
+ desc = CatalogUtil.newTableDesc(response.getTableDesc());
+ conf.setVar(ConfVars.USERNAME, response.getTajoUserName());
+ res = new TajoResultSet(client, queryId, conf, desc);
+ }
+ try {
+ if (res == null) {
+ sout.println("OK");
+ return;
+ }
+
+ ResultSetMetaData rsmd = res.getMetaData();
+
+ TableStats stat = desc.getStats();
+ String volume = FileUtil.humanReadableByteCount(stat.getNumBytes(), false);
+ long resultRows = stat.getNumRows();
+ sout.println("result: " + desc.getPath() + ", " + resultRows + " rows (" + volume + ")");
+
+ int numOfColumns = rsmd.getColumnCount();
+ for (int i = 1; i <= numOfColumns; i++) {
+ if (i > 1) sout.print(", ");
+ String columnName = rsmd.getColumnName(i);
+ sout.print(columnName);
+ }
+ sout.println("\n-------------------------------");
+
+ int numOfPrintedRows = 0;
+ while (res.next()) {
+ // TODO - to be improved to print more formatted text
+ for (int i = 1; i <= numOfColumns; i++) {
+ if (i > 1) sout.print(", ");
+ String columnValue = res.getObject(i).toString();
+ if(res.wasNull()){
+ sout.print("null");
+ } else {
+ sout.print(columnValue);
+ }
+ }
+ sout.println();
+ sout.flush();
+ numOfPrintedRows++;
+ if (numOfPrintedRows >= PRINT_LIMIT) {
+ sout.print("continue... ('q' is quit)");
+ sout.flush();
+ if (sin.read() == 'q') {
+ break;
+ }
+ numOfPrintedRows = 0;
+ sout.println();
+ }
+ }
+ } finally {
+ if(res != null) {
+ res.close();
+ }
+ }
+ } else {
+ sout.println("OK");
+ }
+ }
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ System.err.println(t.getMessage());
+ }
+ }
+
+ private void printUsage() {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp( "tajo cli [options]", options );
+ }
+
+ public static abstract class Command {
+ public abstract String getCommand();
+ public abstract void invoke(String [] command) throws Exception;
+ public abstract String getUsage();
+ public abstract String getDescription();
+ }
+
+ private String toFormattedString(TableDesc desc) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("\ntable name: ").append(desc.getName()).append("\n");
+ sb.append("table path: ").append(desc.getPath()).append("\n");
+ sb.append("store type: ").append(desc.getMeta().getStoreType()).append("\n");
+ if (desc.getStats() != null) {
+ sb.append("number of rows: ").append(desc.getStats().getNumRows()).append("\n");
+ sb.append("volume: ").append(
+ FileUtil.humanReadableByteCount(desc.getStats().getNumBytes(),
+ true)).append("\n");
+ }
+ sb.append("Options: \n");
+ for(Map.Entry<String, String> entry : desc.getMeta().toMap().entrySet()){
+ sb.append("\t").append("'").append(entry.getKey()).append("'").append("=")
+ .append("'").append(entry.getValue()).append("'").append("\n");
+ }
+ sb.append("\n");
+ sb.append("schema: \n");
+
+ for(int i = 0; i < desc.getSchema().getColumnNum(); i++) {
+ Column col = desc.getSchema().getColumn(i);
+ sb.append(col.getColumnName()).append("\t").append(col.getDataType().getType());
+ if (col.getDataType().hasLength()) {
+ sb.append("(").append(col.getDataType().getLength()).append(")");
+ }
+ sb.append("\n");
+ }
+
+ sb.append("\n");
+ sb.append("Partitions: \n");
+ if (desc.getPartitions() != null) {
+ sb.append("type:").append(desc.getPartitions().getPartitionsType().name()).append("\n");
+ if (desc.getPartitions().getNumPartitions() > 0)
+ sb.append("numbers:").append(desc.getPartitions().getNumPartitions()).append("\n");
+
+ sb.append("columns:").append("\n");
+ for(Column eachColumn: desc.getPartitions().getColumns()) {
+ sb.append(" ");
+ sb.append(eachColumn.getColumnName()).append("\t").append(eachColumn.getDataType().getType());
+ if (eachColumn.getDataType().hasLength()) {
+ sb.append("(").append(eachColumn.getDataType().getLength()).append(")");
+ }
+ sb.append("\n");
+ }
+
+ if (desc.getPartitions().getSpecifiers() != null) {
+ sb.append("specifier:").append("\n");
+ for(Specifier specifier :desc.getPartitions().getSpecifiers()) {
+ sb.append(" ");
+ sb.append("name:").append(specifier.getName());
+ if (!specifier.getExpressions().equals("")) {
+ sb.append(", expressions:").append(specifier.getExpressions());
+ } else {
+ if (desc.getPartitions().getPartitionsType().name().equals("RANGE"));
+ sb.append(" expressions: MAXVALUE");
+ }
+ sb.append("\n");
+ }
+ }
+ }
+
+ return sb.toString();
+ }
+
+ public class DescTableCommand extends Command {
+ public DescTableCommand() {}
+
+ @Override
+ public String getCommand() {
+ return "\\d";
+ }
+
+ @Override
+ public void invoke(String[] cmd) throws Exception {
+ if (cmd.length == 2) {
+ TableDesc desc = client.getTableDesc(cmd[1]);
+ if (desc == null) {
+ sout.println("Did not find any relation named \"" + cmd[1] + "\"");
+ } else {
+ sout.println(toFormattedString(desc));
+ }
+ } else if (cmd.length == 1) {
+ List<String> tableList = client.getTableList();
+ if (tableList.size() == 0) {
+ sout.println("No Relation Found");
+ }
+ for (String table : tableList) {
+ sout.println(table);
+ }
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ @Override
+ public String getUsage() {
+ return "[table_name]";
+ }
+
+ @Override
+ public String getDescription() {
+ return "show table description";
+ }
+ }
+
+ public class HelpCommand extends Command {
+
+ @Override
+ public String getCommand() {
+ return "\\?";
+ }
+
+ @Override
+ public void invoke(String[] cmd) throws Exception {
+ sout.println();
+
+ sout.println("General");
+ sout.println(" \\copyright show Apache License 2.0");
+ sout.println(" \\version show Tajo version");
+ sout.println(" \\? show help");
+ sout.println(" \\q quit tsql");
+ sout.println();
+ sout.println();
+
+ sout.println("Informational");
+ sout.println(" \\d list tables");
+ sout.println(" \\d NAME describe table");
+ sout.println();
+ sout.println();
+
+ sout.println("Documentations");
+ sout.println(" tsql guide http://wiki.apache.org/tajo/tsql");
+ sout.println(" Query language http://wiki.apache.org/tajo/QueryLanguage");
+ sout.println(" Functions http://wiki.apache.org/tajo/Functions");
+ sout.println(" Backup & restore http://wiki.apache.org/tajo/BackupAndRestore");
+ sout.println(" Configuration http://wiki.apache.org/tajo/Configuration");
+ sout.println();
+ }
+
+ @Override
+ public String getUsage() {
+ return "";
+ }
+
+ @Override
+ public String getDescription() {
+ return "show command lists and their usages";
+ }
+ }
+
+ public class Version extends Command {
+
+ @Override
+ public String getCommand() {
+ return "\\version";
+ }
+
+ @Override
+ public void invoke(String[] cmd) throws Exception {
+ sout.println(TajoConstants.TAJO_VERSION);
+ }
+
+ @Override
+ public String getUsage() {
+ return "";
+ }
+
+ @Override
+ public String getDescription() {
+ return "show Apache License 2.0";
+ }
+ }
+
+ public class Copyright extends Command {
+
+ @Override
+ public String getCommand() {
+ return "\\copyright";
+ }
+
+ @Override
+ public void invoke(String[] cmd) throws Exception {
+ sout.println();
+ sout.println(
+ " Licensed to the Apache Software Foundation (ASF) under one\n" +
+ " or more contributor license agreements. See the NOTICE file\n" +
+ " distributed with this work for additional information\n" +
+ " regarding copyright ownership. The ASF licenses this file\n" +
+ " to you under the Apache License, Version 2.0 (the\n" +
+ " \"License\"); you may not use this file except in compliance\n" +
+ " with the License. You may obtain a copy of the License at\n" +
+ "\n" +
+ " http://www.apache.org/licenses/LICENSE-2.0\n" +
+ "\n" +
+ " Unless required by applicable law or agreed to in writing, software\n" +
+ " distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
+ " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
+ " See the License for the specific language governing permissions and\n" +
+ " limitations under the License.");
+ sout.println();
+ }
+
+ @Override
+ public String getUsage() {
+ return "";
+ }
+
+ @Override
+ public String getDescription() {
+ return "show Apache License 2.0";
+ }
+ }
+
+ public class ExitCommand extends Command {
+
+ @Override
+ public String getCommand() {
+ return "\\q";
+ }
+
+ @Override
+ public void invoke(String[] cmd) throws Exception {
+ sout.println("bye!");
+ System.exit(0);
+ }
+
+ @Override
+ public String getUsage() {
+ return "";
+ }
+
+ @Override
+ public String getDescription() {
+ return "quit";
+ }
+ }
+
+ public int executeCommand(String line) throws Exception {
+ String [] metaCommands = line.split(";");
+ for (String metaCommand : metaCommands) {
+ String arguments [];
+ arguments = metaCommand.split(" ");
+
+ Command invoked = commands.get(arguments[0]);
+ if (invoked == null) {
+ printInvalidCommand(arguments[0]);
+ return -1;
+ }
+
+ try {
+ invoked.invoke(arguments);
+ } catch (IllegalArgumentException ige) {
+ sout.println(ige.getMessage());
+ } catch (Exception e) {
+ sout.println(e.getMessage());
+ }
+ }
+
+ return 0;
+ }
+
+ private void printInvalidCommand(String command) {
+ sout.println("Invalid command " + command +". Try \\? for help.");
+ }
+
+ public static void main(String [] args) throws Exception {
+ TajoConf conf = new TajoConf();
+ TajoCli shell = new TajoCli(conf, args, System.in, System.out);
+ System.out.println();
+ int status = shell.runShell();
+ System.exit(status);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/b6a5ff0c/tajo-client/src/main/java/org/apache/tajo/client/QueryStatus.java
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/java/org/apache/tajo/client/QueryStatus.java b/tajo-client/src/main/java/org/apache/tajo/client/QueryStatus.java
new file mode 100644
index 0000000..203f9aa
--- /dev/null
+++ b/tajo-client/src/main/java/org/apache/tajo/client/QueryStatus.java
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.client;
+
+import org.apache.tajo.QueryId;
+import org.apache.tajo.TajoProtos.QueryState;
+import org.apache.tajo.ipc.ClientProtos.GetQueryStatusResponse;
+
+public class QueryStatus {
+ private QueryId queryId;
+ private QueryState state;
+ private float progress;
+ private long submitTime;
+ private long finishTime;
+ private boolean hasResult;
+ private String errorText;
+ private String queryMasterHost;
+ private int queryMasterPort;
+
+ public QueryStatus(GetQueryStatusResponse proto) {
+ queryId = new QueryId(proto.getQueryId());
+ state = proto.getState();
+ progress = proto.getProgress();
+ submitTime = proto.getSubmitTime();
+ finishTime = proto.getFinishTime();
+ hasResult = proto.getHasResult();
+ if (proto.hasErrorMessage()) {
+ errorText = proto.getErrorMessage();
+ }
+
+ queryMasterHost = proto.getQueryMasterHost();
+ queryMasterPort = proto.getQueryMasterPort();
+ }
+
+ public String getQueryMasterHost() {
+ return queryMasterHost;
+ }
+
+ public int getQueryMasterPort() {
+ return queryMasterPort;
+ }
+
+ public QueryId getQueryId() {
+ return this.queryId;
+ }
+
+ public QueryState getState() {
+ return this.state;
+ }
+
+ public float getProgress() {
+ return progress;
+ }
+
+ public long getSubmitTime() {
+ return this.submitTime;
+ }
+
+ public long getFinishTime() {
+ return this.finishTime;
+ }
+
+ public boolean hasResult() {
+ return this.hasResult;
+ }
+
+ public String getErrorMessage() {
+ return errorText;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/b6a5ff0c/tajo-client/src/main/java/org/apache/tajo/client/ResultSetUtil.java
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/java/org/apache/tajo/client/ResultSetUtil.java b/tajo-client/src/main/java/org/apache/tajo/client/ResultSetUtil.java
new file mode 100644
index 0000000..1573978
--- /dev/null
+++ b/tajo-client/src/main/java/org/apache/tajo/client/ResultSetUtil.java
@@ -0,0 +1,193 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.client;
+
+import org.apache.tajo.common.TajoDataTypes;
+import org.apache.tajo.exception.UnsupportedException;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Types;
+
+public class ResultSetUtil {
+ public static String prettyFormat(ResultSet res) throws SQLException {
+ StringBuilder sb = new StringBuilder();
+ ResultSetMetaData rsmd = res.getMetaData();
+ int numOfColumns = rsmd.getColumnCount();
+
+ for (int i = 1; i <= numOfColumns; i++) {
+ if (i > 1) sb.append(", ");
+ String columnName = rsmd.getColumnName(i);
+ sb.append(columnName);
+ }
+ sb.append("\n-------------------------------\n");
+
+ while (res.next()) {
+ for (int i = 1; i <= numOfColumns; i++) {
+ if (i > 1) sb.append(", ");
+ String columnValue = res.getObject(i).toString();
+ sb.append(columnValue);
+ }
+ sb.append("\n");
+ }
+
+ return sb.toString();
+ }
+
+ public static String toSqlType(TajoDataTypes.DataType type) {
+ switch (type.getType()) {
+ case BOOLEAN:
+ return "boolean";
+ case INT1:
+ return "tinyint";
+ case INT2:
+ return "smallint";
+ case INT4:
+ return "integer";
+ case INT8:
+ return "bigint";
+ case FLOAT4:
+ return "float";
+ case FLOAT8:
+ return "float8";
+ case DECIMAL:
+ return "numeric";
+ case VARBINARY:
+ return "bytea";
+ case CHAR:
+ return "character";
+ case DATE:
+ return "date";
+ case VARCHAR:
+ return "varchar";
+ case TEXT:
+ return "varchar";
+ default:
+ throw new UnsupportedException("Unrecognized column type:" + type);
+ }
+ }
+
+ public static int tajoTypeToSqlType(TajoDataTypes.DataType type) throws SQLException {
+ switch (type.getType()) {
+ case BOOLEAN:
+ return Types.BOOLEAN;
+ case INT1:
+ return Types.TINYINT;
+ case INT2:
+ return Types.SMALLINT;
+ case INT4:
+ return Types.INTEGER;
+ case INT8:
+ return Types.BIGINT;
+ case FLOAT4:
+ return Types.FLOAT;
+ case FLOAT8:
+ return Types.DOUBLE;
+ case DECIMAL:
+ return Types.DECIMAL;
+ case DATE:
+ return Types.TIMESTAMP;
+ case VARCHAR:
+ return Types.VARCHAR;
+ case TEXT:
+ return Types.VARCHAR;
+ default:
+ throw new SQLException("Unrecognized column type: " + type);
+ }
+ }
+
+ public static int columnDisplaySize(int columnType) throws SQLException {
+ // according to hiveTypeToSqlType possible options are:
+ switch(columnType) {
+ case Types.BOOLEAN:
+ return columnPrecision(columnType);
+ case Types.VARCHAR:
+ return Integer.MAX_VALUE; // hive has no max limit for strings
+ case Types.TINYINT:
+ case Types.SMALLINT:
+ case Types.INTEGER:
+ case Types.BIGINT:
+ return columnPrecision(columnType) + 1; // allow +/-
+ case Types.TIMESTAMP:
+ return columnPrecision(columnType);
+ // see http://download.oracle.com/javase/6/docs/api/constant-values.html#java.lang.Float.MAX_EXPONENT
+ case Types.FLOAT:
+ return 24; // e.g. -(17#).e-###
+ // see http://download.oracle.com/javase/6/docs/api/constant-values.html#java.lang.Double.MAX_EXPONENT
+ case Types.DOUBLE:
+ return 25; // e.g. -(17#).e-####
+ case Types.DECIMAL:
+ return Integer.MAX_VALUE;
+ default:
+ throw new SQLException("Invalid column type: " + columnType);
+ }
+ }
+
+ public static int columnPrecision(int columnType) throws SQLException {
+ // according to hiveTypeToSqlType possible options are:
+ switch(columnType) {
+ case Types.BOOLEAN:
+ return 1;
+ case Types.VARCHAR:
+ return Integer.MAX_VALUE; // hive has no max limit for strings
+ case Types.TINYINT:
+ return 3;
+ case Types.SMALLINT:
+ return 5;
+ case Types.INTEGER:
+ return 10;
+ case Types.BIGINT:
+ return 19;
+ case Types.FLOAT:
+ return 7;
+ case Types.DOUBLE:
+ return 15;
+ case Types.TIMESTAMP:
+ return 29;
+ case Types.DECIMAL:
+ return Integer.MAX_VALUE;
+ default:
+ throw new SQLException("Invalid column type: " + columnType);
+ }
+ }
+
+ public static int columnScale(int columnType) throws SQLException {
+ // according to hiveTypeToSqlType possible options are:
+ switch(columnType) {
+ case Types.BOOLEAN:
+ case Types.VARCHAR:
+ case Types.TINYINT:
+ case Types.SMALLINT:
+ case Types.INTEGER:
+ case Types.BIGINT:
+ return 0;
+ case Types.FLOAT:
+ return 7;
+ case Types.DOUBLE:
+ return 15;
+ case Types.TIMESTAMP:
+ return 9;
+ case Types.DECIMAL:
+ return Integer.MAX_VALUE;
+ default:
+ throw new SQLException("Invalid column type: " + columnType);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/b6a5ff0c/tajo-client/src/main/java/org/apache/tajo/client/TajoClient.java
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/java/org/apache/tajo/client/TajoClient.java b/tajo-client/src/main/java/org/apache/tajo/client/TajoClient.java
new file mode 100644
index 0000000..05a5eff
--- /dev/null
+++ b/tajo-client/src/main/java/org/apache/tajo/client/TajoClient.java
@@ -0,0 +1,462 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.client;
+
+import com.google.protobuf.ServiceException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.fs.Path;
+import org.apache.tajo.QueryId;
+import org.apache.tajo.QueryIdFactory;
+import org.apache.tajo.TajoProtos.QueryState;
+import org.apache.tajo.annotation.ThreadSafe;
+import org.apache.tajo.catalog.CatalogUtil;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.catalog.TableDesc;
+import org.apache.tajo.catalog.TableMeta;
+import org.apache.tajo.conf.TajoConf;
+import org.apache.tajo.conf.TajoConf.ConfVars;
+import org.apache.tajo.ipc.ClientProtos.*;
+import org.apache.tajo.ipc.QueryMasterClientProtocol;
+import org.apache.tajo.ipc.QueryMasterClientProtocol.QueryMasterClientProtocolService;
+import org.apache.tajo.ipc.TajoMasterClientProtocol;
+import org.apache.tajo.ipc.TajoMasterClientProtocol.TajoMasterClientProtocolService;
+import org.apache.tajo.jdbc.SQLStates;
+import org.apache.tajo.jdbc.TajoResultSet;
+import org.apache.tajo.rpc.*;
+import org.apache.tajo.rpc.protocolrecords.PrimitiveProtos.StringProto;
+import org.apache.tajo.util.NetUtils;
+import org.apache.tajo.rpc.ServerCallable;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@ThreadSafe
+public class TajoClient {
+ private final Log LOG = LogFactory.getLog(TajoClient.class);
+
+ private final TajoConf conf;
+
+ private Map<QueryId, InetSocketAddress> queryMasterMap = new ConcurrentHashMap<QueryId, InetSocketAddress>();
+
+ private InetSocketAddress tajoMasterAddr;
+
+ private RpcConnectionPool connPool;
+
+ public TajoClient(TajoConf conf) throws IOException {
+ this(conf, NetUtils.createSocketAddr(conf.getVar(ConfVars.TAJO_MASTER_CLIENT_RPC_ADDRESS)));
+ }
+
+ public TajoClient(TajoConf conf, InetSocketAddress addr) throws IOException {
+ this.conf = conf;
+ this.conf.set("tajo.disk.scheduler.report.interval", "0");
+ this.tajoMasterAddr = addr;
+
+ connPool = RpcConnectionPool.getPool(conf);
+ }
+
+ public TajoClient(InetSocketAddress addr) throws IOException {
+ this(new TajoConf(), addr);
+ }
+
+ public TajoClient(String hostname, int port) throws IOException {
+ this(new TajoConf(), NetUtils.createSocketAddr(hostname, port));
+ }
+
+ public void close() {
+ if(connPool != null) {
+ connPool.close();
+ }
+ queryMasterMap.clear();
+ }
+
+ public TajoConf getConf() {
+ return conf;
+ }
+
+ /**
+ * Call to QueryMaster closing query resources
+ * @param queryId
+ */
+ public void closeQuery(final QueryId queryId) {
+ if(queryMasterMap.containsKey(queryId)) {
+ NettyClientBase qmClient = null;
+ try {
+ qmClient = connPool.getConnection(queryMasterMap.get(queryId), QueryMasterClientProtocol.class, false);
+ QueryMasterClientProtocolService.BlockingInterface queryMasterService = qmClient.getStub();
+ queryMasterService.killQuery(null, queryId.getProto());
+ } catch (Exception e) {
+ LOG.warn("Fail to close a QueryMaster connection (qid=" + queryId + ", msg=" + e.getMessage() + ")", e);
+ } finally {
+ connPool.closeConnection(qmClient);
+ queryMasterMap.remove(queryId);
+ }
+ }
+ }
+
+ /**
+ * It submits a query statement and get a response immediately.
+ * The response only contains a query id, and submission status.
+ * In order to get the result, you should use {@link #getQueryResult(org.apache.tajo.QueryId)}
+ * or {@link #getQueryResultAndWait(org.apache.tajo.QueryId)}.
+ */
+ public GetQueryStatusResponse executeQuery(final String sql) throws ServiceException {
+ return new ServerCallable<GetQueryStatusResponse>(conf, tajoMasterAddr,
+ TajoMasterClientProtocol.class, false, true) {
+ public GetQueryStatusResponse call(NettyClientBase client) throws ServiceException {
+ final QueryRequest.Builder builder = QueryRequest.newBuilder();
+ builder.setQuery(sql);
+
+ TajoMasterClientProtocolService.BlockingInterface tajoMasterService = client.getStub();
+ return tajoMasterService.submitQuery(null, builder.build());
+ }
+ }.withRetries();
+ }
+
+ /**
+ * It submits a query statement and get a response.
+ * The main difference from {@link #executeQuery(String)}
+ * is a blocking method. So, this method is wait for
+ * the finish of the submitted query.
+ *
+ * @return If failed, return null.
+ */
+ public ResultSet executeQueryAndGetResult(final String sql)
+ throws ServiceException, IOException {
+ GetQueryStatusResponse response = new ServerCallable<GetQueryStatusResponse>(conf, tajoMasterAddr,
+ TajoMasterClientProtocol.class, false, true) {
+ public GetQueryStatusResponse call(NettyClientBase client) throws ServiceException {
+ final QueryRequest.Builder builder = QueryRequest.newBuilder();
+ builder.setQuery(sql);
+
+ TajoMasterClientProtocolService.BlockingInterface tajoMasterService = client.getStub();
+ return tajoMasterService.submitQuery(null, builder.build());
+ }
+ }.withRetries();
+
+ QueryId queryId = new QueryId(response.getQueryId());
+ if (queryId.equals(QueryIdFactory.NULL_QUERY_ID)) {
+ return this.createNullResultSet(queryId);
+ } else {
+ return this.getQueryResultAndWait(queryId);
+ }
+ }
+
+ public QueryStatus getQueryStatus(QueryId queryId) throws ServiceException {
+ GetQueryStatusRequest.Builder builder
+ = GetQueryStatusRequest.newBuilder();
+ builder.setQueryId(queryId.getProto());
+
+ GetQueryStatusResponse res = null;
+ if(queryMasterMap.containsKey(queryId)) {
+ NettyClientBase qmClient = null;
+ try {
+ qmClient = connPool.getConnection(queryMasterMap.get(queryId),
+ QueryMasterClientProtocol.class, false);
+ QueryMasterClientProtocolService.BlockingInterface queryMasterService = qmClient.getStub();
+ res = queryMasterService.getQueryStatus(null, builder.build());
+ } catch (Exception e) {
+ throw new ServiceException(e.getMessage(), e);
+ } finally {
+ connPool.closeConnection(qmClient);
+ }
+ } else {
+ NettyClientBase tmClient = null;
+ try {
+ tmClient = connPool.getConnection(tajoMasterAddr,
+ TajoMasterClientProtocol.class, false);
+ TajoMasterClientProtocolService.BlockingInterface tajoMasterService = tmClient.getStub();
+ res = tajoMasterService.getQueryStatus(null, builder.build());
+
+ String queryMasterHost = res.getQueryMasterHost();
+ if(queryMasterHost != null && !queryMasterHost.isEmpty()) {
+ NettyClientBase qmClient = null;
+ try {
+ InetSocketAddress qmAddr = NetUtils.createSocketAddr(queryMasterHost, res.getQueryMasterPort());
+ qmClient = connPool.getConnection(
+ qmAddr, QueryMasterClientProtocol.class, false);
+ QueryMasterClientProtocolService.BlockingInterface queryMasterService = qmClient.getStub();
+ res = queryMasterService.getQueryStatus(null, builder.build());
+
+ queryMasterMap.put(queryId, qmAddr);
+ } catch (Exception e) {
+ throw new ServiceException(e.getMessage(), e);
+ } finally {
+ connPool.closeConnection(qmClient);
+ }
+ }
+ } catch (Exception e) {
+ throw new ServiceException(e.getMessage(), e);
+ } finally {
+ connPool.closeConnection(tmClient);
+ }
+ }
+ return new QueryStatus(res);
+ }
+
+ private static boolean isQueryRunnning(QueryState state) {
+ return state == QueryState.QUERY_NEW ||
+ state == QueryState.QUERY_RUNNING ||
+ state == QueryState.QUERY_MASTER_LAUNCHED ||
+ state == QueryState.QUERY_MASTER_INIT ||
+ state == QueryState.QUERY_NOT_ASSIGNED;
+ }
+
+ public ResultSet getQueryResult(QueryId queryId)
+ throws ServiceException, IOException {
+ if (queryId.equals(QueryIdFactory.NULL_QUERY_ID)) {
+ return createNullResultSet(queryId);
+ }
+ GetQueryResultResponse response = getResultResponse(queryId);
+ TableDesc tableDesc = CatalogUtil.newTableDesc(response.getTableDesc());
+ conf.setVar(ConfVars.USERNAME, response.getTajoUserName());
+ return new TajoResultSet(this, queryId, conf, tableDesc);
+ }
+
+ public ResultSet getQueryResultAndWait(QueryId queryId)
+ throws ServiceException, IOException {
+ if (queryId.equals(QueryIdFactory.NULL_QUERY_ID)) {
+ return createNullResultSet(queryId);
+ }
+ QueryStatus status = getQueryStatus(queryId);
+
+ while(status != null && isQueryRunnning(status.getState())) {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ status = getQueryStatus(queryId);
+ }
+
+ if (status.getState() == QueryState.QUERY_SUCCEEDED) {
+ if (status.hasResult()) {
+ return getQueryResult(queryId);
+ } else {
+ return createNullResultSet(queryId);
+ }
+
+ } else {
+ LOG.warn("Query (" + status.getQueryId() + ") failed: " + status.getState());
+
+ //TODO throw SQLException(?)
+ return createNullResultSet(queryId);
+ }
+ }
+
+ public ResultSet createNullResultSet(QueryId queryId) throws IOException {
+ return new TajoResultSet(this, queryId);
+ }
+
+ public GetQueryResultResponse getResultResponse(QueryId queryId) throws ServiceException {
+ if (queryId.equals(QueryIdFactory.NULL_QUERY_ID)) {
+ return null;
+ }
+
+ NettyClientBase client = null;
+ try {
+ InetSocketAddress queryMasterAddr = queryMasterMap.get(queryId);
+ if(queryMasterAddr == null) {
+ LOG.warn("No Connection to QueryMaster for " + queryId);
+ return null;
+ }
+ client = connPool.getConnection(queryMasterAddr, QueryMasterClientProtocol.class, false);
+ QueryMasterClientProtocolService.BlockingInterface queryMasterService = client.getStub();
+ GetQueryResultRequest.Builder builder = GetQueryResultRequest.newBuilder();
+ builder.setQueryId(queryId.getProto());
+ GetQueryResultResponse response = queryMasterService.getQueryResult(null,
+ builder.build());
+
+ return response;
+ } catch (Exception e) {
+ throw new ServiceException(e.getMessage(), e);
+ } finally {
+ connPool.closeConnection(client);
+ }
+ }
+
+ public boolean updateQuery(final String sql) throws ServiceException {
+ return new ServerCallable<Boolean>(conf, tajoMasterAddr,
+ TajoMasterClientProtocol.class, false, true) {
+ public Boolean call(NettyClientBase client) throws ServiceException {
+ QueryRequest.Builder builder = QueryRequest.newBuilder();
+ builder.setQuery(sql);
+
+ TajoMasterClientProtocolService.BlockingInterface tajoMasterService = client.getStub();
+ ResultCode resultCode =
+ tajoMasterService.updateQuery(null, builder.build()).getResultCode();
+ return resultCode == ResultCode.OK;
+ }
+ }.withRetries();
+ }
+
+ /**
+ * Test for the existence of table in catalog data.
+ * <p/>
+ * This will return true if table exists, false if not.
+ * @param name
+ * @return
+ * @throws ServiceException
+ */
+ public boolean existTable(final String name) throws ServiceException {
+ return new ServerCallable<Boolean>(conf, tajoMasterAddr,
+ TajoMasterClientProtocol.class, false, true) {
+ public Boolean call(NettyClientBase client) throws ServiceException {
+ StringProto.Builder builder = StringProto.newBuilder();
+ builder.setValue(name);
+
+ TajoMasterClientProtocolService.BlockingInterface tajoMasterService = client.getStub();
+ return tajoMasterService.existTable(null, builder.build()).getValue();
+ }
+ }.withRetries();
+ }
+
+ public TableDesc createExternalTable(final String name, final Schema schema, final Path path, final TableMeta meta)
+ throws SQLException, ServiceException {
+ return new ServerCallable<TableDesc>(conf, tajoMasterAddr,
+ TajoMasterClientProtocol.class, false, true) {
+ public TableDesc call(NettyClientBase client) throws ServiceException, SQLException {
+ TajoMasterClientProtocolService.BlockingInterface tajoMasterService = client.getStub();
+
+ CreateTableRequest.Builder builder = CreateTableRequest.newBuilder();
+ builder.setName(name);
+ builder.setSchema(schema.getProto());
+ builder.setMeta(meta.getProto());
+ builder.setPath(path.toUri().toString());
+ TableResponse res = tajoMasterService.createExternalTable(null, builder.build());
+ if (res.getResultCode() == ResultCode.OK) {
+ return CatalogUtil.newTableDesc(res.getTableDesc());
+ } else {
+ throw new SQLException(res.getErrorMessage(), SQLStates.ER_NO_SUCH_TABLE.getState());
+ }
+ }
+ }.withRetries();
+ }
+
+ public boolean dropTable(final String tableName) throws ServiceException {
+ return dropTable(tableName, false);
+ }
+
+ /**
+ * Deletes table schema from catalog data and deletes data file in hdfs
+ * @param tableName
+ * @return
+ * @throws ServiceException
+ */
+ public boolean dropTable(final String tableName, final boolean purge) throws ServiceException {
+ return new ServerCallable<Boolean>(conf, tajoMasterAddr,
+ TajoMasterClientProtocol.class, false, true) {
+ public Boolean call(NettyClientBase client) throws ServiceException {
+ TajoMasterClientProtocolService.BlockingInterface tajoMasterService = client.getStub();
+
+ DropTableRequest.Builder builder = DropTableRequest.newBuilder();
+ builder.setName(tableName);
+ builder.setPurge(purge);
+ return tajoMasterService.dropTable(null, builder.build()).getValue();
+ }
+ }.withRetries();
+
+ }
+
+ /**
+ * Get a list of table names. All table and column names are
+ * represented as lower-case letters.
+ */
+ public List<String> getTableList() throws ServiceException {
+ return new ServerCallable<List<String>>(conf, tajoMasterAddr,
+ TajoMasterClientProtocol.class, false, true) {
+ public List<String> call(NettyClientBase client) throws ServiceException {
+ TajoMasterClientProtocolService.BlockingInterface tajoMasterService = client.getStub();
+
+ GetTableListRequest.Builder builder = GetTableListRequest.newBuilder();
+ GetTableListResponse res = tajoMasterService.getTableList(null, builder.build());
+ return res.getTablesList();
+ }
+ }.withRetries();
+ }
+
+ public TableDesc getTableDesc(final String tableName) throws SQLException, ServiceException {
+ return new ServerCallable<TableDesc>(conf, tajoMasterAddr,
+ TajoMasterClientProtocol.class, false, true) {
+ public TableDesc call(NettyClientBase client) throws ServiceException, SQLException {
+ TajoMasterClientProtocolService.BlockingInterface tajoMasterService = client.getStub();
+
+ GetTableDescRequest.Builder build = GetTableDescRequest.newBuilder();
+ build.setTableName(tableName);
+ TableResponse res = tajoMasterService.getTableDesc(null, build.build());
+ if (res.getResultCode() == ResultCode.OK) {
+ return CatalogUtil.newTableDesc(res.getTableDesc());
+ } else {
+ throw new SQLException(res.getErrorMessage(), SQLStates.ER_NO_SUCH_TABLE.getState());
+ }
+ }
+ }.withRetries();
+ }
+
+ public boolean killQuery(final QueryId queryId)
+ throws ServiceException, IOException {
+
+ QueryStatus status = getQueryStatus(queryId);
+
+ NettyClientBase tmClient = null;
+ try {
+ /* send a kill to the TM */
+ tmClient = connPool.getConnection(tajoMasterAddr, TajoMasterClientProtocol.class, false);
+ TajoMasterClientProtocolService.BlockingInterface tajoMasterService = tmClient.getStub();
+ tajoMasterService.killQuery(null, queryId.getProto());
+
+ long currentTimeMillis = System.currentTimeMillis();
+ long timeKillIssued = currentTimeMillis;
+ while ((currentTimeMillis < timeKillIssued + 10000L) && (status.getState()
+ != QueryState.QUERY_KILLED)) {
+ try {
+ Thread.sleep(1000L);
+ } catch(InterruptedException ie) {
+ /** interrupted, just break */
+ break;
+ }
+ currentTimeMillis = System.currentTimeMillis();
+ status = getQueryStatus(queryId);
+ }
+ } catch(Exception e) {
+ LOG.debug("Error when checking for application status", e);
+ return false;
+ } finally {
+ connPool.closeConnection(tmClient);
+ }
+
+ return true;
+ }
+
+ public static void main(String[] args) throws Exception {
+ TajoClient client = new TajoClient(new TajoConf());
+
+ client.close();
+
+ synchronized(client) {
+ client.wait();
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/b6a5ff0c/tajo-client/src/main/java/org/apache/tajo/client/TajoDump.java
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/java/org/apache/tajo/client/TajoDump.java b/tajo-client/src/main/java/org/apache/tajo/client/TajoDump.java
new file mode 100644
index 0000000..486ff9f
--- /dev/null
+++ b/tajo-client/src/main/java/org/apache/tajo/client/TajoDump.java
@@ -0,0 +1,129 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.client;
+
+import com.google.common.collect.Lists;
+import com.google.protobuf.ServiceException;
+import org.apache.commons.cli.*;
+import org.apache.tajo.catalog.DDLBuilder;
+import org.apache.tajo.catalog.TableDesc;
+import org.apache.tajo.conf.TajoConf;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.sql.SQLException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.List;
+
+public class TajoDump {
+ private static final org.apache.commons.cli.Options options;
+
+ static {
+ options = new Options();
+ options.addOption("h", "host", true, "Tajo server host");
+ options.addOption("p", "port", true, "Tajo server port");
+ options.addOption("a", "all", false, "dump all table DDLs");
+ }
+
+ private static void printUsage() {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp( "tajo_dump [options] [table_name]", options );
+ }
+
+ public static void main(String [] args) throws ParseException, IOException, ServiceException, SQLException {
+ TajoConf conf = new TajoConf();
+
+ CommandLineParser parser = new PosixParser();
+ CommandLine cmd = parser.parse(options, args);
+
+ String hostName = null;
+ Integer port = null;
+ if (cmd.hasOption("h")) {
+ hostName = cmd.getOptionValue("h");
+ }
+ if (cmd.hasOption("p")) {
+ port = Integer.parseInt(cmd.getOptionValue("p"));
+ }
+
+ // if there is no "-h" option,
+ if(hostName == null) {
+ if (conf.getVar(TajoConf.ConfVars.TAJO_MASTER_CLIENT_RPC_ADDRESS) != null) {
+ // it checks if the client service address is given in configuration and distributed mode.
+ // if so, it sets entryAddr.
+ hostName = conf.getVar(TajoConf.ConfVars.TAJO_MASTER_CLIENT_RPC_ADDRESS).split(":")[0];
+ }
+ }
+ if (port == null) {
+ if (conf.getVar(TajoConf.ConfVars.TAJO_MASTER_CLIENT_RPC_ADDRESS) != null) {
+ // it checks if the client service address is given in configuration and distributed mode.
+ // if so, it sets entryAddr.
+ port = Integer.parseInt(conf.getVar(TajoConf.ConfVars.TAJO_MASTER_CLIENT_RPC_ADDRESS).split(":")[1]);
+ }
+ }
+
+ TajoClient client = null;
+ if ((hostName == null) ^ (port == null)) {
+ System.err.println("ERROR: cannot find valid Tajo server address");
+ System.exit(-1);
+ } else if (hostName != null && port != null) {
+ conf.setVar(TajoConf.ConfVars.TAJO_MASTER_CLIENT_RPC_ADDRESS, hostName+":"+port);
+ client = new TajoClient(conf);
+ } else if (hostName == null && port == null) {
+ client = new TajoClient(conf);
+ }
+
+ List<TableDesc> tableDescList = Lists.newArrayList();
+
+ if (cmd.hasOption("a")) {
+ for (String tableName : client.getTableList()) {
+ tableDescList.add(client.getTableDesc(tableName));
+ }
+ } else if (cmd.getArgs().length > 0) {
+ for (String tableName : cmd.getArgs()) {
+ tableDescList.add(client.getTableDesc(tableName));
+ }
+ } else {
+ printUsage();
+ }
+
+
+ Writer writer = new PrintWriter(System.out);
+ writer.write("--\n");
+ writer.write("-- Tajo database dump\n");
+ writer.write("-- Dump date: " + toDateString() + "\n");
+ writer.write("--\n");
+ writer.write("\n");
+ for (TableDesc tableDesc : tableDescList) {
+ writer.write(DDLBuilder.buildDDL(tableDesc));
+ writer.write("\n\n");
+ }
+ writer.flush();
+ writer.close();
+ System.exit(0);
+ }
+
+ private static String toDateString() {
+ DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
+ java.util.Date today = Calendar.getInstance().getTime();
+ return df.format(today);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/b6a5ff0c/tajo-client/src/main/java/org/apache/tajo/jdbc/SQLStates.java
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/java/org/apache/tajo/jdbc/SQLStates.java b/tajo-client/src/main/java/org/apache/tajo/jdbc/SQLStates.java
new file mode 100644
index 0000000..32ab19c
--- /dev/null
+++ b/tajo-client/src/main/java/org/apache/tajo/jdbc/SQLStates.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.jdbc;
+
+public enum SQLStates {
+ ER_NO_SUCH_TABLE("42S02");
+
+ private String state;
+
+ SQLStates(String state) {
+ this.state = state;
+ }
+
+ public String getState() {
+ return state;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/b6a5ff0c/tajo-client/src/main/java/org/apache/tajo/jdbc/TajoResultSet.java
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/java/org/apache/tajo/jdbc/TajoResultSet.java b/tajo-client/src/main/java/org/apache/tajo/jdbc/TajoResultSet.java
new file mode 100644
index 0000000..1005765
--- /dev/null
+++ b/tajo-client/src/main/java/org/apache/tajo/jdbc/TajoResultSet.java
@@ -0,0 +1,152 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.jdbc;
+
+import com.google.common.collect.Lists;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.PathFilter;
+import org.apache.tajo.QueryId;
+import org.apache.tajo.catalog.TableDesc;
+import org.apache.tajo.catalog.TableMeta;
+import org.apache.tajo.client.TajoClient;
+import org.apache.tajo.conf.TajoConf;
+import org.apache.tajo.storage.FileScanner;
+import org.apache.tajo.storage.MergeScanner;
+import org.apache.tajo.storage.Scanner;
+import org.apache.tajo.storage.Tuple;
+import org.apache.tajo.storage.fragment.FileFragment;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+
+public class TajoResultSet extends TajoResultSetBase {
+ private FileSystem fs;
+ private Scanner scanner;
+ private TajoClient tajoClient;
+ QueryId queryId;
+
+ public TajoResultSet(TajoClient tajoClient, QueryId queryId) {
+ this.tajoClient = tajoClient;
+ this.queryId = queryId;
+ init();
+ }
+
+ public TajoResultSet(TajoClient tajoClient, QueryId queryId,
+ Configuration conf, TableDesc desc) throws IOException {
+ this.schema = desc.getSchema();
+ this.tajoClient = tajoClient;
+ this.queryId = queryId;
+ if(desc != null) {
+ fs = FileScanner.getFileSystem((TajoConf)conf, desc.getPath());
+ this.totalRow = desc.getStats() != null ? desc.getStats().getNumRows() : 0;
+
+ Collection<FileFragment> frags = getFragments(desc.getMeta(), desc.getPath());
+ scanner = new MergeScanner(conf, schema, desc.getMeta(), frags);
+ }
+ init();
+ }
+
+ @Override
+ protected void init() {
+ cur = null;
+ curRow = 0;
+ }
+
+ class FileNameComparator implements Comparator<FileStatus> {
+
+ @Override
+ public int compare(FileStatus f1, FileStatus f2) {
+ return f2.getPath().getName().compareTo(f1.getPath().getName());
+ }
+ }
+
+ private Collection<FileFragment> getFragments(TableMeta meta, Path tablePath)
+ throws IOException {
+ List<FileFragment> fraglist = Lists.newArrayList();
+ FileStatus[] files = fs.listStatus(tablePath, new PathFilter() {
+ @Override
+ public boolean accept(Path path) {
+ return path.getName().charAt(0) != '.';
+ }
+ });
+ Arrays.sort(files, new FileNameComparator());
+
+ String tbname = tablePath.getName();
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].getLen() == 0) {
+ continue;
+ }
+ fraglist.add(new FileFragment(tbname + "_" + i, files[i].getPath(), 0l, files[i].getLen()));
+ }
+ return fraglist;
+ }
+
+ @Override
+ public void close() throws SQLException {
+ try {
+ if(tajoClient != null) {
+ this.tajoClient.closeQuery(queryId);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ try {
+ if(scanner != null) {
+ this.scanner.close();
+ }
+ //TODO clean temp result file
+ cur = null;
+ curRow = -1;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void beforeFirst() throws SQLException {
+ try {
+ if(scanner != null) {
+ scanner.reset();
+ }
+ init();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ @Override
+ protected Tuple nextTuple() throws IOException {
+ if(scanner == null) {
+ return null;
+ }
+ return scanner.next();
+ }
+
+ public boolean hasResult() {
+ return scanner != null;
+ }
+}