diff --git a/src/java/org/apache/cassandra/cql3/statements/schema/CreateTableStatement.java b/src/java/org/apache/cassandra/cql3/statements/schema/CreateTableStatement.java index 03c024b55694..dfd7fcd59621 100644 --- a/src/java/org/apache/cassandra/cql3/statements/schema/CreateTableStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/schema/CreateTableStatement.java @@ -114,50 +114,51 @@ public Keyspaces apply(ClusterMetadata metadata) Keyspaces schema = metadata.schema.getKeyspaces(); KeyspaceMetadata keyspace = schema.getNullable(keyspaceName); - KeyspaceMetadata targetKeyspace = keyspace; if (null == keyspace) throw ire("Keyspace '%s' doesn't exist", keyspaceName); + KeyspaceMetadata targetKeyspace = keyspace; + TableMetadata table; if (isCreateLike) { // when using create table like ,that means the source table has already been created // so there is no need to do some validation for the first time creating a new table - if (!keyspace.hasTable(tableName)) - { - throw ire("Souce Table '%s'.'%s' doesn't exist", keyspaceName, tableName); - } - TableMetadata sourceTableMeta = keyspace.getTableNullable(tableName); + TableMetadata sourceTable = keyspace.getTableNullable(tableName); - if (sourceTableMeta.isIndex()) - throw ire("Cannot use CTREAT TABLE LIKE on a index table '%s'.'%s'.", keyspaceName, tableName); + if (sourceTable == null) + throw ire("Souce Table '%s'.'%s' doesn't exist", keyspaceName, tableName); - if (sourceTableMeta.isView()) - throw ire("Cannot use CTREAT TABLE LIKE on a materialized view '%s'.'%s'.", keyspaceName, tableName); + if (sourceTable.isIndex()) + throw ire("Cannot use CREATE TABLE LIKE on a index table '%s'.'%s'.", keyspaceName, tableName); - KeyspaceMetadata likeKeyspaceMeta = schema.getNullable(likeKeyspaceName); - if (null == likeKeyspaceMeta) - throw ire("Target Keyspace '%s' doesn't exist", likeKeyspaceName); + if (sourceTable.isView()) + throw ire("Cannot use CREATE TABLE LIKE on a materialized view '%s'.'%s'.", keyspaceName, tableName); - targetKeyspace = likeKeyspaceMeta; - if (likeKeyspaceMeta.hasTable(likeTableName)) - { + KeyspaceMetadata likeKeyspace = schema.getNullable(likeKeyspaceName); + if (null == likeKeyspace) + throw ire("Target keyspace '%s' doesn't exist", likeKeyspaceName); + + targetKeyspace = likeKeyspace; + if (likeKeyspace.hasTable(likeTableName)) throw new AlreadyExistsException(likeKeyspaceName, likeTableName); - } - // todo support udt for differenet ks latter - if (!keyspaceName.equalsIgnoreCase(likeKeyspaceName) && - !keyspace.types.isEmpty()) - { - throw ire("Cannot use CTREAT TABLE LIKE across different keyspace when source table have UDT."); - } + // todo support udt for different ks latter + if (!keyspaceName.equalsIgnoreCase(likeKeyspaceName) && !keyspace.types.isEmpty()) + throw ire("Cannot use CREATE TABLE LIKE across different keyspace when source table have UDT."); - table = buildTargetTableMeta(metadata, sourceTableMeta); + String sourceCQLString = sourceTable.toCqlString(false, true, false); + TableMetadata.Builder targetBuilder = CreateTableStatement.parse(sourceCQLString, likeKeyspaceName, likeTableName); + table = targetBuilder.id(TableId.get(metadata)) + .indexes(Indexes.none()) + .triggers(Triggers.none()) + .epoch(metadata.nextEpoch()) + .build(); } else { - assert likeKeyspaceName == null && likeTableName == null ; + assert likeKeyspaceName == null && likeTableName == null; if (keyspace.hasTable(tableName)) { if (ifNotExists) @@ -203,22 +204,20 @@ public void validate(ClientState state) if (isCreateLike) { if (ifNotExists) - throw ire("CREATE TABLE LIKE do not support using 'IF NOT EXISTS'."); + throw ire("CREATE TABLE LIKE does not support using 'IF NOT EXISTS'."); if (!rawColumns.isEmpty() || - (partitionKeyColumns != null &&!partitionKeyColumns.isEmpty()) || + (partitionKeyColumns != null && !partitionKeyColumns.isEmpty()) || !clusteringColumns.isEmpty() || !staticColumns.isEmpty() || !clusteringOrder.isEmpty()) { - throw ire("CREATE TABLE LIKE do not support creating table columns."); + throw ire("CREATE TABLE LIKE does not support creating table columns."); } //todo support latter - if (!attrs.propertyIsEmpty()) - { - throw ire("CREATE TABLE LIKE do not support create table with table properties."); - } + if (attrs.hasProperties()) + throw ire("CREATE TABLE LIKE does not support the specification of any properties."); //todo support table params definition return; @@ -251,10 +250,10 @@ public void validate(ClientState state) validateDefaultTimeToLive(attrs.asNewTableParams()); if (rawColumns.isEmpty()) - throw ire("There must be at least one table column when create table."); + throw ire("There must be at least one table column when creating table."); if (partitionKeyColumns.isEmpty()) - throw ire("There must be at least one partition key column when create table."); + throw ire("There must be at least one partition key column when creating table."); rawColumns.forEach((name, raw) -> raw.validate(state, name)); } @@ -295,8 +294,8 @@ public AuditLogContext getAuditLogContext() public String toString() { - return isCreateLike ? String.format("CREATE TABLE (%s, %s) LIKE (%s, %s)", likeKeyspaceName, likeTableName, keyspaceName, tableName) : - String.format("%s (%s, %s)", getClass().getSimpleName(), keyspaceName, tableName); + return isCreateLike ? String.format("CREATE TABLE %s.%s LIKE %s.%s", likeKeyspaceName, likeTableName, keyspaceName, tableName) : + String.format("CREATE TABLE %s.%s", keyspaceName, tableName); } public TableMetadata.Builder builder(Types types, UserFunctions functions) @@ -537,15 +536,6 @@ else if (!builder.hasRegularColumns()) } } - private TableMetadata buildTargetTableMeta(ClusterMetadata metadata, TableMetadata sourceTableMetadata) - { - TableMetadata.Builder builder = sourceTableMetadata.cloneBuilder(likeKeyspaceName, likeTableName); - // todo support indexes and triggers's copy latter - builder.id(TableId.get(metadata)) - .epoch(metadata.nextEpoch()); // new table with next expoch - return builder.build(); - } - private static class DefaultNames { private static final String DEFAULT_CLUSTERING_NAME = "column"; @@ -583,12 +573,21 @@ public String defaultCompactValueName() } } + public static TableMetadata.Builder parse(String cql, String keyspace, String table) + { + Raw createTable = CQLFragmentParser.parseAny(CqlParser::createTableStatement, cql, "CREATE TABLE") + .keyspace(keyspace); + + if (table != null) + createTable.table(table); + + return createTable.prepare(null) // works around a messy ClientState/QueryProcessor class init deadlock + .builder(Types.none(), UserFunctions.none()); + } + public static TableMetadata.Builder parse(String cql, String keyspace) { - return CQLFragmentParser.parseAny(CqlParser::createTableStatement, cql, "CREATE TABLE") - .keyspace(keyspace) - .prepare(null) // works around a messy ClientState/QueryProcessor class init deadlock - .builder(Types.none(), UserFunctions.none()); + return parse(cql, keyspace, null); } public final static class Raw extends CQLStatement.Raw @@ -619,7 +618,7 @@ public Raw(QualifiedName name, QualifiedName likeName, boolean ifNotExists, bool public CreateTableStatement prepare(ClientState state) { String keyspaceName = name.hasKeyspace() ? name.getKeyspace() : state.getKeyspace(); - String likeKeyspaceName = likeName == null ? null : likeName.hasKeyspace() ? likeName.getKeyspace() : state.getKeyspace(); + String likeKeyspaceName = likeName == null ? null : likeName.hasKeyspace() ? likeName.getKeyspace() : keyspaceName; String likeTableName = likeName == null ? null : likeName.getName(); if (!isCreateLike && null == partitionKeyColumns) @@ -651,6 +650,12 @@ public Raw keyspace(String keyspace) return this; } + public Raw table(String table) + { + name.setName(table, true); + return this; + } + public String table() { return name.getName(); diff --git a/src/java/org/apache/cassandra/cql3/statements/schema/TableAttributes.java b/src/java/org/apache/cassandra/cql3/statements/schema/TableAttributes.java index fe05e3bd2c0f..4f7f1b5217cd 100644 --- a/src/java/org/apache/cassandra/cql3/statements/schema/TableAttributes.java +++ b/src/java/org/apache/cassandra/cql3/statements/schema/TableAttributes.java @@ -175,9 +175,9 @@ private Map getMap(Option option) return value; } - public boolean propertyIsEmpty() + public boolean hasProperties() { - return this.properties.isEmpty(); + return !properties.isEmpty(); } private boolean getBoolean(Option option) diff --git a/src/java/org/apache/cassandra/schema/ColumnMetadata.java b/src/java/org/apache/cassandra/schema/ColumnMetadata.java index cfa55ea82e38..819a74164381 100644 --- a/src/java/org/apache/cassandra/schema/ColumnMetadata.java +++ b/src/java/org/apache/cassandra/schema/ColumnMetadata.java @@ -208,11 +208,6 @@ public ColumnMetadata(String ksName, this.mask = mask; } - protected ColumnMetadata cloneWithoutTableName(String keyspace, String table) - { - return new ColumnMetadata(keyspace, table, name, type, position, kind, mask); - } - private static Comparator makeCellPathComparator(Kind kind, AbstractType type) { if (kind.isPrimaryKeyKind() || !type.isMultiCell()) diff --git a/src/java/org/apache/cassandra/schema/DroppedColumn.java b/src/java/org/apache/cassandra/schema/DroppedColumn.java index e98e6bd2b149..17f4c55d2b45 100644 --- a/src/java/org/apache/cassandra/schema/DroppedColumn.java +++ b/src/java/org/apache/cassandra/schema/DroppedColumn.java @@ -62,11 +62,6 @@ public boolean equalsWithoutKsTb(DroppedColumn other) return column.equalsWithoutKsTb(other.column) && droppedTime == other.droppedTime; } - protected DroppedColumn cloneWithoutTableName(String keyspace, String table) - { - return new DroppedColumn(column.cloneWithoutTableName(keyspace, table), droppedTime); - } - @Override public int hashCode() { diff --git a/src/java/org/apache/cassandra/schema/TableMetadata.java b/src/java/org/apache/cassandra/schema/TableMetadata.java index 14aad642af7b..c7f043a67439 100644 --- a/src/java/org/apache/cassandra/schema/TableMetadata.java +++ b/src/java/org/apache/cassandra/schema/TableMetadata.java @@ -261,50 +261,6 @@ public Builder unbuild() .epoch(epoch); } - /** - * clone the basical information of the original table, see CEP-43 - * the table params, indexs and trigger may be differenet from source - * table. This is used for a new copied table's creation, so the epoch - * and id is not used. The newly created table's indexes and triggers - * are not cloned because the names should not be same. - * - * @param newKeyspace new keyspace name that will clone the TableMetadata - * @param newTable new table name that will clone the TableMetadata - */ - public Builder cloneBuilder(String newKeyspace, String newTable) - { - ImmutableCollection clonedColumns = cloneColumns(newKeyspace, newTable); - Map clonedDroppedColumns = cloneDroppedColumns(newKeyspace, newTable); - return builder(newKeyspace, newTable) - .partitioner(partitioner) - .kind(kind) - .flags(flags) - .params(params) - .addColumns(clonedColumns) - .droppedColumns(clonedDroppedColumns); - } - - private ImmutableCollection cloneColumns(String keyspace, String table) - { - ImmutableCollection.Builder builder = new ImmutableSet.Builder<>(); - for (ColumnMetadata cm : columns()) - { - builder.add(cm.cloneWithoutTableName(keyspace, table)); - } - return builder.build(); - } - - private Map cloneDroppedColumns(String keyspace, String table) - { - ImmutableMap.Builder builder = ImmutableMap.builder(); - for(Entry entry : droppedColumns.entrySet()) - { - DroppedColumn droppedColumn = entry.getValue(); - builder.put(entry.getKey(), droppedColumn.cloneWithoutTableName(keyspace, table)); - } - return builder.build(); - } - public boolean isIndex() { return kind == Kind.INDEX; @@ -330,26 +286,6 @@ public TableMetadata withSwapped(Indexes indexes) return unbuild().indexes(indexes).build(); } - public TableMetadata cloneWithNewTableParams(String newKeyspace, String newTable, TableParams newParams) - { - return cloneBuilder(newKeyspace, newTable).params(newParams).build(); - } - - public TableMetadata cloneWithNewIndexs(String newKeyspace, String newTable, Indexes newIndexes) - { - return cloneBuilder(newKeyspace, newTable).indexes(newIndexes).build(); - } - - public TableMetadata cloneWithNewTriggers(String newKeyspace, String newTable, Triggers newTriggers) - { - return cloneBuilder(newKeyspace, newTable).triggers(newTriggers).build(); - } - - public TableMetadata cloneWithNewTriggersAndIndexs(String newKeyspace, String newTable, Triggers newTriggers, Indexes newIndexes) - { - return cloneBuilder(newKeyspace, newTable).triggers(newTriggers).indexes(newIndexes).build(); - } - public boolean isView() { return kind == Kind.VIEW;