You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by ee...@apache.org on 2011/01/27 22:57:20 UTC
svn commit: r1064326 - in /cassandra/trunk:
src/java/org/apache/cassandra/cql/ test/system/
Author: eevans
Date: Thu Jan 27 21:57:20 2011
New Revision: 1064326
URL: http://svn.apache.org/viewvc?rev=1064326&view=rev
Log:
CQL: keyspace creation
Patch by eevans for CASSANDRA-1709
Added:
cassandra/trunk/src/java/org/apache/cassandra/cql/CreateKeyspaceStatement.java
Modified:
cassandra/trunk/src/java/org/apache/cassandra/cql/Cql.g
cassandra/trunk/src/java/org/apache/cassandra/cql/QueryProcessor.java
cassandra/trunk/src/java/org/apache/cassandra/cql/StatementType.java
cassandra/trunk/test/system/test_cql.py
Modified: cassandra/trunk/src/java/org/apache/cassandra/cql/Cql.g
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/cql/Cql.g?rev=1064326&r1=1064325&r2=1064326&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/cql/Cql.g (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/cql/Cql.g Thu Jan 27 21:57:20 2011
@@ -46,6 +46,7 @@ query returns [CQLStatement stmnt]
| useStatement { $stmnt = new CQLStatement(StatementType.USE, $useStatement.keyspace); }
| truncateStatement { $stmnt = new CQLStatement(StatementType.TRUNCATE, $truncateStatement.cfam); }
| deleteStatement { $stmnt = new CQLStatement(StatementType.DELETE, $deleteStatement.expr); }
+ | createKeyspaceStatement { $stmnt = new CQLStatement(StatementType.CREATE_KEYSPACE, $createKeyspaceStatement.expr); }
;
// USE <KEYSPACE>;
@@ -161,6 +162,20 @@ deleteStatement returns [DeleteStatement
}
;
+/** CREATE KEYSPACE <KEYSPACE> WITH attr1 = value1 AND attr2 = value2; */
+createKeyspaceStatement returns [CreateKeyspaceStatement expr]
+ : {
+ Map<String, String> attrs = new HashMap<String, String>();
+ }
+ K_CREATE K_KEYSPACE keyspace=IDENT
+ K_WITH a1=( COMPIDENT | IDENT ) '=' v1=( STRING_LITERAL | INTEGER ) { attrs.put($a1.text, $v1.text); }
+ ( K_AND aN=( COMPIDENT | IDENT ) '=' vN=( STRING_LITERAL | INTEGER ) { attrs.put($aN.text, $vN.text); } )*
+ endStmnt
+ {
+ return new CreateKeyspaceStatement($keyspace.text, attrs);
+ }
+ ;
+
// TODO: date/time, utf8
term returns [Term item]
: ( t=STRING_LITERAL | t=LONG )
@@ -245,6 +260,8 @@ K_BATCH: B A T C H;
K_TRUNCATE: T R U N C A T E;
K_DELETE: D E L E T E;
K_IN: I N;
+K_CREATE: C R E A T E;
+K_KEYSPACE: K E Y S P A C E;
// Case-insensitive alpha characters
fragment A: ('a'|'A');
@@ -304,6 +321,10 @@ IDENT
: LETTER (LETTER | DIGIT | '_')*
;
+COMPIDENT
+ : IDENT ( ':' IDENT)*
+ ;
+
WS
: (' ' | '\t' | '\n' | '\r')+ { $channel = HIDDEN; }
;
Added: cassandra/trunk/src/java/org/apache/cassandra/cql/CreateKeyspaceStatement.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/cql/CreateKeyspaceStatement.java?rev=1064326&view=auto
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/cql/CreateKeyspaceStatement.java (added)
+++ cassandra/trunk/src/java/org/apache/cassandra/cql/CreateKeyspaceStatement.java Thu Jan 27 21:57:20 2011
@@ -0,0 +1,82 @@
+package org.apache.cassandra.cql;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.cassandra.thrift.InvalidRequestException;
+
+/** A <code>CREATE KEYSPACE</code> statement parsed from a CQL query. */
+public class CreateKeyspaceStatement
+{
+ private final String name;
+ private final Map<String, String> attrs;
+ private String strategyClass;
+ private int replicationFactor;
+ private Map<String, String> strategyOptions = new HashMap<String, String>();
+
+ /**
+ * Creates a new <code>CreateKeyspaceStatement</code> instance for a given
+ * keyspace name and keyword arguments.
+ *
+ * @param name the name of the keyspace to create
+ * @param attrs map of the raw keyword arguments that followed the <code>WITH</code> keyword.
+ */
+ public CreateKeyspaceStatement(String name, Map<String, String> attrs)
+ {
+ this.name = name;
+ this.attrs = attrs;
+ }
+
+ /**
+ * The <code>CqlParser</code> only goes as far as extracting the keyword arguments
+ * from these statements, so this method is responsible for processing and
+ * validating, and must be called prior to access.
+ *
+ * @throws InvalidRequestException if arguments are missing or unacceptable
+ */
+ public void validate() throws InvalidRequestException
+ {
+ // required
+ if (!attrs.containsKey("strategy_class"))
+ throw new InvalidRequestException("missing required argument \"strategy_class\"");
+ strategyClass = attrs.get("strategy_class");
+
+ // required
+ if (!attrs.containsKey("replication_factor"))
+ throw new InvalidRequestException("missing required argument \"replication_factor\"");
+
+ try
+ {
+ replicationFactor = Integer.parseInt(attrs.get("replication_factor"));
+ }
+ catch (NumberFormatException e)
+ {
+ throw new InvalidRequestException(String.format("\"%s\" is not valid for replication_factor",
+ attrs.get("replication_factor")));
+ }
+
+ // optional
+ for (String key : attrs.keySet())
+ if ((key.contains(":")) && (key.startsWith("strategy_options")))
+ strategyOptions.put(key.split(":")[1], attrs.get(key));
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public String getStrategyClass()
+ {
+ return strategyClass;
+ }
+
+ public int getReplicationFactor()
+ {
+ return replicationFactor;
+ }
+
+ public Map<String, String> getStrategyOptions()
+ {
+ return strategyOptions;
+ }
+}
Modified: cassandra/trunk/src/java/org/apache/cassandra/cql/QueryProcessor.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/cql/QueryProcessor.java?rev=1064326&r1=1064325&r2=1064326&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/cql/QueryProcessor.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/cql/QueryProcessor.java Thu Jan 27 21:57:20 2011
@@ -24,17 +24,27 @@ package org.apache.cassandra.cql;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeoutException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.antlr.runtime.*;
+import org.apache.cassandra.concurrent.Stage;
+import org.apache.cassandra.concurrent.StageManager;
+import org.apache.cassandra.config.ConfigurationException;
+import org.apache.cassandra.config.KSMetaData;
import org.apache.cassandra.db.*;
import org.apache.cassandra.db.filter.QueryPath;
+import org.apache.cassandra.db.migration.AddKeyspace;
+import org.apache.cassandra.db.migration.Migration;
import org.apache.cassandra.dht.AbstractBounds;
import org.apache.cassandra.dht.Bounds;
import org.apache.cassandra.dht.IPartitioner;
+import org.apache.cassandra.locator.AbstractReplicationStrategy;
import org.apache.cassandra.service.ClientState;
import org.apache.cassandra.service.StorageProxy;
import org.apache.cassandra.service.StorageService;
@@ -267,6 +277,44 @@ public class QueryProcessor
throw new InvalidRequestException("No indexed columns present in by-columns clause with \"equals\" operator");
}
}
+
+ // Copypasta from o.a.c.thrift.CassandraDaemon
+ private static void applyMigrationOnStage(final Migration m) throws InvalidRequestException
+ {
+ Future f = StageManager.getStage(Stage.MIGRATION).submit(new Callable()
+ {
+ public Object call() throws Exception
+ {
+ m.apply();
+ m.announce();
+ return null;
+ }
+ });
+ try
+ {
+ f.get();
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+ catch (ExecutionException e)
+ {
+ // this means call() threw an exception. deal with it directly.
+ if (e.getCause() != null)
+ {
+ InvalidRequestException ex = new InvalidRequestException(e.getCause().getMessage());
+ ex.initCause(e.getCause());
+ throw ex;
+ }
+ else
+ {
+ InvalidRequestException ex = new InvalidRequestException(e.getMessage());
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+ }
public static CqlResult process(String queryString, ClientState clientState)
throws RecognitionException, UnavailableException, InvalidRequestException, TimedOutException
@@ -426,6 +474,35 @@ public class QueryProcessor
avroResult.type = CqlResultType.VOID;
return avroResult;
+
+ case CREATE_KEYSPACE:
+ CreateKeyspaceStatement create = (CreateKeyspaceStatement)statement.statement;
+ create.validate();
+
+ try
+ {
+ KSMetaData ksm = new KSMetaData(create.getName(),
+ AbstractReplicationStrategy.getClass(create.getStrategyClass()),
+ create.getStrategyOptions(),
+ create.getReplicationFactor());
+ applyMigrationOnStage(new AddKeyspace(ksm));
+ }
+ catch (ConfigurationException e)
+ {
+ InvalidRequestException ex = new InvalidRequestException(e.getMessage());
+ ex.initCause(e);
+ throw ex;
+ }
+ catch (IOException e)
+ {
+ InvalidRequestException ex = new InvalidRequestException(e.getMessage());
+ ex.initCause(e);
+ throw ex;
+ }
+
+ avroResult.type = CqlResultType.VOID;
+ return avroResult;
+
}
return null; // We should never get here.
Modified: cassandra/trunk/src/java/org/apache/cassandra/cql/StatementType.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/cql/StatementType.java?rev=1064326&r1=1064325&r2=1064326&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/cql/StatementType.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/cql/StatementType.java Thu Jan 27 21:57:20 2011
@@ -22,5 +22,5 @@ package org.apache.cassandra.cql;
public enum StatementType
{
- SELECT, UPDATE, BATCH_UPDATE, USE, TRUNCATE, DELETE;
+ SELECT, UPDATE, BATCH_UPDATE, USE, TRUNCATE, DELETE, CREATE_KEYSPACE;
}
Modified: cassandra/trunk/test/system/test_cql.py
URL: http://svn.apache.org/viewvc/cassandra/trunk/test/system/test_cql.py?rev=1064326&r1=1064325&r2=1064326&view=diff
==============================================================================
--- cassandra/trunk/test/system/test_cql.py (original)
+++ cassandra/trunk/test/system/test_cql.py Thu Jan 27 21:57:20 2011
@@ -7,6 +7,7 @@ sys.path.append(join(abspath(dirname(__f
from cql import Connection
from cql.errors import CQLException
from . import ThriftTester
+from . import thrift_client # TODO: temporary
def assert_raises(exception, method, *args):
try:
@@ -207,4 +208,19 @@ class TestCql(ThriftTester):
conn.execute('DELETE FROM Standard1 WHERE KEY = "kd"')
r = conn.execute('SELECT "cd1", "col" FROM Standard1 WHERE KEY = "kd"')
assert len(r[0].columns) == 0
+
+ def test_create_keyspace(self):
+ "create a new keyspace"
+ init().execute("""
+ CREATE KEYSPACE TestKeyspace42 WITH strategy_options:DC1 = 1"
+ AND strategy_class = "SimpleStrategy" AND replication_factor = 3
+ """)
+
+ # TODO: temporary (until this can be done with CQL).
+ ksdef = thrift_client.describe_keyspace("TestKeyspace42")
+
+ assert ksdef.replication_factor == 3
+ strategy_class = "org.apache.cassandra.locator.SimpleStrategy"
+ assert ksdef.strategy_class == strategy_class
+ assert ksdef.strategy_options['DC1'] == "1"