| /* |
| * 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.cassandra.cli; |
| |
| import java.util.List; |
| |
| import org.antlr.runtime.ANTLRStringStream; |
| import org.antlr.runtime.CharStream; |
| import org.antlr.runtime.CommonTokenStream; |
| import org.antlr.runtime.tree.Tree; |
| import org.apache.cassandra.thrift.CfDef; |
| import org.apache.cassandra.thrift.KsDef; |
| |
| |
| public class CliCompiler |
| { |
| |
| // ANTLR does not provide case-insensitive tokenization support |
| // out of the box. So we override the LA (lookahead) function |
| // of the ANTLRStringStream class. Note: This doesn't change the |
| // token text-- but just relaxes the matching rules to match |
| // in upper case. [Logic borrowed from Hive code.] |
| // |
| // Also see discussion on this topic in: |
| // http://www.antlr.org/wiki/pages/viewpage.action?pageId=1782. |
| public static class ANTLRNoCaseStringStream extends ANTLRStringStream |
| { |
| public ANTLRNoCaseStringStream(String input) |
| { |
| super(input); |
| } |
| |
| public int LA(int i) |
| { |
| int returnChar = super.LA(i); |
| if (returnChar == CharStream.EOF) |
| { |
| return returnChar; |
| } |
| else if (returnChar == 0) |
| { |
| return returnChar; |
| } |
| |
| return Character.toUpperCase((char)returnChar); |
| } |
| } |
| |
| public static Tree compileQuery(String query) |
| { |
| Tree queryTree; |
| |
| try |
| { |
| ANTLRStringStream input = new ANTLRNoCaseStringStream(query); |
| |
| CliLexer lexer = new CliLexer(input); |
| CommonTokenStream tokens = new CommonTokenStream(lexer); |
| |
| CliParser parser = new CliParser(tokens); |
| |
| // start parsing... |
| queryTree = (Tree)(parser.root().getTree()); |
| |
| // semantic analysis if any... |
| // [tbd] |
| |
| } |
| catch(Exception e) |
| { |
| // if there was an exception we don't want to process request any further |
| throw new RuntimeException(e.getMessage(), e); |
| } |
| |
| return queryTree; |
| } |
| /* |
| * NODE_COLUMN_ACCESS related functions. |
| */ |
| |
| public static String getColumnFamily(Tree astNode, Iterable<CfDef> cfDefs) |
| { |
| return getColumnFamily(CliUtils.unescapeSQLString(astNode.getChild(0).getText()), cfDefs); |
| } |
| |
| public static String getColumnFamily(String cfName, Iterable<CfDef> cfDefs) |
| { |
| int matches = 0; |
| String lastMatchedName = ""; |
| |
| for (CfDef cfDef : cfDefs) |
| { |
| if (cfDef.name.equals(cfName)) |
| { |
| return cfName; |
| } |
| else if (cfDef.name.toUpperCase().equals(cfName.toUpperCase())) |
| { |
| lastMatchedName = cfDef.name; |
| matches++; |
| } |
| } |
| |
| if (matches > 1 || matches == 0) |
| throw new RuntimeException(cfName + " not found in current keyspace."); |
| |
| return lastMatchedName; |
| } |
| |
| public static String getKeySpace(Tree statement, List<KsDef> keyspaces) |
| { |
| return getKeySpace(CliUtils.unescapeSQLString(statement.getChild(0).getText()), keyspaces); |
| } |
| |
| public static String getKeySpace(String ksName, List<KsDef> keyspaces) |
| { |
| int matches = 0; |
| String lastMatchedName = ""; |
| |
| for (KsDef ksDef : keyspaces) |
| { |
| if (ksDef.name.equals(ksName)) |
| { |
| return ksName; |
| } |
| else if (ksDef.name.toUpperCase().equals(ksName.toUpperCase())) |
| { |
| lastMatchedName = ksDef.name; |
| matches++; |
| } |
| } |
| |
| if (matches > 1 || matches == 0) |
| throw new RuntimeException("Keyspace '" + ksName + "' not found."); |
| |
| return lastMatchedName; |
| } |
| |
| public static String getKey(Tree astNode) |
| { |
| return CliUtils.unescapeSQLString(astNode.getChild(1).getText()); |
| } |
| |
| public static int numColumnSpecifiers(Tree astNode) |
| { |
| // Skip over keyspace, column family and rowKey |
| return astNode.getChildCount() - 2; |
| } |
| |
| // Returns the pos'th (0-based index) column specifier in the astNode |
| public static String getColumn(Tree astNode, int pos) |
| { |
| // Skip over keyspace, column family and rowKey |
| return CliUtils.unescapeSQLString(astNode.getChild(pos + 2).getText()); |
| } |
| |
| } |