Return-Path: X-Original-To: apmail-tajo-commits-archive@minotaur.apache.org Delivered-To: apmail-tajo-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 7ADDB10160 for ; Wed, 22 Jan 2014 02:07:53 +0000 (UTC) Received: (qmail 52581 invoked by uid 500); 22 Jan 2014 02:07:53 -0000 Delivered-To: apmail-tajo-commits-archive@tajo.apache.org Received: (qmail 52541 invoked by uid 500); 22 Jan 2014 02:07:52 -0000 Mailing-List: contact commits-help@tajo.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@tajo.incubator.apache.org Delivered-To: mailing list commits@tajo.incubator.apache.org Received: (qmail 52534 invoked by uid 99); 22 Jan 2014 02:07:52 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 22 Jan 2014 02:07:52 +0000 X-ASF-Spam-Status: No, hits=-2000.5 required=5.0 tests=ALL_TRUSTED,RP_MATCHES_RCVD X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO mail.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with SMTP; Wed, 22 Jan 2014 02:07:49 +0000 Received: (qmail 52386 invoked by uid 99); 22 Jan 2014 02:07:28 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 22 Jan 2014 02:07:28 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 7626181811A; Wed, 22 Jan 2014 02:07:28 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: hyunsik@apache.org To: commits@tajo.incubator.apache.org Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: git commit: TAJO-482: Implements listing functions and describing a specified function. (hyoungjunkim via hyunsik) Date: Wed, 22 Jan 2014 02:07:28 +0000 (UTC) X-Virus-Checked: Checked by ClamAV on apache.org 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 Authored: Wed Jan 22 10:53:13 2014 +0900 Committer: Hyunsik Choi 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, Cloneable, GsonObject { private FunctionDescProto.Builder builder = FunctionDescProto.newBuilder(); @@ -205,4 +206,15 @@ public class FunctionDesc implements ProtoObject, Cloneable, public String getHelpSignature() { return returnType.getType() + " " + CatalogUtil.getCanonicalName(signature, getParamTypes()); } + + public static String dataTypesToStr(List 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 functions = + new ArrayList(client.getFunctions(functionName)); + + Collections.sort(functions, new Comparator() { + @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 functionMap = + new HashMap(); + + 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 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 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 commands = new TreeMap(); + private final Map commands = new TreeMap(); 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 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 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 getFunctions(final String functionName) throws ServiceException { + return new ServerCallable>(conf, tajoMasterAddr, + TajoMasterClientProtocol.class, false, true) { + public List 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 functions = catalog.getFunctions(); + + List functionProtos = new ArrayList(); + + 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 catalogFunctions = cluster.getMaster().getCatalog().getFunctions(); + String functionName = "sum"; + int numFunctions = 0; + for(FunctionDesc eachFunction: catalogFunctions) { + if(functionName.equals(eachFunction.getSignature())) { + numFunctions++; + } + } + + List 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()); + } }