Skip to content

Commit

Permalink
add table params to create table like and fix some review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
Maxwell-Guo committed Dec 9, 2024
1 parent e40726c commit ed700a8
Show file tree
Hide file tree
Showing 15 changed files with 306 additions and 202 deletions.
8 changes: 5 additions & 3 deletions src/antlr/Parser.g
Original file line number Diff line number Diff line change
Expand Up @@ -815,12 +815,14 @@ tableClusteringOrder[CreateTableStatement.Raw stmt]
;

/**
* CREATE TABLE [IF NOT EXISTS] <NEW_TABLE> LIKE <OLD_TABLE>
* CREATE TABLE [IF NOT EXISTS] <NEW_TABLE> LIKE <OLD_TABLE> WITH <property> = <value> AND ...;
*/
copyTableStatement returns [CopyTableStatement.Raw stmt]
@init { boolean ifNotExists = false; }
: K_CREATE K_COLUMNFAMILY newCf=columnFamilyName K_LIKE oldCf=columnFamilyName
{ $stmt = new CopyTableStatement.Raw(newCf, oldCf); }
: K_CREATE K_COLUMNFAMILY (K_IF K_NOT K_EXISTS { ifNotExists = true; } )?
newCf=columnFamilyName K_LIKE oldCf=columnFamilyName
{ $stmt = new CopyTableStatement.Raw(newCf, oldCf, ifNotExists); }
( K_WITH property[stmt.attrs] ( K_AND property[stmt.attrs] )*)?
;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,30 +30,40 @@
import org.apache.cassandra.schema.Keyspaces;
import org.apache.cassandra.schema.TableId;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.schema.TableParams;
import org.apache.cassandra.schema.Triggers;
import org.apache.cassandra.schema.UserFunctions;
import org.apache.cassandra.service.ClientState;
import org.apache.cassandra.service.reads.repair.ReadRepairStrategy;
import org.apache.cassandra.tcm.ClusterMetadata;
import org.apache.cassandra.transport.Event.SchemaChange;

/**
* {@code CREATE TABLE [IF NOT EXISTS] <newtable> LIKE <oldtable> WITH <property> = <value>}
*/
public final class CopyTableStatement extends AlterSchemaStatement
{
private final String sourceKeyspace;
private final String sourceTableName;
private final String targetKeyspace;
private final String targetTableName;
private final boolean ifNotExists;
private final TableAttributes attrs;

public CopyTableStatement(String sourceKeyspace,
String targetKeyspace,
String sourceTableName,
String targetTableName)
String targetTableName,
boolean ifNotExists,
TableAttributes attrs)
{
super(targetKeyspace);
this.sourceKeyspace = sourceKeyspace;
this.targetKeyspace = targetKeyspace;
this.sourceTableName = sourceTableName;
this.targetTableName = targetTableName;
this.ifNotExists = ifNotExists;
this.attrs = attrs;
}

@Override
Expand Down Expand Up @@ -89,21 +99,25 @@ public Keyspaces apply(ClusterMetadata metadata)
throw ire("Souce Table '%s'.'%s' doesn't exist", sourceKeyspace, sourceTableName);

if (sourceTableMeta.isIndex())
throw ire("Cannot use CTREATE TABLE LIKE on a index table '%s'.'%s'.", sourceKeyspace, sourceTableName);
throw ire("Cannot use CREATE TABLE LIKE on a index table '%s'.'%s'.", sourceKeyspace, sourceTableName);

if (sourceTableMeta.isView())
throw ire("Cannot use CTREATE TABLE LIKE on a materialized view '%s'.'%s'.", sourceKeyspace, sourceTableName);
throw ire("Cannot use CREATE TABLE LIKE on a materialized view '%s'.'%s'.", sourceKeyspace, sourceTableName);

KeyspaceMetadata targetKeyspaceMeta = schema.getNullable(targetKeyspace);
if (null == targetKeyspaceMeta)
throw ire("Target Keyspace '%s' doesn't exist", targetKeyspace);

