Author: brandonwilliams Date: Mon Aug 8 21:08:04 2011 New Revision: 1155100
URL: http://svn.apache.org/viewvc?rev=1155100&view=rev Log: Add 'show creates' commands to the cli to export schema. Patch by Aaron Morton, reviewed by xedin for CASSANDRA-2221 Modified: cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cli/Cli.g cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cli/CliClient.java cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cli/CliCompleter.java cassandra/branches/cassandra-0.8/src/resources/org/apache/cassandra/cli/CliHelp.yaml cassandra/branches/cassandra-0.8/test/unit/org/apache/cassandra/cli/CliTest.java Modified: cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cli/Cli.g URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cli/Cli.g?rev=1155100&r1=1155099&r2=1155100&view=diff ============================================================================== --- cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cli/Cli.g (original) +++ cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cli/Cli.g Mon Aug 8 21:08:04 2011 @@ -44,6 +44,7 @@ tokens { NODE_SHOW_CLUSTER_NAME; NODE_SHOW_VERSION; NODE_SHOW_KEYSPACES; + NODE_SHOW_SCHEMA; NODE_THRIFT_GET; NODE_THRIFT_GET_WITH_CONDITIONS; NODE_THRIFT_SET; @@ -191,6 +192,8 @@ helpStatement -> ^(NODE_HELP NODE_SHOW_CLUSTER_NAME) | HELP SHOW KEYSPACES -> ^(NODE_HELP NODE_SHOW_KEYSPACES) + | HELP SHOW SCHEMA + -> ^(NODE_HELP NODE_SHOW_SCHEMA) | HELP SHOW API_VERSION -> ^(NODE_HELP NODE_SHOW_VERSION) | HELP CREATE KEYSPACE @@ -284,6 +287,7 @@ showStatement : showClusterName | showVersion | showKeyspaces + | showSchema ; listStatement @@ -356,6 +360,11 @@ showKeyspaces -> ^(NODE_SHOW_KEYSPACES) ; +showSchema + : SHOW SCHEMA (keyspace)? + -> ^(NODE_SHOW_SCHEMA (keyspace)?) + ; + describeTable : DESCRIBE KEYSPACE (keyspace)? -> ^(NODE_DESCRIBE_TABLE (keyspace)?) @@ -573,6 +582,7 @@ TTL: 'TTL'; CONSISTENCYLEVEL: 'CONSISTENCYLEVEL'; INDEX: 'INDEX'; ON: 'ON'; +SCHEMA: 'SCHEMA'; IP_ADDRESS : IntegerPositiveLiteral '.' IntegerPositiveLiteral '.' IntegerPositiveLiteral '.' IntegerPositiveLiteral Modified: cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cli/CliClient.java URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cli/CliClient.java?rev=1155100&r1=1155099&r2=1155100&view=diff ============================================================================== --- cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cli/CliClient.java (original) +++ cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cli/CliClient.java Mon Aug 8 21:08:04 2011 @@ -26,6 +26,9 @@ 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; @@ -71,7 +74,7 @@ public class CliClient COUNTERCOLUMN (CounterColumnType.instance); private AbstractType validator; - + Function(AbstractType validator) { this.validator = validator; @@ -136,6 +139,8 @@ public class CliClient } 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; @@ -241,6 +246,9 @@ public class CliClient case CliParser.NODE_SHOW_KEYSPACES: executeShowKeySpaces(); break; + case CliParser.NODE_SHOW_SCHEMA: + executeShowSchema(tree); + break; case CliParser.NODE_DESCRIBE_TABLE: executeDescribeKeySpace(tree); break; @@ -1246,7 +1254,7 @@ public class CliClient cfDef.setReplicate_on_write(Boolean.parseBoolean(mValue)); break; case ROW_CACHE_PROVIDER: - cfDef.setRow_cache_provider(mValue); + cfDef.setRow_cache_provider(CliUtils.unescapeSQLString(mValue)); break; case KEY_VALIDATION_CLASS: cfDef.setKey_validation_class(CliUtils.unescapeSQLString(mValue)); @@ -1560,6 +1568,187 @@ public class CliClient } } + // 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); + if (ksDef.isSetReplication_factor()) + writeAttr(sb, false, "replication_factor", ksDef.getReplication_factor()); + 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, "memtable_operations", cfDef.memtable_operations_in_millions); + writeAttr(sb, false, "memtable_throughput", cfDef.memtable_throughput_in_mb); + writeAttr(sb, false, "memtable_flush_after", cfDef.memtable_flush_after_mins); + 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()))); + + } + 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 Modified: cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cli/CliCompleter.java URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cli/CliCompleter.java?rev=1155100&r1=1155099&r2=1155100&view=diff ============================================================================== --- cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cli/CliCompleter.java (original) +++ cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cli/CliCompleter.java Mon Aug 8 21:08:04 2011 @@ -29,6 +29,7 @@ public class CliCompleter extends Simple "quit", "show cluster name", "show keyspaces", + "show schema", "show api version", "create keyspace", "create column family", @@ -45,6 +46,7 @@ public class CliCompleter extends Simple "help quit", "help show cluster name", "help show keyspaces", + "help show schema", "help show api version", "help create keyspace", "help create column family", Modified: cassandra/branches/cassandra-0.8/src/resources/org/apache/cassandra/cli/CliHelp.yaml URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/resources/org/apache/cassandra/cli/CliHelp.yaml?rev=1155100&r1=1155099&r2=1155100&view=diff ============================================================================== --- cassandra/branches/cassandra-0.8/src/resources/org/apache/cassandra/cli/CliHelp.yaml (original) +++ cassandra/branches/cassandra-0.8/src/resources/org/apache/cassandra/cli/CliHelp.yaml Mon Aug 8 21:08:04 2011 @@ -52,6 +52,7 @@ help: | show api version Show the server API version. show cluster name Show the cluster name. show keyspaces Show all keyspaces and their column families. + show schema Show a cli script to create keyspaces and column families. truncate Drop the data in a column family. update column family Update the settings for a column family. update keyspace Update the settings for a keyspace. @@ -116,7 +117,8 @@ commands: use Keyspace1 user 'badpasswd'; - name: NODE_DESCRIBE_TABLE help: | - describe keyspace (<keyspace>)?; + describe keyspace; + describe keyspace <keyspace>; Describes the settings for the current or named keyspace, and the settings for all column families in the keyspace. @@ -126,7 +128,7 @@ commands: Examples: describe keyspace; - describe keyspace system; + describe keyspace Keyspace1; - name: NODE_DESCRIBE_CLUSTER help: | describe cluster; @@ -177,6 +179,22 @@ commands: Examples: show keyspaces; + - name: NODE_SHOW_SCHEMA + help: | + show schema; + show schema <keyspace>; + + Creates a CLI script to create the current, specified or all keyspaces + and their column families. + + Optional Parameters: + - keyspace: Name of the keyspace to create the script for. If omitted + the current keyspace is used, if there is no current keyspace all + keyspaces are considered. + + Examples: + show schema; + show schema Keyspace1; - name: NODE_ADD_KEYSPACE help: | create keyspace <keyspace>; Modified: cassandra/branches/cassandra-0.8/test/unit/org/apache/cassandra/cli/CliTest.java URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/test/unit/org/apache/cassandra/cli/CliTest.java?rev=1155100&r1=1155099&r2=1155100&view=diff ============================================================================== --- cassandra/branches/cassandra-0.8/test/unit/org/apache/cassandra/cli/CliTest.java (original) +++ cassandra/branches/cassandra-0.8/test/unit/org/apache/cassandra/cli/CliTest.java Mon Aug 8 21:08:04 2011 @@ -166,6 +166,7 @@ public class CliTest extends CleanupHelp "help QUIT", "help show cluster name", "help show keyspaces", + "help show schema", "help show api version", "help create keyspace", "HELP update KEYSPACE", @@ -181,7 +182,9 @@ public class CliTest extends CleanupHelp "HELP TRUNCATE", "help assume", "HELP", - "?" + "?", + "show schema", + "show schema TestKeySpace" }; @Test @@ -270,4 +273,4 @@ public class CliTest extends CleanupHelp assertEquals(unescaped, CliUtils.unescapeSQLString("'" + escaped + "'")); assertEquals(escaped, CliUtils.escapeSQLString(unescaped)); } -} \ No newline at end of file +}