You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by ty...@apache.org on 2014/08/21 21:29:38 UTC
[1/5] git commit: Don't send schema change msg for no-op DDL stmts
Repository: cassandra
Updated Branches:
refs/heads/trunk df9cac094 -> e60d9f43d
Don't send schema change msg for no-op DDL stmts
Patch by Tyler Hobbs; review by Mikhail Stepura for CASSANDRA-7600
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/e4d5edae
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/e4d5edae
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/e4d5edae
Branch: refs/heads/trunk
Commit: e4d5edae72838533445efadc001d2b6b656fd0ce
Parents: fe39eb7
Author: Tyler Hobbs <ty...@datastax.com>
Authored: Thu Aug 21 14:18:40 2014 -0500
Committer: Tyler Hobbs <ty...@datastax.com>
Committed: Thu Aug 21 14:20:15 2014 -0500
----------------------------------------------------------------------
CHANGES.txt | 2 ++
.../cql3/statements/AlterKeyspaceStatement.java | 3 ++-
.../cql3/statements/AlterTableStatement.java | 3 ++-
.../cql3/statements/CreateIndexStatement.java | 5 +++--
.../cql3/statements/CreateKeyspaceStatement.java | 8 +++++---
.../cql3/statements/CreateTableStatement.java | 10 ++++++----
.../cql3/statements/CreateTriggerStatement.java | 3 ++-
.../cql3/statements/DropIndexStatement.java | 5 +++--
.../cql3/statements/DropKeyspaceStatement.java | 8 +++++---
.../cql3/statements/DropTableStatement.java | 8 +++++---
.../cql3/statements/DropTriggerStatement.java | 3 ++-
.../cql3/statements/SchemaAlteringStatement.java | 15 +++++++++++++--
12 files changed, 50 insertions(+), 23 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 71cfca0..9aeeb29 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,6 @@
2.0.10
+ * Don't send schema change responses and events for no-op DDL
+ statements (CASSANDRA-7600)
* (Hadoop) fix cluster initialisation for a split fetching (CASSANDRA-7774)
* Configure system.paxos with LeveledCompactionStrategy (CASSANDRA-7753)
* Fix ALTER clustering column type from DateType to TimestampType when
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java b/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
index 39d1cde..4f6d1f2 100644
--- a/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
@@ -79,7 +79,7 @@ public class AlterKeyspaceStatement extends SchemaAlteringStatement
}
}
- public void announceMigration() throws RequestValidationException
+ public boolean announceMigration() throws RequestValidationException
{
KSMetaData ksm = Schema.instance.getKSMetaData(name);
// In the (very) unlikely case the keyspace was dropped since validate()
@@ -87,6 +87,7 @@ public class AlterKeyspaceStatement extends SchemaAlteringStatement
throw new InvalidRequestException("Unknown keyspace " + name);
MigrationManager.announceKeyspaceUpdate(attrs.asKSMetadataUpdate(ksm));
+ return true;
}
public ResultMessage.SchemaChange.Change changeType()
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java b/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
index 136c430..dfcd601 100644
--- a/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
@@ -76,7 +76,7 @@ public class AlterTableStatement extends SchemaAlteringStatement
// validated in announceMigration()
}
- public void announceMigration() throws RequestValidationException
+ public boolean announceMigration() throws RequestValidationException
{
CFMetaData meta = validateColumnFamily(keyspace(), columnFamily());
CFMetaData cfm = meta.clone();
@@ -266,6 +266,7 @@ public class AlterTableStatement extends SchemaAlteringStatement
}
MigrationManager.announceColumnFamilyUpdate(cfm, false);
+ return true;
}
public String toString()
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
index 376fa4a..8b40978 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
@@ -103,14 +103,14 @@ public class CreateIndexStatement extends SchemaAlteringStatement
throw new InvalidRequestException(String.format("Cannot add secondary index to already primarily indexed column %s", columnName));
}
- public void announceMigration() throws RequestValidationException
+ public boolean announceMigration() throws RequestValidationException
{
logger.debug("Updating column {} definition for index {}", columnName, indexName);
CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).clone();
ColumnDefinition cd = cfm.getColumnDefinition(columnName.key);
if (cd.getIndexType() != null && ifNotExists)
- return;
+ return false;
if (properties.isCustom)
cd.setIndexType(IndexType.CUSTOM, properties.getOptions());
@@ -122,6 +122,7 @@ public class CreateIndexStatement extends SchemaAlteringStatement
cd.setIndexName(indexName);
cfm.addDefaultIndexNames();
MigrationManager.announceColumnFamilyUpdate(cfm, false);
+ return true;
}
public ResultMessage.SchemaChange.Change changeType()
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
index 2ed1d91..7a8473a 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
@@ -97,16 +97,18 @@ public class CreateKeyspaceStatement extends SchemaAlteringStatement
attrs.getReplicationOptions());
}
- public void announceMigration() throws RequestValidationException
+ public boolean announceMigration() throws RequestValidationException
{
try
{
MigrationManager.announceNewKeyspace(attrs.asKSMetadata(name));
+ return true;
}
catch (AlreadyExistsException e)
{
- if (!ifNotExists)
- throw e;
+ if (ifNotExists)
+ return false;
+ throw e;
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
index 08ad069..b7f43d3 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
@@ -114,16 +114,18 @@ public class CreateTableStatement extends SchemaAlteringStatement
return columnDefs;
}
- public void announceMigration() throws RequestValidationException
+ public boolean announceMigration() throws RequestValidationException
{
try
{
- MigrationManager.announceNewColumnFamily(getCFMetaData());
+ MigrationManager.announceNewColumnFamily(getCFMetaData());
+ return true;
}
catch (AlreadyExistsException e)
{
- if (!ifNotExists)
- throw e;
+ if (ifNotExists)
+ return false;
+ throw e;
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
index 760d870..70b3acb 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
@@ -65,12 +65,13 @@ public class CreateTriggerStatement extends SchemaAlteringStatement
}
}
- public void announceMigration() throws ConfigurationException
+ public boolean announceMigration() throws ConfigurationException
{
CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).clone();
cfm.addTriggerDefinition(TriggerDefinition.create(triggerName, triggerClass));
logger.info("Adding trigger with name {} and class {}", triggerName, triggerClass);
MigrationManager.announceColumnFamilyUpdate(cfm, false);
+ return true;
}
public ResultMessage.SchemaChange.Change changeType()
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java b/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
index c62ad47..ac5262e 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
@@ -60,14 +60,15 @@ public class DropIndexStatement extends SchemaAlteringStatement
return ResultMessage.SchemaChange.Change.UPDATED;
}
- public void announceMigration() throws InvalidRequestException, ConfigurationException
+ public boolean announceMigration() throws InvalidRequestException, ConfigurationException
{
CFMetaData cfm = findIndexedCF();
if (cfm == null)
- return;
+ return false;
CFMetaData updatedCfm = updateCFMetadata(cfm);
MigrationManager.announceColumnFamilyUpdate(updatedCfm, false);
+ return true;
}
private CFMetaData updateCFMetadata(CFMetaData cfm)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java b/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
index 30fd964..7582af0 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
@@ -55,16 +55,18 @@ public class DropKeyspaceStatement extends SchemaAlteringStatement
return keyspace;
}
- public void announceMigration() throws ConfigurationException
+ public boolean announceMigration() throws ConfigurationException
{
try
{
MigrationManager.announceKeyspaceDrop(keyspace);
+ return true;
}
catch(ConfigurationException e)
{
- if (!ifExists)
- throw e;
+ if (ifExists)
+ return false;
+ throw e;
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java b/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
index d27261c..65a3f14 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
@@ -54,16 +54,18 @@ public class DropTableStatement extends SchemaAlteringStatement
// validated in announceMigration()
}
- public void announceMigration() throws ConfigurationException
+ public boolean announceMigration() throws ConfigurationException
{
try
{
MigrationManager.announceColumnFamilyDrop(keyspace(), columnFamily());
+ return true;
}
catch (ConfigurationException e)
{
- if (!ifExists)
- throw e;
+ if (ifExists)
+ return false;
+ throw e;
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java b/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
index ce17047..f0bd637 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
@@ -53,13 +53,14 @@ public class DropTriggerStatement extends SchemaAlteringStatement
ThriftValidation.validateColumnFamily(keyspace(), columnFamily());
}
- public void announceMigration() throws ConfigurationException
+ public boolean announceMigration() throws ConfigurationException
{
CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).clone();
if (!cfm.removeTrigger(triggerName))
throw new ConfigurationException(String.format("Trigger %s was not found", triggerName));
logger.info("Dropping trigger with name {}", triggerName);
MigrationManager.announceColumnFamilyUpdate(cfm, false);
+ return true;
}
public ResultMessage.SchemaChange.Change changeType()
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java b/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
index 94df854..845d8cc 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
@@ -64,11 +64,22 @@ public abstract class SchemaAlteringStatement extends CFStatement implements CQL
public abstract ResultMessage.SchemaChange.Change changeType();
- public abstract void announceMigration() throws RequestValidationException;
+ /**
+ * Announces the migration to other nodes in the cluster.
+ * @return true if the execution of this statement resulted in a schema change, false otherwise (when IF NOT EXISTS
+ * is used, for example)
+ * @throws RequestValidationException
+ */
+ public abstract boolean announceMigration() throws RequestValidationException;
public ResultMessage execute(QueryState state, QueryOptions options) throws RequestValidationException
{
- announceMigration();
+ // If an IF [NOT] EXISTS clause was used, this may not result in an actual schema change. To avoid doing
+ // extra work in the drivers to handle schema changes, we return an empty message in this case. (CASSANDRA-7600)
+ boolean didChangeSchema = announceMigration();
+ if (!didChangeSchema)
+ return new ResultMessage.Void();
+
String tableName = cfName == null || columnFamily() == null ? "" : columnFamily();
return new ResultMessage.SchemaChange(changeType(), keyspace(), tableName);
}
[5/5] git commit: Merge branch 'cassandra-2.1' into trunk
Posted by ty...@apache.org.
Merge branch 'cassandra-2.1' into trunk
Conflicts:
src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/e60d9f43
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/e60d9f43
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/e60d9f43
Branch: refs/heads/trunk
Commit: e60d9f43d9e8ea06ddbc0c532cc89ea1348992f5
Parents: df9cac0 edbd7d3
Author: Tyler Hobbs <ty...@datastax.com>
Authored: Thu Aug 21 14:29:28 2014 -0500
Committer: Tyler Hobbs <ty...@datastax.com>
Committed: Thu Aug 21 14:29:28 2014 -0500
----------------------------------------------------------------------
CHANGES.txt | 2 ++
.../cql3/statements/AlterKeyspaceStatement.java | 3 ++-
.../cql3/statements/AlterTableStatement.java | 3 ++-
.../cql3/statements/AlterTypeStatement.java | 3 ++-
.../statements/CreateFunctionStatement.java | 3 ++-
.../cql3/statements/CreateIndexStatement.java | 5 +++--
.../statements/CreateKeyspaceStatement.java | 8 +++++---
.../cql3/statements/CreateTableStatement.java | 10 ++++++----
.../cql3/statements/CreateTriggerStatement.java | 3 ++-
.../cql3/statements/CreateTypeStatement.java | 5 +++--
.../cql3/statements/DropFunctionStatement.java | 8 +++++---
.../cql3/statements/DropIndexStatement.java | 5 +++--
.../cql3/statements/DropKeyspaceStatement.java | 8 +++++---
.../cql3/statements/DropTableStatement.java | 8 +++++---
.../cql3/statements/DropTriggerStatement.java | 3 ++-
.../cql3/statements/DropTypeStatement.java | 9 ++++++---
.../statements/SchemaAlteringStatement.java | 20 +++++++++++++++++---
17 files changed, 72 insertions(+), 34 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e60d9f43/CHANGES.txt
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e60d9f43/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e60d9f43/src/java/org/apache/cassandra/cql3/statements/CreateFunctionStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CreateFunctionStatement.java
index 094c318,0000000..47bacd2
mode 100644,000000..100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateFunctionStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateFunctionStatement.java
@@@ -1,180 -1,0 +1,181 @@@
+/*
+ * 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.cql3.statements;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.config.Schema;
+import org.apache.cassandra.config.UFMetaData;
+import org.apache.cassandra.cql3.CQL3Type;
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.functions.Functions;
+import org.apache.cassandra.cql3.udf.UDFRegistry;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.exceptions.RequestValidationException;
+import org.apache.cassandra.exceptions.UnauthorizedException;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.MigrationManager;
+import org.apache.cassandra.service.QueryState;
+import org.apache.cassandra.transport.Event;
+import org.apache.cassandra.transport.messages.ResultMessage;
+
+/**
+ * A <code>CREATE FUNCTION</code> statement parsed from a CQL query.
+ */
+public final class CreateFunctionStatement extends SchemaAlteringStatement
+{
+ final boolean orReplace;
+ final boolean ifNotExists;
+ final String namespace;
+ final String functionName;
+ final String qualifiedName;
+ final String language;
+ final String body;
+ final boolean deterministic;
+ final CQL3Type.Raw returnType;
+ final List<Argument> arguments;
+
+ private UFMetaData ufMeta;
+
+ public CreateFunctionStatement(String namespace, String functionName, String language, String body, boolean deterministic,
+ CQL3Type.Raw returnType, List<Argument> arguments, boolean orReplace, boolean ifNotExists)
+ {
+ super();
+ this.namespace = namespace != null ? namespace : "";
+ this.functionName = functionName;
+ this.qualifiedName = UFMetaData.qualifiedName(namespace, functionName);
+ this.language = language;
+ this.body = body;
+ this.deterministic = deterministic;
+ this.returnType = returnType;
+ this.arguments = arguments;
+ assert functionName != null : "null function name";
+ assert language != null : "null function language";
+ assert body != null : "null function body";
+ assert returnType != null : "null function returnType";
+ assert arguments != null : "null function arguments";
+ this.orReplace = orReplace;
+ this.ifNotExists = ifNotExists;
+ }
+
+ public void checkAccess(ClientState state) throws UnauthorizedException
+ {
+ // TODO CASSANDRA-7557 (function DDL permission)
+
+ state.hasAllKeyspacesAccess(Permission.CREATE);
+ }
+
+ /**
+ * 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.
+ *
+ * @throws org.apache.cassandra.exceptions.InvalidRequestException if arguments are missing or unacceptable
+ */
+ public void validate(ClientState state) throws RequestValidationException
+ {
+ if (!namespace.isEmpty() && !namespace.matches("\\w+"))
+ throw new InvalidRequestException(String.format("\"%s\" is not a valid function name", qualifiedName));
+ if (!functionName.matches("\\w+"))
+ throw new InvalidRequestException(String.format("\"%s\" is not a valid function name", qualifiedName));
+ if (namespace.length() > Schema.NAME_LENGTH)
+ throw new InvalidRequestException(String.format("UDF namespace names shouldn't be more than %s characters long (got \"%s\")", Schema.NAME_LENGTH, qualifiedName));
+ if (functionName.length() > Schema.NAME_LENGTH)
+ throw new InvalidRequestException(String.format("UDF function names shouldn't be more than %s characters long (got \"%s\")", Schema.NAME_LENGTH, qualifiedName));
+ }
+
+ public Event.SchemaChange changeEvent()
+ {
+ return null;
+ }
+
+ public ResultMessage executeInternal(QueryState state, QueryOptions options)
+ {
+ try
+ {
+ doExecute();
+ return super.executeInternal(state, options);
+ }
+ catch (RequestValidationException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public ResultMessage execute(QueryState state, QueryOptions options) throws RequestValidationException
+ {
+ doExecute();
+ return super.execute(state, options);
+ }
+
+ private void doExecute() throws RequestValidationException
+ {
+ boolean exists = UDFRegistry.hasFunction(qualifiedName);
+ if (exists && ifNotExists)
+ throw new InvalidRequestException(String.format("Function '%s' already exists.", qualifiedName));
+ if (exists && !orReplace)
+ throw new InvalidRequestException(String.format("Function '%s' already exists.", qualifiedName));
+
+ if (namespace.isEmpty() && Functions.contains(functionName))
+ throw new InvalidRequestException(String.format("Function name '%s' is reserved by CQL.", qualifiedName));
+
+ List<Argument> args = arguments;
+ List<String> argumentNames = new ArrayList<>(args.size());
+ List<String> argumentTypes = new ArrayList<>(args.size());
+ for (Argument arg : args)
+ {
+ argumentNames.add(arg.getName().toString());
+ argumentTypes.add(arg.getType().toString());
+ }
+ this.ufMeta = new UFMetaData(namespace, functionName, deterministic, argumentNames, argumentTypes,
+ returnType.toString(), language, body);
+
+ UDFRegistry.tryCreateFunction(ufMeta);
+ }
+
- public void announceMigration(boolean isLocalOnly) throws RequestValidationException
++ public boolean announceMigration(boolean isLocalOnly) throws RequestValidationException
+ {
+ MigrationManager.announceNewFunction(ufMeta, isLocalOnly);
++ return true;
+ }
+
+ public static final class Argument
+ {
+ final ColumnIdentifier name;
+ final CQL3Type.Raw type;
+
+ public Argument(ColumnIdentifier name, CQL3Type.Raw type)
+ {
+ this.name = name;
+ this.type = type;
+ }
+
+ public ColumnIdentifier getName()
+ {
+ return name;
+ }
+
+ public CQL3Type.Raw getType()
+ {
+ return type;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e60d9f43/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e60d9f43/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
index 7627ab4,0000000..159f385
mode 100644,000000..100644
--- a/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
@@@ -1,94 -1,0 +1,96 @@@
+/*
+ * 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.cql3.statements;
+
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.config.Schema;
+import org.apache.cassandra.config.UFMetaData;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.exceptions.RequestValidationException;
+import org.apache.cassandra.exceptions.UnauthorizedException;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.MigrationManager;
+import org.apache.cassandra.transport.Event;
+
+/**
+ * A <code>DROP FUNCTION</code> statement parsed from a CQL query.
+ */
+public final class DropFunctionStatement extends SchemaAlteringStatement
+{
+ private final String namespace;
+ private final String functionName;
+ private final String qualifiedName;
+ private final boolean ifExists;
+
+ public DropFunctionStatement(String namespace, String functionName, boolean ifExists)
+ {
+ super();
+ this.namespace = namespace == null ? "" : namespace;
+ this.functionName = functionName;
+ this.qualifiedName = UFMetaData.qualifiedName(namespace, functionName);
+ this.ifExists = ifExists;
+ }
+
+ public void checkAccess(ClientState state) throws UnauthorizedException
+ {
+ // TODO CASSANDRA-7557 (function DDL permission)
+
+ state.hasAllKeyspacesAccess(Permission.DROP);
+ }
+
+ /**
+ * 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.
+ *
+ * @throws org.apache.cassandra.exceptions.InvalidRequestException if arguments are missing or unacceptable
+ */
+ public void validate(ClientState state) throws RequestValidationException
+ {
+ if (!namespace.isEmpty() && !namespace.matches("\\w+"))
+ throw new InvalidRequestException(String.format("\"%s\" is not a valid function name", qualifiedName));
+ if (!functionName.matches("\\w+"))
+ throw new InvalidRequestException(String.format("\"%s\" is not a valid function name", qualifiedName));
+ if (namespace.length() > Schema.NAME_LENGTH)
+ throw new InvalidRequestException(String.format("UDF namespace names shouldn't be more than %s characters long (got \"%s\")", Schema.NAME_LENGTH, qualifiedName));
+ if (functionName.length() > Schema.NAME_LENGTH)
+ throw new InvalidRequestException(String.format("UDF function names shouldn't be more than %s characters long (got \"%s\")", Schema.NAME_LENGTH, qualifiedName));
+ }
+
+ public Event.SchemaChange changeEvent()
+ {
+ return null;
+ }
+
+ // no execute() - drop propagated via MigrationManager
+
- public void announceMigration(boolean isLocalOnly) throws RequestValidationException
++ public boolean announceMigration(boolean isLocalOnly) throws RequestValidationException
+ {
+ try
+ {
+ MigrationManager.announceFunctionDrop(namespace, functionName, isLocalOnly);
++ return true;
+ }
+ catch (InvalidRequestException e)
+ {
- if (!ifExists)
- throw e;
++ if (ifExists)
++ return false;
++ throw e;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e60d9f43/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
index 876568a,8882871..018d244
--- a/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
@@@ -69,18 -75,18 +75,26 @@@ public abstract class SchemaAlteringSta
public ResultMessage execute(QueryState state, QueryOptions options) throws RequestValidationException
{
- announceMigration(false);
+ // If an IF [NOT] EXISTS clause was used, this may not result in an actual schema change. To avoid doing
+ // extra work in the drivers to handle schema changes, we return an empty message in this case. (CASSANDRA-7600)
+ boolean didChangeSchema = announceMigration(false);
- return didChangeSchema ? new ResultMessage.SchemaChange(changeEvent()) : new ResultMessage.Void();
++ if (!didChangeSchema)
++ return new ResultMessage.Void();
++
+ Event.SchemaChange ce = changeEvent();
+ return ce == null ? new ResultMessage.Void() : new ResultMessage.SchemaChange(ce);
}
public ResultMessage executeInternal(QueryState state, QueryOptions options)
{
try
{
- announceMigration(true);
+ boolean didChangeSchema = announceMigration(true);
- return didChangeSchema ? new ResultMessage.SchemaChange(changeEvent()) : new ResultMessage.Void();
++ if (!didChangeSchema)
++ return new ResultMessage.Void();
++
+ Event.SchemaChange ce = changeEvent();
+ return ce == null ? new ResultMessage.Void() : new ResultMessage.SchemaChange(ce);
}
catch (RequestValidationException e)
{
[2/5] git commit: Merge branch 'cassandra-2.0' into cassandra-2.1.0
Posted by ty...@apache.org.
Merge branch 'cassandra-2.0' into cassandra-2.1.0
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/a0923dbc
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/a0923dbc
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/a0923dbc
Branch: refs/heads/trunk
Commit: a0923dbc0461352cc2f735dee8260b68f015063c
Parents: a41d527 e4d5eda
Author: Tyler Hobbs <ty...@datastax.com>
Authored: Thu Aug 21 14:20:49 2014 -0500
Committer: Tyler Hobbs <ty...@datastax.com>
Committed: Thu Aug 21 14:20:49 2014 -0500
----------------------------------------------------------------------
----------------------------------------------------------------------
[3/5] git commit: Merge branch 'cassandra-2.0' into cassandra-2.1
Posted by ty...@apache.org.
Merge branch 'cassandra-2.0' into cassandra-2.1
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/664efd41
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/664efd41
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/664efd41
Branch: refs/heads/trunk
Commit: 664efd41b037d17a7e2c991a9ad660c5d2ec2ce5
Parents: d088f02 e4d5eda
Author: Tyler Hobbs <ty...@datastax.com>
Authored: Thu Aug 21 14:23:07 2014 -0500
Committer: Tyler Hobbs <ty...@datastax.com>
Committed: Thu Aug 21 14:23:07 2014 -0500
----------------------------------------------------------------------
CHANGES.txt | 2 ++
.../cql3/statements/AlterKeyspaceStatement.java | 3 ++-
.../cql3/statements/AlterTableStatement.java | 3 ++-
.../cql3/statements/AlterTypeStatement.java | 3 ++-
.../cql3/statements/CreateIndexStatement.java | 5 +++--
.../cql3/statements/CreateKeyspaceStatement.java | 8 +++++---
.../cql3/statements/CreateTableStatement.java | 10 ++++++----
.../cql3/statements/CreateTriggerStatement.java | 3 ++-
.../cql3/statements/CreateTypeStatement.java | 5 +++--
.../cql3/statements/DropIndexStatement.java | 5 +++--
.../cql3/statements/DropKeyspaceStatement.java | 8 +++++---
.../cql3/statements/DropTableStatement.java | 8 +++++---
.../cql3/statements/DropTriggerStatement.java | 3 ++-
.../cql3/statements/DropTypeStatement.java | 9 ++++++---
.../cql3/statements/SchemaAlteringStatement.java | 18 +++++++++++++-----
15 files changed, 61 insertions(+), 32 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index 701fd38,9aeeb29..80eb279
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,52 -1,7 +1,54 @@@
-2.0.10
+2.1.1
+ * (cqlsh) Order UDTs according to cross-type dependencies in DESCRIBE
+ output (CASSANDRA-7659)
+ * (cqlsh) Fix handling of CAS statement results (CASSANDRA-7671)
+ * (cqlsh) COPY TO/FROM improvements (CASSANDRA-7405)
+ * Support list index operations with conditions (CASSANDRA-7499)
+ * Add max live/tombstoned cells to nodetool cfstats output (CASSANDRA-7731)
+ * Validate IPv6 wildcard addresses properly (CASSANDRA-7680)
+ * (cqlsh) Error when tracing query (CASSANDRA-7613)
+ * Avoid IOOBE when building SyntaxError message snippet (CASSANDRA-7569)
+ * SSTableExport uses correct validator to create string representation of partition
+ keys (CASSANDRA-7498)
+ * Avoid NPEs when receiving type changes for an unknown keyspace (CASSANDRA-7689)
+ * Add support for custom 2i validation (CASSANDRA-7575)
+ * Pig support for hadoop CqlInputFormat (CASSANDRA-6454)
+ * Add listen_interface and rpc_interface options (CASSANDRA-7417)
+ * Improve schema merge performance (CASSANDRA-7444)
+ * Adjust MT depth based on # of partition validating (CASSANDRA-5263)
+ * Optimise NativeCell comparisons (CASSANDRA-6755)
+ * Configurable client timeout for cqlsh (CASSANDRA-7516)
+ * Include snippet of CQL query near syntax error in messages (CASSANDRA-7111)
+Merged from 2.0:
+ * Don't send schema change responses and events for no-op DDL
+ statements (CASSANDRA-7600)
* (Hadoop) fix cluster initialisation for a split fetching (CASSANDRA-7774)
+ * Throw InvalidRequestException when queries contain relations on entire
+ collection columns (CASSANDRA-7506)
+ * (cqlsh) enable CTRL-R history search with libedit (CASSANDRA-7577)
+ * (Hadoop) allow ACFRW to limit nodes to local DC (CASSANDRA-7252)
+ * (cqlsh) cqlsh should automatically disable tracing when selecting
+ from system_traces (CASSANDRA-7641)
+ * (Hadoop) Add CqlOutputFormat (CASSANDRA-6927)
+ * Don't depend on cassandra config for nodetool ring (CASSANDRA-7508)
+ * (cqlsh) Fix failing cqlsh formatting tests (CASSANDRA-7703)
+ * Fix IncompatibleClassChangeError from hadoop2 (CASSANDRA-7229)
+ * Add 'nodetool sethintedhandoffthrottlekb' (CASSANDRA-7635)
+ * (cqlsh) Add tab-completion for CREATE/DROP USER IF [NOT] EXISTS (CASSANDRA-7611)
+ * Catch errors when the JVM pulls the rug out from GCInspector (CASSANDRA-5345)
+ * cqlsh fails when version number parts are not int (CASSANDRA-7524)
+Merged from 1.2:
+ * Improve PasswordAuthenticator default super user setup (CASSANDRA-7788)
+
+
+2.1.0
+ * Correctly remove tmplink files (CASSANDRA-7803)
+ * (cqlsh) Fix column name formatting for functions, CAS operations,
+ and UDT field selections (CASSANDRA-7806)
+ * (cqlsh) Fix COPY FROM handling of null/empty primary key
+ values (CASSANDRA-7792)
+ * Fix ordering of static cells (CASSANDRA-7763)
+Merged from 2.0:
* Configure system.paxos with LeveledCompactionStrategy (CASSANDRA-7753)
* Fix ALTER clustering column type from DateType to TimestampType when
using DESC clustering order (CASSANRDA-7797)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
index 27cda49,4f6d1f2..e65a51e
--- a/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
@@@ -79,18 -79,19 +79,19 @@@ public class AlterKeyspaceStatement ext
}
}
- public void announceMigration(boolean isLocalOnly) throws RequestValidationException
- public boolean announceMigration() throws RequestValidationException
++ public boolean announceMigration(boolean isLocalOnly) throws RequestValidationException
{
KSMetaData ksm = Schema.instance.getKSMetaData(name);
// In the (very) unlikely case the keyspace was dropped since validate()
if (ksm == null)
throw new InvalidRequestException("Unknown keyspace " + name);
- MigrationManager.announceKeyspaceUpdate(attrs.asKSMetadataUpdate(ksm));
+ MigrationManager.announceKeyspaceUpdate(attrs.asKSMetadataUpdate(ksm), isLocalOnly);
+ return true;
}
- public ResultMessage.SchemaChange.Change changeType()
+ public Event.SchemaChange changeEvent()
{
- return ResultMessage.SchemaChange.Change.UPDATED;
+ return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, keyspace());
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
index be28943,dfcd601..3005ac7
--- a/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
@@@ -74,14 -76,13 +74,14 @@@ public class AlterTableStatement extend
// validated in announceMigration()
}
- public void announceMigration(boolean isLocalOnly) throws RequestValidationException
- public boolean announceMigration() throws RequestValidationException
++ public boolean announceMigration(boolean isLocalOnly) throws RequestValidationException
{
CFMetaData meta = validateColumnFamily(keyspace(), columnFamily());
- CFMetaData cfm = meta.clone();
+ CFMetaData cfm = meta.copy();
- CFDefinition cfDef = meta.getCfDef();
- CFDefinition.Name name = columnName == null ? null : cfDef.get(columnName);
+ CQL3Type validator = this.validator == null ? null : this.validator.prepare(keyspace());
+
+ ColumnDefinition def = columnName == null ? null : cfm.getColumnDefinition(columnName);
switch (oType)
{
case ADD:
@@@ -256,7 -265,8 +256,8 @@@
break;
}
- MigrationManager.announceColumnFamilyUpdate(cfm, false);
+ MigrationManager.announceColumnFamilyUpdate(cfm, false, isLocalOnly);
+ return true;
}
public String toString()
http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
index 94f7c87,0000000..cfdd65f
mode 100644,000000..100644
--- a/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
@@@ -1,343 -1,0 +1,344 @@@
+/*
+ * 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.cql3.statements;
+
+import java.nio.ByteBuffer;
+import java.util.*;
+
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.config.*;
+import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.db.composites.CellNames;
+import org.apache.cassandra.db.marshal.*;
+import org.apache.cassandra.exceptions.*;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.MigrationManager;
+import org.apache.cassandra.transport.Event;
+
+public abstract class AlterTypeStatement extends SchemaAlteringStatement
+{
+ protected final UTName name;
+
+ protected AlterTypeStatement(UTName name)
+ {
+ super();
+ this.name = name;
+ }
+
+ @Override
+ public void prepareKeyspace(ClientState state) throws InvalidRequestException
+ {
+ if (!name.hasKeyspace())
+ name.setKeyspace(state.getKeyspace());
+
+ if (name.getKeyspace() == null)
+ throw new InvalidRequestException("You need to be logged in a keyspace or use a fully qualified user type name");
+ }
+
+ protected abstract UserType makeUpdatedType(UserType toUpdate) throws InvalidRequestException;
+
+ public static AlterTypeStatement addition(UTName name, ColumnIdentifier fieldName, CQL3Type.Raw type)
+ {
+ return new AddOrAlter(name, true, fieldName, type);
+ }
+
+ public static AlterTypeStatement alter(UTName name, ColumnIdentifier fieldName, CQL3Type.Raw type)
+ {
+ return new AddOrAlter(name, false, fieldName, type);
+ }
+
+ public static AlterTypeStatement renames(UTName name, Map<ColumnIdentifier, ColumnIdentifier> renames)
+ {
+ return new Renames(name, renames);
+ }
+
+ public void checkAccess(ClientState state) throws UnauthorizedException, InvalidRequestException
+ {
+ state.hasKeyspaceAccess(keyspace(), Permission.ALTER);
+ }
+
+ public void validate(ClientState state) throws RequestValidationException
+ {
+ // Validation is left to announceMigration as it's easier to do it while constructing the updated type.
+ // It doesn't really change anything anyway.
+ }
+
+ public Event.SchemaChange changeEvent()
+ {
+ return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, Event.SchemaChange.Target.TYPE, keyspace(), name.getStringTypeName());
+ }
+
+ @Override
+ public String keyspace()
+ {
+ return name.getKeyspace();
+ }
+
- public void announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
++ public boolean announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
+ {
+ KSMetaData ksm = Schema.instance.getKSMetaData(name.getKeyspace());
+ if (ksm == null)
+ throw new InvalidRequestException(String.format("Cannot alter type in unknown keyspace %s", name.getKeyspace()));
+
+ UserType toUpdate = ksm.userTypes.getType(name.getUserTypeName());
+ // Shouldn't happen, unless we race with a drop
+ if (toUpdate == null)
+ throw new InvalidRequestException(String.format("No user type named %s exists.", name));
+
+ UserType updated = makeUpdatedType(toUpdate);
+
+ // Now, we need to announce the type update to basically change it for new tables using this type,
+ // but we also need to find all existing user types and CF using it and change them.
+ MigrationManager.announceTypeUpdate(updated, isLocalOnly);
+
+ for (KSMetaData ksm2 : Schema.instance.getKeyspaceDefinitions())
+ {
+ for (CFMetaData cfm : ksm2.cfMetaData().values())
+ {
+ CFMetaData copy = cfm.copy();
+ boolean modified = false;
+ for (ColumnDefinition def : copy.allColumns())
+ modified |= updateDefinition(copy, def, toUpdate.keyspace, toUpdate.name, updated);
+ if (modified)
+ MigrationManager.announceColumnFamilyUpdate(copy, false, isLocalOnly);
+ }
+
+ // Other user types potentially using the updated type
+ for (UserType ut : ksm2.userTypes.getAllTypes().values())
+ {
+ // Re-updating the type we've just updated would be harmless but useless so we avoid it.
+ // Besides, we use the occasion to drop the old version of the type if it's a type rename
+ if (ut.keyspace.equals(toUpdate.keyspace) && ut.name.equals(toUpdate.name))
+ {
+ if (!ut.keyspace.equals(updated.keyspace) || !ut.name.equals(updated.name))
+ MigrationManager.announceTypeDrop(ut);
+ continue;
+ }
+ AbstractType<?> upd = updateWith(ut, toUpdate.keyspace, toUpdate.name, updated);
+ if (upd != null)
+ MigrationManager.announceTypeUpdate((UserType)upd, isLocalOnly);
+ }
+ }
++ return true;
+ }
+
+ private static int getIdxOfField(UserType type, ColumnIdentifier field)
+ {
+ for (int i = 0; i < type.size(); i++)
+ if (field.bytes.equals(type.fieldName(i)))
+ return i;
+ return -1;
+ }
+
+ private boolean updateDefinition(CFMetaData cfm, ColumnDefinition def, String keyspace, ByteBuffer toReplace, UserType updated)
+ {
+ AbstractType<?> t = updateWith(def.type, keyspace, toReplace, updated);
+ if (t == null)
+ return false;
+
+ // We need to update this validator ...
+ cfm.addOrReplaceColumnDefinition(def.withNewType(t));
+
+ // ... but if it's part of the comparator or key validator, we need to go update those too.
+ switch (def.kind)
+ {
+ case PARTITION_KEY:
+ cfm.keyValidator(updateWith(cfm.getKeyValidator(), keyspace, toReplace, updated));
+ break;
+ case CLUSTERING_COLUMN:
+ cfm.comparator = CellNames.fromAbstractType(updateWith(cfm.comparator.asAbstractType(), keyspace, toReplace, updated), cfm.comparator.isDense());
+ break;
+ default:
+ // If it's a collection, we still want to modify the comparator because the collection is aliased in it
+ if (def.type instanceof CollectionType)
+ cfm.comparator = CellNames.fromAbstractType(updateWith(cfm.comparator.asAbstractType(), keyspace, toReplace, updated), cfm.comparator.isDense());
+ }
+ return true;
+ }
+
+ // Update the provided type were all instance of a given userType is replaced by a new version
+ // Note that this methods reaches inside other UserType, CompositeType and CollectionType.
+ private static AbstractType<?> updateWith(AbstractType<?> type, String keyspace, ByteBuffer toReplace, UserType updated)
+ {
+ if (type instanceof UserType)
+ {
+ UserType ut = (UserType)type;
+
+ // If it's directly the type we've updated, then just use the new one.
+ if (keyspace.equals(ut.keyspace) && toReplace.equals(ut.name))
+ return updated;
+
+ // Otherwise, check for nesting
+ List<AbstractType<?>> updatedTypes = updateTypes(ut.fieldTypes(), keyspace, toReplace, updated);
+ return updatedTypes == null ? null : new UserType(ut.keyspace, ut.name, new ArrayList<>(ut.fieldNames()), updatedTypes);
+ }
+ else if (type instanceof CompositeType)
+ {
+ CompositeType ct = (CompositeType)type;
+ List<AbstractType<?>> updatedTypes = updateTypes(ct.types, keyspace, toReplace, updated);
+ return updatedTypes == null ? null : CompositeType.getInstance(updatedTypes);
+ }
+ else if (type instanceof ColumnToCollectionType)
+ {
+ ColumnToCollectionType ctct = (ColumnToCollectionType)type;
+ Map<ByteBuffer, CollectionType> updatedTypes = null;
+ for (Map.Entry<ByteBuffer, CollectionType> entry : ctct.defined.entrySet())
+ {
+ AbstractType<?> t = updateWith(entry.getValue(), keyspace, toReplace, updated);
+ if (t == null)
+ continue;
+
+ if (updatedTypes == null)
+ updatedTypes = new HashMap<>(ctct.defined);
+
+ updatedTypes.put(entry.getKey(), (CollectionType)t);
+ }
+ return updatedTypes == null ? null : ColumnToCollectionType.getInstance(updatedTypes);
+ }
+ else if (type instanceof CollectionType)
+ {
+ if (type instanceof ListType)
+ {
+ AbstractType<?> t = updateWith(((ListType)type).elements, keyspace, toReplace, updated);
+ return t == null ? null : ListType.getInstance(t);
+ }
+ else if (type instanceof SetType)
+ {
+ AbstractType<?> t = updateWith(((SetType)type).elements, keyspace, toReplace, updated);
+ return t == null ? null : SetType.getInstance(t);
+ }
+ else
+ {
+ assert type instanceof MapType;
+ MapType mt = (MapType)type;
+ AbstractType<?> k = updateWith(mt.keys, keyspace, toReplace, updated);
+ AbstractType<?> v = updateWith(mt.values, keyspace, toReplace, updated);
+ if (k == null && v == null)
+ return null;
+ return MapType.getInstance(k == null ? mt.keys : k, v == null ? mt.values : v);
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ private static List<AbstractType<?>> updateTypes(List<AbstractType<?>> toUpdate, String keyspace, ByteBuffer toReplace, UserType updated)
+ {
+ // But this can also be nested.
+ List<AbstractType<?>> updatedTypes = null;
+ for (int i = 0; i < toUpdate.size(); i++)
+ {
+ AbstractType<?> t = updateWith(toUpdate.get(i), keyspace, toReplace, updated);
+ if (t == null)
+ continue;
+
+ if (updatedTypes == null)
+ updatedTypes = new ArrayList<>(toUpdate);
+
+ updatedTypes.set(i, t);
+ }
+ return updatedTypes;
+ }
+
+ private static class AddOrAlter extends AlterTypeStatement
+ {
+ private final boolean isAdd;
+ private final ColumnIdentifier fieldName;
+ private final CQL3Type.Raw type;
+
+ public AddOrAlter(UTName name, boolean isAdd, ColumnIdentifier fieldName, CQL3Type.Raw type)
+ {
+ super(name);
+ this.isAdd = isAdd;
+ this.fieldName = fieldName;
+ this.type = type;
+ }
+
+ private UserType doAdd(UserType toUpdate) throws InvalidRequestException
+ {
+ if (getIdxOfField(toUpdate, fieldName) >= 0)
+ throw new InvalidRequestException(String.format("Cannot add new field %s to type %s: a field of the same name already exists", fieldName, name));
+
+ List<ByteBuffer> newNames = new ArrayList<>(toUpdate.size() + 1);
+ newNames.addAll(toUpdate.fieldNames());
+ newNames.add(fieldName.bytes);
+
+ List<AbstractType<?>> newTypes = new ArrayList<>(toUpdate.size() + 1);
+ newTypes.addAll(toUpdate.fieldTypes());
+ newTypes.add(type.prepare(keyspace()).getType());
+
+ return new UserType(toUpdate.keyspace, toUpdate.name, newNames, newTypes);
+ }
+
+ private UserType doAlter(UserType toUpdate) throws InvalidRequestException
+ {
+ int idx = getIdxOfField(toUpdate, fieldName);
+ if (idx < 0)
+ throw new InvalidRequestException(String.format("Unknown field %s in type %s", fieldName, name));
+
+ AbstractType<?> previous = toUpdate.fieldType(idx);
+ if (!type.prepare(keyspace()).getType().isCompatibleWith(previous))
+ throw new InvalidRequestException(String.format("Type %s is incompatible with previous type %s of field %s in user type %s", type, previous.asCQL3Type(), fieldName, name));
+
+ List<ByteBuffer> newNames = new ArrayList<>(toUpdate.fieldNames());
+ List<AbstractType<?>> newTypes = new ArrayList<>(toUpdate.fieldTypes());
+ newTypes.set(idx, type.prepare(keyspace()).getType());
+
+ return new UserType(toUpdate.keyspace, toUpdate.name, newNames, newTypes);
+ }
+
+ protected UserType makeUpdatedType(UserType toUpdate) throws InvalidRequestException
+ {
+ return isAdd ? doAdd(toUpdate) : doAlter(toUpdate);
+ }
+ }
+
+ private static class Renames extends AlterTypeStatement
+ {
+ private final Map<ColumnIdentifier, ColumnIdentifier> renames;
+
+ public Renames(UTName name, Map<ColumnIdentifier, ColumnIdentifier> renames)
+ {
+ super(name);
+ this.renames = renames;
+ }
+
+ protected UserType makeUpdatedType(UserType toUpdate) throws InvalidRequestException
+ {
+ List<ByteBuffer> newNames = new ArrayList<>(toUpdate.fieldNames());
+ List<AbstractType<?>> newTypes = new ArrayList<>(toUpdate.fieldTypes());
+
+ for (Map.Entry<ColumnIdentifier, ColumnIdentifier> entry : renames.entrySet())
+ {
+ ColumnIdentifier from = entry.getKey();
+ ColumnIdentifier to = entry.getValue();
+ int idx = getIdxOfField(toUpdate, from);
+ if (idx < 0)
+ throw new InvalidRequestException(String.format("Unknown field %s in type %s", from, name));
+ newNames.set(idx, to.bytes);
+ }
+
+ UserType updated = new UserType(toUpdate.keyspace, toUpdate.name, newNames, newTypes);
+ CreateTypeStatement.checkForDuplicateNames(updated);
+ return updated;
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
index 3f2635f,8b40978..4809187
--- a/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
@@@ -110,49 -93,41 +110,50 @@@ public class CreateIndexStatement exten
// would pull the full partition every time the static column of partition is 'bar', which sounds like offering a
// fair potential for foot-shooting, so I prefer leaving that to a follow up ticket once we have identified cases where
// such indexing is actually useful.
- if (cd.type == ColumnDefinition.Type.STATIC)
+ if (cd.isStatic())
throw new InvalidRequestException("Secondary indexes are not allowed on static columns");
- if (cd.getValidator().isCollection() && !properties.isCustom)
- throw new InvalidRequestException("Indexes on collections are no yet supported");
-
- if (cd.type == ColumnDefinition.Type.PARTITION_KEY && cd.componentIndex == null)
- throw new InvalidRequestException(String.format("Cannot add secondary index to already primarily indexed column %s", columnName));
+ if (cd.kind == ColumnDefinition.Kind.PARTITION_KEY && cd.isOnAllComponents())
+ throw new InvalidRequestException(String.format("Cannot add secondary index to already primarily indexed column %s", target.column));
}
- public void announceMigration(boolean isLocalOnly) throws RequestValidationException
- public boolean announceMigration() throws RequestValidationException
++ public boolean announceMigration(boolean isLocalOnly) throws RequestValidationException
{
- logger.debug("Updating column {} definition for index {}", columnName, indexName);
- CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).clone();
- ColumnDefinition cd = cfm.getColumnDefinition(columnName.key);
+ logger.debug("Updating column {} definition for index {}", target.column, indexName);
+ CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).copy();
+ ColumnDefinition cd = cfm.getColumnDefinition(target.column);
if (cd.getIndexType() != null && ifNotExists)
- return;
+ return false;
if (properties.isCustom)
+ {
cd.setIndexType(IndexType.CUSTOM, properties.getOptions());
- else if (cfm.getCfDef().isComposite)
- cd.setIndexType(IndexType.COMPOSITES, Collections.<String, String>emptyMap());
+ }
+ else if (cfm.comparator.isCompound())
+ {
+ Map<String, String> options = Collections.emptyMap();
+ // For now, we only allow indexing values for collections, but we could later allow
+ // to also index map keys, so we record that this is the values we index to make our
+ // lives easier then.
+ if (cd.type.isCollection())
+ options = ImmutableMap.of(target.isCollectionKeys ? "index_keys" : "index_values", "");
+ cd.setIndexType(IndexType.COMPOSITES, options);
+ }
else
+ {
cd.setIndexType(IndexType.KEYS, Collections.<String, String>emptyMap());
+ }
cd.setIndexName(indexName);
cfm.addDefaultIndexNames();
- MigrationManager.announceColumnFamilyUpdate(cfm, false);
+ MigrationManager.announceColumnFamilyUpdate(cfm, false, isLocalOnly);
+ return true;
}
- public ResultMessage.SchemaChange.Change changeType()
+ public Event.SchemaChange changeEvent()
{
// Creating an index is akin to updating the CF
- return ResultMessage.SchemaChange.Change.UPDATED;
+ return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
index 78263b6,7a8473a..8281cbd
--- a/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
@@@ -97,11 -97,12 +97,12 @@@ public class CreateKeyspaceStatement ex
attrs.getReplicationOptions());
}
- public void announceMigration(boolean isLocalOnly) throws RequestValidationException
- public boolean announceMigration() throws RequestValidationException
++ public boolean announceMigration(boolean isLocalOnly) throws RequestValidationException
{
try
{
- MigrationManager.announceNewKeyspace(attrs.asKSMetadata(name));
+ MigrationManager.announceNewKeyspace(attrs.asKSMetadata(name), isLocalOnly);
+ return true;
}
catch (AlreadyExistsException e)
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
index 47f05bb,b7f43d3..891a895
--- a/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
@@@ -107,11 -114,12 +107,12 @@@ public class CreateTableStatement exten
return columnDefs;
}
- public void announceMigration(boolean isLocalOnly) throws RequestValidationException
- public boolean announceMigration() throws RequestValidationException
++ public boolean announceMigration(boolean isLocalOnly) throws RequestValidationException
{
try
{
- MigrationManager.announceNewColumnFamily(getCFMetaData(), isLocalOnly);
- MigrationManager.announceNewColumnFamily(getCFMetaData());
++ MigrationManager.announceNewColumnFamily(getCFMetaData(), isLocalOnly);
+ return true;
}
catch (AlreadyExistsException e)
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
index 9b7313f,70b3acb..db0cc22
--- a/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
@@@ -65,16 -65,17 +65,17 @@@ public class CreateTriggerStatement ext
}
}
- public void announceMigration(boolean isLocalOnly) throws ConfigurationException
- public boolean announceMigration() throws ConfigurationException
++ public boolean announceMigration(boolean isLocalOnly) throws ConfigurationException
{
- CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).clone();
+ CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).copy();
cfm.addTriggerDefinition(TriggerDefinition.create(triggerName, triggerClass));
logger.info("Adding trigger with name {} and class {}", triggerName, triggerClass);
- MigrationManager.announceColumnFamilyUpdate(cfm, false);
+ MigrationManager.announceColumnFamilyUpdate(cfm, false, isLocalOnly);
+ return true;
}
- public ResultMessage.SchemaChange.Change changeType()
+ public Event.SchemaChange changeEvent()
{
- return ResultMessage.SchemaChange.Change.UPDATED;
+ return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/CreateTypeStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CreateTypeStatement.java
index 5224474,0000000..82c2808
mode 100644,000000..100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateTypeStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateTypeStatement.java
@@@ -1,132 -1,0 +1,133 @@@
+/*
+ * 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.cql3.statements;
+
+import java.nio.ByteBuffer;
+import java.util.*;
+
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.config.*;
+import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.UTF8Type;
+import org.apache.cassandra.db.marshal.UserType;
+import org.apache.cassandra.exceptions.*;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.MigrationManager;
+import org.apache.cassandra.transport.Event;
+
+public class CreateTypeStatement extends SchemaAlteringStatement
+{
+ private final UTName name;
+ private final List<ColumnIdentifier> columnNames = new ArrayList<>();
+ private final List<CQL3Type.Raw> columnTypes = new ArrayList<>();
+ private final boolean ifNotExists;
+
+ public CreateTypeStatement(UTName name, boolean ifNotExists)
+ {
+ super();
+ this.name = name;
+ this.ifNotExists = ifNotExists;
+ }
+
+ @Override
+ public void prepareKeyspace(ClientState state) throws InvalidRequestException
+ {
+ if (!name.hasKeyspace())
+ name.setKeyspace(state.getKeyspace());
+ }
+
+ public void addDefinition(ColumnIdentifier name, CQL3Type.Raw type)
+ {
+ columnNames.add(name);
+ columnTypes.add(type);
+ }
+
+ public void checkAccess(ClientState state) throws UnauthorizedException, InvalidRequestException
+ {
+ state.hasKeyspaceAccess(keyspace(), Permission.CREATE);
+ }
+
+ public void validate(ClientState state) throws RequestValidationException
+ {
+ KSMetaData ksm = Schema.instance.getKSMetaData(name.getKeyspace());
+ if (ksm == null)
+ throw new InvalidRequestException(String.format("Cannot add type in unknown keyspace %s", name.getKeyspace()));
+
+ if (ksm.userTypes.getType(name.getUserTypeName()) != null && !ifNotExists)
+ throw new InvalidRequestException(String.format("A user type of name %s already exists", name));
+
+ for (CQL3Type.Raw type : columnTypes)
+ if (type.isCounter())
+ throw new InvalidRequestException("A user type cannot contain counters");
+ }
+
+ public static void checkForDuplicateNames(UserType type) throws InvalidRequestException
+ {
+ for (int i = 0; i < type.size() - 1; i++)
+ {
+ ByteBuffer fieldName = type.fieldName(i);
+ for (int j = i+1; j < type.size(); j++)
+ {
+ if (fieldName.equals(type.fieldName(j)))
+ throw new InvalidRequestException(String.format("Duplicate field name %s in type %s",
+ UTF8Type.instance.getString(fieldName),
+ UTF8Type.instance.getString(type.name)));
+ }
+ }
+ }
+
+ public Event.SchemaChange changeEvent()
+ {
+ return new Event.SchemaChange(Event.SchemaChange.Change.CREATED, Event.SchemaChange.Target.TYPE, keyspace(), name.getStringTypeName());
+ }
+
+ @Override
+ public String keyspace()
+ {
+ return name.getKeyspace();
+ }
+
+ private UserType createType() throws InvalidRequestException
+ {
+ List<ByteBuffer> names = new ArrayList<>(columnNames.size());
+ for (ColumnIdentifier name : columnNames)
+ names.add(name.bytes);
+
+ List<AbstractType<?>> types = new ArrayList<>(columnTypes.size());
+ for (CQL3Type.Raw type : columnTypes)
+ types.add(type.prepare(keyspace()).getType());
+
+ return new UserType(name.getKeyspace(), name.getUserTypeName(), names, types);
+ }
+
- public void announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
++ public boolean announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
+ {
+ KSMetaData ksm = Schema.instance.getKSMetaData(name.getKeyspace());
+ assert ksm != null; // should haven't validate otherwise
+
+ // Can happen with ifNotExists
+ if (ksm.userTypes.getType(name.getUserTypeName()) != null)
- return;
++ return false;
+
+ UserType type = createType();
+ checkForDuplicateNames(type);
+ MigrationManager.announceNewType(type, isLocalOnly);
++ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
index f70f526,ac5262e..5df8188
--- a/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
@@@ -60,28 -54,21 +60,29 @@@ public class DropIndexStatement extend
// validated in findIndexedCf()
}
- public ResultMessage.SchemaChange.Change changeType()
+ public Event.SchemaChange changeEvent()
{
// Dropping an index is akin to updating the CF
- return ResultMessage.SchemaChange.Change.UPDATED;
+ return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
+ }
+
+ @Override
+ public ResultMessage execute(QueryState state, QueryOptions options) throws RequestValidationException
+ {
+ announceMigration(false);
+ return indexedCF == null ? null : new ResultMessage.SchemaChange(changeEvent());
}
- public void announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
- public boolean announceMigration() throws InvalidRequestException, ConfigurationException
++ public boolean announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
{
CFMetaData cfm = findIndexedCF();
if (cfm == null)
- return;
+ return false;
CFMetaData updatedCfm = updateCFMetadata(cfm);
- MigrationManager.announceColumnFamilyUpdate(updatedCfm, false);
+ indexedCF = updatedCfm.cfName;
+ MigrationManager.announceColumnFamilyUpdate(updatedCfm, false, isLocalOnly);
+ return true;
}
private CFMetaData updateCFMetadata(CFMetaData cfm)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
index 0a3a510,7582af0..ba6b917
--- a/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
@@@ -55,11 -55,12 +55,12 @@@ public class DropKeyspaceStatement exte
return keyspace;
}
- public void announceMigration(boolean isLocalOnly) throws ConfigurationException
- public boolean announceMigration() throws ConfigurationException
++ public boolean announceMigration(boolean isLocalOnly) throws ConfigurationException
{
try
{
- MigrationManager.announceKeyspaceDrop(keyspace);
+ MigrationManager.announceKeyspaceDrop(keyspace, isLocalOnly);
+ return true;
}
catch(ConfigurationException e)
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
index 49979b1,65a3f14..e690c3e
--- a/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
@@@ -54,11 -54,12 +54,12 @@@ public class DropTableStatement extend
// validated in announceMigration()
}
- public void announceMigration(boolean isLocalOnly) throws ConfigurationException
- public boolean announceMigration() throws ConfigurationException
++ public boolean announceMigration(boolean isLocalOnly) throws ConfigurationException
{
try
{
- MigrationManager.announceColumnFamilyDrop(keyspace(), columnFamily());
+ MigrationManager.announceColumnFamilyDrop(keyspace(), columnFamily(), isLocalOnly);
+ return true;
}
catch (ConfigurationException e)
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
index 594aeac,f0bd637..4fdc21e
--- a/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
@@@ -53,17 -53,18 +53,18 @@@ public class DropTriggerStatement exten
ThriftValidation.validateColumnFamily(keyspace(), columnFamily());
}
- public void announceMigration(boolean isLocalOnly) throws ConfigurationException
- public boolean announceMigration() throws ConfigurationException
++ public boolean announceMigration(boolean isLocalOnly) throws ConfigurationException
{
- CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).clone();
+ CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).copy();
if (!cfm.removeTrigger(triggerName))
throw new ConfigurationException(String.format("Trigger %s was not found", triggerName));
logger.info("Dropping trigger with name {}", triggerName);
- MigrationManager.announceColumnFamilyUpdate(cfm, false);
+ MigrationManager.announceColumnFamilyUpdate(cfm, false, isLocalOnly);
+ return true;
}
- public ResultMessage.SchemaChange.Change changeType()
+ public Event.SchemaChange changeEvent()
{
- return ResultMessage.SchemaChange.Change.UPDATED;
+ return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
index 5acfdea,0000000..8bcaaf6
mode 100644,000000..100644
--- a/src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
@@@ -1,150 -1,0 +1,153 @@@
+/*
+ * 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.cql3.statements;
+
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.config.*;
+import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.db.marshal.*;
+import org.apache.cassandra.exceptions.*;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.MigrationManager;
+import org.apache.cassandra.transport.Event;
+
+public class DropTypeStatement extends SchemaAlteringStatement
+{
+ private final UTName name;
+ private final boolean ifExists;
+
+ public DropTypeStatement(UTName name, boolean ifExists)
+ {
+ super();
+ this.name = name;
+ this.ifExists = ifExists;
+ }
+
+ @Override
+ public void prepareKeyspace(ClientState state) throws InvalidRequestException
+ {
+ if (!name.hasKeyspace())
+ name.setKeyspace(state.getKeyspace());
+ }
+
+ public void checkAccess(ClientState state) throws UnauthorizedException, InvalidRequestException
+ {
+ state.hasKeyspaceAccess(keyspace(), Permission.DROP);
+ }
+
+ public void validate(ClientState state) throws RequestValidationException
+ {
+ KSMetaData ksm = Schema.instance.getKSMetaData(name.getKeyspace());
+ if (ksm == null)
+ throw new InvalidRequestException(String.format("Cannot drop type in unknown keyspace %s", name.getKeyspace()));
+
+ UserType old = ksm.userTypes.getType(name.getUserTypeName());
+ if (old == null)
+ {
+ if (ifExists)
+ return;
+ else
+ throw new InvalidRequestException(String.format("No user type named %s exists.", name));
+ }
+
+ // We don't want to drop a type unless it's not used anymore (mainly because
+ // if someone drops a type and recreates one with the same name but different
+ // definition with the previous name still in use, things can get messy).
+ // We have two places to check: 1) other user type that can nest the one
+ // we drop and 2) existing tables referencing the type (maybe in a nested
+ // way).
+
+ for (KSMetaData ksm2 : Schema.instance.getKeyspaceDefinitions())
+ {
+ for (UserType ut : ksm2.userTypes.getAllTypes().values())
+ {
+ if (ut.keyspace.equals(name.getKeyspace()) && ut.name.equals(name.getUserTypeName()))
+ continue;
+ if (isUsedBy(ut))
+ throw new InvalidRequestException(String.format("Cannot drop user type %s as it is still used by user type %s", name, ut.asCQL3Type()));
+ }
+
+ for (CFMetaData cfm : ksm2.cfMetaData().values())
+ for (ColumnDefinition def : cfm.allColumns())
+ if (isUsedBy(def.type))
+ throw new InvalidRequestException(String.format("Cannot drop user type %s as it is still used by table %s.%s", name, cfm.ksName, cfm.cfName));
+ }
+ }
+
+ private boolean isUsedBy(AbstractType<?> toCheck) throws RequestValidationException
+ {
+ if (toCheck instanceof UserType)
+ {
+ UserType ut = (UserType)toCheck;
+ if (name.getKeyspace().equals(ut.keyspace) && name.getUserTypeName().equals(ut.name))
+ return true;
+
+ for (AbstractType<?> subtype : ut.fieldTypes())
+ if (isUsedBy(subtype))
+ return true;
+ }
+ else if (toCheck instanceof CompositeType)
+ {
+ CompositeType ct = (CompositeType)toCheck;
+ for (AbstractType<?> subtype : ct.types)
+ if (isUsedBy(subtype))
+ return true;
+ }
+ else if (toCheck instanceof ColumnToCollectionType)
+ {
+ for (CollectionType collection : ((ColumnToCollectionType)toCheck).defined.values())
+ if (isUsedBy(collection))
+ return true;
+ }
+ else if (toCheck instanceof CollectionType)
+ {
+ if (toCheck instanceof ListType)
+ return isUsedBy(((ListType)toCheck).elements);
+ else if (toCheck instanceof SetType)
+ return isUsedBy(((SetType)toCheck).elements);
+ else
+ return isUsedBy(((MapType)toCheck).keys) || isUsedBy(((MapType)toCheck).keys);
+ }
+ return false;
+ }
+
+ public Event.SchemaChange changeEvent()
+ {
+ return new Event.SchemaChange(Event.SchemaChange.Change.DROPPED, Event.SchemaChange.Target.TYPE, keyspace(), name.getStringTypeName());
+ }
+
+ @Override
+ public String keyspace()
+ {
+ return name.getKeyspace();
+ }
+
- public void announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
++ public boolean announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
+ {
+ KSMetaData ksm = Schema.instance.getKSMetaData(name.getKeyspace());
+ assert ksm != null;
+
+ UserType toDrop = ksm.userTypes.getType(name.getUserTypeName());
+ // Can be null with ifExists
- if (toDrop != null)
- MigrationManager.announceTypeDrop(toDrop, isLocalOnly);
++ if (toDrop == null)
++ return false;
++
++ MigrationManager.announceTypeDrop(toDrop, isLocalOnly);
++ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
index e70aac9,845d8cc..8882871
--- a/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
@@@ -63,26 -62,31 +63,34 @@@ public abstract class SchemaAlteringSta
return new Prepared(this);
}
- public abstract ResultMessage.SchemaChange.Change changeType();
+ public abstract Event.SchemaChange changeEvent();
- public abstract void announceMigration(boolean isLocalOnly) throws RequestValidationException;
+ /**
+ * Announces the migration to other nodes in the cluster.
+ * @return true if the execution of this statement resulted in a schema change, false otherwise (when IF NOT EXISTS
+ * is used, for example)
+ * @throws RequestValidationException
+ */
- public abstract boolean announceMigration() throws RequestValidationException;
++ public abstract boolean announceMigration(boolean isLocalOnly) throws RequestValidationException;
public ResultMessage execute(QueryState state, QueryOptions options) throws RequestValidationException
{
- announceMigration(false);
- return new ResultMessage.SchemaChange(changeEvent());
+ // If an IF [NOT] EXISTS clause was used, this may not result in an actual schema change. To avoid doing
+ // extra work in the drivers to handle schema changes, we return an empty message in this case. (CASSANDRA-7600)
- boolean didChangeSchema = announceMigration();
- if (!didChangeSchema)
- return new ResultMessage.Void();
-
- String tableName = cfName == null || columnFamily() == null ? "" : columnFamily();
- return new ResultMessage.SchemaChange(changeType(), keyspace(), tableName);
++ boolean didChangeSchema = announceMigration(false);
++ return didChangeSchema ? new ResultMessage.SchemaChange(changeEvent()) : new ResultMessage.Void();
}
public ResultMessage executeInternal(QueryState state, QueryOptions options)
{
- // executeInternal is for local query only, thus altering schema is not supported
- throw new UnsupportedOperationException();
+ try
+ {
- announceMigration(true);
- return new ResultMessage.SchemaChange(changeEvent());
++ boolean didChangeSchema = announceMigration(true);
++ return didChangeSchema ? new ResultMessage.SchemaChange(changeEvent()) : new ResultMessage.Void();
+ }
+ catch (RequestValidationException e)
+ {
+ throw new RuntimeException(e);
+ }
}
}
[4/5] git commit: Merge branch 'cassandra-2.1.0' into cassandra-2.1
Posted by ty...@apache.org.
Merge branch 'cassandra-2.1.0' into cassandra-2.1
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/edbd7d39
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/edbd7d39
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/edbd7d39
Branch: refs/heads/trunk
Commit: edbd7d3922743ba0c81f61b7c3358249421f3205
Parents: 664efd4 a0923db
Author: Tyler Hobbs <ty...@datastax.com>
Authored: Thu Aug 21 14:23:17 2014 -0500
Committer: Tyler Hobbs <ty...@datastax.com>
Committed: Thu Aug 21 14:23:17 2014 -0500
----------------------------------------------------------------------
----------------------------------------------------------------------