You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by al...@apache.org on 2014/06/07 22:46:37 UTC
[4/6] git commit: Merge branch 'cassandra-1.2' into cassandra-2.0
Merge branch 'cassandra-1.2' into cassandra-2.0
Conflicts:
src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/429e5cf1
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/429e5cf1
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/429e5cf1
Branch: refs/heads/trunk
Commit: 429e5cf19e3c306f05f47b68b9b485114f2bd062
Parents: 0dbb4e0 ce98b2d
Author: Aleksey Yeschenko <al...@apache.org>
Authored: Sat Jun 7 23:45:12 2014 +0300
Committer: Aleksey Yeschenko <al...@apache.org>
Committed: Sat Jun 7 23:45:12 2014 +0300
----------------------------------------------------------------------
.../org/apache/cassandra/cql3/statements/CreateTableStatement.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/429e5cf1/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
index 632194c,0000000..28c7fb2
mode 100644,000000..100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
@@@ -1,437 -1,0 +1,437 @@@
+/*
+ * 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.exceptions.*;
+import org.apache.commons.lang3.StringUtils;
+import com.google.common.collect.HashMultiset;
+import com.google.common.collect.Multiset;
+
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.config.Schema;
+import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.db.ColumnFamilyType;
+import org.apache.cassandra.db.marshal.*;
+import org.apache.cassandra.exceptions.AlreadyExistsException;
+import org.apache.cassandra.io.compress.CompressionParameters;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.MigrationManager;
+import org.apache.cassandra.thrift.CqlResult;
+import org.apache.cassandra.transport.messages.ResultMessage;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+/** A <code>CREATE TABLE</code> parsed from a CQL query statement. */
+public class CreateTableStatement extends SchemaAlteringStatement
+{
+ public AbstractType<?> comparator;
+ private AbstractType<?> defaultValidator;
+ private AbstractType<?> keyValidator;
+
+ private final List<ByteBuffer> keyAliases = new ArrayList<ByteBuffer>();
+ private final List<ByteBuffer> columnAliases = new ArrayList<ByteBuffer>();
+ private ByteBuffer valueAlias;
+
+ private final Map<ColumnIdentifier, AbstractType> columns = new HashMap<ColumnIdentifier, AbstractType>();
+ private final Set<ColumnIdentifier> staticColumns;
+ private final CFPropDefs properties;
+ private final boolean ifNotExists;
+
+ public CreateTableStatement(CFName name, CFPropDefs properties, boolean ifNotExists, Set<ColumnIdentifier> staticColumns)
+ {
+ super(name);
+ this.properties = properties;
+ this.ifNotExists = ifNotExists;
+ this.staticColumns = staticColumns;
+
+ try
+ {
+ if (!this.properties.hasProperty(CFPropDefs.KW_COMPRESSION) && CFMetaData.DEFAULT_COMPRESSOR != null)
+ this.properties.addProperty(CFPropDefs.KW_COMPRESSION,
+ new HashMap<String, String>()
+ {{
+ put(CompressionParameters.SSTABLE_COMPRESSION, CFMetaData.DEFAULT_COMPRESSOR);
+ }});
+ }
+ catch (SyntaxException e)
+ {
+ throw new AssertionError(e);
+ }
+ }
+
+ public void checkAccess(ClientState state) throws UnauthorizedException, InvalidRequestException
+ {
+ state.hasKeyspaceAccess(keyspace(), Permission.CREATE);
+ }
+
+ public void validate(ClientState state)
+ {
+ // validated in announceMigration()
+ }
+
+ // Column definitions
+ private Map<ByteBuffer, ColumnDefinition> getColumns()
+ {
+ Map<ByteBuffer, ColumnDefinition> columnDefs = new HashMap<ByteBuffer, ColumnDefinition>();
+ Integer componentIndex = null;
+ if (comparator instanceof CompositeType)
+ {
+ CompositeType ct = (CompositeType) comparator;
+ componentIndex = ct.types.get(ct.types.size() - 1) instanceof ColumnToCollectionType
+ ? ct.types.size() - 2
+ : ct.types.size() - 1;
+ }
+
+ for (Map.Entry<ColumnIdentifier, AbstractType> col : columns.entrySet())
+ {
+ ColumnIdentifier id = col.getKey();
+ columnDefs.put(id.key, staticColumns.contains(id)
+ ? ColumnDefinition.staticDef(id.key, col.getValue(), componentIndex)
+ : ColumnDefinition.regularDef(id.key, col.getValue(), componentIndex));
+ }
+
+ return columnDefs;
+ }
+
+ public void announceMigration() throws RequestValidationException
+ {
+ try
+ {
+ MigrationManager.announceNewColumnFamily(getCFMetaData());
+ }
+ catch (AlreadyExistsException e)
+ {
+ if (!ifNotExists)
+ throw e;
+ }
+ }
+
+ public ResultMessage.SchemaChange.Change changeType()
+ {
+ return ResultMessage.SchemaChange.Change.CREATED;
+ }
+
+ /**
+ * Returns a CFMetaData instance based on the parameters parsed from this
+ * <code>CREATE</code> statement, or defaults where applicable.
+ *
+ * @return a CFMetaData instance corresponding to the values parsed from this statement
+ * @throws InvalidRequestException on failure to validate parsed parameters
+ */
+ public CFMetaData getCFMetaData() throws RequestValidationException
+ {
+ CFMetaData newCFMD;
+ newCFMD = new CFMetaData(keyspace(),
+ columnFamily(),
+ ColumnFamilyType.Standard,
+ comparator,
+ null);
+ applyPropertiesTo(newCFMD);
+ return newCFMD;
+ }
+
+ public void applyPropertiesTo(CFMetaData cfmd) throws RequestValidationException
+ {
+ cfmd.defaultValidator(defaultValidator)
+ .keyValidator(keyValidator)
+ .columnMetadata(getColumns());
+
+ cfmd.addColumnMetadataFromAliases(keyAliases, keyValidator, ColumnDefinition.Type.PARTITION_KEY);
+ cfmd.addColumnMetadataFromAliases(columnAliases, comparator, ColumnDefinition.Type.CLUSTERING_KEY);
+ if (valueAlias != null)
+ cfmd.addColumnMetadataFromAliases(Collections.<ByteBuffer>singletonList(valueAlias), defaultValidator, ColumnDefinition.Type.COMPACT_VALUE);
+
+ properties.applyToCFMetadata(cfmd);
+ }
+
+ public static class RawStatement extends CFStatement
+ {
+ private final Map<ColumnIdentifier, CQL3Type> definitions = new HashMap<ColumnIdentifier, CQL3Type>();
+ public final CFPropDefs properties = new CFPropDefs();
+
+ private final List<List<ColumnIdentifier>> keyAliases = new ArrayList<List<ColumnIdentifier>>();
+ private final List<ColumnIdentifier> columnAliases = new ArrayList<ColumnIdentifier>();
+ private final Map<ColumnIdentifier, Boolean> definedOrdering = new LinkedHashMap<ColumnIdentifier, Boolean>(); // Insertion ordering is important
+ private final Set<ColumnIdentifier> staticColumns = new HashSet<ColumnIdentifier>();
+
+ private boolean useCompactStorage;
+ private final Multiset<ColumnIdentifier> definedNames = HashMultiset.create(1);
+
+ private final boolean ifNotExists;
+
+ public RawStatement(CFName name, boolean ifNotExists)
+ {
+ super(name);
+ this.ifNotExists = ifNotExists;
+ }
+
+ /**
+ * Transform this raw statement into a CreateTableStatement.
+ */
+ public ParsedStatement.Prepared prepare() throws RequestValidationException
+ {
+ // Column family name
+ if (!columnFamily().matches("\\w+"))
+ throw new InvalidRequestException(String.format("\"%s\" is not a valid column family name (must be alphanumeric character only: [0-9A-Za-z]+)", columnFamily()));
+ if (columnFamily().length() > Schema.NAME_LENGTH)
+ throw new InvalidRequestException(String.format("Column family names shouldn't be more than %s characters long (got \"%s\")", Schema.NAME_LENGTH, columnFamily()));
+
+ for (Multiset.Entry<ColumnIdentifier> entry : definedNames.entrySet())
+ if (entry.getCount() > 1)
+ throw new InvalidRequestException(String.format("Multiple definition of identifier %s", entry.getElement()));
+
+ properties.validate();
+
+ CreateTableStatement stmt = new CreateTableStatement(cfName, properties, ifNotExists, staticColumns);
+
+ Map<ByteBuffer, CollectionType> definedCollections = null;
+ for (Map.Entry<ColumnIdentifier, CQL3Type> entry : definitions.entrySet())
+ {
+ ColumnIdentifier id = entry.getKey();
+ CQL3Type pt = entry.getValue();
+ if (pt.isCollection())
+ {
+ if (definedCollections == null)
+ definedCollections = new HashMap<ByteBuffer, CollectionType>();
+ definedCollections.put(id.key, (CollectionType)pt.getType());
+ }
+ stmt.columns.put(id, pt.getType()); // we'll remove what is not a column below
+ }
+
+ if (keyAliases.isEmpty())
+ throw new InvalidRequestException("No PRIMARY KEY specifed (exactly one required)");
+ else if (keyAliases.size() > 1)
+ throw new InvalidRequestException("Multiple PRIMARY KEYs specifed (exactly one required)");
+
+ List<ColumnIdentifier> kAliases = keyAliases.get(0);
+
+ List<AbstractType<?>> keyTypes = new ArrayList<AbstractType<?>>(kAliases.size());
+ for (ColumnIdentifier alias : kAliases)
+ {
+ stmt.keyAliases.add(alias.key);
+ AbstractType<?> t = getTypeAndRemove(stmt.columns, alias);
+ if (t instanceof CounterColumnType)
+ throw new InvalidRequestException(String.format("counter type is not supported for PRIMARY KEY part %s", alias));
+ if (staticColumns.contains(alias))
+ throw new InvalidRequestException(String.format("Static column %s cannot be part of the PRIMARY KEY", alias));
+ keyTypes.add(t);
+ }
+ stmt.keyValidator = keyTypes.size() == 1 ? keyTypes.get(0) : CompositeType.getInstance(keyTypes);
+
+ // Handle column aliases
+ if (columnAliases.isEmpty())
+ {
+ if (useCompactStorage)
+ {
+ // There should remain some column definition since it is a non-composite "static" CF
+ if (stmt.columns.isEmpty())
+ throw new InvalidRequestException("No definition found that is not part of the PRIMARY KEY");
+
+ if (definedCollections != null)
+ throw new InvalidRequestException("Collection types are not supported with COMPACT STORAGE");
+
+ stmt.comparator = CFDefinition.definitionType;
+ }
+ else
+ {
+ List<AbstractType<?>> types = new ArrayList<AbstractType<?>>(definedCollections == null ? 1 : 2);
+ types.add(CFDefinition.definitionType);
+ if (definedCollections != null)
+ types.add(ColumnToCollectionType.getInstance(definedCollections));
+ stmt.comparator = CompositeType.getInstance(types);
+ }
+ }
+ else
+ {
+ // If we use compact storage and have only one alias, it is a
+ // standard "dynamic" CF, otherwise it's a composite
+ if (useCompactStorage && columnAliases.size() == 1)
+ {
+ if (definedCollections != null)
+ throw new InvalidRequestException("Collection types are not supported with COMPACT STORAGE");
+ ColumnIdentifier alias = columnAliases.get(0);
+ stmt.columnAliases.add(alias.key);
+ stmt.comparator = getTypeAndRemove(stmt.columns, alias);
+ if (stmt.comparator instanceof CounterColumnType)
+ throw new InvalidRequestException(String.format("counter type is not supported for PRIMARY KEY part %s", alias));
+ if (staticColumns.contains(alias))
+ throw new InvalidRequestException(String.format("Static column %s cannot be part of the PRIMARY KEY", alias));
+ }
+ else
+ {
+ List<AbstractType<?>> types = new ArrayList<AbstractType<?>>(columnAliases.size() + 1);
+ for (ColumnIdentifier t : columnAliases)
+ {
+ stmt.columnAliases.add(t.key);
+
+ AbstractType<?> type = getTypeAndRemove(stmt.columns, t);
+ if (type instanceof CounterColumnType)
- throw new InvalidRequestException(String.format("counter type is not supported for PRIMARY KEY part %s", t.key));
++ throw new InvalidRequestException(String.format("counter type is not supported for PRIMARY KEY part %s", t));
+ if (staticColumns.contains(t))
+ throw new InvalidRequestException(String.format("Static column %s cannot be part of the PRIMARY KEY", t));
+ types.add(type);
+ }
+
+ if (useCompactStorage)
+ {
+ if (definedCollections != null)
+ throw new InvalidRequestException("Collection types are not supported with COMPACT STORAGE");
+ }
+ else
+ {
+ // For sparse, we must add the last UTF8 component
+ // and the collection type if there is one
+ types.add(CFDefinition.definitionType);
+ if (definedCollections != null)
+ types.add(ColumnToCollectionType.getInstance(definedCollections));
+ }
+
+ if (types.isEmpty())
+ throw new IllegalStateException("Nonsensical empty parameter list for CompositeType");
+ stmt.comparator = CompositeType.getInstance(types);
+ }
+ }
+
+ if (!staticColumns.isEmpty())
+ {
+ // Only CQL3 tables can have static columns
+ if (useCompactStorage)
+ throw new InvalidRequestException("Static columns are not supported in COMPACT STORAGE tables");
+ // Static columns only make sense if we have at least one clustering column. Otherwise everything is static anyway
+ if (columnAliases.isEmpty())
+ throw new InvalidRequestException("Static columns are only useful (and thus allowed) if the table has at least one clustering column");
+ }
+
+ if (useCompactStorage && !stmt.columnAliases.isEmpty())
+ {
+ if (stmt.columns.isEmpty())
+ {
+ // The only value we'll insert will be the empty one, so the default validator don't matter
+ stmt.defaultValidator = BytesType.instance;
+ // We need to distinguish between
+ // * I'm upgrading from thrift so the valueAlias is null
+ // * I've defined my table with only a PK (and the column value will be empty)
+ // So, we use an empty valueAlias (rather than null) for the second case
+ stmt.valueAlias = ByteBufferUtil.EMPTY_BYTE_BUFFER;
+ }
+ else
+ {
+ if (stmt.columns.size() > 1)
+ throw new InvalidRequestException(String.format("COMPACT STORAGE with composite PRIMARY KEY allows no more than one column not part of the PRIMARY KEY (got: %s)", StringUtils.join(stmt.columns.keySet(), ", ")));
+
+ Map.Entry<ColumnIdentifier, AbstractType> lastEntry = stmt.columns.entrySet().iterator().next();
+ stmt.defaultValidator = lastEntry.getValue();
+ stmt.valueAlias = lastEntry.getKey().key;
+ stmt.columns.remove(lastEntry.getKey());
+ }
+ }
+ else
+ {
+ // For compact, we are in the "static" case, so we need at least one column defined. For non-compact however, having
+ // just the PK is fine since we have CQL3 row marker.
+ if (useCompactStorage && stmt.columns.isEmpty())
+ throw new InvalidRequestException("COMPACT STORAGE with non-composite PRIMARY KEY require one column not part of the PRIMARY KEY, none given");
+
+ // There is no way to insert/access a column that is not defined for non-compact storage, so
+ // the actual validator don't matter much (except that we want to recognize counter CF as limitation apply to them).
+ stmt.defaultValidator = !stmt.columns.isEmpty() && (stmt.columns.values().iterator().next() instanceof CounterColumnType)
+ ? CounterColumnType.instance
+ : BytesType.instance;
+ }
+
+
+ // If we give a clustering order, we must explicitly do so for all aliases and in the order of the PK
+ if (!definedOrdering.isEmpty())
+ {
+ if (definedOrdering.size() > columnAliases.size())
+ throw new InvalidRequestException("Only clustering key columns can be defined in CLUSTERING ORDER directive");
+
+ int i = 0;
+ for (ColumnIdentifier id : definedOrdering.keySet())
+ {
+ ColumnIdentifier c = columnAliases.get(i);
+ if (!id.equals(c))
+ {
+ if (definedOrdering.containsKey(c))
+ throw new InvalidRequestException(String.format("The order of columns in the CLUSTERING ORDER directive must be the one of the clustering key (%s must appear before %s)", c, id));
+ else
+ throw new InvalidRequestException(String.format("Missing CLUSTERING ORDER for column %s", c));
+ }
+ ++i;
+ }
+ }
+
+ return new ParsedStatement.Prepared(stmt);
+ }
+
+ private AbstractType<?> getTypeAndRemove(Map<ColumnIdentifier, AbstractType> columns, ColumnIdentifier t) throws InvalidRequestException
+ {
+ AbstractType type = columns.get(t);
+ if (type == null)
+ throw new InvalidRequestException(String.format("Unknown definition %s referenced in PRIMARY KEY", t));
+ if (type instanceof CollectionType)
+ throw new InvalidRequestException(String.format("Invalid collection type for PRIMARY KEY component %s", t));
+
+ columns.remove(t);
+ Boolean isReversed = definedOrdering.get(t);
+ return isReversed != null && isReversed ? ReversedType.getInstance(type) : type;
+ }
+
+ public void addDefinition(ColumnIdentifier def, CQL3Type type, boolean isStatic)
+ {
+ definedNames.add(def);
+ definitions.put(def, type);
+ if (isStatic)
+ staticColumns.add(def);
+ }
+
+ public void addKeyAliases(List<ColumnIdentifier> aliases)
+ {
+ keyAliases.add(aliases);
+ }
+
+ public void addColumnAlias(ColumnIdentifier alias)
+ {
+ columnAliases.add(alias);
+ }
+
+ public void setOrdering(ColumnIdentifier alias, boolean reversed)
+ {
+ definedOrdering.put(alias, reversed);
+ }
+
+ public void setCompactStorage()
+ {
+ useCompactStorage = true;
+ }
+
+ public void checkAccess(ClientState state)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public CqlResult execute(ClientState state, List<ByteBuffer> variables)
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+}