Add AlterKeyspace statement to 1.1 patch by slebresne; reviewed by xedin for CASSANDRA-4611
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/2ce7b9b3 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/2ce7b9b3 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/2ce7b9b3 Branch: refs/heads/trunk Commit: 2ce7b9b3ada14182067c934c475c6ab899086355 Parents: 59a6a5d Author: Sylvain Lebresne <[email protected]> Authored: Thu Oct 4 11:19:21 2012 +0200 Committer: Sylvain Lebresne <[email protected]> Committed: Thu Oct 4 11:19:21 2012 +0200 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../org/apache/cassandra/config/KSMetaData.java | 8 +- .../org/apache/cassandra/cql/QueryProcessor.java | 3 +- src/java/org/apache/cassandra/cql3/CFPropDefs.java | 123 +++------------ src/java/org/apache/cassandra/cql3/Cql.g | 35 +++-- src/java/org/apache/cassandra/cql3/KSPropDefs.java | 89 +++++++++++ .../apache/cassandra/cql3/PropertyDefinitions.java | 122 ++++++++++++++ .../cql3/statements/AlterKeyspaceStatement.java | 95 +++++++++++ .../cql3/statements/AlterTableStatement.java | 10 +- .../statements/CreateColumnFamilyStatement.java | 23 ++- .../cql3/statements/CreateKeyspaceStatement.java | 31 ++--- 11 files changed, 387 insertions(+), 153 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/2ce7b9b3/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index d803c0f..cb725cc 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -16,6 +16,7 @@ * Fix CQL3 'is reversed' logic (CASSANDRA-4716) * (CQL3) Don't return ReversedType in result set metadata (CASSANDRA-4717) * Pluggable Thrift transport factories for CLI (CASSANDRA-4609) + * Backport adding AlterKeyspace statement (CASSANDRA-4611) Merged from 1.0: * Switch from NBHM to CHM in MessagingService's callback map, which prevents OOM in long-running instances (CASSANDRA-4708) http://git-wip-us.apache.org/repos/asf/cassandra/blob/2ce7b9b3/src/java/org/apache/cassandra/config/KSMetaData.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/config/KSMetaData.java b/src/java/org/apache/cassandra/config/KSMetaData.java index 7b27875..a5fccc3 100644 --- a/src/java/org/apache/cassandra/config/KSMetaData.java +++ b/src/java/org/apache/cassandra/config/KSMetaData.java @@ -60,18 +60,18 @@ public final class KSMetaData } // For new user created keyspaces (through CQL) - public static KSMetaData newKeyspace(String name, String strategyName, Map<String, String> options) throws ConfigurationException + public static KSMetaData newKeyspace(String name, String strategyName, Map<String, String> options, boolean durableWrites) throws ConfigurationException { Class<? extends AbstractReplicationStrategy> cls = AbstractReplicationStrategy.getClass(strategyName); if (cls.equals(LocalStrategy.class)) throw new ConfigurationException("Unable to use given strategy class: LocalStrategy is reserved for internal use."); - return newKeyspace(name, cls, options, Collections.<CFMetaData>emptyList()); + return newKeyspace(name, cls, options, durableWrites, Collections.<CFMetaData>emptyList()); } - public static KSMetaData newKeyspace(String name, Class<? extends AbstractReplicationStrategy> strategyClass, Map<String, String> options, Iterable<CFMetaData> cfDefs) + public static KSMetaData newKeyspace(String name, Class<? extends AbstractReplicationStrategy> strategyClass, Map<String, String> options, boolean durablesWrites, Iterable<CFMetaData> cfDefs) { - return new KSMetaData(name, strategyClass, options, true, cfDefs); + return new KSMetaData(name, strategyClass, options, durablesWrites, cfDefs); } public static KSMetaData cloneWith(KSMetaData ksm, Iterable<CFMetaData> cfDefs) http://git-wip-us.apache.org/repos/asf/cassandra/blob/2ce7b9b3/src/java/org/apache/cassandra/cql/QueryProcessor.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql/QueryProcessor.java b/src/java/org/apache/cassandra/cql/QueryProcessor.java index 4a829c6..ab1c15b 100644 --- a/src/java/org/apache/cassandra/cql/QueryProcessor.java +++ b/src/java/org/apache/cassandra/cql/QueryProcessor.java @@ -700,7 +700,8 @@ public class QueryProcessor { KSMetaData ksm = KSMetaData.newKeyspace(create.getName(), create.getStrategyClass(), - create.getStrategyOptions()); + create.getStrategyOptions(), + true); ThriftValidation.validateKeyspaceNotYetExisting(ksm.name); MigrationManager.announceNewKeyspace(ksm); validateSchemaIsSettled(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/2ce7b9b3/src/java/org/apache/cassandra/cql3/CFPropDefs.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/CFPropDefs.java b/src/java/org/apache/cassandra/cql3/CFPropDefs.java index 01e14fb..ab209dd 100644 --- a/src/java/org/apache/cassandra/cql3/CFPropDefs.java +++ b/src/java/org/apache/cassandra/cql3/CFPropDefs.java @@ -18,7 +18,16 @@ */ package org.apache.cassandra.cql3; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + import com.google.common.collect.Sets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.apache.cassandra.config.CFMetaData; import org.apache.cassandra.config.ConfigurationException; import org.apache.cassandra.db.compaction.AbstractCompactionStrategy; @@ -29,12 +38,7 @@ import org.apache.cassandra.thrift.InvalidRequestException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -public class CFPropDefs +public class CFPropDefs extends PropertyDefinitions { private static Logger logger = LoggerFactory.getLogger(CFPropDefs.class); @@ -89,7 +93,6 @@ public class CFPropDefs allowedKeywords.addAll(obsoleteKeywords); } - public final Map<String, String> properties = new HashMap<String, String>(); private Class<? extends AbstractCompactionStrategy> compactionStrategyClass = null; public final Map<String, String> compactionStrategyOptions = new HashMap<String, String>(); public final Map<String, String> compressionParameters = new HashMap<String, String>() @@ -115,18 +118,9 @@ public class CFPropDefs } } - /* If not comparator/validator is not specified, default to text (BytesType is the wrong default for CQL - * since it uses hex terms). If the value specified is not found in the comparators map, assume the user - * knows what they are doing (a custom comparator/validator for example), and pass it on as-is. - */ - - public void validate() throws ConfigurationException + public void validate() throws ConfigurationException, InvalidRequestException { - // Catch the case where someone passed a kwarg that is not recognized. - for (String bogus : Sets.difference(properties.keySet(), allowedKeywords)) - throw new ConfigurationException(bogus + " is not a valid keyword argument for CREATE TABLE"); - for (String obsolete : Sets.intersection(properties.keySet(), obsoleteKeywords)) - logger.warn("Ignoring obsolete property {}", obsolete); + validate(keywords, obsoleteKeywords); if (properties.containsKey(KW_COMPACTION_STRATEGY_CLASS)) { @@ -135,8 +129,8 @@ public class CFPropDefs } } - /** Map a keyword to the corresponding value */ - public void addProperty(String name, String value) + @Override + public void addProperty(String name, String value) throws InvalidRequestException { String[] composite = name.split(":"); if (composite.length > 1) @@ -152,24 +146,13 @@ public class CFPropDefs return; } } - properties.put(name, value); - } - - public void addAll(Map<String, String> propertyMap) - { - for (Map.Entry<String, String> entry : propertyMap.entrySet()) - addProperty(entry.getKey(), entry.getValue()); - } - - public Boolean hasProperty(String name) - { - return properties.containsKey(name); + super.addProperty(name, value); } - public void applyToCFMetadata(CFMetaData cfm) throws ConfigurationException + public void applyToCFMetadata(CFMetaData cfm) throws ConfigurationException, InvalidRequestException { if (hasProperty(KW_COMMENT)) - cfm.comment(get(KW_COMMENT)); + cfm.comment(getString(KW_COMMENT, "")); cfm.readRepairChance(getDouble(KW_READREPAIRCHANCE, cfm.getReadRepairChance())); cfm.dcLocalReadRepairChance(getDouble(KW_DCLOCALREADREPAIRCHANCE, cfm.getDcLocalReadRepair())); @@ -181,80 +164,12 @@ public class CFPropDefs cfm.bloomFilterFpChance(getDouble(KW_BF_FP_CHANCE, cfm.getBloomFilterFpChance())); if (compactionStrategyClass != null) + { cfm.compactionStrategyClass(compactionStrategyClass); - - if (!compactionStrategyOptions.isEmpty()) cfm.compactionStrategyOptions(new HashMap<String, String>(compactionStrategyOptions)); - - if (!compressionParameters.isEmpty()) - cfm.compressionParameters(CompressionParameters.create(compressionParameters)); - } - - public String get(String name) - { - return properties.get(name); - } - - public String getString(String key, String defaultValue) - { - String value = properties.get(key); - return value != null ? value : defaultValue; - } - - // Return a property value, typed as a Boolean - public Boolean getBoolean(String key, Boolean defaultValue) - { - String value = properties.get(key); - return (value == null) ? defaultValue : value.toLowerCase().matches("(1|true|yes)"); - } - - // Return a property value, typed as a Double - public Double getDouble(String key, Double defaultValue) throws ConfigurationException - { - Double result; - String value = properties.get(key); - - if (value == null) - result = defaultValue; - else - { - try - { - result = Double.parseDouble(value); - } - catch (NumberFormatException e) - { - throw new ConfigurationException(String.format("%s not valid for \"%s\"", value, key)); - } } - return result; - } - - // Return a property value, typed as an Integer - public Integer getInt(String key, Integer defaultValue) throws ConfigurationException - { - String value = properties.get(key); - return toInt(key, value, defaultValue); - } - - public static Integer toInt(String key, String value, Integer defaultValue) throws ConfigurationException - { - Integer result; - if (value == null) - result = defaultValue; - else - { - try - { - result = Integer.parseInt(value); - } - catch (NumberFormatException e) - { - throw new ConfigurationException(String.format("%s not valid for \"%s\"", value, key)); - } - } - return result; + cfm.compressionParameters(CompressionParameters.create(compressionParameters)); } @Override http://git-wip-us.apache.org/repos/asf/cassandra/blob/2ce7b9b3/src/java/org/apache/cassandra/cql3/Cql.g ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/Cql.g b/src/java/org/apache/cassandra/cql3/Cql.g index f0481f6..387e694 100644 --- a/src/java/org/apache/cassandra/cql3/Cql.g +++ b/src/java/org/apache/cassandra/cql3/Cql.g @@ -144,6 +144,7 @@ cqlStatement returns [ParsedStatement stmt] | st15=grantStatement { $stmt = st15; } | st16=revokeStatement { $stmt = st16; } | st17=listGrantsStatement { $stmt = st17; } + | st18=alterKeyspaceStatement { $stmt = st18; } ; /* @@ -341,8 +342,9 @@ batchStatementObjective returns [ModificationStatement statement] * CREATE KEYSPACE <KEYSPACE> WITH attr1 = value1 AND attr2 = value2; */ createKeyspaceStatement returns [CreateKeyspaceStatement expr] + @init { KSPropDefs attrs = new KSPropDefs(); } : K_CREATE K_KEYSPACE ks=keyspaceName - K_WITH props=properties { $expr = new CreateKeyspaceStatement(ks, props); } + K_WITH properties[attrs] { $expr = new CreateKeyspaceStatement(ks, attrs); } ; /** @@ -368,7 +370,7 @@ cfamColumns[CreateColumnFamilyStatement.RawStatement expr] ; cfamProperty[CreateColumnFamilyStatement.RawStatement expr] - : k=property '=' v=propertyValue { $expr.addProperty(k, v); } + : k=propertyKey '=' v=propertyValue { try { $expr.addProperty(k, v); } catch (InvalidRequestException e) { addRecognitionError(e.getMessage()); } } | K_COMPACT K_STORAGE { $expr.setCompactStorage(); } | K_CLUSTERING K_ORDER K_BY '(' cfamOrdering[expr] (',' cfamOrdering[expr])* ')' ; @@ -387,6 +389,16 @@ createIndexStatement returns [CreateIndexStatement expr] ; /** + * ALTER KEYSPACE <KS> WITH <property> = <value>; + */ +alterKeyspaceStatement returns [AlterKeyspaceStatement expr] + @init { KSPropDefs attrs = new KSPropDefs(); } + : K_ALTER K_KEYSPACE ks=keyspaceName + K_WITH properties[attrs] { $expr = new AlterKeyspaceStatement(ks, attrs); } + ; + + +/** * ALTER COLUMN FAMILY <CF> ALTER <column> TYPE <newtype>; * ALTER COLUMN FAMILY <CF> ADD <column> <newtype>; * ALTER COLUMN FAMILY <CF> DROP <column>; @@ -395,13 +407,13 @@ createIndexStatement returns [CreateIndexStatement expr] alterTableStatement returns [AlterTableStatement expr] @init { AlterTableStatement.Type type = null; - props = new HashMap<String, String>(); + CFPropDefs props = new CFPropDefs(); } : K_ALTER K_COLUMNFAMILY cf=columnFamilyName ( K_ALTER id=cident K_TYPE v=comparatorType { type = AlterTableStatement.Type.ALTER; } | K_ADD id=cident v=comparatorType { type = AlterTableStatement.Type.ADD; } | K_DROP id=cident { type = AlterTableStatement.Type.DROP; } - | K_WITH props=properties { type = AlterTableStatement.Type.OPTS; } + | K_WITH properties[props] { type = AlterTableStatement.Type.OPTS; } ) { $expr = new AlterTableStatement(cf, type, id, v, props); @@ -545,7 +557,15 @@ termPairWithOperation[Map<ColumnIdentifier, Operation> columns] ) ; -property returns [String str] +properties[PropertyDefinitions props] + : property[props] (K_AND property[props])* + ; + +property[PropertyDefinitions props] + : k=propertyKey '=' simple=propertyValue { try { $props.addProperty(k, simple); } catch (InvalidRequestException e) { addRecognitionError(e.getMessage()); } } + ; + +propertyKey returns [String str] @init{ StringBuilder sb = new StringBuilder(); } : c1=cident { sb.append(c1); } ( ':' cn=cident { sb.append(':').append(cn); } )* { $str = sb.toString(); } ; @@ -555,11 +575,6 @@ propertyValue returns [String str] | u=unreserved_keyword { $str = u; } ; -properties returns [Map<String, String> props] - @init{ $props = new HashMap<String, String>(); } - : k1=property '=' v1=propertyValue { $props.put(k1, v1); } (K_AND kn=property '=' vn=propertyValue { $props.put(kn, vn); } )* - ; - relation returns [Relation rel] : name=cident type=('=' | '<' | '<=' | '>=' | '>') t=term { $rel = new Relation($name.id, $type.text, $t.term); } | K_TOKEN '(' name=cident ')' type=('=' |'<' | '<=' | '>=' | '>') t=extendedTerm { $rel = new Relation($name.id, $type.text, $t.term, true); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/2ce7b9b3/src/java/org/apache/cassandra/cql3/KSPropDefs.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/KSPropDefs.java b/src/java/org/apache/cassandra/cql3/KSPropDefs.java new file mode 100644 index 0000000..d480df4 --- /dev/null +++ b/src/java/org/apache/cassandra/cql3/KSPropDefs.java @@ -0,0 +1,89 @@ +/* + * 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; + +import java.util.*; + +import org.apache.cassandra.config.KSMetaData; +import org.apache.cassandra.config.ConfigurationException; +import org.apache.cassandra.thrift.InvalidRequestException; + +public class KSPropDefs extends PropertyDefinitions +{ + public static final String KW_DURABLE_WRITES = "durable_writes"; + + public static final String KW_REPLICATION_STRATEGY = "strategy_class"; + + public static final Set<String> keywords = new HashSet<String>(); + public static final Set<String> obsoleteKeywords = new HashSet<String>(); + + static + { + keywords.add(KW_DURABLE_WRITES); + keywords.add(KW_REPLICATION_STRATEGY); + } + + private String strategyClass; + private final Map<String, String> strategyOptions = new HashMap<String, String>(); + + public void validate() throws ConfigurationException, InvalidRequestException + { + validate(keywords, obsoleteKeywords); + + if (!properties.containsKey("strategy_class")) + throw new InvalidRequestException("missing required argument \"strategy_class\""); + strategyClass = properties.get("strategy_class"); + } + + @Override + public void addProperty(String name, String value) throws InvalidRequestException + { + // optional + if (name.contains(":") && name.startsWith("strategy_options")) + strategyOptions.put(name.split(":")[1], value); + else + super.addProperty(name, value); + } + + public String getReplicationStrategyClass() + { + return strategyClass; + } + + public Map<String, String> getReplicationOptions() + { + return strategyOptions; + } + + public KSMetaData asKSMetadata(String ksName) throws InvalidRequestException, ConfigurationException + { + return KSMetaData.newKeyspace(ksName, getReplicationStrategyClass(), getReplicationOptions(), getBoolean(KW_DURABLE_WRITES, true)); + } + + public KSMetaData asKSMetadataUpdate(KSMetaData old) throws InvalidRequestException, ConfigurationException + { + String sClass = strategyClass; + Map<String, String> sOptions = getReplicationOptions(); + if (sClass == null) + { + sClass = old.strategyClass.getName(); + sOptions = old.strategyOptions; + } + return KSMetaData.newKeyspace(old.name, sClass, sOptions, getBoolean(KW_DURABLE_WRITES, old.durableWrites)); + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/2ce7b9b3/src/java/org/apache/cassandra/cql3/PropertyDefinitions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/PropertyDefinitions.java b/src/java/org/apache/cassandra/cql3/PropertyDefinitions.java new file mode 100644 index 0000000..75b8ba5 --- /dev/null +++ b/src/java/org/apache/cassandra/cql3/PropertyDefinitions.java @@ -0,0 +1,122 @@ +/* + * 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; + +import java.util.*; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.cassandra.thrift.InvalidRequestException; + +public class PropertyDefinitions +{ + protected static final Logger logger = LoggerFactory.getLogger(PropertyDefinitions.class); + + protected final Map<String, String> properties = new HashMap<String, String>(); + + public void addProperty(String name, String value) throws InvalidRequestException + { + if (properties.put(name, value) != null) + throw new InvalidRequestException(String.format("Multiple definition for property '%s'", name)); + } + + public void validate(Set<String> keywords, Set<String> obsolete) throws InvalidRequestException + { + for (String name : properties.keySet()) + { + if (keywords.contains(name)) + continue; + + if (obsolete.contains(name)) + logger.warn("Ignoring obsolete property {}", name); + else + throw new InvalidRequestException(String.format("Unknown property '%s'", name)); + } + } + + protected String getSimple(String name) throws InvalidRequestException + { + return properties.get(name); + } + + public Boolean hasProperty(String name) + { + return properties.containsKey(name); + } + + public String getString(String key, String defaultValue) throws InvalidRequestException + { + String value = getSimple(key); + return value != null ? value : defaultValue; + } + + // Return a property value, typed as a Boolean + public Boolean getBoolean(String key, Boolean defaultValue) throws InvalidRequestException + { + String value = getSimple(key); + return (value == null) ? defaultValue : value.toLowerCase().matches("(1|true|yes)"); + } + + // Return a property value, typed as a Double + public Double getDouble(String key, Double defaultValue) throws InvalidRequestException + { + String value = getSimple(key); + if (value == null) + { + return defaultValue; + } + else + { + try + { + return Double.valueOf(value); + } + catch (NumberFormatException e) + { + throw new InvalidRequestException(String.format("Invalid double value %s for '%s'", value, key)); + } + } + } + + // Return a property value, typed as an Integer + public Integer getInt(String key, Integer defaultValue) throws InvalidRequestException + { + String value = getSimple(key); + return toInt(key, value, defaultValue); + } + + public static Integer toInt(String key, String value, Integer defaultValue) throws InvalidRequestException + { + if (value == null) + { + return defaultValue; + } + else + { + try + { + return Integer.valueOf(value); + } + catch (NumberFormatException e) + { + throw new InvalidRequestException(String.format("Invalid integer value %s for '%s'", value, key)); + } + } + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/2ce7b9b3/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 new file mode 100644 index 0000000..644fd24 --- /dev/null +++ b/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java @@ -0,0 +1,95 @@ +/* + * 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.ConfigurationException; +import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.config.KSMetaData; +import org.apache.cassandra.config.Schema; +import org.apache.cassandra.cql3.KSPropDefs; +import org.apache.cassandra.db.Table; +import org.apache.cassandra.locator.AbstractReplicationStrategy; +import org.apache.cassandra.service.ClientState; +import org.apache.cassandra.service.MigrationManager; +import org.apache.cassandra.service.StorageService; +import org.apache.cassandra.thrift.InvalidRequestException; +import org.apache.cassandra.thrift.SchemaDisagreementException; + +public class AlterKeyspaceStatement extends SchemaAlteringStatement +{ + private final String name; + private final KSPropDefs attrs; + + public AlterKeyspaceStatement(String name, KSPropDefs attrs) + { + super(); + this.name = name; + this.attrs = attrs; + } + + public void checkAccess(ClientState state) throws InvalidRequestException + { + state.hasKeyspaceAccess(name, Permission.ALTER); + } + + @Override + public void validate(ClientState state) throws InvalidRequestException, SchemaDisagreementException + { + super.validate(state); + + KSMetaData ksm = Schema.instance.getKSMetaData(name); + if (ksm == null) + throw new InvalidRequestException("Unknown keyspace " + name); + if (ksm.name.equalsIgnoreCase(Table.SYSTEM_TABLE)) + throw new InvalidRequestException("Cannot alter system keyspace"); + + try + { + attrs.validate(); + + if (attrs.getReplicationStrategyClass() == null && !attrs.getReplicationOptions().isEmpty()) + { + throw new InvalidRequestException("Missing replication strategy class"); + } + else if (attrs.getReplicationStrategyClass() != null) + { + // trial run to let ARS validate class + per-class options + AbstractReplicationStrategy.createReplicationStrategy(name, + AbstractReplicationStrategy.getClass(attrs.getReplicationStrategyClass()), + StorageService.instance.getTokenMetadata(), + DatabaseDescriptor.getEndpointSnitch(), + attrs.getReplicationOptions()); + } + } + catch (ConfigurationException e) + { + throw new InvalidRequestException(e.getMessage()); + } + } + + public void announceMigration() throws InvalidRequestException, ConfigurationException + { + 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)); + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/2ce7b9b3/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 7867019..965b27e 100644 --- a/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java @@ -23,9 +23,7 @@ import java.util.*; import org.apache.cassandra.auth.Permission; import org.apache.cassandra.cql3.*; import org.apache.cassandra.config.*; -import org.apache.cassandra.db.marshal.AbstractType; -import org.apache.cassandra.db.marshal.CompositeType; -import org.apache.cassandra.db.marshal.CounterColumnType; +import org.apache.cassandra.db.marshal.*; import org.apache.cassandra.service.ClientState; import org.apache.cassandra.service.MigrationManager; import org.apache.cassandra.thrift.InvalidRequestException; @@ -42,15 +40,15 @@ public class AlterTableStatement extends SchemaAlteringStatement public final Type oType; public final String validator; public final ColumnIdentifier columnName; - private final CFPropDefs cfProps = new CFPropDefs(); + private final CFPropDefs cfProps; - public AlterTableStatement(CFName name, Type type, ColumnIdentifier columnName, String validator, Map<String, String> propertyMap) + public AlterTableStatement(CFName name, Type type, ColumnIdentifier columnName, String validator, CFPropDefs cfProps) { super(name); this.oType = type; this.columnName = columnName; this.validator = validator; // used only for ADD/ALTER commands - this.cfProps.addAll(propertyMap); + this.cfProps = cfProps; } public void checkAccess(ClientState state) throws InvalidRequestException http://git-wip-us.apache.org/repos/asf/cassandra/blob/2ce7b9b3/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java index 763db28..286f265 100644 --- a/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java @@ -108,14 +108,7 @@ public class CreateColumnFamilyStatement extends SchemaAlteringStatement comparator, null); - newCFMD.defaultValidator(defaultValidator) - .columnMetadata(getColumns()) - .keyValidator(keyValidator) - .keyAlias(keyAlias) - .columnAliases(columnAliases) - .valueAlias(valueAlias); - - properties.applyToCFMetadata(newCFMD); + applyPropertiesTo(newCFMD); } catch (ConfigurationException e) { @@ -124,6 +117,18 @@ public class CreateColumnFamilyStatement extends SchemaAlteringStatement return newCFMD; } + public void applyPropertiesTo(CFMetaData cfmd) throws InvalidRequestException, ConfigurationException + { + cfmd.defaultValidator(defaultValidator) + .columnMetadata(getColumns()) + .keyValidator(keyValidator) + .keyAlias(keyAlias) + .columnAliases(columnAliases) + .valueAlias(valueAlias); + + properties.applyToCFMetadata(cfmd); + } + public static class RawStatement extends CFStatement { private final Map<ColumnIdentifier, String> definitions = new HashMap<ColumnIdentifier, String>(); @@ -277,7 +282,7 @@ public class CreateColumnFamilyStatement extends SchemaAlteringStatement columnAliases.add(alias); } - public void addProperty(String name, String value) + public void addProperty(String name, String value) throws InvalidRequestException { properties.addProperty(name, value); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/2ce7b9b3/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 863a869..9b36531 100644 --- a/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java @@ -26,6 +26,7 @@ import org.apache.cassandra.config.ConfigurationException; import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.config.KSMetaData; import org.apache.cassandra.config.Schema; +import org.apache.cassandra.cql3.KSPropDefs; import org.apache.cassandra.locator.AbstractReplicationStrategy; import org.apache.cassandra.service.ClientState; import org.apache.cassandra.service.MigrationManager; @@ -38,9 +39,7 @@ import org.apache.cassandra.thrift.ThriftValidation; public class CreateKeyspaceStatement extends SchemaAlteringStatement { private final String name; - private final Map<String, String> attrs; - private String strategyClass; - private Map<String, String> strategyOptions = new HashMap<String, String>(); + private final KSPropDefs attrs; /** * Creates a new <code>CreateKeyspaceStatement</code> instance for a given @@ -49,7 +48,7 @@ public class CreateKeyspaceStatement extends SchemaAlteringStatement * @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) + public CreateKeyspaceStatement(String name, KSPropDefs attrs) { super(); this.name = name; @@ -80,24 +79,19 @@ public class CreateKeyspaceStatement extends SchemaAlteringStatement if (name.length() > Schema.NAME_LENGTH) throw new InvalidRequestException(String.format("Keyspace names shouldn't be more than %s characters long (got \"%s\")", Schema.NAME_LENGTH, name)); - // required - if (!attrs.containsKey("strategy_class")) - throw new InvalidRequestException("missing required argument \"strategy_class\""); - strategyClass = attrs.get("strategy_class"); - - // optional - for (String key : attrs.keySet()) - if ((key.contains(":")) && (key.startsWith("strategy_options"))) - strategyOptions.put(key.split(":")[1], attrs.get(key)); - - // trial run to let ARS validate class + per-class options try { + attrs.validate(); + + if (attrs.getReplicationStrategyClass() == null) + throw new ConfigurationException("Missing mandatory replication strategy class"); + + // trial run to let ARS validate class + per-class options AbstractReplicationStrategy.createReplicationStrategy(name, - AbstractReplicationStrategy.getClass(strategyClass), + AbstractReplicationStrategy.getClass(attrs.getReplicationStrategyClass()), StorageService.instance.getTokenMetadata(), DatabaseDescriptor.getEndpointSnitch(), - strategyOptions); + attrs.getReplicationOptions()); } catch (ConfigurationException e) { @@ -107,8 +101,7 @@ public class CreateKeyspaceStatement extends SchemaAlteringStatement public void announceMigration() throws InvalidRequestException, ConfigurationException { - KSMetaData ksm = KSMetaData.newKeyspace(name, strategyClass, strategyOptions); ThriftValidation.validateKeyspaceNotYetExisting(name); - MigrationManager.announceNewKeyspace(ksm); + MigrationManager.announceNewKeyspace(attrs.asKSMetadata(name)); } }
