tajo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hyun...@apache.org
Subject git commit: TAJO-482: Implements listing functions and describing a specified function. (hyoungjunkim via hyunsik)
Date Wed, 22 Jan 2014 02:07:28 GMT
Updated Branches:
  refs/heads/master 9693b7397 -> 9a9d6eaf4


TAJO-482: Implements listing functions and describing a specified function. (hyoungjunkim via 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/9a9d6eaf
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tajo/tree/9a9d6eaf
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tajo/diff/9a9d6eaf

Branch: refs/heads/master
Commit: 9a9d6eaf432f1903414792a0384b464753aa52a3
Parents: 9693b73
Author: Hyunsik Choi <hyunsik@apache.org>
Authored: Wed Jan 22 10:53:13 2014 +0900
Committer: Hyunsik Choi <hyunsik@apache.org>
Committed: Wed Jan 22 10:53:13 2014 +0900

----------------------------------------------------------------------
 CHANGES.txt                                     |   3 +
 .../org/apache/tajo/catalog/FunctionDesc.java   |  12 +
 .../org/apache/tajo/cli/CopyrightCommand.java   |  67 +++++
 .../apache/tajo/cli/DescFunctionCommand.java    | 133 +++++++++
 .../org/apache/tajo/cli/DescTableCommand.java   | 136 +++++++++
 .../java/org/apache/tajo/cli/ExitCommand.java   |  51 ++++
 .../java/org/apache/tajo/cli/HelpCommand.java   |  73 +++++
 .../main/java/org/apache/tajo/cli/TajoCli.java  | 285 +------------------
 .../org/apache/tajo/cli/TajoShellCommand.java   | 124 ++++++++
 .../org/apache/tajo/cli/VersionCommand.java     |  51 ++++
 .../java/org/apache/tajo/client/TajoClient.java |  20 ++
 tajo-client/src/main/proto/ClientProtos.proto   |   6 +
 .../main/proto/TajoMasterClientProtocol.proto   |   4 +-
 .../java/org/apache/tajo/conf/TajoConf.java     |   5 +-
 .../tajo/master/TajoMasterClientService.java    |  28 +-
 .../org/apache/tajo/client/TestTajoClient.java  |  26 ++
 16 files changed, 743 insertions(+), 281 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index c19392d..7999e5b 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -4,6 +4,9 @@ Release 0.8.0 - unreleased
 
   NEW FEATURES
 
+    TAJO-482: Implements listing functions and describing a specified
+    function. (hyoungjunkim via hyunsik)
+
     TAJO-498: Implement digest(text, text) function.
     (DaeMyung Kang via hyunsik)
 

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java
----------------------------------------------------------------------
diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java
index b0bc68d..00a687c 100644
--- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java
+++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java
@@ -31,6 +31,7 @@ import org.apache.tajo.exception.InternalException;
 
 import java.lang.reflect.Constructor;
 import java.util.Arrays;
+import java.util.List;
 
 public class FunctionDesc implements ProtoObject<FunctionDescProto>, Cloneable, GsonObject {
   private FunctionDescProto.Builder builder = FunctionDescProto.newBuilder();
@@ -205,4 +206,15 @@ public class FunctionDesc implements ProtoObject<FunctionDescProto>, Cloneable,
   public String getHelpSignature() {
     return returnType.getType() + " " + CatalogUtil.getCanonicalName(signature, getParamTypes());
   }
+
+  public static String dataTypesToStr(List<DataType> parameterTypesList) {
+    String result = "";
+    String prefix = "";
+    for(DataType eachType: parameterTypesList) {
+      result += prefix + eachType.getType().toString();
+      prefix = ",";
+    }
+
+    return result;
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/tajo-client/src/main/java/org/apache/tajo/cli/CopyrightCommand.java
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/java/org/apache/tajo/cli/CopyrightCommand.java b/tajo-client/src/main/java/org/apache/tajo/cli/CopyrightCommand.java
new file mode 100644
index 0000000..809cd37
--- /dev/null
+++ b/tajo-client/src/main/java/org/apache/tajo/cli/CopyrightCommand.java
@@ -0,0 +1,67 @@
+/**
+ * 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 org.apache.tajo.client.TajoClient;
+
+import java.io.PrintWriter;
+
+public class CopyrightCommand extends TajoShellCommand {
+  public CopyrightCommand(TajoClient client, PrintWriter sout) {
+    super(client, sout);
+  }
+
+  @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";
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/tajo-client/src/main/java/org/apache/tajo/cli/DescFunctionCommand.java
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/java/org/apache/tajo/cli/DescFunctionCommand.java b/tajo-client/src/main/java/org/apache/tajo/cli/DescFunctionCommand.java
new file mode 100644
index 0000000..e9f4964
--- /dev/null
+++ b/tajo-client/src/main/java/org/apache/tajo/cli/DescFunctionCommand.java
@@ -0,0 +1,133 @@
+/**
+ * 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 org.apache.tajo.catalog.CatalogUtil;
+import org.apache.tajo.catalog.FunctionDesc;
+import org.apache.tajo.catalog.proto.CatalogProtos;
+import org.apache.tajo.client.TajoClient;
+
+import java.io.PrintWriter;
+import java.util.*;
+
+public class DescFunctionCommand extends TajoShellCommand {
+  public DescFunctionCommand(TajoClient client, PrintWriter sout) {
+    super(client, sout);
+  }
+
+  @Override
+  public String getCommand() {
+    return "\\df";
+  }
+
+  @Override
+  public void invoke(String[] cmd) throws Exception {
+    boolean printDetail = false;
+    String functionName = "";
+    if(cmd.length == 0) {
+      throw new IllegalArgumentException();
+    }
+
+    if (cmd.length == 2) {
+      printDetail = true;
+      functionName = cmd[1];
+    }
+
+    List<CatalogProtos.FunctionDescProto> functions =
+        new ArrayList<CatalogProtos.FunctionDescProto>(client.getFunctions(functionName));
+
+    Collections.sort(functions, new Comparator<CatalogProtos.FunctionDescProto>() {
+      @Override
+      public int compare(CatalogProtos.FunctionDescProto f1, CatalogProtos.FunctionDescProto f2) {
+        int nameCompared = f1.getSignature().compareTo(f2.getSignature());
+        if (nameCompared != 0) {
+          return nameCompared;
+        } else {
+          return f1.getReturnType().getType().compareTo(f2.getReturnType().getType());
+        }
+      }
+    });
+
+    String[] headers = new String[]{"Name", "Result type", "Argument types", "Description", "Type"};
+    float[] columnWidthRates = new float[]{0.15f, 0.15f, 0.2f, 0.4f, 0.1f};
+    int[] columnWidths = printHeader(headers, columnWidthRates);
+
+    for(CatalogProtos.FunctionDescProto eachFunction: functions) {
+      String name = eachFunction.getSignature();
+      String resultDataType = eachFunction.getReturnType().getType().toString();
+      String arguments = FunctionDesc.dataTypesToStr(eachFunction.getParameterTypesList());
+      String functionType = eachFunction.getType().toString();
+      String description = eachFunction.getDescription();
+
+      int index = 0;
+      printLeft(" " + name, columnWidths[index++]);
+      sout.print("|");
+      printLeft(" " + resultDataType, columnWidths[index++]);
+      sout.print("|");
+      printLeft(" " + arguments, columnWidths[index++]);
+      sout.print("|");
+      printLeft(" " + description, columnWidths[index++]);
+      sout.print("|");
+      printLeft(" " + functionType, columnWidths[index++]);
+
+      println();
+    }
+
+    println();
+    sout.println("(" + functions.size() + ") rows");
+    println();
+
+    if (printDetail && !functions.isEmpty()) {
+      Map<String, CatalogProtos.FunctionDescProto> functionMap =
+          new HashMap<String, CatalogProtos.FunctionDescProto>();
+
+      for (CatalogProtos.FunctionDescProto eachFunction: functions) {
+        if (!functionMap.containsKey(eachFunction.getDescription())) {
+          functionMap.put(eachFunction.getDescription(), eachFunction);
+        }
+      }
+
+      for (CatalogProtos.FunctionDescProto eachFunction: functionMap.values()) {
+        String signature = eachFunction.getReturnType().getType() + " " +
+            CatalogUtil.getCanonicalName(eachFunction.getSignature(), eachFunction.getParameterTypesList());
+        String fullDescription = eachFunction.getDescription();
+        if(eachFunction.getDetail() != null && !eachFunction.getDetail().isEmpty()) {
+          fullDescription += "\n" + eachFunction.getDetail();
+        }
+
+        sout.println("Function:    " + signature);
+        sout.println("Description: " + fullDescription);
+        sout.println("Example:\n" + eachFunction.getExample());
+        println();
+      }
+    }
+  }
+
+  @Override
+  public String getUsage() {
+    return "[function_name]";
+  }
+
+  @Override
+  public String getDescription() {
+    return "show function description";
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/tajo-client/src/main/java/org/apache/tajo/cli/DescTableCommand.java
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/java/org/apache/tajo/cli/DescTableCommand.java b/tajo-client/src/main/java/org/apache/tajo/cli/DescTableCommand.java
new file mode 100644
index 0000000..b4678c0
--- /dev/null
+++ b/tajo-client/src/main/java/org/apache/tajo/cli/DescTableCommand.java
@@ -0,0 +1,136 @@
+/**
+ * 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 org.apache.tajo.catalog.Column;
+import org.apache.tajo.catalog.TableDesc;
+import org.apache.tajo.catalog.partition.Specifier;
+import org.apache.tajo.client.TajoClient;
+import org.apache.tajo.util.FileUtil;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Map;
+
+public class DescTableCommand extends TajoShellCommand {
+  public DescTableCommand(TajoClient client, PrintWriter sout) {
+    super(client, sout);
+  }
+
+  @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";
+  }
+
+  protected 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();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/tajo-client/src/main/java/org/apache/tajo/cli/ExitCommand.java
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/java/org/apache/tajo/cli/ExitCommand.java b/tajo-client/src/main/java/org/apache/tajo/cli/ExitCommand.java
new file mode 100644
index 0000000..dcf8893
--- /dev/null
+++ b/tajo-client/src/main/java/org/apache/tajo/cli/ExitCommand.java
@@ -0,0 +1,51 @@
+/**
+ * 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 org.apache.tajo.client.TajoClient;
+
+import java.io.PrintWriter;
+
+public class ExitCommand extends TajoShellCommand {
+
+  public ExitCommand(TajoClient client, PrintWriter sout) {
+    super(client, sout);
+  }
+
+  @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";
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/tajo-client/src/main/java/org/apache/tajo/cli/HelpCommand.java
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/java/org/apache/tajo/cli/HelpCommand.java b/tajo-client/src/main/java/org/apache/tajo/cli/HelpCommand.java
new file mode 100644
index 0000000..85ba808
--- /dev/null
+++ b/tajo-client/src/main/java/org/apache/tajo/cli/HelpCommand.java
@@ -0,0 +1,73 @@
+/**
+ * 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 org.apache.tajo.client.TajoClient;
+
+import java.io.PrintWriter;
+
+public class HelpCommand extends TajoShellCommand {
+  public HelpCommand(TajoClient client, PrintWriter sout) {
+    super(client, sout);
+  }
+
+  @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("  \\df        list functions");
+    sout.println("  \\df NAME   describe function");
+    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";
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/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
index 80188a4..be4be3f 100644
--- a/tajo-client/src/main/java/org/apache/tajo/cli/TajoCli.java
+++ b/tajo-client/src/main/java/org/apache/tajo/cli/TajoCli.java
@@ -25,12 +25,9 @@ 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;
@@ -47,11 +44,12 @@ 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 {
+  public static final int PRINT_LIMIT = 24;
+
   private final TajoConf conf;
   private static final Options options;
 
@@ -61,15 +59,15 @@ public class TajoCli {
   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 final Map<String, TajoShellCommand> commands = new TreeMap<String, TajoShellCommand>();
 
   private static final Class [] registeredCommands = {
       DescTableCommand.class,
+      DescFunctionCommand.class,
       HelpCommand.class,
       ExitCommand.class,
-      Copyright.class,
-      Version.class
+      CopyrightCommand.class,
+      VersionCommand.class
   };
 
   private static final String HOME_DIR = System.getProperty("user.home");
@@ -165,10 +163,10 @@ public class TajoCli {
 
   private void initCommands() {
     for (Class clazz : registeredCommands) {
-      Command cmd = null;
+      TajoShellCommand cmd = null;
       try {
-         Constructor cons = clazz.getConstructor(new Class[] {TajoCli.class});
-         cmd = (Command) cons.newInstance(this);
+         Constructor cons = clazz.getConstructor(new Class[] {TajoClient.class, PrintWriter.class});
+         cmd = (TajoShellCommand) cons.newInstance(client, sout);
       } catch (Exception e) {
         System.err.println(e.getMessage());
         System.exit(-1);
@@ -257,7 +255,7 @@ public class TajoCli {
 
   private void invokeCommand(String [] cmds) {
     // this command should be moved to GlobalEngine
-    Command invoked;
+    TajoShellCommand invoked;
     try {
       invoked = commands.get(cmds[0]);
       invoked.invoke(cmds);
@@ -288,22 +286,7 @@ public class TajoCli {
       } else if (cmds[0].equalsIgnoreCase("detach") && cmds.length > 1 && cmds[1].equalsIgnoreCase("table")) {
         // this command should be moved to GlobalEngine
         invokeCommand(cmds);
-      } else if (cmds[0].equalsIgnoreCase("explain") && cmds.length > 1) {
-        String sql = stripped.substring(8);
-        ClientProtos.ExplainQueryResponse response = client.explainQuery(sql);
-        if (response == null) {
-          sout.println("response is null");
-        } else {
-          if (response.hasExplain()) {
-            sout.println(response.getExplain());
-          } else {
-            if (response.hasErrorMessage()) {
-                sout.println(response.getErrorMessage());
-            } else {
-                sout.println("No Explain");
-            }
-          }
-        }
+
       } else { // submit a query to TajoMaster
         ClientProtos.GetQueryStatusResponse response = client.executeQuery(stripped);
         if (response == null) {
@@ -456,257 +439,13 @@ public class TajoCli {
     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]);
+      TajoShellCommand invoked = commands.get(arguments[0]);
       if (invoked == null) {
         printInvalidCommand(arguments[0]);
         return -1;

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/tajo-client/src/main/java/org/apache/tajo/cli/TajoShellCommand.java
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/java/org/apache/tajo/cli/TajoShellCommand.java b/tajo-client/src/main/java/org/apache/tajo/cli/TajoShellCommand.java
new file mode 100644
index 0000000..2b61068
--- /dev/null
+++ b/tajo-client/src/main/java/org/apache/tajo/cli/TajoShellCommand.java
@@ -0,0 +1,124 @@
+/**
+ * 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 org.apache.tajo.client.TajoClient;
+import org.apache.tajo.conf.TajoConf;
+
+import java.io.PrintWriter;
+
+public abstract class TajoShellCommand {
+  public abstract String getCommand();
+  public abstract void invoke(String [] command) throws Exception;
+  public abstract String getUsage();
+  public abstract String getDescription();
+
+  protected TajoClient client;
+  protected PrintWriter sout;
+
+  protected int maxColumn;
+
+  public TajoShellCommand(TajoClient client, PrintWriter sout) {
+    this.client = client;
+    this.sout = sout;
+
+    maxColumn = client.getConf().getIntVar(TajoConf.ConfVars.CLI_MAX_COLUMN);
+  }
+
+  protected void println() {
+    this.sout.println();
+  }
+
+  protected void printLeft(String message, int columnWidth) {
+    int messageLength = message.length();
+
+    if(messageLength >= columnWidth) {
+      sout.print(message.substring(0, columnWidth - 1));
+    } else {
+      sout.print(message);
+      print(' ', columnWidth - messageLength - 1);
+    }
+  }
+
+  protected void printCenter(String message, int columnWidth, boolean warp) {
+    int messageLength = message.length();
+
+    if(messageLength > columnWidth) {
+      sout.print(message.substring(0, columnWidth - 1));
+    } else {
+      int numPadding = (columnWidth - messageLength)/2;
+
+      print(' ', numPadding);
+      sout.print(message);
+      print(' ', numPadding);
+    }
+    if(warp) {
+      println();
+    }
+  }
+
+  protected void printCenter(String message) {
+    printCenter(message, maxColumn, true);
+  }
+
+  protected void print(char c, int count) {
+    for(int i = 0; i < count; i++) {
+      sout.print(c);
+    }
+  }
+
+  protected int[] printHeader(String[] headers, float[] columnWidthRates) {
+    int[] columnWidths = new int[columnWidthRates.length];
+
+    int columnWidthSum = 0;
+    for(int i = 0; i < columnWidths.length; i++) {
+      columnWidths[i] = (int)(maxColumn * columnWidthRates[i]);
+      if(i > 0) {
+        columnWidthSum += columnWidths[i - 1];
+      }
+    }
+
+    columnWidths[columnWidths.length - 1] = maxColumn - columnWidthSum;
+
+    String prefix = "";
+    for(int i = 0; i < headers.length; i++) {
+      sout.print(prefix);
+      printLeft(" " + headers[i], columnWidths[i]);
+      prefix = "|";
+    }
+    println();
+
+    int index = 0;
+    int printPos = columnWidths[index] - 1;
+    for(int i = 0; i < maxColumn; i++) {
+      if(i == printPos) {
+        if(index < columnWidths.length - 1) {
+          print('+', 1);
+          index++;
+          printPos += columnWidths[index];
+        }
+      } else {
+        print('-', 1);
+      }
+    }
+
+    println();
+    return columnWidths;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/tajo-client/src/main/java/org/apache/tajo/cli/VersionCommand.java
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/java/org/apache/tajo/cli/VersionCommand.java b/tajo-client/src/main/java/org/apache/tajo/cli/VersionCommand.java
new file mode 100644
index 0000000..744c786
--- /dev/null
+++ b/tajo-client/src/main/java/org/apache/tajo/cli/VersionCommand.java
@@ -0,0 +1,51 @@
+/**
+ * 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 org.apache.tajo.TajoConstants;
+import org.apache.tajo.client.TajoClient;
+
+import java.io.PrintWriter;
+
+public class VersionCommand extends TajoShellCommand {
+
+  public VersionCommand(TajoClient client, PrintWriter sout) {
+    super(client, sout);
+  }
+
+  @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";
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/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
index cda0608..2846398 100644
--- a/tajo-client/src/main/java/org/apache/tajo/client/TajoClient.java
+++ b/tajo-client/src/main/java/org/apache/tajo/client/TajoClient.java
@@ -30,6 +30,7 @@ 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.catalog.proto.CatalogProtos;
 import org.apache.tajo.conf.TajoConf;
 import org.apache.tajo.conf.TajoConf.ConfVars;
 import org.apache.tajo.ipc.ClientProtos.*;
@@ -494,4 +495,23 @@ public class TajoClient {
 
     return true;
   }
+
+  public List<CatalogProtos.FunctionDescProto> getFunctions(final String functionName) throws ServiceException {
+    return new ServerCallable<List<CatalogProtos.FunctionDescProto>>(conf, tajoMasterAddr,
+        TajoMasterClientProtocol.class, false, true) {
+      public List<CatalogProtos.FunctionDescProto> call(NettyClientBase client) throws ServiceException, SQLException {
+        TajoMasterClientProtocolService.BlockingInterface tajoMasterService = client.getStub();
+
+        String paramFunctionName = functionName == null ? "" : functionName;
+
+        FunctionResponse res = tajoMasterService.getFunctionList(null,
+            StringProto.newBuilder().setValue(paramFunctionName).build());
+        if (res.getResultCode() == ResultCode.OK) {
+          return res.getFunctionsList();
+        } else {
+          throw new SQLException(res.getErrorMessage());
+        }
+      }
+    }.withRetries();
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/tajo-client/src/main/proto/ClientProtos.proto
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/proto/ClientProtos.proto b/tajo-client/src/main/proto/ClientProtos.proto
index 05cd4e9..d75b5af 100644
--- a/tajo-client/src/main/proto/ClientProtos.proto
+++ b/tajo-client/src/main/proto/ClientProtos.proto
@@ -175,3 +175,9 @@ message TableResponse {
   optional TableDescProto tableDesc = 2;
   optional string errorMessage = 3;
 }
+
+message FunctionResponse {
+  required ResultCode resultCode = 1;
+  repeated FunctionDescProto functions = 2;
+  optional string errorMessage = 3;
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/tajo-client/src/main/proto/TajoMasterClientProtocol.proto
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/proto/TajoMasterClientProtocol.proto b/tajo-client/src/main/proto/TajoMasterClientProtocol.proto
index 4a25905..9feecdb 100644
--- a/tajo-client/src/main/proto/TajoMasterClientProtocol.proto
+++ b/tajo-client/src/main/proto/TajoMasterClientProtocol.proto
@@ -43,20 +43,18 @@ service TajoMasterClientProtocolService {
   rpc getTableDesc(GetTableDescRequest) returns (TableResponse);
   rpc createExternalTable(CreateTableRequest) returns (TableResponse);
   rpc dropTable(DropTableRequest) returns (BoolProto);
-
+  rpc getFunctionList(StringProto) returns (FunctionResponse);
 
   // TODO - to be implemented
   //
   // authenticate
   //
   // getSessionVariableList
-  // dropTable
   // detachTable
   // createIndex
   // dropIndex
   // registerUDF
   // dropUDF
-  // listUdfs
   // getUDFDesc
   // registerJars
   // getListRegisteredJars

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/tajo-common/src/main/java/org/apache/tajo/conf/TajoConf.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/conf/TajoConf.java b/tajo-common/src/main/java/org/apache/tajo/conf/TajoConf.java
index f2fc1aa..d18bd20 100644
--- a/tajo-common/src/main/java/org/apache/tajo/conf/TajoConf.java
+++ b/tajo-common/src/main/java/org/apache/tajo/conf/TajoConf.java
@@ -201,7 +201,10 @@ public class TajoConf extends Configuration {
     //////////////////////////////////
 
     // Metrics
-    METRICS_PROPERTY_FILENAME("tajo.metrics.property.file", "tajo-metrics.properties")
+    METRICS_PROPERTY_FILENAME("tajo.metrics.property.file", "tajo-metrics.properties"),
+
+    //CLI
+    CLI_MAX_COLUMN("tajo.cli.max_columns", 120)
     ;
 
     public final String varname;

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMasterClientService.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMasterClientService.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMasterClientService.java
index 9bcdf53..35e6dd9 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMasterClientService.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMasterClientService.java
@@ -31,11 +31,9 @@ import org.apache.tajo.QueryId;
 import org.apache.tajo.QueryIdFactory;
 import org.apache.tajo.TajoIdProtos;
 import org.apache.tajo.TajoProtos;
-import org.apache.tajo.catalog.CatalogService;
-import org.apache.tajo.catalog.Schema;
-import org.apache.tajo.catalog.TableDesc;
-import org.apache.tajo.catalog.TableMeta;
+import org.apache.tajo.catalog.*;
 import org.apache.tajo.catalog.partition.PartitionDesc;
+import org.apache.tajo.catalog.proto.CatalogProtos;
 import org.apache.tajo.conf.TajoConf;
 import org.apache.tajo.conf.TajoConf.ConfVars;
 import org.apache.tajo.ipc.ClientProtos;
@@ -437,5 +435,27 @@ public class TajoMasterClientService extends AbstractService {
       context.getGlobalEngine().dropTable(dropTable.getName(), dropTable.getPurge());
       return BOOL_TRUE;
     }
+
+    @Override
+    public FunctionResponse getFunctionList(RpcController controller, StringProto request) throws ServiceException {
+      String functionName = request.getValue();
+      Collection<FunctionDesc> functions = catalog.getFunctions();
+
+      List<CatalogProtos.FunctionDescProto> functionProtos = new ArrayList<CatalogProtos.FunctionDescProto>();
+
+      for (FunctionDesc eachFunction: functions) {
+        if (functionName == null || functionName.isEmpty()) {
+          functionProtos.add(eachFunction.getProto());
+        } else {
+          if(functionName.equals(eachFunction.getSignature())) {
+            functionProtos.add(eachFunction.getProto());
+          }
+        }
+      }
+      return FunctionResponse.newBuilder()
+          .setResultCode(ResultCode.OK)
+          .addAllFunctions(functionProtos)
+          .build();
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/9a9d6eaf/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/client/TestTajoClient.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/client/TestTajoClient.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/client/TestTajoClient.java
index 6e33d7c..174f204 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/client/TestTajoClient.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/client/TestTajoClient.java
@@ -28,7 +28,9 @@ import org.apache.tajo.BackendTestingUtil;
 import org.apache.tajo.IntegrationTest;
 import org.apache.tajo.TajoTestingCluster;
 import org.apache.tajo.TpchTestBase;
+import org.apache.tajo.catalog.FunctionDesc;
 import org.apache.tajo.catalog.TableDesc;
+import org.apache.tajo.catalog.proto.CatalogProtos;
 import org.apache.tajo.conf.TajoConf;
 import org.apache.tajo.storage.StorageUtil;
 import org.apache.tajo.util.CommonTestingUtil;
@@ -38,6 +40,8 @@ import org.junit.experimental.categories.Category;
 
 import java.io.IOException;
 import java.sql.SQLException;
+import java.util.Collection;
+import java.util.List;
 import java.util.Set;
 
 import static org.junit.Assert.*;
@@ -425,4 +429,26 @@ public class TestTajoClient {
     assertFalse(client.existTable(tableName));
     assertFalse(hdfs.exists(tablePath));
   }
+
+  @Test
+  public final void testGetFunctions() throws IOException,
+      ServiceException, SQLException {
+    Collection<FunctionDesc> catalogFunctions = cluster.getMaster().getCatalog().getFunctions();
+    String functionName = "sum";
+    int numFunctions = 0;
+    for(FunctionDesc eachFunction: catalogFunctions) {
+      if(functionName.equals(eachFunction.getSignature())) {
+        numFunctions++;
+      }
+    }
+
+    List<CatalogProtos.FunctionDescProto> functions = client.getFunctions(functionName);
+    assertEquals(numFunctions, functions.size());
+
+    functions = client.getFunctions("notmatched");
+    assertEquals(0, functions.size());
+
+    functions = client.getFunctions(null);
+    assertEquals(catalogFunctions.size(), functions.size());
+  }
 }


Mime
View raw message