/**
* 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 org.apache.cassandra.auth.SimpleAuthenticator;
import org.apache.cassandra.db.ClockType;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.BytesType;
import org.apache.cassandra.thrift.*;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.thrift.*;
import org.antlr.runtime.tree.*;
import java.util.*;
import java.io.UnsupportedEncodingException;
import org.apache.commons.lang.ArrayUtils;
// Cli Client Side Library
public class CliClient
{
/*
* the <i>add column family</i> command requires a list of arguments,
* this enum defines which arguments are valid.
*/
private enum AddColumnFamilyArgument {
COLUMN_TYPE,
CLOCK_TYPE,
COMPARATOR,
SUBCOMPARATOR,
RECONCILER,
COMMENT,
ROWS_CACHED,
PRELOAD_ROW_CACHE,
KEY_CACHE_SIZE,
READ_REPAIR_CHANCE,
GC_GRACE_SECONDS
}
/*
* the <i>add keyspace</i> command requires a list of arguments,
* this enum defines which arguments are valid
*/
private enum AddKeyspaceArgument {
REPLICATION_FACTOR,
PLACEMENT_STRATEGY
}
private Cassandra.Client thriftClient_ = null;
private CliSessionState css_ = null;
private String keySpace = null;
private String username = null;
private Map<String, KsDef> keyspacesMap = new HashMap<String, KsDef>();
public CliClient(CliSessionState css, Cassandra.Client thriftClient)
{
css_ = css;
thriftClient_ = thriftClient;
}
// Execute a CLI Statement
public void executeCLIStmt(String stmt) throws TException, NotFoundException, InvalidRequestException, UnavailableException, TimedOutException, IllegalAccessException, ClassNotFoundException, InstantiationException, NoSuchFieldException
{
CommonTree ast = null;
ast = CliCompiler.compileQuery(stmt);
try
{
switch (ast.getType()) {
case CliParser.NODE_EXIT:
cleanupAndExit();
break;
case CliParser.NODE_THRIFT_GET:
executeGet(ast);
break;
case CliParser.NODE_HELP:
printCmdHelp(ast);
break;
case CliParser.NODE_THRIFT_SET:
executeSet(ast);
break;
case CliParser.NODE_THRIFT_DEL:
executeDelete(ast);
break;
case CliParser.NODE_THRIFT_COUNT:
executeCount(ast);
break;
case CliParser.NODE_ADD_COLUMN_FAMILY:
executeAddColumnFamily(ast);
break;
case CliParser.NODE_ADD_KEYSPACE:
executeAddKeyspace(ast);
break;
case CliParser.NODE_DEL_COLUMN_FAMILY:
executeDelColumnFamily(ast);
break;
case CliParser.NODE_DEL_KEYSPACE:
executeDelKeyspace(ast);
break;
case CliParser.NODE_RENAME_COLUMN_FAMILY:
executeRenameColumnFamily(ast);
break;
case CliParser.NODE_RENAME_KEYSPACE:
executeRenameKeyspace(ast);
break;
case CliParser.NODE_SHOW_CLUSTER_NAME:
executeShowClusterName();
break;
case CliParser.NODE_SHOW_VERSION:
executeShowVersion();
break;
case CliParser.NODE_SHOW_TABLES:
executeShowTables(ast);
break;
case CliParser.NODE_DESCRIBE_TABLE:
executeDescribeTable(ast);
break;
case CliParser.NODE_USE_TABLE:
executeUseTable(ast);
break;
case CliParser.NODE_CONNECT:
executeConnect(ast);
break;
case CliParser.NODE_NO_OP:
// comment lines come here; they are treated as no ops.
break;
default:
css_.err.println("Invalid Statement (Type: " + ast.getType() + ")");
if (css_.batch)
System.exit(2);
break;
}
}
catch (UnsupportedEncodingException e)
{
throw new RuntimeException("Unable to encode string as UTF-8", e);
}
}
private void printCmdHelp(CommonTree ast)
{
if(ast.getChildCount() > 0) {
int helpType = ast.getChild(0).getType();
switch(helpType)
{
case CliParser.NODE_HELP:
css_.out.println("help <command>");
css_.out.println("");
css_.out.println("Display the general help page with a list of available commands.");
break;
case CliParser.NODE_CONNECT:
css_.out.println("connect <hostname>/<port>");
css_.out.println("");
css_.out.println("Connect to the specified host on the specified port. ");
css_.out.println("");
css_.out.println("example:");
css_.out.println("connect localhost/9160");
break;
case CliParser.NODE_USE_TABLE:
css_.out.println("use <keyspace>");
css_.out.println("use <keyspace> <username> '<password>'");
css_.out.println("");
css_.out.println("Switch to the specified keyspace. The optional username and password fields");
css_.out.println("are needed when performing authentication.");
css_.out.println("");
break;
case CliParser.NODE_DESCRIBE_TABLE:
css_.out.println("describe keyspace <keyspace>");
css_.out.println("");
css_.out.println("Show additional information about the specified keyspace.");
css_.out.println();
css_.out.println("example:");
css_.out.println("describe keyspace system");
break;
case CliParser.NODE_EXIT:
css_.out.println("exit");
css_.out.println("quit");
css_.out.println("");
css_.out.println("Exit this utility.");
break;
case CliParser.NODE_SHOW_CLUSTER_NAME:
css_.out.println("show cluster name");
css_.out.println("");
css_.out.println("Displays the name of the currently connected cluster.");
break;
case CliParser.NODE_SHOW_VERSION:
css_.out.println("show api version");
css_.out.println("");
css_.out.println("Displays the API version number.");
break;
case CliParser.NODE_SHOW_TABLES:
css_.out.println("show keyspaces");
css_.out.println("");
css_.out.println("Displays a list of the keyspaces available on the currently connected cluster.");
break;
case CliParser.NODE_ADD_KEYSPACE:
css_.out.println("create keyspace <keyspace>");
css_.out.println("create keyspace <keyspace> with <att1>=<value1>");
css_.out.println("create keyspace <keyspace> with <att1>=<value1> and <att2>=<value2> ...");
css_.out.println("");
css_.out.println("Create a new keyspace with the specified values for the given set of attributes.");
css_.out.println("");
css_.out.println("valid attributes are:");
css_.out.println(" replication_factor: to how many nodes should entries to this keyspace be");
css_.out.println(" replicated. Valid entries are integers greater than 0.");
css_.out.println(" placement_strategy: the fully qualified class used to place replicas in");
css_.out.println(" this keyspace. Valid values are");
css_.out.println(" org.apache.cassandra.locator.SimpleStrategy,");
css_.out.println(" org.apache.cassandra.locator.NetworkTopologyStrategy,");
css_.out.println(" and org.apache.cassandra.locator.OldNetworkTopologyStrategy");
css_.out.println("");
css_.out.println("example:");
css_.out.println("create keyspace foo with replication_factor = 3 and ");
css_.out.println(" placement_strategy = 'org.apache.cassandra.locator.SimpleStrategy'");
break;
case CliParser.NODE_ADD_COLUMN_FAMILY:
css_.out.println("create column family Bar");
css_.out.println("create column family Bar with <att1>=<value1>");
css_.out.println("create column family Bar with <att1>=<value1> and <att2>=<value2>...");
css_.out.println("");
css_.out.println("Create a new column family with the specified values for the given set of");
css_.out.println("attributes. Note that you must be using a keyspace.");
css_.out.println("");
css_.out.println("valid attributes are:");
css_.out.println(" - column_type: One of Super or Standard");
css_.out.println(" - clock_type: Timestamp");
css_.out.println(" - comparator: The class used as a comparator when sorting column names.");
css_.out.println(" Valid options include: AsciiType, BytesType, LexicalUUIDType,");
css_.out.println(" LongType, TimeUUIDType, and UTF8Type");
css_.out.println(" - subcomparator: Name of comparator used for subcolumns (when");
css_.out.println(" column_type=Super only). Valid options are identical to");
css_.out.println(" comparator above.");
css_.out.println(" - reconciler: Name of reconciler class that determines what to do with");
css_.out.println(" conflicting versions of a column. Timestamp is currently the");
css_.out.println(" only valid value.");
css_.out.println(" - comment: Human-readable column family description. Any string is valid.");
css_.out.println(" - rows_cached: Number of rows to cache");
css_.out.println(" - preload_row_cache: Set to true to automatically load the row cache");
css_.out.println(" - key_cache_size: Number of keys to cache");
css_.out.println(" - read_repair_chance: Valid values for this attribute are any number");
css_.out.println(" between 0.0 and 1.0");
css_.out.println("");
css_.out.println("example:");
css_.out.println("");
css_.out.println("create column family bar with column_type = 'Super' and comparator = 'AsciiType'");
css_.out.println(" and rows_cached = 10000");
css_.out.println("create column family baz with comparator = 'LongType' and rows_cached = 10000");
break;
case CliParser.NODE_RENAME_KEYSPACE:
css_.out.println("rename keyspace <old_name> <new_name>");
css_.out.println("");
css_.out.println("Renames the specified keyspace with the given new name.");
css_.out.println("");
css_.out.println("example:");
css_.out.println("rename keyspace foo bar");
break;
case CliParser.NODE_RENAME_COLUMN_FAMILY:
css_.out.println("rename column family <name> <new_name>");
css_.out.println("");
css_.out.println("Renames the specified column family with the given new name.");
css_.out.println("");
css_.out.println("example:");
css_.out.println("rename column family foo bar");
break;
case CliParser.NODE_DEL_KEYSPACE:
css_.out.println("drop keyspace <keyspace>");
css_.out.println("");
css_.out.println("Drops the specified keyspace.");
css_.out.println("");
css_.out.println("example:");
css_.out.println("drop keyspace foo");
break;
case CliParser.NODE_DEL_COLUMN_FAMILY:
css_.out.println("drop column family <name>");
css_.out.println("");
css_.out.println("Drops the specified column family.");
css_.out.println("");
css_.out.println("example:");
css_.out.println("drop column family foo");
break;
case CliParser.NODE_THRIFT_GET :
css_.out.println("get <cf>['<key>']");
css_.out.println("get <cf>['<key>']['<col>'] ");
css_.out.println("get <cf>['<key>']['<super>'] ");
css_.out.println("get <cf>['<key>']['<super>']['<col>'] ");
css_.out.println("");
css_.out.println("example:");
css_.out.println("get bar['testkey']");
break;
case CliParser.NODE_THRIFT_SET:
css_.out.println("set <cf>['<key>']['<col>'] = '<value>' ");
css_.out.println("set <cf>['<key>']['<super>']['<col>'] = '<value>' ");
css_.out.println("");
css_.out.println("example:");
css_.out.println("set bar['testkey']['my super']['test col']='this is a test'");
css_.out.println("set baz['testkey']['test col']='this is also a test'");
break;
case CliParser.NODE_THRIFT_DEL:
css_.out.println("del <cf>['<key>'] ");
css_.out.println("del <cf>['<key>']['<col>'] ");
css_.out.println("del <cf>['<key>']['<super>']['<col>'] ");
css_.out.println("");
css_.out.println("Deletes a record, a column, or a subcolumn.");
css_.out.println("");
css_.out.println("example:");
css_.out.println("del bar['testkey']['my super']['test col']");
css_.out.println("del baz['testkey']['test col']");
css_.out.println("del baz['testkey']");
break;
case CliParser.NODE_THRIFT_COUNT:
css_.out.println("count <cf>['<key>']");
css_.out.println("count <cf>['<key>']['<super>'] ");
css_.out.println("");
css_.out.println("Count the number of columns in the specified key or subcolumns in the specified");
css_.out.println("super column.");
css_.out.println("");
css_.out.println("example:");
css_.out.println("count bar['testkey']['my super']");
css_.out.println("count baz['testkey']");
break;
default:
css_.out.println("?");
break;
}
}
else
{
css_.out.println("List of all CLI commands:");
css_.out.println("? Display this message.");
css_.out.println("help Display this help.");
css_.out.println("help <command> Display detailed, command-specific help.");
css_.out.println("connect <hostname>/<port> Connect to thrift service.");
css_.out.println("use <keyspace> [<username> 'password'] Switch to a keyspace.");
css_.out.println("describe keyspace <keyspacename> Describe keyspace.");
css_.out.println("exit Exit CLI.");
css_.out.println("quit Exit CLI.");
css_.out.println("show cluster name Display cluster name.");
css_.out.println("show keyspaces Show list of keyspaces.");
css_.out.println("show api version Show server API version.");
css_.out.println("create keyspace <keyspace> [with <att1>=<value1> [and <att2>=<value2> ...]]");
css_.out.println(" Add a new keyspace with the specified attribute and value(s).");
css_.out.println("create column family <cf> [with <att1>=<value1> [and <att2>=<value2> ...]]");
css_.out.println(" Create a new column family with the specified attribute and value(s).");
css_.out.println("drop keyspace <keyspace> Delete a keyspace.");
css_.out.println("drop column family <cf> Delete a column family.");
css_.out.println("rename keyspace <keyspace> <keyspace_new_name> Rename a keyspace.");
css_.out.println("rename column family <cf> <new_name> Rename a column family.");
css_.out.println("get <cf>['<key>'] Get a slice of columns.");
css_.out.println("get <cf>['<key>']['<super>'] Get a slice of sub columns.");
css_.out.println("get <cf>['<key>']['<col>'] Get a column value.");
css_.out.println("get <cf>['<key>']['<super>']['<col>'] Get a sub column value.");
css_.out.println("set <cf>['<key>']['<col>'] = '<value>' Set a column.");
css_.out.println("set <cf>['<key>']['<super>']['<col>'] = '<value>' Set a sub column.");
css_.out.println("del <cf>['<key>'] Delete record.");
css_.out.println("del <cf>['<key>']['<col>'] Delete column.");
css_.out.println("del <cf>['<key>']['<super>']['<col>'] Delete sub column.");
css_.out.println("count <cf>['<key>'] Count columns in record.");
css_.out.println("count <cf>['<key>']['<super>'] Count columns in a super column.");
return;
}
}
private void cleanupAndExit()
{
CliMain.disconnect();
System.exit(0);
}
KsDef getKSMetaData(String keyspace) throws NotFoundException, TException
{
// Lazily lookup keyspace meta-data.
if (!(keyspacesMap.containsKey(keyspace)))
keyspacesMap.put(keyspace, thriftClient_.describe_keyspace(keyspace));
return keyspacesMap.get(keyspace);
}
private void executeCount(CommonTree ast) throws TException, InvalidRequestException, UnavailableException, TimedOutException, UnsupportedEncodingException
{
if (!CliMain.isConnected() || !hasKeySpace())
return;
int childCount = ast.getChildCount();
assert(childCount == 1);
CommonTree columnFamilySpec = (CommonTree)ast.getChild(0);
assert(columnFamilySpec.getType() == CliParser.NODE_COLUMN_ACCESS);
String key = CliCompiler.getKey(columnFamilySpec);
String columnFamily = CliCompiler.getColumnFamily(columnFamilySpec);
int columnSpecCnt = CliCompiler.numColumnSpecifiers(columnFamilySpec);
ColumnParent colParent;
if (columnSpecCnt == 0)
{
colParent = new ColumnParent(columnFamily).setSuper_column(null);
}
else
{
assert (columnSpecCnt == 1);
colParent = new ColumnParent(columnFamily).setSuper_column(CliCompiler.getColumn(columnFamilySpec, 0).getBytes("UTF-8"));
}
SliceRange range = new SliceRange(ArrayUtils.EMPTY_BYTE_ARRAY, ArrayUtils.EMPTY_BYTE_ARRAY, false, Integer.MAX_VALUE);
SlicePredicate predicate = new SlicePredicate().setColumn_names(null).setSlice_range(range);
int count = thriftClient_.get_count(key.getBytes(), colParent, predicate, ConsistencyLevel.ONE);
css_.out.printf("%d columns\n", count);
}
private void executeDelete(CommonTree ast) throws TException, InvalidRequestException, UnavailableException, TimedOutException, UnsupportedEncodingException
{
if (!CliMain.isConnected() || !hasKeySpace())
return;
int childCount = ast.getChildCount();
assert(childCount == 1);
CommonTree columnFamilySpec = (CommonTree)ast.getChild(0);
assert(columnFamilySpec.getType() == CliParser.NODE_COLUMN_ACCESS);
String key = CliCompiler.getKey(columnFamilySpec);
String columnFamily = CliCompiler.getColumnFamily(columnFamilySpec);
int columnSpecCnt = CliCompiler.numColumnSpecifiers(columnFamilySpec);
byte[] superColumnName = null;
byte[] columnName = null;
boolean isSuper;
List<String> cfnames = new ArrayList<String>();
for (CfDef cfd : keyspacesMap.get(keySpace).cf_defs) {
cfnames.add(cfd.name);
}
int idx = cfnames.indexOf(columnFamily);
if (idx == -1)
{
css_.out.println("No such column family: " + columnFamily);
return;
}
isSuper = keyspacesMap.get(keySpace).cf_defs.get(idx).column_type.equals("Super");
if ((columnSpecCnt < 0) || (columnSpecCnt > 2))
{
css_.out.println("Invalid row, super column, or column specification.");
return;
}
if (columnSpecCnt == 1)
{
// table.cf['key']['column']
if (isSuper)
superColumnName = CliCompiler.getColumn(columnFamilySpec, 0).getBytes("UTF-8");
else
columnName = CliCompiler.getColumn(columnFamilySpec, 0).getBytes("UTF-8");
}
else if (columnSpecCnt == 2)
{
// table.cf['key']['column']['column']
superColumnName = CliCompiler.getColumn(columnFamilySpec, 0).getBytes("UTF-8");
columnName = CliCompiler.getColumn(columnFamilySpec, 1).getBytes("UTF-8");
}
Clock thrift_clock = getClock(columnFamily);
thriftClient_.remove(key.getBytes(), new ColumnPath(columnFamily).setSuper_column(superColumnName).setColumn(columnName),
thrift_clock, ConsistencyLevel.ONE);
css_.out.println(String.format("%s removed.", (columnSpecCnt == 0) ? "row" : "column"));
}
private void doSlice(String keyspace, String key, String columnFamily, byte[] superColumnName)
throws InvalidRequestException, UnavailableException, TimedOutException, TException, UnsupportedEncodingException, IllegalAccessException, NotFoundException, InstantiationException, NoSuchFieldException
{
SliceRange range = new SliceRange(ArrayUtils.EMPTY_BYTE_ARRAY, ArrayUtils.EMPTY_BYTE_ARRAY, true, 1000000);
List<ColumnOrSuperColumn> columns = thriftClient_.get_slice(key.getBytes(),
new ColumnParent(columnFamily).setSuper_column(superColumnName),
new SlicePredicate().setColumn_names(null).setSlice_range(range), ConsistencyLevel.ONE);
int size = columns.size();
// Print out super columns or columns.
for (ColumnOrSuperColumn cosc : columns)
{
if (cosc.isSetSuper_column())
{
SuperColumn superColumn = cosc.super_column;
css_.out.printf("=> (super_column=%s,", formatSuperColumnName(keyspace, columnFamily, superColumn));
for (Column col : superColumn.getColumns())
css_.out.printf("\n (column=%s, value=%s, timestamp=%d)", formatSubcolumnName(keyspace, columnFamily, col),
new String(col.value, "UTF-8"), col.clock.timestamp);
css_.out.println(")");
}
else
{
Column column = cosc.column;
css_.out.printf("=> (column=%s, value=%s, timestamp=%d)\n", formatColumnName(keyspace, columnFamily, column),
new String(column.value, "UTF-8"), column.clock.timestamp);
}
}
css_.out.println("Returned " + size + " results.");
}
private String formatSuperColumnName(String keyspace, String columnFamily, SuperColumn column) throws NotFoundException, TException, IllegalAccessException, InstantiationException, NoSuchFieldException
{
return getFormatTypeForColumn(getCfDef(keyspace,columnFamily).comparator_type).getString(column.name);
}
private String formatSubcolumnName(String keyspace, String columnFamily, Column subcolumn) throws NotFoundException, TException, IllegalAccessException, InstantiationException, NoSuchFieldException
{
return getFormatTypeForColumn(getCfDef(keyspace,columnFamily).subcomparator_type).getString(subcolumn.name);
}
private String formatColumnName(String keyspace, String columnFamily, Column column) throws NotFoundException, TException, IllegalAccessException, InstantiationException, NoSuchFieldException
{
return getFormatTypeForColumn(getCfDef(keyspace,columnFamily).comparator_type).getString(column.name);
}
private AbstractType getFormatTypeForColumn(String compareWith) throws IllegalAccessException, InstantiationException, NoSuchFieldException
{
AbstractType type;
try {
// Get the singleton instance of the AbstractType subclass
Class c = Class.forName(compareWith);
type = (AbstractType) c.getField("instance").get(c);
} catch (ClassNotFoundException e) {
type = BytesType.instance;
}
return type;
}
// Execute GET statement
private void executeGet(CommonTree ast) throws TException, NotFoundException, InvalidRequestException, UnavailableException, TimedOutException, UnsupportedEncodingException, IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchFieldException
{
if (!CliMain.isConnected() || !hasKeySpace())
return;
// This will never happen unless the grammar is broken
assert (ast.getChildCount() == 1) : "serious parsing error (this is a bug).";
CommonTree columnFamilySpec = (CommonTree)ast.getChild(0);
assert(columnFamilySpec.getType() == CliParser.NODE_COLUMN_ACCESS);
String key = CliCompiler.getKey(columnFamilySpec);
String columnFamily = CliCompiler.getColumnFamily(columnFamilySpec);
int columnSpecCnt = CliCompiler.numColumnSpecifiers(columnFamilySpec);
List<String> cfnames = new ArrayList<String>();
for (CfDef cfd : keyspacesMap.get(keySpace).cf_defs) {
cfnames.add(cfd.name);
}
int idx = cfnames.indexOf(columnFamily);
if (idx == -1)
{
css_.out.println("No such column family: " + columnFamily);
return;
}
boolean isSuper = keyspacesMap.get(keySpace).cf_defs.get(idx).column_type.equals("Super");
byte[] superColumnName = null;
byte[] columnName = null;
// table.cf['key'] -- row slice
if (columnSpecCnt == 0)
{
doSlice(keySpace, key, columnFamily, superColumnName);
return;
}
// table.cf['key']['column'] -- slice of a super, or get of a standard
if (columnSpecCnt == 1)
{
if (isSuper)
{
superColumnName = CliCompiler.getColumn(columnFamilySpec, 0).getBytes("UTF-8");
doSlice(keySpace, key, columnFamily, superColumnName);
return;
}
else
{
columnName = CliCompiler.getColumn(columnFamilySpec, 0).getBytes("UTF-8");
}
}
// table.cf['key']['column']['column'] -- get of a sub-column
else if (columnSpecCnt == 2)
{
superColumnName = CliCompiler.getColumn(columnFamilySpec, 0).getBytes("UTF-8");
columnName = CliCompiler.getColumn(columnFamilySpec, 1).getBytes("UTF-8");
}
// The parser groks an arbitrary number of these so it is possible to get here.
else
{
css_.out.println("Invalid row, super column, or column specification.");
return;
}
// Perform a get(), print out the results.
ColumnPath path = new ColumnPath(columnFamily).setSuper_column(superColumnName).setColumn(columnName);
Column column = thriftClient_.get(key.getBytes(), path, ConsistencyLevel.ONE).column;
css_.out.printf("=> (column=%s, value=%s, timestamp=%d)\n", formatColumnName(keySpace, columnFamily, column),
new String(column.value, "UTF-8"), column.clock.timestamp);
}
// Execute SET statement
private void executeSet(CommonTree ast) throws TException, InvalidRequestException, UnavailableException, TimedOutException, UnsupportedEncodingException
{
if (!CliMain.isConnected() || !hasKeySpace())
return;
assert (ast.getChildCount() == 2) : "serious parsing error (this is a bug).";
CommonTree columnFamilySpec = (CommonTree)ast.getChild(0);
assert(columnFamilySpec.getType() == CliParser.NODE_COLUMN_ACCESS);
String key = CliCompiler.getKey(columnFamilySpec);
String columnFamily = CliCompiler.getColumnFamily(columnFamilySpec);
int columnSpecCnt = CliCompiler.numColumnSpecifiers(columnFamilySpec);
String value = CliUtils.unescapeSQLString(ast.getChild(1).getText());
byte[] superColumnName = null;
byte[] columnName = null;
// table.cf['key']
if (columnSpecCnt == 0)
{
css_.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
columnName = CliCompiler.getColumn(columnFamilySpec, 0).getBytes("UTF-8");
}
// table.cf['key']['super_column']['column'] = 'value'
else
{
assert (columnSpecCnt == 2) : "serious parsing error (this is a bug).";
// get the super column and column names
superColumnName = CliCompiler.getColumn(columnFamilySpec, 0).getBytes("UTF-8");
columnName = CliCompiler.getColumn(columnFamilySpec, 1).getBytes("UTF-8");
}
// do the insert
Clock thrift_clock = getClock(columnFamily);
thriftClient_.insert(key.getBytes(), new ColumnParent(columnFamily).setSuper_column(superColumnName),
new Column(columnName, value.getBytes(), thrift_clock), ConsistencyLevel.ONE);
css_.out.println("Value inserted.");
}
private Clock getClock(String columnFamily) throws TException
{
try
{
KsDef keyspace = thriftClient_.describe_keyspace(this.keySpace);
for (CfDef cf : keyspace.getCf_defs())
{
if (cf.name.equalsIgnoreCase(columnFamily)) {
ClockType clockType = ClockType.create(cf.clock_type);
switch (clockType)
{
case IncrementCounter:
return new Clock();
default:
case Timestamp:
return new Clock().setTimestamp(FBUtilities.timestampMicros());
}
}
}
// no matching cf found, return default.
return new Clock().setTimestamp(FBUtilities.timestampMicros());
} catch (NotFoundException e)
{
// returning default if keyspace is not found
return new Clock().setTimestamp(FBUtilities.timestampMicros());
}
}
private void executeShowClusterName() throws TException
{
if (!CliMain.isConnected())
return;
css_.out.println(thriftClient_.describe_cluster_name());
}
/**
* Add a keyspace
* @throws TException
* @throws InvalidRequestException
* @throws NotFoundException
*/
private void executeAddKeyspace(CommonTree ast) throws TException, InvalidRequestException, NotFoundException
{
if (!CliMain.isConnected())
{
return;
}
CommonTree newKSSpec = (CommonTree)ast.getChild(0);
//parser send the keyspace, plus a series of key value pairs, ie should always be an odd number...
assert(newKSSpec.getChildCount() > 0);
assert(newKSSpec.getChildCount() % 2 == 1);
//defaults
String replicaPlacementStrategy = "org.apache.cassandra.locator.SimpleStrategy";
int replicationFactor = 2;
/*
* first value is the keyspace name, after that it is all key=value
*/
String keyspaceName = newKSSpec.getChild(0).getText();
int argumentLength = newKSSpec.getChildCount();
for(int i = 1; i < argumentLength; i = i + 2)
{
AddKeyspaceArgument mArgument = AddKeyspaceArgument.valueOf(newKSSpec.getChild(i).getText().toUpperCase());
String mValue = newKSSpec.getChild(i + 1).getText();
switch(mArgument)
{
case PLACEMENT_STRATEGY:
replicaPlacementStrategy = CliUtils.unescapeSQLString(mValue);
break;
case REPLICATION_FACTOR:
replicationFactor = Integer.parseInt( mValue);
break;
default:
//must match one of the above or we'd throw an exception at the valueOf statement above.
assert(false);
}
}
List<CfDef> mList = new LinkedList<CfDef>();
KsDef ks_def = new KsDef(keyspaceName, replicaPlacementStrategy, replicationFactor, mList);
css_.out.println(thriftClient_.system_add_keyspace(ks_def));
keyspacesMap.put(keyspaceName, thriftClient_.describe_keyspace(keyspaceName));
}
/**
* Add a column family
* @throws TException
* @throws InvalidRequestException
* @throws NotFoundException
*/
private void executeAddColumnFamily(CommonTree ast) throws TException, InvalidRequestException, NotFoundException
{
if (!CliMain.isConnected() || !hasKeySpace())
{
return;
}
CommonTree newCFTree = (CommonTree)ast.getChild(0);
//parser send the keyspace, plus a series of key value pairs, ie should always be an odd number...
assert(newCFTree.getChildCount() > 0);
assert(newCFTree.getChildCount() % 2 == 1);
/*
* first value is the keyspace name, after that it is all key=value
*/
String columnName = newCFTree.getChild(0).getText();
int argumentLength = newCFTree.getChildCount();
CfDef cfDef = new CfDef(keySpace, columnName);
for(int i = 1; i < argumentLength; i = i + 2)
{
AddColumnFamilyArgument mArgument = AddColumnFamilyArgument.valueOf(newCFTree.getChild(i).getText().toUpperCase());
String mValue = newCFTree.getChild(i + 1).getText();
switch(mArgument)
{
case COLUMN_TYPE:
cfDef.setColumn_type(CliUtils.unescapeSQLString(mValue));
break;
case CLOCK_TYPE:
cfDef.setClock_type(CliUtils.unescapeSQLString(mValue));
break;
case COMPARATOR:
cfDef.setComparator_type(CliUtils.unescapeSQLString(mValue));
break;
case SUBCOMPARATOR:
cfDef.setSubcomparator_type(CliUtils.unescapeSQLString(mValue));
break;
case RECONCILER:
cfDef.setReconciler(CliUtils.unescapeSQLString(mValue));
break;
case COMMENT:
cfDef.setComment(CliUtils.unescapeSQLString(mValue));
break;
case ROWS_CACHED:
cfDef.setRow_cache_size(Double.parseDouble(mValue));
break;
case PRELOAD_ROW_CACHE:
cfDef.setPreload_row_cache(Boolean.parseBoolean(CliUtils.unescapeSQLString(mValue)));
break;
case KEY_CACHE_SIZE:
cfDef.setKey_cache_size(Double.parseDouble(mValue));
break;
case READ_REPAIR_CHANCE:
cfDef.setRead_repair_chance(Double.parseDouble(mValue));
break;
case GC_GRACE_SECONDS:
cfDef.setGc_grace_seconds(Integer.parseInt(mValue));
default:
//must match one of the above or we'd throw an exception at the valueOf statement above.
assert(false);
}
}
css_.out.println(thriftClient_.system_add_column_family(cfDef));
keyspacesMap.put(keySpace, thriftClient_.describe_keyspace(keySpace));
}
/**
* Delete a keyspace
* @throws TException
* @throws InvalidRequestException
* @throws NotFoundException
*/
private void executeDelKeyspace(CommonTree ast) throws TException, InvalidRequestException, NotFoundException
{
if (!CliMain.isConnected())
{
return;
}
String keyspaceName = ast.getChild(0).getText();
css_.out.println(thriftClient_.system_drop_keyspace(keyspaceName));
}
/**
* Delete a column family
* @throws TException
* @throws InvalidRequestException
* @throws NotFoundException
*/
private void executeDelColumnFamily(CommonTree ast) throws TException, InvalidRequestException, NotFoundException
{
if (!CliMain.isConnected() || !hasKeySpace())
{
return;
}
String columnName = ast.getChild(0).getText();
css_.out.println(thriftClient_.system_drop_column_family(columnName));
}
/**
* Add a column family
* @throws TException
* @throws InvalidRequestException
* @throws NotFoundException
*/
private void executeRenameKeyspace(CommonTree ast) throws TException, InvalidRequestException, NotFoundException
{
if (!CliMain.isConnected())
{
return;
}
String keyspaceName = ast.getChild(0).getText();
String keyspaceNewName = ast.getChild(1).getText();
css_.out.println(thriftClient_.system_rename_keyspace(keyspaceName, keyspaceNewName));
}
/**
* Add a column family
* @throws TException
* @throws InvalidRequestException
* @throws NotFoundException
*/
private void executeRenameColumnFamily(CommonTree ast) throws TException, InvalidRequestException, NotFoundException
{
if (!CliMain.isConnected() || !hasKeySpace())
{
return;
}
String columnName = ast.getChild(0).getText();
String columnNewName = ast.getChild(1).getText();
css_.out.println(thriftClient_.system_rename_column_family(columnName, columnNewName));
}
private void executeShowVersion() throws TException
{
if (!CliMain.isConnected())
return;
css_.out.println(thriftClient_.describe_version());
}
// process "show tables" statement
private void executeShowTables(CommonTree ast) throws TException
{
if (!CliMain.isConnected())
return;
List<KsDef> tables = thriftClient_.describe_keyspaces();
for (KsDef t : tables) {
describeTableInternal(t.name, t);
}
}
private boolean hasKeySpace()
{
if (keySpace == null)
{
css_.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, 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;
}
private void executeUseTable(CommonTree ast) throws TException
{
if (!CliMain.isConnected())
return;
int childCount = ast.getChildCount();
String tableName, username = null, password = null;
assert(childCount > 0);
// Get table name
tableName = ast.getChild(0).getText();
if (childCount == 3) {
username = ast.getChild(1).getText();
password = ast.getChild(2).getText();
}
if( tableName == null )
{
css_.out.println("Keyspace argument required");
return;
}
try
{
AuthenticationRequest authRequest;
Map<String, String> credentials = new HashMap<String, String>();
thriftClient_.set_keyspace(tableName);
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 = tableName;
this.username = username != null ? username : "default";
if (!(keyspacesMap.containsKey(keySpace)))
{
keyspacesMap.put(keySpace, thriftClient_.describe_keyspace(keySpace));
}
Set<String> cfnames = new HashSet<String>();
KsDef ksd = keyspacesMap.get(keySpace);
for (CfDef cfd : ksd.cf_defs) {
cfnames.add(cfd.name);
}
CliMain.updateCompletor(cfnames);
css_.out.println("Authenticated to keyspace: " + keySpace);
}
catch (AuthenticationException e)
{
css_.err.println("Exception during authentication to the cassandra node: " +
"verify keyspace exists, and you are using correct credentials.");
return;
}
catch (AuthorizationException e)
{
css_.err.println("You are not authorized to use keyspace: " + tableName);
return;
}
catch (InvalidRequestException e)
{
css_.err.println(tableName + " does not exist.");
return;
}
catch (NotFoundException e)
{
css_.err.println(tableName + " does not exist.");
return;
}
catch (TException e)
{
if (css_.debug)
e.printStackTrace();
css_.err.println("Login failure. Did you specify 'keyspace', 'username' and 'password'?");
return;
}
}
private void describeTableInternal(String tableName, KsDef metadata) throws TException {
// Describe and display
css_.out.println("Keyspace: " + tableName);
try
{
KsDef ks_def;
if (metadata != null) {
ks_def = metadata;
}
else {
ks_def = thriftClient_.describe_keyspace(tableName);
}
css_.out.println(" Replication Factor: " + ks_def.replication_factor);
css_.out.println(" Column Families:");
for (CfDef cf_def : ks_def.cf_defs)
{
/**
String desc = columnMap.get("Desc");
String columnFamilyType = columnMap.get("Type");
String sort = columnMap.get("CompareWith");
String flushperiod = columnMap.get("FlushPeriodInMinutes");
css_.out.println(desc);
*/
//css_.out.println("description");
css_.out.println(" Column Family Name: " + cf_def.name + " {");
css_.out.println(" Column Family Type: " + cf_def.column_type);
css_.out.println(" Column Sorted By: " + cf_def.comparator_type);
//css_.out.println(" flush period: " + flushperiod + " minutes");
css_.out.println(" }");
}
}
catch (NotFoundException e)
{
css_.out.println("Keyspace " + tableName + " could not be found.");
}
}
// process a statement of the form: describe table <tablename>
private void executeDescribeTable(CommonTree ast) throws TException
{
if (!CliMain.isConnected())
return;
// Get table name
int childCount = ast.getChildCount();
assert(childCount == 1);
String tableName = ast.getChild(0).getText();
if( tableName == null ) {
css_.out.println("Keyspace argument required");
return;
}
describeTableInternal(tableName, null);
}
// process a statement of the form: connect hostname/port
private void executeConnect(CommonTree ast)
{
int portNumber = Integer.parseInt(ast.getChild(1).getText());
Tree idList = ast.getChild(0);
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
css_.hostName = hostName.toString();
css_.thriftPort = portNumber;
CliMain.connect(css_.hostName, css_.thriftPort);
}
private CfDef getCfDef(String ksname, String cfname) {
List<String> cfnames = new ArrayList<String>();
KsDef ksd = keyspacesMap.get(ksname);
for (CfDef cfd : ksd.cf_defs) {
cfnames.add(cfd.name);
}
int idx = cfnames.indexOf(cfname);
return ksd.cf_defs.get(idx);
}
}