if (targetKeyspaceMeta.hasTable(targetTableName))
throw new AlreadyExistsException(targetKeyspace, targetTableName);
{
if(ifNotExists)
return schema;

throw new AlreadyExistsException(targetKeyspace, targetTableName);
}
// todo support udt for differenet ks latter
if (!sourceKeyspace.equalsIgnoreCase(targetKeyspace) && !sourceKeyspaceMeta.types.isEmpty())
throw ire("Cannot use CTREATE TABLE LIKE across different keyspace when source table have UDTs.");
throw ire("Cannot use CREATE TABLE LIKE across different keyspace when source table have UDTs.");

String sourceCQLString = sourceTableMeta.toCqlString(false, false, true, false);
// add all user functions to be able to give a good error message to the user if the alter references
Expand All @@ -112,7 +126,6 @@ public Keyspaces apply(ClusterMetadata metadata)
for (KeyspaceMetadata ksm : schema)
ufBuilder.add(ksm.userFunctions);

//todo support table params' setting in the future
TableMetadata.Builder targetBuilder = CreateTableStatement.parse(sourceCQLString,
targetKeyspace,
targetTableName,
Expand All @@ -121,7 +134,11 @@ public Keyspaces apply(ClusterMetadata metadata)
.indexes(Indexes.none())
.triggers(Triggers.none());

TableMetadata table = targetBuilder.id(TableId.get(metadata)).build();
TableParams originalParams = targetBuilder.build().params;
TableParams newTableParams = attrs.asAlteredTableParams(originalParams);
TableMetadata table = targetBuilder.params(newTableParams)
.id(TableId.get(metadata))
.build();
table.validate();

if (targetKeyspaceMeta.replicationStrategy.hasTransientReplicas()
Expand All @@ -140,19 +157,22 @@ public final static class Raw extends CQLStatement.Raw
{
private final QualifiedName oldName;
private final QualifiedName newName;
private final boolean ifNotExists;
public final TableAttributes attrs = new TableAttributes();

public Raw(QualifiedName newName, QualifiedName oldName)
public Raw(QualifiedName newName, QualifiedName oldName, boolean ifNotExists)
{
this.newName = newName;
this.oldName = oldName;
this.ifNotExists = ifNotExists;
}

@Override
public CQLStatement prepare(ClientState state)
{
String oldKeyspace = oldName.hasKeyspace() ? oldName.getKeyspace() : state.getKeyspace();
String newKeyspace = newName.hasKeyspace() ? newName.getKeyspace() : state.getKeyspace();
return new CopyTableStatement(oldKeyspace, newKeyspace, oldName.getName(), newName.getName());
return new CopyTableStatement(oldKeyspace, newKeyspace, oldName.getName(), newName.getName(), ifNotExists, attrs);
}
}
}
9 changes: 0 additions & 9 deletions src/java/org/apache/cassandra/schema/ColumnMetadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -313,15 +313,6 @@ public boolean equals(Object o)
return equalsWithoutType(cd) && type.equals(cd.type);
}

protected boolean equalsWithoutKsTb(ColumnMetadata other)
{
return name.equals(other.name)
&& kind == other.kind
&& position == other.position
&& Objects.equals(mask, other.mask)
&& type.equals(other.type);
}

private boolean equalsWithoutType(ColumnMetadata other)
{
return name.equals(other.name)
Expand Down
5 changes: 0 additions & 5 deletions src/java/org/apache/cassandra/schema/DroppedColumn.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,6 @@ public boolean equals(Object o)
return column.equals(dc.column) && droppedTime == dc.droppedTime;
}

public boolean equalsWithoutKsTb(DroppedColumn other)
{
return column.equalsWithoutKsTb(other.column) && droppedTime == other.droppedTime;
}

@Override
public int hashCode()
{
Expand Down
27 changes: 0 additions & 27 deletions src/java/org/apache/cassandra/schema/TableMetadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -716,33 +716,6 @@ private boolean equalsWithoutColumns(TableMetadata tm)
&& triggers.equals(tm.triggers);
}

public boolean equalsWithoutTableNameAndDropCns(TableMetadata tm)
{
return partitioner.equals(tm.partitioner)
&& kind == tm.kind
&& params.equals(tm.params)
&& flags.equals(tm.flags)
&& indexes.equals(tm.indexes)
&& triggers.equals(tm.triggers)
&& columnsEqualWitoutKsTb(tm);
}

