You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by jb...@apache.org on 2011/09/09 18:49:35 UTC
svn commit: r1167287 [2/3] - in /cassandra/branches/cassandra-1.0.0: ./
doc/cql/ src/java/org/apache/cassandra/cli/
src/java/org/apache/cassandra/cql/ src/java/org/apache/cassandra/cql/jdbc/
src/java/org/apache/cassandra/db/marshal/ src/resources/org/a...
Added: cassandra/branches/cassandra-1.0.0/src/java/org/apache/cassandra/cli/CliClient.java.orig
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-1.0.0/src/java/org/apache/cassandra/cli/CliClient.java.orig?rev=1167287&view=auto
==============================================================================
--- cassandra/branches/cassandra-1.0.0/src/java/org/apache/cassandra/cli/CliClient.java.orig (added)
+++ cassandra/branches/cassandra-1.0.0/src/java/org/apache/cassandra/cli/CliClient.java.orig Fri Sep 9 16:49:35 2011
@@ -0,0 +1,2800 @@
+/**
+ * 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.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.util.*;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import org.apache.commons.lang.StringUtils;
+import com.google.common.base.Charsets;
+import com.google.common.base.Joiner;
+
+import org.antlr.runtime.tree.Tree;
+import org.apache.cassandra.auth.SimpleAuthenticator;
+import org.apache.cassandra.config.ConfigurationException;
+import org.apache.cassandra.db.ColumnFamilyStoreMBean;
+import org.apache.cassandra.db.compaction.CompactionInfo;
+import org.apache.cassandra.db.compaction.CompactionManagerMBean;
+import org.apache.cassandra.db.compaction.OperationType;
+import org.apache.cassandra.db.marshal.*;
+import org.apache.cassandra.io.util.FileUtils;
+import org.apache.cassandra.locator.SimpleSnitch;
+import org.apache.cassandra.service.StorageProxy;
+import org.apache.cassandra.thrift.*;
+import org.apache.cassandra.tools.NodeProbe;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.cassandra.utils.FBUtilities;
+import org.apache.cassandra.utils.UUIDGen;
+import org.apache.thrift.TBaseHelper;
+import org.apache.thrift.TException;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Yaml;
+
+// Cli Client Side Library
+public class CliClient
+{
+ /**
+ * Available value conversion functions
+ * Used by convertValueByFunction(Tree functionCall) method
+ */
+ public enum Function
+ {
+ BYTES (BytesType.instance),
+ INTEGER (IntegerType.instance),
+ LONG (LongType.instance),
+ LEXICALUUID (LexicalUUIDType.instance),
+ TIMEUUID (TimeUUIDType.instance),
+ UTF8 (UTF8Type.instance),
+ ASCII (AsciiType.instance),
+ COUNTERCOLUMN (CounterColumnType.instance);
+
+ private AbstractType validator;
+
+ Function(AbstractType validator)
+ {
+ this.validator = validator;
+ }
+
+ public AbstractType getValidator()
+ {
+ return this.validator;
+ }
+
+ public static String getFunctionNames()
+ {
+ Function[] functions = Function.values();
+ StringBuilder functionNames = new StringBuilder();
+
+ for (int i = 0; i < functions.length; i++)
+ {
+ StringBuilder currentName = new StringBuilder(functions[i].name().toLowerCase());
+ functionNames.append(currentName.append(((i != functions.length-1) ? ", " : ".")));
+ }
+
+ return functionNames.toString();
+ }
+ }
+
+ /*
+ * the <i>add keyspace</i> command requires a list of arguments,
+ * this enum defines which arguments are valid
+ */
+ private enum AddKeyspaceArgument {
+ PLACEMENT_STRATEGY,
+ STRATEGY_OPTIONS,
+ DURABLE_WRITES
+ }
+
+ /*
+ * the <i>add column family</i> command requires a list of arguments,
+ * this enum defines which arguments are valid.
+ */
+ protected enum ColumnFamilyArgument
+ {
+ COLUMN_TYPE,
+ COMPARATOR,
+ SUBCOMPARATOR,
+ COMMENT,
+ ROWS_CACHED,
+ ROW_CACHE_SAVE_PERIOD,
+ ROW_CACHE_KEYS_TO_SAVE,
+ KEYS_CACHED,
+ KEY_CACHE_SAVE_PERIOD,
+ READ_REPAIR_CHANCE,
+ GC_GRACE,
+ COLUMN_METADATA,
+ MEMTABLE_OPERATIONS,
+ MEMTABLE_THROUGHPUT,
+ DEFAULT_VALIDATION_CLASS,
+ MIN_COMPACTION_THRESHOLD,
+ MAX_COMPACTION_THRESHOLD,
+ REPLICATE_ON_WRITE,
+ ROW_CACHE_PROVIDER,
+ KEY_VALIDATION_CLASS,
+ COMPACTION_STRATEGY,
+ COMPACTION_STRATEGY_OPTIONS,
+ COMPRESSION_OPTIONS,
+ }
+
+ private static final String DEFAULT_PLACEMENT_STRATEGY = "org.apache.cassandra.locator.NetworkTopologyStrategy";
+ private final String NEWLINE = System.getProperty("line.separator");
+ private final String TAB = " ";
+
+ private Cassandra.Client thriftClient = null;
+ private CliSessionState sessionState = null;
+ private String keySpace = null;
+ private String username = null;
+ private Map<String, KsDef> keyspacesMap = new HashMap<String, KsDef>();
+ private Map<String, AbstractType> cfKeysComparators;
+ private ConsistencyLevel consistencyLevel = ConsistencyLevel.ONE;
+ private CliUserHelp help;
+ public CliClient(CliSessionState cliSessionState, Cassandra.Client thriftClient)
+ {
+ this.sessionState = cliSessionState;
+ this.thriftClient = thriftClient;
+ this.cfKeysComparators = new HashMap<String, AbstractType>();
+ }
+
+ private CliUserHelp getHelp()
+ {
+ if (help == null)
+ help = loadHelp();
+ return help;
+ }
+
+ private CliUserHelp loadHelp()
+ {
+ final InputStream is = CliClient.class.getClassLoader().getResourceAsStream("org/apache/cassandra/cli/CliHelp.yaml");
+ assert is != null;
+
+ try
+ {
+ final Constructor constructor = new Constructor(CliUserHelp.class);
+ TypeDescription desc = new TypeDescription(CliUserHelp.class);
+ desc.putListPropertyType("commands", CliCommandHelp.class);
+ final Yaml yaml = new Yaml(new Loader(constructor));
+ return (CliUserHelp) yaml.load(is);
+ }
+ finally
+ {
+ FileUtils.closeQuietly(is);
+ }
+ }
+
+ public void printBanner()
+ {
+ sessionState.out.println(getHelp().banner);
+ }
+
+ // Execute a CLI Statement
+ public void executeCLIStatement(String statement) throws CharacterCodingException, TException, TimedOutException, NotFoundException, NoSuchFieldException, InvalidRequestException, UnavailableException, InstantiationException, IllegalAccessException, ClassNotFoundException, SchemaDisagreementException
+ {
+ Tree tree = CliCompiler.compileQuery(statement);
+
+ try
+ {
+ switch (tree.getType())
+ {
+ case CliParser.NODE_EXIT:
+ cleanupAndExit();
+ break;
+ case CliParser.NODE_THRIFT_GET:
+ executeGet(tree);
+ break;
+ case CliParser.NODE_THRIFT_GET_WITH_CONDITIONS:
+ executeGetWithConditions(tree);
+ break;
+ case CliParser.NODE_HELP:
+ executeHelp(tree);
+ break;
+ case CliParser.NODE_THRIFT_SET:
+ executeSet(tree);
+ break;
+ case CliParser.NODE_THRIFT_DEL:
+ executeDelete(tree);
+ break;
+ case CliParser.NODE_THRIFT_COUNT:
+ executeCount(tree);
+ break;
+ case CliParser.NODE_ADD_KEYSPACE:
+ executeAddKeySpace(tree.getChild(0));
+ break;
+ case CliParser.NODE_ADD_COLUMN_FAMILY:
+ executeAddColumnFamily(tree.getChild(0));
+ break;
+ case CliParser.NODE_UPDATE_KEYSPACE:
+ executeUpdateKeySpace(tree.getChild(0));
+ break;
+ case CliParser.NODE_UPDATE_COLUMN_FAMILY:
+ executeUpdateColumnFamily(tree.getChild(0));
+ break;
+ case CliParser.NODE_DEL_COLUMN_FAMILY:
+ executeDelColumnFamily(tree);
+ break;
+ case CliParser.NODE_DEL_KEYSPACE:
+ executeDelKeySpace(tree);
+ break;
+ case CliParser.NODE_SHOW_CLUSTER_NAME:
+ executeShowClusterName();
+ break;
+ case CliParser.NODE_SHOW_VERSION:
+ executeShowVersion();
+ break;
+ case CliParser.NODE_SHOW_KEYSPACES:
+ executeShowKeySpaces();
+ break;
+ case CliParser.NODE_SHOW_SCHEMA:
+ executeShowSchema(tree);
+ break;
+ case CliParser.NODE_DESCRIBE:
+ executeDescribe(tree);
+ break;
+ case CliParser.NODE_DESCRIBE_CLUSTER:
+ executeDescribeCluster();
+ break;
+ case CliParser.NODE_USE_TABLE:
+ executeUseKeySpace(tree);
+ break;
+ case CliParser.NODE_CONNECT:
+ executeConnect(tree);
+ break;
+ case CliParser.NODE_LIST:
+ executeList(tree);
+ break;
+ case CliParser.NODE_TRUNCATE:
+ executeTruncate(tree.getChild(0).getText());
+ break;
+ case CliParser.NODE_ASSUME:
+ executeAssumeStatement(tree);
+ break;
+ case CliParser.NODE_CONSISTENCY_LEVEL:
+ executeConsistencyLevelStatement(tree);
+ break;
+ case CliParser.NODE_THRIFT_INCR:
+ executeIncr(tree, 1L);
+ break;
+ case CliParser.NODE_THRIFT_DECR:
+ executeIncr(tree, -1L);
+ break;
+ case CliParser.NODE_DROP_INDEX:
+ executeDropIndex(tree);
+ break;
+
+ case CliParser.NODE_NO_OP:
+ // comment lines come here; they are treated as no ops.
+ break;
+ default:
+ sessionState.err.println("Invalid Statement (Type: " + tree.getType() + ")");
+ if (sessionState.batch)
+ System.exit(2);
+ break;
+ }
+ }
+ catch (SchemaDisagreementException e)
+ {
+ RuntimeException rtEx = new RuntimeException("schema does not match across nodes, (try again later).");
+ rtEx.initCause(e);
+ throw new RuntimeException();
+ }
+ }
+
+ private void cleanupAndExit()
+ {
+ CliMain.disconnect();
+ System.exit(0);
+ }
+
+ public KsDef getKSMetaData(String keyspace)
+ throws NotFoundException, InvalidRequestException, TException
+ {
+ // Lazily lookup keyspace meta-data.
+ if (!(keyspacesMap.containsKey(keyspace)))
+ keyspacesMap.put(keyspace, thriftClient.describe_keyspace(keyspace));
+
+ return keyspacesMap.get(keyspace);
+ }
+
+ private void executeHelp(Tree tree)
+ {
+ if (tree.getChildCount() > 0)
+ {
+ String token = tree.getChild(0).getText();
+ for (CliCommandHelp ch : getHelp().commands)
+ {
+ if (token.equals(ch.name))
+ {
+ sessionState.out.println(ch.help);
+ break;
+ }
+ }
+ }
+ else
+ {
+ sessionState.out.println(getHelp().help);
+ }
+ }
+
+ private void executeCount(Tree statement)
+ throws TException, InvalidRequestException, UnavailableException, TimedOutException
+ {
+ if (!CliMain.isConnected() || !hasKeySpace())
+ return;
+
+ Tree columnFamilySpec = statement.getChild(0);
+
+ String columnFamily = CliCompiler.getColumnFamily(columnFamilySpec, keyspacesMap.get(keySpace).cf_defs);
+ int columnSpecCnt = CliCompiler.numColumnSpecifiers(columnFamilySpec);
+
+ ColumnParent colParent = new ColumnParent(columnFamily).setSuper_column((ByteBuffer) null);
+
+ if (columnSpecCnt != 0)
+ {
+ Tree columnTree = columnFamilySpec.getChild(2);
+
+ byte[] superColumn = (columnTree.getType() == CliParser.FUNCTION_CALL)
+ ? convertValueByFunction(columnTree, null, null).array()
+ : columnNameAsByteArray(CliCompiler.getColumn(columnFamilySpec, 0), columnFamily);
+
+ colParent = new ColumnParent(columnFamily).setSuper_column(superColumn);
+ }
+
+ SliceRange range = new SliceRange(ByteBufferUtil.EMPTY_BYTE_BUFFER, ByteBufferUtil.EMPTY_BYTE_BUFFER, false, Integer.MAX_VALUE);
+ SlicePredicate predicate = new SlicePredicate().setColumn_names(null).setSlice_range(range);
+
+ int count = thriftClient.get_count(getKeyAsBytes(columnFamily, columnFamilySpec.getChild(1)), colParent, predicate, consistencyLevel);
+ sessionState.out.printf("%d columns%n", count);
+ }
+
+ private void executeDelete(Tree statement)
+ throws TException, InvalidRequestException, UnavailableException, TimedOutException
+ {
+ if (!CliMain.isConnected() || !hasKeySpace())
+ return;
+
+ Tree columnFamilySpec = statement.getChild(0);
+
+ String columnFamily = CliCompiler.getColumnFamily(columnFamilySpec, keyspacesMap.get(keySpace).cf_defs);
+ CfDef cfDef = getCfDef(columnFamily);
+
+ ByteBuffer key = getKeyAsBytes(columnFamily, columnFamilySpec.getChild(1));
+ int columnSpecCnt = CliCompiler.numColumnSpecifiers(columnFamilySpec);
+
+ byte[] superColumnName = null;
+ byte[] columnName = null;
+ boolean isSuper = cfDef.column_type.equals("Super");
+
+ if ((columnSpecCnt < 0) || (columnSpecCnt > 2))
+ {
+ sessionState.out.println("Invalid row, super column, or column specification.");
+ return;
+ }
+
+ Tree columnTree = (columnSpecCnt >= 1)
+ ? columnFamilySpec.getChild(2)
+ : null;
+
+ Tree subColumnTree = (columnSpecCnt == 2)
+ ? columnFamilySpec.getChild(3)
+ : null;
+
+ if (columnSpecCnt == 1)
+ {
+ assert columnTree != null;
+
+ byte[] columnNameBytes = (columnTree.getType() == CliParser.FUNCTION_CALL)
+ ? convertValueByFunction(columnTree, null, null).array()
+ : columnNameAsByteArray(CliCompiler.getColumn(columnFamilySpec, 0), cfDef);
+
+
+ if (isSuper)
+ superColumnName = columnNameBytes;
+ else
+ columnName = columnNameBytes;
+ }
+ else if (columnSpecCnt == 2)
+ {
+ assert columnTree != null;
+ assert subColumnTree != null;
+
+ // table.cf['key']['column']['column']
+ superColumnName = (columnTree.getType() == CliParser.FUNCTION_CALL)
+ ? convertValueByFunction(columnTree, null, null).array()
+ : columnNameAsByteArray(CliCompiler.getColumn(columnFamilySpec, 0), cfDef);
+
+ columnName = (subColumnTree.getType() == CliParser.FUNCTION_CALL)
+ ? convertValueByFunction(subColumnTree, null, null).array()
+ : subColumnNameAsByteArray(CliCompiler.getColumn(columnFamilySpec, 1), cfDef);
+ }
+
+ ColumnPath path = new ColumnPath(columnFamily);
+ if (superColumnName != null)
+ path.setSuper_column(superColumnName);
+
+ if (columnName != null)
+ path.setColumn(columnName);
+
+ if (isCounterCF(cfDef))
+ {
+ thriftClient.remove_counter(key, path, consistencyLevel);
+ }
+ else
+ {
+ thriftClient.remove(key, path, FBUtilities.timestampMicros(), consistencyLevel);
+ }
+ sessionState.out.println(String.format("%s removed.", (columnSpecCnt == 0) ? "row" : "column"));
+ }
+
+ private void doSlice(String keyspace, ByteBuffer key, String columnFamily, byte[] superColumnName, int limit)
+ throws InvalidRequestException, UnavailableException, TimedOutException, TException, IllegalAccessException, NotFoundException, InstantiationException, NoSuchFieldException
+ {
+
+ ColumnParent parent = new ColumnParent(columnFamily);
+ if(superColumnName != null)
+ parent.setSuper_column(superColumnName);
+
+ SliceRange range = new SliceRange(ByteBufferUtil.EMPTY_BYTE_BUFFER, ByteBufferUtil.EMPTY_BYTE_BUFFER, false, limit);
+ SlicePredicate predicate = new SlicePredicate().setColumn_names(null).setSlice_range(range);
+
+ CfDef cfDef = getCfDef(columnFamily);
+ boolean isSuperCF = cfDef.column_type.equals("Super");
+
+ List<ColumnOrSuperColumn> columns = thriftClient.get_slice(key, parent, predicate, consistencyLevel);
+ AbstractType validator;
+
+ // Print out super columns or columns.
+ for (ColumnOrSuperColumn cosc : columns)
+ {
+ if (cosc.isSetSuper_column())
+ {
+ SuperColumn superColumn = cosc.super_column;
+
+ sessionState.out.printf("=> (super_column=%s,", formatColumnName(keyspace, columnFamily, superColumn.name));
+ for (Column col : superColumn.getColumns())
+ {
+ validator = getValidatorForValue(cfDef, col.getName());
+ sessionState.out.printf("%n (column=%s, value=%s, timestamp=%d%s)", formatSubcolumnName(keyspace, columnFamily, col.name),
+ validator.getString(col.value), col.timestamp,
+ col.isSetTtl() ? String.format(", ttl=%d", col.getTtl()) : "");
+ }
+
+ sessionState.out.println(")");
+ }
+ else if (cosc.isSetColumn())
+ {
+ Column column = cosc.column;
+ validator = getValidatorForValue(cfDef, column.getName());
+
+ String formattedName = isSuperCF
+ ? formatSubcolumnName(keyspace, columnFamily, column.name)
+ : formatColumnName(keyspace, columnFamily, column.name);
+
+ sessionState.out.printf("=> (column=%s, value=%s, timestamp=%d%s)%n",
+ formattedName,
+ validator.getString(column.value),
+ column.timestamp,
+ column.isSetTtl() ? String.format(", ttl=%d", column.getTtl()) : "");
+ }
+ else if (cosc.isSetCounter_super_column())
+ {
+ CounterSuperColumn superColumn = cosc.counter_super_column;
+
+ sessionState.out.printf("=> (super_column=%s,", formatColumnName(keyspace, columnFamily, superColumn.name));
+ for (CounterColumn col : superColumn.getColumns())
+ {
+ sessionState.out.printf("%n (counter=%s, value=%s)", formatSubcolumnName(keyspace, columnFamily, col.name), col.value);
+ }
+ sessionState.out.println(")");
+ }
+ else // cosc.isSetCounter_column()
+ {
+ CounterColumn column = cosc.counter_column;
+ String formattedName = isSuperCF
+ ? formatSubcolumnName(keyspace, columnFamily, column.name)
+ : formatColumnName(keyspace, columnFamily, column.name);
+
+ sessionState.out.printf("=> (counter=%s, value=%s)%n", formattedName, column.value);
+ }
+ }
+
+ sessionState.out.println("Returned " + columns.size() + " results.");
+ }
+
+ private AbstractType getFormatType(String compareWith)
+ {
+ Function function;
+
+ try
+ {
+ function = Function.valueOf(compareWith.toUpperCase());
+ }
+ catch (IllegalArgumentException e)
+ {
+ try
+ {
+ return TypeParser.parse(compareWith);
+ }
+ catch (ConfigurationException ce)
+ {
+ StringBuilder errorMessage = new StringBuilder("Unknown comparator '" + compareWith + "'. ");
+ errorMessage.append("Available functions: ");
+ throw new RuntimeException(errorMessage.append(Function.getFunctionNames()).toString());
+ }
+ }
+
+ return function.getValidator();
+ }
+
+ // Execute GET statement
+ private void executeGet(Tree statement)
+ throws TException, NotFoundException, InvalidRequestException, UnavailableException, TimedOutException, IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchFieldException
+ {
+ if (!CliMain.isConnected() || !hasKeySpace())
+ return;
+
+ Tree columnFamilySpec = statement.getChild(0);
+ String columnFamily = CliCompiler.getColumnFamily(columnFamilySpec, keyspacesMap.get(keySpace).cf_defs);
+ ByteBuffer key = getKeyAsBytes(columnFamily, columnFamilySpec.getChild(1));
+ int columnSpecCnt = CliCompiler.numColumnSpecifiers(columnFamilySpec);
+ CfDef cfDef = getCfDef(columnFamily);
+ boolean isSuper = cfDef.column_type.equals("Super");
+
+ byte[] superColumnName = null;
+ ByteBuffer columnName;
+
+ Tree typeTree = null;
+ Tree limitTree = null;
+
+ int limit = 1000000;
+
+ if (statement.getChildCount() >= 2)
+ {
+ if (statement.getChild(1).getType() == CliParser.CONVERT_TO_TYPE)
+ {
+ typeTree = statement.getChild(1).getChild(0);
+ if (statement.getChildCount() == 3)
+ limitTree = statement.getChild(2).getChild(0);
+ }
+ else
+ {
+ limitTree = statement.getChild(1).getChild(0);
+ }
+ }
+
+ if (limitTree != null)
+ {
+ limit = Integer.parseInt(limitTree.getText());
+
+ if (limit == 0)
+ {
+ throw new IllegalArgumentException("LIMIT should be greater than zero.");
+ }
+ }
+
+ // table.cf['key'] -- row slice
+ if (columnSpecCnt == 0)
+ {
+ doSlice(keySpace, key, columnFamily, superColumnName, limit);
+ return;
+ }
+ // table.cf['key']['column'] -- slice of a super, or get of a standard
+ else if (columnSpecCnt == 1)
+ {
+ columnName = getColumnName(columnFamily, columnFamilySpec.getChild(2));
+
+ if (isSuper)
+ {
+ superColumnName = columnName.array();
+ doSlice(keySpace, key, columnFamily, superColumnName, limit);
+ return;
+ }
+ }
+ // table.cf['key']['column']['column'] -- get of a sub-column
+ else if (columnSpecCnt == 2)
+ {
+ superColumnName = getColumnName(columnFamily, columnFamilySpec.getChild(2)).array();
+ columnName = getSubColumnName(columnFamily, columnFamilySpec.getChild(3));
+ }
+ // The parser groks an arbitrary number of these so it is possible to get here.
+ else
+ {
+ sessionState.out.println("Invalid row, super column, or column specification.");
+ return;
+ }
+
+ AbstractType validator = getValidatorForValue(cfDef, TBaseHelper.byteBufferToByteArray(columnName));
+
+ // Perform a get()
+ ColumnPath path = new ColumnPath(columnFamily);
+ if(superColumnName != null) path.setSuper_column(superColumnName);
+ path.setColumn(columnName);
+
+ if (isCounterCF(cfDef))
+ {
+ doGetCounter(key, path);
+ return;
+ }
+
+ Column column;
+ try
+ {
+ column = thriftClient.get(key, path, consistencyLevel).column;
+ }
+ catch (NotFoundException e)
+ {
+ sessionState.out.println("Value was not found");
+ return;
+ }
+
+ byte[] columnValue = column.getValue();
+ String valueAsString;
+
+ // we have ^(CONVERT_TO_TYPE <type>) inside of GET statement
+ // which means that we should try to represent byte[] value according
+ // to specified type
+ if (typeTree != null)
+ {
+ // .getText() will give us <type>
+ String typeName = CliUtils.unescapeSQLString(typeTree.getText());
+ // building AbstractType from <type>
+ AbstractType valueValidator = getFormatType(typeName);
+
+ // setting value for output
+ valueAsString = valueValidator.getString(ByteBuffer.wrap(columnValue));
+ // updating column value validator class
+ updateColumnMetaData(cfDef, columnName, valueValidator.toString());
+ }
+ else
+ {
+ valueAsString = (validator == null) ? new String(columnValue, Charsets.UTF_8) : validator.getString(ByteBuffer.wrap(columnValue));
+ }
+
+ String formattedColumnName = isSuper
+ ? formatSubcolumnName(keySpace, columnFamily, column.name)
+ : formatColumnName(keySpace, columnFamily, column.name);
+
+ // print results
+ sessionState.out.printf("=> (column=%s, value=%s, timestamp=%d%s)%n",
+ formattedColumnName,
+ valueAsString,
+ column.timestamp,
+ column.isSetTtl() ? String.format(", ttl=%d", column.getTtl()) : "");
+ }
+
+ private void doGetCounter(ByteBuffer key, ColumnPath path)
+ throws TException, NotFoundException, InvalidRequestException, UnavailableException, TimedOutException, IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchFieldException
+ {
+ boolean isSuper = path.super_column != null;
+
+ CounterColumn column;
+ try
+ {
+ column = thriftClient.get(key, path, consistencyLevel).counter_column;
+ }
+ catch (NotFoundException e)
+ {
+ sessionState.out.println("Value was not found");
+ return;
+ }
+
+ String formattedColumnName = isSuper
+ ? formatSubcolumnName(keySpace, path.column_family, column.name)
+ : formatColumnName(keySpace, path.column_family, column.name);
+
+ // print results
+ sessionState.out.printf("=> (counter=%s, value=%d)%n",
+ formattedColumnName,
+ column.value);
+ }
+
+ /**
+ * Process get operation with conditions (using Thrift get_indexed_slices method)
+ * @param statement - tree representation of the current statement
+ * Format: ^(NODE_THRIFT_GET_WITH_CONDITIONS cf ^(CONDITIONS ^(CONDITION >= column1 value1) ...) ^(NODE_LIMIT int)*)
+ */
+ private void executeGetWithConditions(Tree statement)
+ {
+ if (!CliMain.isConnected() || !hasKeySpace())
+ return;
+
+ IndexClause clause = new IndexClause();
+ String columnFamily = CliCompiler.getColumnFamily(statement, keyspacesMap.get(keySpace).cf_defs);
+ // ^(CONDITIONS ^(CONDITION $column $value) ...)
+ Tree conditions = statement.getChild(1);
+
+ // fetching column family definition
+ CfDef columnFamilyDef = getCfDef(columnFamily);
+
+ // fetching all columns
+ SlicePredicate predicate = new SlicePredicate();
+ SliceRange sliceRange = new SliceRange();
+ sliceRange.setStart(new byte[0]).setFinish(new byte[0]);
+ predicate.setSlice_range(sliceRange);
+
+ for (int i = 0; i < conditions.getChildCount(); i++)
+ {
+ // ^(CONDITION operator $column $value)
+ Tree condition = conditions.getChild(i);
+
+ // =, >, >=, <, <=
+ String operator = condition.getChild(0).getText();
+ String columnNameString = CliUtils.unescapeSQLString(condition.getChild(1).getText());
+ // it could be a basic string or function call
+ Tree valueTree = condition.getChild(2);
+
+ try
+ {
+ ByteBuffer value;
+ ByteBuffer columnName = columnNameAsBytes(columnNameString, columnFamily);
+
+ if (valueTree.getType() == CliParser.FUNCTION_CALL)
+ {
+ value = convertValueByFunction(valueTree, columnFamilyDef, columnName);
+ }
+ else
+ {
+ String valueString = CliUtils.unescapeSQLString(valueTree.getText());
+ value = columnValueAsBytes(columnName, columnFamily, valueString);
+ }
+
+ // index operator from string
+ IndexOperator idxOperator = CliUtils.getIndexOperator(operator);
+ // adding new index expression into index clause
+ clause.addToExpressions(new IndexExpression(columnName, idxOperator, value));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ List<KeySlice> slices;
+ clause.setStart_key(new byte[] {});
+
+ // when we have ^(NODE_LIMIT Integer)
+ if (statement.getChildCount() == 3)
+ {
+ Tree limitNode = statement.getChild(2);
+ int limitValue = Integer.parseInt(limitNode.getChild(0).getText());
+
+ if (limitValue == 0)
+ {
+ throw new IllegalArgumentException("LIMIT should be greater than zero.");
+ }
+
+ clause.setCount(limitValue);
+ }
+
+ try
+ {
+ ColumnParent parent = new ColumnParent(columnFamily);
+ slices = thriftClient.get_indexed_slices(parent, clause, predicate, consistencyLevel);
+ printSliceList(columnFamilyDef, slices);
+ }
+ catch (InvalidRequestException e)
+ {
+ throw new RuntimeException(e.getWhy());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ // Execute SET statement
+ private void executeSet(Tree statement)
+ throws TException, InvalidRequestException, UnavailableException, TimedOutException, NoSuchFieldException, InstantiationException, IllegalAccessException
+ {
+ if (!CliMain.isConnected() || !hasKeySpace())
+ return;
+
+ // ^(NODE_COLUMN_ACCESS <cf> <key> <column>)
+ Tree columnFamilySpec = statement.getChild(0);
+ Tree keyTree = columnFamilySpec.getChild(1); // could be a function or regular text
+
+ String columnFamily = CliCompiler.getColumnFamily(columnFamilySpec, keyspacesMap.get(keySpace).cf_defs);
+ CfDef cfDef = getCfDef(columnFamily);
+ int columnSpecCnt = CliCompiler.numColumnSpecifiers(columnFamilySpec);
+ String value = CliUtils.unescapeSQLString(statement.getChild(1).getText());
+ Tree valueTree = statement.getChild(1);
+
+ byte[] superColumnName = null;
+ ByteBuffer columnName;
+
+ // table.cf['key']
+ if (columnSpecCnt == 0)
+ {
+ sessionState.err.println("No column name specified, (type 'help;' or '?' for help on syntax).");
+ return;
+ }
+ // table.cf['key']['column'] = 'value'
+ else if (columnSpecCnt == 1)
+ {
+ // get the column name
+ if (cfDef.column_type.equals("Super"))
+ {
+ sessionState.out.println("Column family " + columnFamily + " may only contain SuperColumns");
+ return;
+ }
+ columnName = getColumnName(columnFamily, columnFamilySpec.getChild(2));
+ }
+ // table.cf['key']['super_column']['column'] = 'value'
+ else
+ {
+ assert (columnSpecCnt == 2) : "serious parsing error (this is a bug).";
+
+ superColumnName = getColumnName(columnFamily, columnFamilySpec.getChild(2)).array();
+ columnName = getSubColumnName(columnFamily, columnFamilySpec.getChild(3));
+ }
+
+ ByteBuffer columnValueInBytes;
+
+ switch (valueTree.getType())
+ {
+ case CliParser.FUNCTION_CALL:
+ columnValueInBytes = convertValueByFunction(valueTree, cfDef, columnName, true);
+ break;
+ default:
+ columnValueInBytes = columnValueAsBytes(columnName, columnFamily, value);
+ }
+
+ ColumnParent parent = new ColumnParent(columnFamily);
+ if(superColumnName != null)
+ parent.setSuper_column(superColumnName);
+
+ Column columnToInsert = new Column(columnName).setValue(columnValueInBytes).setTimestamp(FBUtilities.timestampMicros());
+
+ // children count = 3 mean that we have ttl in arguments
+ if (statement.getChildCount() == 3)
+ {
+ String ttl = statement.getChild(2).getText();
+
+ try
+ {
+ columnToInsert.setTtl(Integer.parseInt(ttl));
+ }
+ catch (NumberFormatException e)
+ {
+ sessionState.err.println(String.format("TTL '%s' is invalid, should be a positive integer.", ttl));
+ return;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ // do the insert
+ thriftClient.insert(getKeyAsBytes(columnFamily, keyTree), parent, columnToInsert, consistencyLevel);
+ sessionState.out.println("Value inserted.");
+ }
+
+ // Execute INCR statement
+ private void executeIncr(Tree statement, long multiplier)
+ throws TException, NotFoundException, InvalidRequestException, UnavailableException, TimedOutException, IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchFieldException
+ {
+ if (!CliMain.isConnected() || !hasKeySpace())
+ return;
+
+ Tree columnFamilySpec = statement.getChild(0);
+
+ String columnFamily = CliCompiler.getColumnFamily(columnFamilySpec, keyspacesMap.get(keySpace).cf_defs);
+ ByteBuffer key = getKeyAsBytes(columnFamily, columnFamilySpec.getChild(1));
+ int columnSpecCnt = CliCompiler.numColumnSpecifiers(columnFamilySpec);
+ CfDef cfDef = getCfDef(columnFamily);
+ boolean isSuper = cfDef.column_type.equals("Super");
+
+ byte[] superColumnName = null;
+ ByteBuffer columnName;
+
+ // table.cf['key']['column'] -- incr standard
+ if (columnSpecCnt == 1)
+ {
+ columnName = getColumnName(columnFamily, columnFamilySpec.getChild(2));
+ }
+ // table.cf['key']['column']['column'] -- incr super
+ else if (columnSpecCnt == 2)
+ {
+ superColumnName = getColumnName(columnFamily, columnFamilySpec.getChild(2)).array();
+ columnName = getSubColumnName(columnFamily, columnFamilySpec.getChild(3));
+ }
+ // The parser groks an arbitrary number of these so it is possible to get here.
+ else
+ {
+ sessionState.out.println("Invalid row, super column, or column specification.");
+ return;
+ }
+
+ ColumnParent parent = new ColumnParent(columnFamily);
+ if(superColumnName != null)
+ parent.setSuper_column(superColumnName);
+
+ long value = 1L;
+
+ // children count = 3 mean that we have by in arguments
+ if (statement.getChildCount() == 2)
+ {
+ String byValue = statement.getChild(1).getText();
+
+ try
+ {
+ value = Long.parseLong(byValue);
+ }
+ catch (NumberFormatException e)
+ {
+ sessionState.err.println(String.format("'%s' is an invalid value, should be an integer.", byValue));
+ return;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ CounterColumn columnToInsert = new CounterColumn(columnName, multiplier * value);
+
+ // do the insert
+ thriftClient.add(key, parent, columnToInsert, consistencyLevel);
+ sessionState.out.printf("Value %s%n", multiplier < 0 ? "decremented." : "incremented.");
+ }
+
+ private void executeShowClusterName() throws TException
+ {
+ if (!CliMain.isConnected())
+ return;
+
+ sessionState.out.println(thriftClient.describe_cluster_name());
+ }
+
+ /**
+ * Add a keyspace
+ * @param statement - a token tree representing current statement
+ */
+ private void executeAddKeySpace(Tree statement)
+ {
+
+ if (!CliMain.isConnected())
+ return;
+
+ // first value is the keyspace name, after that it is all key=value
+ String keyspaceName = statement.getChild(0).getText();
+ KsDef ksDef = new KsDef(keyspaceName, DEFAULT_PLACEMENT_STRATEGY, new LinkedList<CfDef>());
+
+ try
+ {
+ String mySchemaVersion = thriftClient.system_add_keyspace(updateKsDefAttributes(statement, ksDef));
+ sessionState.out.println(mySchemaVersion);
+ validateSchemaIsSettled(mySchemaVersion);
+
+ keyspacesMap.put(keyspaceName, thriftClient.describe_keyspace(keyspaceName));
+ }
+ catch (InvalidRequestException e)
+ {
+ throw new RuntimeException(e.getWhy());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
+
+ /**
+ * Add a column family
+ * @param statement - a token tree representing current statement
+ */
+ private void executeAddColumnFamily(Tree statement)
+ {
+ if (!CliMain.isConnected() || !hasKeySpace())
+ return;
+
+ // first value is the column family name, after that it is all key=value
+ CfDef cfDef = new CfDef(keySpace, statement.getChild(0).getText());
+
+ try
+ {
+ String mySchemaVersion = thriftClient.system_add_column_family(updateCfDefAttributes(statement, cfDef));
+ sessionState.out.println(mySchemaVersion);
+ validateSchemaIsSettled(mySchemaVersion);
+ keyspacesMap.put(keySpace, thriftClient.describe_keyspace(keySpace));
+ }
+ catch (InvalidRequestException e)
+ {
+ throw new RuntimeException(e.getWhy());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Update existing keyspace identified by name
+ * @param statement - tree represeting statement
+ */
+ private void executeUpdateKeySpace(Tree statement)
+ {
+ if (!CliMain.isConnected())
+ return;
+
+ try
+ {
+ String keyspaceName = CliCompiler.getKeySpace(statement, thriftClient.describe_keyspaces());
+
+ KsDef currentKsDef = getKSMetaData(keyspaceName);
+ KsDef updatedKsDef = updateKsDefAttributes(statement, currentKsDef);
+
+ String mySchemaVersion = thriftClient.system_update_keyspace(updatedKsDef);
+ sessionState.out.println(mySchemaVersion);
+ validateSchemaIsSettled(mySchemaVersion);
+ keyspacesMap.put(keyspaceName, thriftClient.describe_keyspace(keyspaceName));
+ }
+ catch (InvalidRequestException e)
+ {
+ throw new RuntimeException(e.getWhy());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Update existing column family identified by name
+ * @param statement - tree represeting statement
+ */
+ private void executeUpdateColumnFamily(Tree statement)
+ {
+ if (!CliMain.isConnected() || !hasKeySpace())
+ return;
+
+ String cfName = CliCompiler.getColumnFamily(statement, keyspacesMap.get(keySpace).cf_defs);
+
+ try
+ {
+ // request correct cfDef from the server
+ CfDef cfDef = getCfDef(thriftClient.describe_keyspace(this.keySpace), cfName);
+
+ if (cfDef == null)
+ throw new RuntimeException("Column Family " + cfName + " was not found in the current keyspace.");
+
+ String mySchemaVersion = thriftClient.system_update_column_family(updateCfDefAttributes(statement, cfDef));
+ sessionState.out.println(mySchemaVersion);
+ validateSchemaIsSettled(mySchemaVersion);
+ keyspacesMap.put(keySpace, thriftClient.describe_keyspace(keySpace));
+ }
+ catch (InvalidRequestException e)
+ {
+ throw new RuntimeException(e.getWhy());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Used to update keyspace definition attributes
+ * @param statement - ANTRL tree representing current statement
+ * @param ksDefToUpdate - keyspace definition to update
+ * @return ksDef - updated keyspace definition
+ */
+ private KsDef updateKsDefAttributes(Tree statement, KsDef ksDefToUpdate)
+ {
+ KsDef ksDef = new KsDef(ksDefToUpdate);
+ // server helpfully sets deprecated replication factor when it sends a KsDef back, for older clients.
+ // we need to unset that on the new KsDef we create to avoid being treated as a legacy client in return.
+ ksDef.unsetReplication_factor();
+
+ // removing all column definitions - thrift system_update_keyspace method requires that
+ ksDef.setCf_defs(new LinkedList<CfDef>());
+
+ for(int i = 1; i < statement.getChildCount(); i += 2)
+ {
+ String currentStatement = statement.getChild(i).getText().toUpperCase();
+ AddKeyspaceArgument mArgument = AddKeyspaceArgument.valueOf(currentStatement);
+ String mValue = statement.getChild(i + 1).getText();
+
+ switch(mArgument)
+ {
+ case PLACEMENT_STRATEGY:
+ ksDef.setStrategy_class(CliUtils.unescapeSQLString(mValue));
+ break;
+ case STRATEGY_OPTIONS:
+ ksDef.setStrategy_options(getStrategyOptionsFromTree(statement.getChild(i + 1)));
+ break;
+ case DURABLE_WRITES:
+ ksDef.setDurable_writes(Boolean.parseBoolean(mValue));
+ break;
+ default:
+ //must match one of the above or we'd throw an exception at the valueOf statement above.
+ assert(false);
+ }
+ }
+
+ // using default snitch options if strategy is NetworkTopologyStrategy and no options were set.
+ if (ksDef.getStrategy_class().contains(".NetworkTopologyStrategy"))
+ {
+ Map<String, String> currentStrategyOptions = ksDef.getStrategy_options();
+
+ // adding default data center from SimpleSnitch
+ if (currentStrategyOptions == null || currentStrategyOptions.isEmpty())
+ {
+ SimpleSnitch snitch = new SimpleSnitch();
+ Map<String, String> options = new HashMap<String, String>();
+
+ try
+ {
+ options.put(snitch.getDatacenter(InetAddress.getLocalHost()), "1");
+ }
+ catch (UnknownHostException e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ ksDef.setStrategy_options(options);
+ }
+ }
+
+ return ksDef;
+ }
+
+ /**
+ * Update column family definition attributes
+ * @param statement - ANTLR tree representing current statement
+ * @param cfDefToUpdate - column family definition to apply updates on
+ * @return cfDef - updated column family definition
+ */
+ private CfDef updateCfDefAttributes(Tree statement, CfDef cfDefToUpdate)
+ {
+ CfDef cfDef = new CfDef(cfDefToUpdate);
+
+ for (int i = 1; i < statement.getChildCount(); i += 2)
+ {
+ String currentArgument = statement.getChild(i).getText().toUpperCase();
+ ColumnFamilyArgument mArgument = ColumnFamilyArgument.valueOf(currentArgument);
+ String mValue = statement.getChild(i + 1).getText();
+
+ switch(mArgument)
+ {
+ case COLUMN_TYPE:
+ cfDef.setColumn_type(CliUtils.unescapeSQLString(mValue));
+ break;
+ case COMPARATOR:
+ cfDef.setComparator_type(CliUtils.unescapeSQLString(mValue));
+ break;
+ case SUBCOMPARATOR:
+ cfDef.setSubcomparator_type(CliUtils.unescapeSQLString(mValue));
+ break;
+ case COMMENT:
+ cfDef.setComment(CliUtils.unescapeSQLString(mValue));
+ break;
+ case ROWS_CACHED:
+ cfDef.setRow_cache_size(Double.parseDouble(mValue));
+ break;
+ case KEYS_CACHED:
+ cfDef.setKey_cache_size(Double.parseDouble(mValue));
+ break;
+ case READ_REPAIR_CHANCE:
+ double chance = Double.parseDouble(mValue);
+
+ if (chance < 0 || chance > 1)
+ throw new RuntimeException("Error: read_repair_chance must be between 0 and 1.");
+
+ cfDef.setRead_repair_chance(chance);
+ break;
+ case GC_GRACE:
+ cfDef.setGc_grace_seconds(Integer.parseInt(mValue));
+ break;
+ case COLUMN_METADATA:
+ Tree arrayOfMetaAttributes = statement.getChild(i + 1);
+ if (!arrayOfMetaAttributes.getText().equals("ARRAY"))
+ throw new RuntimeException("'column_metadata' format - [{ k:v, k:v, ..}, { ... }, ...]");
+ cfDef.setColumn_metadata(getCFColumnMetaFromTree(cfDef, arrayOfMetaAttributes));
+ break;
+ case MEMTABLE_OPERATIONS:
+ break;
+ case MEMTABLE_THROUGHPUT:
+ break;
+ case ROW_CACHE_SAVE_PERIOD:
+ cfDef.setRow_cache_save_period_in_seconds(Integer.parseInt(mValue));
+ break;
+ case KEY_CACHE_SAVE_PERIOD:
+ cfDef.setKey_cache_save_period_in_seconds(Integer.parseInt(mValue));
+ break;
+ case ROW_CACHE_KEYS_TO_SAVE:
+ cfDef.setRow_cache_keys_to_save(Integer.parseInt(mValue));
+ break;
+ case DEFAULT_VALIDATION_CLASS:
+ cfDef.setDefault_validation_class(CliUtils.unescapeSQLString(mValue));
+ break;
+ case MIN_COMPACTION_THRESHOLD:
+ cfDef.setMin_compaction_threshold(Integer.parseInt(mValue));
+ break;
+ case MAX_COMPACTION_THRESHOLD:
+ cfDef.setMax_compaction_threshold(Integer.parseInt(mValue));
+ break;
+ case REPLICATE_ON_WRITE:
+ cfDef.setReplicate_on_write(Boolean.parseBoolean(mValue));
+ break;
+ case ROW_CACHE_PROVIDER:
+ cfDef.setRow_cache_provider(CliUtils.unescapeSQLString(mValue));
+ break;
+ case KEY_VALIDATION_CLASS:
+ cfDef.setKey_validation_class(CliUtils.unescapeSQLString(mValue));
+ break;
+ case COMPACTION_STRATEGY:
+ cfDef.setCompaction_strategy(CliUtils.unescapeSQLString(mValue));
+ break;
+ case COMPACTION_STRATEGY_OPTIONS:
+ cfDef.setCompaction_strategy_options(getStrategyOptionsFromTree(statement.getChild(i+1)));
+ break;
+ case COMPRESSION_OPTIONS:
+ cfDef.setCompression_options(getStrategyOptionsFromTree(statement.getChild(i+1)));
+ break;
+ default:
+ //must match one of the above or we'd throw an exception at the valueOf statement above.
+ assert(false);
+
+ }
+ }
+
+ return cfDef;
+ }
+
+ /**
+ * Delete a keyspace
+ * @param statement - a token tree representing current statement
+ * @throws TException - exception
+ * @throws InvalidRequestException - exception
+ * @throws NotFoundException - exception
+ * @throws SchemaDisagreementException
+ */
+ private void executeDelKeySpace(Tree statement)
+ throws TException, InvalidRequestException, NotFoundException, SchemaDisagreementException
+ {
+ if (!CliMain.isConnected())
+ return;
+
+ String keyspaceName = CliCompiler.getKeySpace(statement, thriftClient.describe_keyspaces());
+ String version = thriftClient.system_drop_keyspace(keyspaceName);
+ sessionState.out.println(version);
+ validateSchemaIsSettled(version);
+
+ if (keyspaceName.equals(keySpace)) //we just deleted the keyspace we were authenticated too
+ keySpace = null;
+ }
+
+ /**
+ * Delete a column family
+ * @param statement - a token tree representing current statement
+ * @throws TException - exception
+ * @throws InvalidRequestException - exception
+ * @throws NotFoundException - exception
+ * @throws SchemaDisagreementException
+ */
+ private void executeDelColumnFamily(Tree statement)
+ throws TException, InvalidRequestException, NotFoundException, SchemaDisagreementException
+ {
+ if (!CliMain.isConnected() || !hasKeySpace())
+ return;
+
+ String cfName = CliCompiler.getColumnFamily(statement, keyspacesMap.get(keySpace).cf_defs);
+ String mySchemaVersion = thriftClient.system_drop_column_family(cfName);
+ sessionState.out.println(mySchemaVersion);
+ validateSchemaIsSettled(mySchemaVersion);
+ }
+
+ private void executeList(Tree statement)
+ throws TException, InvalidRequestException, NotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, UnavailableException, TimedOutException, CharacterCodingException
+ {
+ if (!CliMain.isConnected() || !hasKeySpace())
+ return;
+
+ // extract column family
+ String columnFamily = CliCompiler.getColumnFamily(statement, keyspacesMap.get(keySpace).cf_defs);
+
+ String rawStartKey = "";
+ String rawEndKey = "";
+ int limitCount = Integer.MAX_VALUE; // will reset to default later if it's not specified
+
+ // optional arguments: key range and limit
+ for (int i = 1; i < statement.getChildCount(); i++)
+ {
+ Tree child = statement.getChild(i);
+ if (child.getType() == CliParser.NODE_KEY_RANGE)
+ {
+ if (child.getChildCount() > 0)
+ {
+ rawStartKey = CliUtils.unescapeSQLString(child.getChild(0).getText());
+ if (child.getChildCount() > 1)
+ rawEndKey = CliUtils.unescapeSQLString(child.getChild(1).getText());
+ }
+ }
+ else
+ {
+ if (child.getChildCount() != 1)
+ {
+ sessionState.out.println("Invalid limit clause");
+ return;
+ }
+ limitCount = Integer.parseInt(child.getChild(0).getText());
+ if (limitCount <= 0)
+ {
+ sessionState.out.println("Invalid limit " + limitCount);
+ return;
+ }
+ }
+ }
+
+ if (limitCount == Integer.MAX_VALUE)
+ {
+ limitCount = 100;
+ sessionState.out.println("Using default limit of 100");
+ }
+
+ CfDef columnFamilyDef = getCfDef(columnFamily);
+
+ // read all columns and superColumns
+ SlicePredicate predicate = new SlicePredicate();
+ SliceRange sliceRange = new SliceRange();
+ sliceRange.setStart(new byte[0]).setFinish(new byte[0]);
+ sliceRange.setCount(Integer.MAX_VALUE);
+ predicate.setSlice_range(sliceRange);
+
+ // set the key range
+ KeyRange range = new KeyRange(limitCount);
+ AbstractType keyComparator = this.cfKeysComparators.get(columnFamily);
+ ByteBuffer startKey = rawStartKey.isEmpty() ? ByteBufferUtil.EMPTY_BYTE_BUFFER : getBytesAccordingToType(rawStartKey, keyComparator);
+ ByteBuffer endKey = rawEndKey.isEmpty() ? ByteBufferUtil.EMPTY_BYTE_BUFFER : getBytesAccordingToType(rawEndKey, keyComparator);
+ range.setStart_key(startKey).setEnd_key(endKey);
+
+ ColumnParent columnParent = new ColumnParent(columnFamily);
+ List<KeySlice> keySlices = thriftClient.get_range_slices(columnParent, predicate, range, consistencyLevel);
+ printSliceList(columnFamilyDef, keySlices);
+ }
+
+ // DROP INDEX ON <CF>.<COLUMN>
+ private void executeDropIndex(Tree statement) throws TException, SchemaDisagreementException, InvalidRequestException, NotFoundException
+ {
+ if (!CliMain.isConnected() || !hasKeySpace())
+ return;
+
+ // getColumnFamily will check if CF exists for us
+ String columnFamily = CliCompiler.getColumnFamily(statement, keyspacesMap.get(keySpace).cf_defs);
+ String rawColumName = CliUtils.unescapeSQLString(statement.getChild(1).getText());
+
+ CfDef cfDef = getCfDef(columnFamily);
+
+ ByteBuffer columnName = columnNameAsBytes(rawColumName, cfDef);
+
+ boolean foundColumn = false;
+
+ for (ColumnDef column : cfDef.getColumn_metadata())
+ {
+ if (column.name.equals(columnName))
+ {
+ foundColumn = true;
+
+ if (column.getIndex_type() == null)
+ throw new RuntimeException(String.format("Column '%s' does not have an index.", rawColumName));
+
+ column.setIndex_name(null);
+ column.setIndex_type(null);
+ }
+ }
+
+ if (!foundColumn)
+ throw new RuntimeException(String.format("Column '%s' definition was not found in ColumnFamily '%s'.",
+ rawColumName,
+ columnFamily));
+
+ String mySchemaVersion = thriftClient.system_update_column_family(cfDef);
+ sessionState.out.println(mySchemaVersion);
+ validateSchemaIsSettled(mySchemaVersion);
+ keyspacesMap.put(keySpace, thriftClient.describe_keyspace(keySpace));
+ }
+
+ // TRUNCATE <columnFamily>
+ private void executeTruncate(String columnFamily) throws TException, InvalidRequestException, UnavailableException
+ {
+ if (!CliMain.isConnected() || !hasKeySpace())
+ return;
+
+ // getting CfDef, it will fail if there is no such column family in current keySpace.
+ CfDef cfDef = getCfDef(CliCompiler.getColumnFamily(columnFamily, keyspacesMap.get(keySpace).cf_defs));
+
+ thriftClient.truncate(cfDef.getName());
+ sessionState.out.println(columnFamily + " truncated.");
+ }
+
+ /**
+ * Command: CONSISTENCYLEVEL AS (ONE | QUORUM ...)
+ * Tree: ^(NODE_CONSISTENCY_LEVEL AS (ONE | QUORUM ...))
+ * @param statement - tree representing current statement
+ */
+ private void executeConsistencyLevelStatement(Tree statement)
+ {
+ if (!CliMain.isConnected())
+ return;
+
+ String userSuppliedLevel = statement.getChild(0).getText().toUpperCase();
+
+ try
+ {
+ consistencyLevel = ConsistencyLevel.valueOf(userSuppliedLevel);
+ }
+ catch (IllegalArgumentException e)
+ {
+ String elements = "ONE, TWO, THREE, QUORUM, ALL, LOCAL_QUORUM, EACH_QUORUM, ANY";
+ sessionState.out.println(String.format("'%s' is invalid. Available: %s", userSuppliedLevel, elements));
+ return;
+ }
+
+ sessionState.out.println(String.format("Consistency level is set to '%s'.", consistencyLevel));
+ }
+
+ /**
+ * Command: ASSUME <columnFamily> (VALIDATOR | COMPARATOR | KEYS | SUB_COMPARATOR) AS <type>
+ * Tree: ^(NODE_ASSUME <columnFamily> (VALIDATOR | COMPARATOR | KEYS | SUB_COMPARATOR) <type>))
+ * @param statement - tree representing current statement
+ */
+ private void executeAssumeStatement(Tree statement)
+ {
+ if (!CliMain.isConnected() || !hasKeySpace())
+ return;
+
+ String cfName = CliCompiler.getColumnFamily(statement, keyspacesMap.get(keySpace).cf_defs);
+ CfDef columnFamily = getCfDef(cfName);
+
+ // VALIDATOR | COMPARATOR | KEYS | SUB_COMPARATOR
+ String assumptionElement = statement.getChild(1).getText().toUpperCase();
+ // used to store in this.cfKeysComparator
+ AbstractType comparator;
+
+ // Could be UTF8Type, IntegerType, LexicalUUIDType etc.
+ String defaultType = statement.getChild(2).getText();
+
+ try
+ {
+ comparator = Function.valueOf(defaultType.toUpperCase()).getValidator();
+ }
+ catch (Exception e)
+ {
+ String functions = Function.getFunctionNames();
+ sessionState.out.println("Type '" + defaultType + "' was not found. Available: " + functions);
+ return;
+ }
+
+ // making string representation look property e.g. o.a.c.db.marshal.UTF8Type
+ defaultType = comparator.getClass().getName();
+
+ if (assumptionElement.equals("COMPARATOR"))
+ {
+ columnFamily.setComparator_type(defaultType);
+ }
+ else if (assumptionElement.equals("SUB_COMPARATOR"))
+ {
+ columnFamily.setSubcomparator_type(defaultType);
+ }
+ else if (assumptionElement.equals("VALIDATOR"))
+ {
+ columnFamily.setDefault_validation_class(defaultType);
+ }
+ else if (assumptionElement.equals("KEYS"))
+ {
+ this.cfKeysComparators.put(columnFamily.getName(), comparator);
+ }
+ else
+ {
+ String elements = "VALIDATOR, COMPARATOR, KEYS, SUB_COMPARATOR.";
+ sessionState.out.println(String.format("'%s' is invalid. Available: %s", assumptionElement, elements));
+ return;
+ }
+
+ sessionState.out.println(String.format("Assumption for column family '%s' added successfully.", columnFamily.getName()));
+ }
+
+ // SHOW API VERSION
+ private void executeShowVersion() throws TException
+ {
+ if (!CliMain.isConnected())
+ return;
+
+ sessionState.out.println(thriftClient.describe_version());
+ }
+
+ // SHOW KEYSPACES
+ private void executeShowKeySpaces() throws TException, InvalidRequestException
+ {
+ if (!CliMain.isConnected())
+ return;
+
+ List<KsDef> keySpaces = thriftClient.describe_keyspaces();
+
+ Collections.sort(keySpaces, new KsDefNamesComparator());
+ for (KsDef keySpace : keySpaces)
+ {
+ describeKeySpace(keySpace.name, keySpace);
+ }
+ }
+
+ // SHOW SCHEMA
+ private void executeShowSchema(Tree statement) throws TException, InvalidRequestException
+ {
+ if (!CliMain.isConnected())
+ return;
+
+ final List<KsDef> keyspaces = thriftClient.describe_keyspaces();
+ Collections.sort(keyspaces, new KsDefNamesComparator());
+ final String keyspaceName = (statement.getChildCount() == 0)
+ ? keySpace
+ : CliCompiler.getKeySpace(statement, keyspaces);
+
+ Iterator<KsDef> ksIter;
+ if (keyspaceName != null)
+ ksIter = Collections2.filter(keyspaces, new Predicate<KsDef>()
+ {
+ public boolean apply(KsDef ksDef)
+ {
+ return keyspaceName.equals(ksDef.name);
+ }
+ }).iterator();
+ else
+ ksIter = keyspaces.iterator();
+
+
+ final StringBuilder sb = new StringBuilder();
+ while (ksIter.hasNext())
+ showKeyspace(sb, ksIter.next());
+
+ sessionState.out.printf(sb.toString());
+ }
+
+ /**
+ * Creates a CLI script to create the Keyspace it's Column Families
+ * @param sb StringBuilder to write to.
+ * @param ksDef KsDef to create the cli script for.
+ */
+ private void showKeyspace(StringBuilder sb, KsDef ksDef)
+ {
+ sb.append("create keyspace " + ksDef.name);
+
+ writeAttr(sb, true, "placement_strategy", normaliseType(ksDef.strategy_class, "org.apache.cassandra.locator"));
+
+ if (ksDef.strategy_options != null && !ksDef.strategy_options.isEmpty())
+ {
+ final StringBuilder opts = new StringBuilder();
+ opts.append("[{");
+ String prefix = "";
+ for (Map.Entry<String, String> opt : ksDef.strategy_options.entrySet())
+ {
+ opts.append(prefix + CliUtils.escapeSQLString(opt.getKey()) + " : " + CliUtils.escapeSQLString(opt.getValue()));
+ prefix = ", ";
+ }
+ opts.append("}]");
+ writeAttrRaw(sb, false, "strategy_options", opts.toString());
+ }
+ sb.append(";" + NEWLINE);
+ sb.append(NEWLINE);
+
+ sb.append("use " + ksDef.name + ";");
+ sb.append(NEWLINE);
+ sb.append(NEWLINE);
+
+ Collections.sort(ksDef.cf_defs, new CfDefNamesComparator());
+ for (CfDef cfDef : ksDef.cf_defs)
+ showColumnFamily(sb, cfDef);
+ sb.append(NEWLINE);
+ sb.append(NEWLINE);
+ }
+
+ /**
+ * Creates a CLI script for the CfDef including meta data to the supplied StringBuilder.
+ * @param sb
+ * @param cfDef
+ */
+ private void showColumnFamily(StringBuilder sb, CfDef cfDef)
+ {
+ sb.append("create column family " + CliUtils.escapeSQLString(cfDef.name));
+
+ writeAttr(sb, true, "column_type", cfDef.column_type);
+ writeAttr(sb, false, "comparator", normaliseType(cfDef.comparator_type, "org.apache.cassandra.db.marshal"));
+ if (cfDef.column_type == "Super")
+ writeAttr(sb, false, "subcomparator", normaliseType(cfDef.subcomparator_type, "org.apache.cassandra.db.marshal"));
+ if (!StringUtils.isEmpty(cfDef.default_validation_class))
+ writeAttr(sb, false, "default_validation_class",
+ normaliseType(cfDef.default_validation_class, "org.apache.cassandra.db.marshal"));
+ writeAttr(sb, false, "key_validation_class",
+ normaliseType(cfDef.key_validation_class, "org.apache.cassandra.db.marshal"));
+ writeAttr(sb, false, "rows_cached", cfDef.row_cache_size);
+ writeAttr(sb, false, "row_cache_save_period", cfDef.row_cache_save_period_in_seconds);
+ writeAttr(sb, false, "keys_cached", cfDef.key_cache_size);
+ writeAttr(sb, false, "key_cache_save_period", cfDef.key_cache_save_period_in_seconds);
+ writeAttr(sb, false, "read_repair_chance", cfDef.read_repair_chance);
+ writeAttr(sb, false, "gc_grace", cfDef.gc_grace_seconds);
+ writeAttr(sb, false, "min_compaction_threshold", cfDef.min_compaction_threshold);
+ writeAttr(sb, false, "max_compaction_threshold", cfDef.max_compaction_threshold);
+ writeAttr(sb, false, "replicate_on_write", cfDef.replicate_on_write);
+ writeAttr(sb, false, "row_cache_provider", normaliseType(cfDef.row_cache_provider, "org.apache.cassandra.cache"));
+
+ if (!StringUtils.isEmpty(cfDef.comment))
+ writeAttr(sb, false, "comment", cfDef.comment);
+
+ if (!cfDef.column_metadata.isEmpty())
+ {
+ StringBuilder colSb = new StringBuilder();
+ colSb.append("[");
+ boolean first = true;
+ for (ColumnDef colDef : cfDef.column_metadata)
+ {
+ if (!first)
+ colSb.append(",");
+ first = false;
+ showColumnMeta(colSb, cfDef, colDef);
+ }
+ colSb.append("]");
+ writeAttrRaw(sb, false, "column_metadata", colSb.toString());
+ }
+ sb.append(";");
+ sb.append(NEWLINE);
+ sb.append(NEWLINE);
+ }
+
+ /**
+ * Writes the supplied ColumnDef to the StringBuilder as a cli script.
+ * @param sb
+ * @param cfDef
+ * @param colDef
+ */
+ private void showColumnMeta(StringBuilder sb, CfDef cfDef, ColumnDef colDef)
+ {
+ sb.append(NEWLINE + TAB + TAB + "{");
+
+ final AbstractType comparator = getFormatType((cfDef.column_type == "Super")
+ ? cfDef.subcomparator_type
+ : cfDef.comparator_type);
+ sb.append("column_name : '" + CliUtils.escapeSQLString(comparator.getString(colDef.name)) + "'," + NEWLINE);
+ String validationClass = normaliseType(colDef.validation_class, "org.apache.cassandra.db.marshal");
+ sb.append(TAB + TAB + "validation_class : " + CliUtils.escapeSQLString(validationClass));
+ if (colDef.isSetIndex_name())
+ {
+ sb.append("," + NEWLINE);
+ sb.append(TAB + TAB + "index_name : '" + CliUtils.escapeSQLString(colDef.index_name) + "'," + NEWLINE);
+ sb.append(TAB + TAB + "index_type : " + CliUtils.escapeSQLString(Integer.toString(colDef.index_type.getValue())) + "," + NEWLINE);
+
+ if (colDef.index_options != null)
+ {
+ sb.append(TAB + TAB + "index_options : {"+NEWLINE);
+ for (Map.Entry<String, String> entry : colDef.index_options.entrySet())
+ {
+ sb.append(TAB + TAB + TAB + CliUtils.escapeSQLString(entry.getKey()) + ": '" + CliUtils.escapeSQLString(entry.getValue()) + "'," + NEWLINE);
+ }
+ sb.append("}");
+ }
+ }
+ sb.append("}");
+ }
+
+ private String normaliseType(String path, String expectedPackage)
+ {
+ if (path.startsWith(expectedPackage))
+ return path.substring(expectedPackage.length() + 1);
+
+ return path;
+ }
+
+ private void writeAttr(StringBuilder sb, boolean first, String name, Boolean value)
+ {
+ writeAttrRaw(sb, first, name, value.toString());
+ }
+ private void writeAttr(StringBuilder sb, boolean first, String name, Number value)
+ {
+ writeAttrRaw(sb, first, name, value.toString());
+ }
+
+ private void writeAttr(StringBuilder sb, boolean first, String name, String value)
+ {
+ writeAttrRaw(sb, first, name, "'" + CliUtils.escapeSQLString(value) + "'");
+ }
+
+ private void writeAttrRaw(StringBuilder sb, boolean first, String name, String value)
+ {
+ sb.append(NEWLINE + TAB);
+ sb.append(first ? "with " : "and ");
+ sb.append(name + " = ");
+ sb.append(value);
+ }
+ /**
+ * Returns true if this.keySpace is set, false otherwise
+ * @return boolean
+ */
+ private boolean hasKeySpace()
+ {
+ if (keySpace == null)
+ {
+ sessionState.out.println("Not authenticated to a working keyspace.");
+ return false;
+ }
+
+ return true;
+ }
+
+ public String getKeySpace()
+ {
+ return keySpace == null ? "unknown" : keySpace;
+ }
+
+ public void setKeySpace(String keySpace) throws NotFoundException, InvalidRequestException, TException
+ {
+ this.keySpace = keySpace;
+ // We do nothing with the return value, but it hits a cache and the tab-completer.
+ getKSMetaData(keySpace);
+ }
+
+ public String getUsername()
+ {
+ return username == null ? "default" : username;
+ }
+
+ public void setUsername(String username)
+ {
+ this.username = username;
+ }
+
+ // USE <keyspace_name>
+ private void executeUseKeySpace(Tree statement) throws TException
+ {
+ if (!CliMain.isConnected())
+ return;
+
+ int childCount = statement.getChildCount();
+ String keySpaceName, username = null, password = null;
+
+ // Get keyspace name
+ keySpaceName = statement.getChild(0).getText();
+
+ if (childCount == 3) {
+ username = statement.getChild(1).getText();
+ password = statement.getChild(2).getText();
+ }
+
+ if (keySpaceName == null)
+ {
+ sessionState.out.println("Keyspace argument required");
+ return;
+ }
+
+ try
+ {
+ AuthenticationRequest authRequest;
+ Map<String, String> credentials = new HashMap<String, String>();
+
+ keySpaceName = CliCompiler.getKeySpace(keySpaceName, thriftClient.describe_keyspaces());
+
+ thriftClient.set_keyspace(keySpaceName);
+
+ if (username != null && password != null)
+ {
+ /* remove quotes */
+ password = password.replace("\'", "");
+ credentials.put(SimpleAuthenticator.USERNAME_KEY, username);
+ credentials.put(SimpleAuthenticator.PASSWORD_KEY, password);
+ authRequest = new AuthenticationRequest(credentials);
+ thriftClient.login(authRequest);
+ }
+
+ keySpace = keySpaceName;
+ this.username = username != null ? username : "default";
+
+ CliMain.updateCompletor(CliUtils.getCfNamesByKeySpace(getKSMetaData(keySpace)));
+ sessionState.out.println("Authenticated to keyspace: " + keySpace);
+ }
+ catch (AuthenticationException e)
+ {
+ sessionState.err.println("Exception during authentication to the cassandra node: " +
+ "verify keyspace exists, and you are using correct credentials.");
+ }
+ catch (AuthorizationException e)
+ {
+ sessionState.err.println("You are not authorized to use keyspace: " + keySpaceName);
+ }
+ catch (InvalidRequestException e)
+ {
+ sessionState.err.println(keySpaceName + " does not exist.");
+ }
+ catch (NotFoundException e)
+ {
+ sessionState.err.println(keySpaceName + " does not exist.");
+ }
+ catch (TException e)
+ {
+ if (sessionState.debug)
+ e.printStackTrace();
+
+ sessionState.err.println("Login failure. Did you specify 'keyspace', 'username' and 'password'?");
+ }
+ }
+
+ private void describeKeySpace(String keySpaceName, KsDef metadata) throws TException
+ {
+ NodeProbe probe = sessionState.getNodeProbe();
+
+ // getting compaction manager MBean to displaying index building information
+ CompactionManagerMBean compactionManagerMBean = (probe == null) ? null : probe.getCompactionManagerProxy();
+
+ // Describe and display
+ sessionState.out.println("Keyspace: " + keySpaceName + ":");
+ try
+ {
+ KsDef ks_def;
+ ks_def = metadata == null ? thriftClient.describe_keyspace(keySpaceName) : metadata;
+ sessionState.out.println(" Replication Strategy: " + ks_def.strategy_class);
+
+ sessionState.out.println(" Durable Writes: " + ks_def.durable_writes);
+
+ Map<String, String> options = ks_def.strategy_options;
+ sessionState.out.println(" Options: [" + ((options == null) ? "" : FBUtilities.toString(options)) + "]");
+
+ sessionState.out.println(" Column Families:");
+
+ Collections.sort(ks_def.cf_defs, new CfDefNamesComparator());
+
+ for (CfDef cf_def : ks_def.cf_defs)
+ describeColumnFamily(ks_def, cf_def, probe);
+
+ // compaction manager information
+ if (compactionManagerMBean != null)
+ {
+ for (CompactionInfo info : compactionManagerMBean.getCompactions())
+ {
+ // if ongoing compaction type is index build
+ if (info.getTaskType() != OperationType.INDEX_BUILD)
+ continue;
+ sessionState.out.printf("%nCurrently building index %s, completed %d of %d bytes.%n",
+ info.getColumnFamily(),
+ info.getBytesComplete(),
+ info.getTotalBytes());
+ }
+ }
+
+ // closing JMX connection
+ if (probe != null)
+ probe.close();
+ }
+ catch (InvalidRequestException e)
+ {
+ sessionState.out.println("Invalid request: " + e);
+ }
+ catch (NotFoundException e)
+ {
+ sessionState.out.println("Keyspace " + keySpaceName + " could not be found.");
+ }
+ catch (IOException e)
+ {
+ sessionState.out.println("Error while closing JMX connection: " + e.getMessage());
+ }
+ }
+
+ private void describeColumnFamily(KsDef ks_def, CfDef cf_def, NodeProbe probe) throws TException
+ {
+ // fetching bean for current column family store
+ ColumnFamilyStoreMBean cfMBean = (probe == null) ? null : probe.getCfsProxy(ks_def.getName(), cf_def.getName());
+
+ boolean isSuper = cf_def.column_type.equals("Super");
+ sessionState.out.printf(" ColumnFamily: %s%s%n", cf_def.name, isSuper ? " (Super)" : "");
+
+ if (cf_def.comment != null && !cf_def.comment.isEmpty())
+ sessionState.out.printf(" \"%s\"%n", cf_def.comment);
+
+ if (cf_def.key_validation_class != null)
+ sessionState.out.printf(" Key Validation Class: %s%n", cf_def.key_validation_class);
+
+ if (cf_def.default_validation_class != null)
+ sessionState.out.printf(" Default column value validator: %s%n", cf_def.default_validation_class);
+
+ sessionState.out.printf(" Columns sorted by: %s%s%n", cf_def.comparator_type, cf_def.column_type.equals("Super") ? "/" + cf_def.subcomparator_type : "");
+ sessionState.out.printf(" Row cache size / save period in seconds / keys to save : %s/%s/%s%n",
+ cf_def.row_cache_size, cf_def.row_cache_save_period_in_seconds,
+ cf_def.row_cache_keys_to_save == Integer.MAX_VALUE ? "all" : cf_def.row_cache_keys_to_save);
+ sessionState.out.printf(" Key cache size / save period in seconds: %s/%s%n", cf_def.key_cache_size, cf_def.key_cache_save_period_in_seconds);
+ sessionState.out.printf(" GC grace seconds: %s%n", cf_def.gc_grace_seconds);
+ sessionState.out.printf(" Compaction min/max thresholds: %s/%s%n", cf_def.min_compaction_threshold, cf_def.max_compaction_threshold);
+ sessionState.out.printf(" Read repair chance: %s%n", cf_def.read_repair_chance);
+ sessionState.out.printf(" Replicate on write: %s%n", cf_def.replicate_on_write);
+
+ // if we have connection to the cfMBean established
+ if (cfMBean != null)
+ sessionState.out.printf(" Built indexes: %s%n", cfMBean.getBuiltIndexes());
+
+ if (cf_def.getColumn_metadataSize() != 0)
+ {
+ String leftSpace = " ";
+ String columnLeftSpace = leftSpace + " ";
+
+ String compareWith = isSuper ? cf_def.subcomparator_type
+ : cf_def.comparator_type;
+ AbstractType columnNameValidator = getFormatType(compareWith);
+
+ sessionState.out.println(leftSpace + "Column Metadata:");
+ for (ColumnDef columnDef : cf_def.getColumn_metadata())
+ {
+ String columnName = columnNameValidator.getString(columnDef.name);
+ if (columnNameValidator instanceof BytesType)
+ {
+ try
+ {
+ String columnString = UTF8Type.instance.getString(columnDef.name);
+ columnName = columnString + " (" + columnName + ")";
+ }
+ catch (MarshalException e)
+ {
+ // guess it wasn't a utf8 column name after all
+ }
+ }
+
+ sessionState.out.println(leftSpace + " Column Name: " + columnName);
+ sessionState.out.println(columnLeftSpace + "Validation Class: " + columnDef.getValidation_class());
+
+ if (columnDef.isSetIndex_name())
+ sessionState.out.println(columnLeftSpace + "Index Name: " + columnDef.getIndex_name());
+
+ if (columnDef.isSetIndex_type())
+ sessionState.out.println(columnLeftSpace + "Index Type: " + columnDef.getIndex_type().name());
+ }
+ }
+
+ sessionState.out.printf(" Compaction Strategy: %s%n", cf_def.compaction_strategy);
+
+ if (!cf_def.compaction_strategy_options.isEmpty())
+ {
+ sessionState.out.println(" Compaction Strategy Options:");
+ for (Map.Entry<String, String> e : cf_def.compaction_strategy_options.entrySet())
+ sessionState.out.printf(" %s: %s%n", e.getKey(), e.getValue());
+ }
+
+ if (cf_def.compression_options != null && !cf_def.compression_options.isEmpty())
+ {
+ sessionState.out.println(" Compression Options:");
+ for (Map.Entry<String, String> e : cf_def.compression_options.entrySet())
+ sessionState.out.printf(" %s: %s%n", e.getKey(), e.getValue());
+ }
+ }
+
+ // DESCRIBE KEYSPACE (<keyspace> | <column_family>)?
+ private void executeDescribe(Tree statement) throws TException, InvalidRequestException
+ {
+ if (!CliMain.isConnected())
+ return;
+
+ int argCount = statement.getChildCount();
+
+ KsDef currentKeySpace = keyspacesMap.get(keySpace);
+
+ if (argCount > 1) // in case somebody changes Cli grammar
+ throw new RuntimeException("`describe` command take maximum one argument. See `help describe;`");
+
+ if (argCount == 0)
+ {
+ if (currentKeySpace != null)
+ {
+ describeKeySpace(currentKeySpace.name, null);
+ return;
+ }
+
+ sessionState.out.println("Authenticate to a Keyspace, before using `describe` or `describe <column_family>`");
+ }
+ else if (argCount == 1)
+ {
+ // name of the keyspace or ColumnFamily
+ String entityName = statement.getChild(0).getText();
+
+ KsDef inputKsDef = CliUtils.getKeySpaceDef(entityName, thriftClient.describe_keyspaces());
+
+ if (inputKsDef == null && currentKeySpace == null)
+ throw new RuntimeException(String.format("Keyspace with name '%s' wasn't found, " +
+ "to lookup ColumnFamily with that name, please, authorize to one " +
+ "of the keyspaces first.", entityName));
+
+ CfDef inputCfDef = (inputKsDef == null)
+ ? getCfDef(currentKeySpace, entityName)
+ : null; // no need to lookup CfDef if we know that it was keyspace
+
+ if (inputKsDef != null)
+ {
+ describeKeySpace(inputKsDef.name, inputKsDef);
+ }
+ else if (inputCfDef != null)
+ {
+ NodeProbe probe = sessionState.getNodeProbe();
+
+ try
+ {
+ describeColumnFamily(currentKeySpace, inputCfDef, probe);
+
+ if (probe != null)
+ probe.close();
+ }
+ catch (IOException e)
+ {
+ sessionState.out.println("Error while closing JMX connection: " + e.getMessage());
+ }
+ }
+ else
+ {
+ sessionState.out.println("Sorry, no Keyspace nor ColumnFamily was found with name: " + entityName);
+ }
+ }
+ }
+
+ // ^(NODE_DESCRIBE_CLUSTER) or describe: schema_versions, partitioner, snitch
+ private void executeDescribeCluster()
+ {
+ if (!CliMain.isConnected())
+ return;
+
+ sessionState.out.println("Cluster Information:");
+ try
+ {
+ sessionState.out.println(" Snitch: " + thriftClient.describe_snitch());
+ sessionState.out.println(" Partitioner: " + thriftClient.describe_partitioner());
+
+ sessionState.out.println(" Schema versions: ");
+ Map<String,List<String>> versions = thriftClient.describe_schema_versions();
+
+ for (String version : versions.keySet())
+ {
+ sessionState.out.println("\t" + version + ": " + versions.get(version));
+ }
+ }
+ catch (Exception e)
+ {
+ String message = (e instanceof InvalidRequestException) ? ((InvalidRequestException) e).getWhy() : e.getMessage();
+ sessionState.err.println("Error retrieving data: " + message);
+ }
+ }
+
+ // process a statement of the form: connect hostname/port
+ private void executeConnect(Tree statement)
+ {
+ Tree idList = statement.getChild(0);
+ int portNumber = Integer.parseInt(statement.getChild(1).getText());
+
+ StringBuilder hostName = new StringBuilder();
+ int idCount = idList.getChildCount();
+ for (int idx = 0; idx < idCount; idx++)
+ {
+ hostName.append(idList.getChild(idx).getText());
+ }
+
+ // disconnect current connection, if any.
+ // This is a no-op, if you aren't currently connected.
+ CliMain.disconnect();
+
+ // now, connect to the newly specified host name and port
+ sessionState.hostName = hostName.toString();
+ sessionState.thriftPort = portNumber;
+
+ // if we have user name and password
+ if (statement.getChildCount() == 4)
+ {
+ sessionState.username = statement.getChild(2).getText();
+ sessionState.password = CliUtils.unescapeSQLString(statement.getChild(3).getText());
+ }
+
+ CliMain.connect(sessionState.hostName, sessionState.thriftPort);
+ }
+
+ /**
+ * To get Column Family Definition object from specified keyspace
+ * @param keySpaceName key space name to search for specific column family
+ * @param columnFamilyName column family name
+ * @return CfDef - Column family definition object
+ */
+ private CfDef getCfDef(String keySpaceName, String columnFamilyName)
+ {
+ KsDef keySpaceDefinition = keyspacesMap.get(keySpaceName);
+
+ for (CfDef columnFamilyDef : keySpaceDefinition.cf_defs)
+ {
+ if (columnFamilyDef.name.equals(columnFamilyName))
+ {
+ return columnFamilyDef;
+ }
+ }
+
+ throw new RuntimeException("No such column family: " + columnFamilyName);
+ }
+
+ /**
+ * Uses getCfDef(keySpaceName, columnFamilyName) with current keyspace
+ * @param columnFamilyName column family name to find in specified keyspace
+ * @return CfDef - Column family definition object
+ */
+ private CfDef getCfDef(String columnFamilyName)
+ {
+ return getCfDef(this.keySpace, columnFamilyName);
+ }
+
+ private CfDef getCfDef(KsDef keyspace, String columnFamilyName)
+ {
+ for (CfDef cfDef : keyspace.cf_defs)
+ {
+ if (cfDef.name.equals(columnFamilyName))
+ return cfDef;
+ }
+
+ return null;
+ }
+
+ /**
+ * Used to parse meta tree and compile meta attributes into List<ColumnDef>
+ * @param cfDef - column family definition
+ * @param meta (Tree representing Array of the hashes with metadata attributes)
+ * @return List<ColumnDef> List of the ColumnDef's
+ *
+ * meta is in following format - ^(ARRAY ^(HASH ^(PAIR .. ..) ^(PAIR .. ..)) ^(HASH ...))
+ */
+ private List<ColumnDef> getCFColumnMetaFromTree(CfDef cfDef, Tree meta)
+ {
+ // this list will be returned
+ List<ColumnDef> columnDefinitions = new ArrayList<ColumnDef>();
+
+ // each child node is a ^(HASH ...)
+ for (int i = 0; i < meta.getChildCount(); i++)
+ {
+ Tree metaHash = meta.getChild(i);
+
+ ColumnDef columnDefinition = new ColumnDef();
+
+ // each child node is ^(PAIR $key $value)
+ for (int j = 0; j < metaHash.getChildCount(); j++)
+ {
+ Tree metaPair = metaHash.getChild(j);
+
+ // current $key
+ String metaKey = CliUtils.unescapeSQLString(metaPair.getChild(0).getText());
+ // current $value
+ String metaVal = CliUtils.unescapeSQLString(metaPair.getChild(1).getText());
+
+ if (metaKey.equals("column_name"))
+ {
+ if (cfDef.column_type.equals("Super"))
+ columnDefinition.setName(subColumnNameAsByteArray(metaVal, cfDef));
+ else
+ columnDefinition.setName(columnNameAsByteArray(metaVal, cfDef));
+ }
+ else if (metaKey.equals("validation_class"))
+ {
+ columnDefinition.setValidation_class(metaVal);
+ }
+ else if (metaKey.equals("index_type"))
+ {
+ columnDefinition.setIndex_type(getIndexTypeFromString(metaVal));
+ }
+ else if (metaKey.equals("index_options"))
+ {
+ columnDefinition.setIndex_options(getStrategyOptionsFromTree(metaPair.getChild(1)));
+ }
+ else if (metaKey.equals("index_name"))
+ {
+ columnDefinition.setIndex_name(metaVal);
+ }
+ }
+
+ // validating columnDef structure, 'name' and 'validation_class' must be set
+ try
+ {
+ columnDefinition.validate();
+ }
+ catch (TException e)
+ {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+
+ columnDefinitions.add(columnDefinition);
+ }
+
+ return columnDefinitions;
+ }
+
+ /**
+ * Getting IndexType object from indexType string
+ * @param indexTypeAsString - string return by parser corresponding to IndexType
+ * @return IndexType - an IndexType object
+ */
[... 573 lines stripped ...]