// only compare columns
private boolean columnsEqualWitoutKsTb(TableMetadata tm)
{
if (columns == tm.columns)
return true;

boolean result = true;
for (Map.Entry<ByteBuffer, ColumnMetadata> entry : columns.entrySet())
{
ColumnMetadata thisColumn = entry.getValue();
ColumnMetadata thatColumn = tm.columns.get(entry.getKey());
result &= thatColumn != null && thisColumn.equalsWithoutKsTb(thatColumn);
}
return result;
}

Optional<Difference> compare(TableMetadata other)
{
return equalsWithoutColumns(other)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ public void testCreateLikeTable() throws IOException
{
try (Cluster cluster = init(Cluster.build(2).start()))
{
cluster.schemaChange(withKeyspace("create table %s.sourcetb (k int primary key, v text)"));
cluster.schemaChange(withKeyspace("CREATE TABLE %s.sourcetb (k int primary key, v text)"));
TableId node1id = tableId(cluster.get(1), "sourcetb");
TableId node2id = tableId(cluster.get(2), "sourcetb");
assertEquals(node1id, node2id);
cluster.schemaChange("create table " + KEYSPACE + ".targettb like " + KEYSPACE + ".sourcetb");
cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".targettb LIKE " + KEYSPACE + ".sourcetb");
TableId node1id2 = tableId(cluster.get(1), "targettb");
TableId node2id2 = tableId(cluster.get(2), "targettb");
assertNotEquals(node1id, node1id2);
Expand Down
2 changes: 1 addition & 1 deletion test/unit/org/apache/cassandra/audit/AuditLoggerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ public void testCqlCreateTableLikeAuditing() throws Throwable

String sourceTable = currentTable();

cql = "CREATE TABLE " + KEYSPACE + "." + createTableName() + " like " + KEYSPACE + "." + sourceTable;
cql = "CREATE TABLE " + KEYSPACE + "." + createTableName() + " LIKE " + KEYSPACE + "." + sourceTable;
executeAndAssert(cql, AuditLogEntryType.CREATE_TABLE_LIKE);

cql = "INSERT INTO " + KEYSPACE + '.' + currentTable() + " (id, v1, v2) VALUES (?, ?, ?)";
Expand Down
15 changes: 12 additions & 3 deletions test/unit/org/apache/cassandra/auth/GrantAndRevokeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ public void testCreateTableLikeAuthorize() throws Throwable

useUser(user, pass);
assertUnauthorizedQuery("User user has no SELECT permission on <table ks1.sourcetb> or any of its parents",
"CREATE TABLE ks1.targetTb like ks1.sourcetb");
"CREATE TABLE ks1.targetTb LIKE ks1.sourcetb");

// has select permission on source table no create permission on target keyspace
useSuperUser();
Expand All @@ -415,7 +415,7 @@ public void testCreateTableLikeAuthorize() throws Throwable

useUser(user, pass);
assertUnauthorizedQuery("User user has no CREATE permission on <all tables in ks1> or any of its parents",
"CREATE TABLE ks1.targetTb like ks1.sourcetb");
"CREATE TABLE ks1.targetTb LIKE ks1.sourcetb");

// different keyspaces
// has select permission on source table no create permission on target keyspace
Expand All @@ -426,7 +426,16 @@ public void testCreateTableLikeAuthorize() throws Throwable

useUser(user, pass);
assertUnauthorizedQuery("User user has no CREATE permission on <all tables in ks2> or any of its parents",
"CREATE TABLE ks2.targetTb like ks1.sourcetb");
"CREATE TABLE ks2.targetTb LIKE ks1.sourcetb");

// source keyspace and table does not exists
assertUnauthorizedQuery("User user has no SELECT permission on <table ks1.tbnotexist> or any of its parents",
"CREATE TABLE ks2.targetTb LIKE ks1.tbnotexist");
assertUnauthorizedQuery("User user has no SELECT permission on <table ksnotexists.sourcetb> or any of its parents",
"CREATE TABLE ks2.targetTb LIKE ksnotexists.sourcetb");
// target keyspace does not exists
assertUnauthorizedQuery("User user has no CREATE permission on <all tables in ksnotexists> or any of its parents",
"CREATE TABLE ksnotexists.targetTb LIKE ks1.sourcetb");

}
}
Loading

0 comments on commit ed700a8

Please sign in to comment.