Skip to content

Commit b4bcdfa

Browse files
Maxwell-Guosmiklosovic
authored andcommitted
Fail CREATE TABLE LIKE statement if UDTs in target keyspace do not exist or they have different structure from ones in source keyspace
patch by Maxwell Guo; reviewed by Stefan Miklosovic, Benjamin Lerer for CASSANDRA-19966
1 parent 0d39ea4 commit b4bcdfa

File tree

4 files changed

+153
-63
lines changed

4 files changed

+153
-63
lines changed

CHANGES.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
5.1
2+
* Fail CREATE TABLE LIKE statement if UDTs in target keyspace do not exist or they have different structure from ones in source keyspace (CASSANDRA-19966)
23
* Support octet_length and length functions (CASSANDRA-20102)
34
* Make JsonUtils serialize Instant always with the same format (CASSANDRA-20209)
45
* Port Harry v2 to trunk (CASSANDRA-20200)

src/java/org/apache/cassandra/cql3/statements/schema/CopyTableStatement.java

+39-5
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,21 @@
1818

1919
package org.apache.cassandra.cql3.statements.schema;
2020

21+
import java.nio.ByteBuffer;
22+
import java.util.Optional;
23+
import java.util.Set;
24+
import java.util.stream.Collectors;
25+
26+
import com.google.common.collect.Sets;
27+
2128
import org.apache.cassandra.audit.AuditLogContext;
2229
import org.apache.cassandra.audit.AuditLogEntryType;
2330
import org.apache.cassandra.auth.Permission;
2431
import org.apache.cassandra.cql3.CQLStatement;
2532
import org.apache.cassandra.cql3.QualifiedName;
2633
import org.apache.cassandra.db.guardrails.Guardrails;
34+
import org.apache.cassandra.db.marshal.UTF8Type;
35+
import org.apache.cassandra.db.marshal.UserType;
2736
import org.apache.cassandra.db.marshal.VectorType;
2837
import org.apache.cassandra.exceptions.AlreadyExistsException;
2938
import org.apache.cassandra.schema.Indexes;
@@ -114,14 +123,39 @@ public Keyspaces apply(ClusterMetadata metadata)
114123

115124
if (targetKeyspaceMeta.hasTable(targetTableName))
116125
{
117-
if(ifNotExists)
126+
if (ifNotExists)
118127
return schema;
119128

120129
throw new AlreadyExistsException(targetKeyspace, targetTableName);
121130
}
122-
// todo support udt for differenet ks latter
123-
if (!sourceKeyspace.equalsIgnoreCase(targetKeyspace) && !sourceTableMeta.getReferencedUserTypes().isEmpty())
124-
throw ire("Cannot use CREATE TABLE LIKE across different keyspace when source table have UDTs.");
131+
132+
if (!sourceKeyspace.equalsIgnoreCase(targetKeyspace))
133+
{
134+
Set<String> missingUserTypes = Sets.newHashSet();
135+
// for different keyspace, if source table used some udts and the target table also need them
136+
for (ByteBuffer sourceUserTypeName : sourceTableMeta.getReferencedUserTypes())
137+
{
138+
Optional<UserType> targetUserType = targetKeyspaceMeta.types.get(sourceUserTypeName);
139+
Optional<UserType> sourceUserType = sourceKeyspaceMeta.types.get(sourceUserTypeName);
140+
if (targetUserType.isPresent() && sourceUserType.isPresent())
141+
{
142+
if (!sourceUserType.get().equalsWithOutKs(targetUserType.get()))
143+
throw ire("Target keyspace '%s' has same UDT name '%s' as source keyspace '%s' but with different structure.",
144+
targetKeyspace,
145+
UTF8Type.instance.getString(targetUserType.get().name),
146+
sourceKeyspace);
147+
}
148+
else
149+
{
150+
missingUserTypes.add(UTF8Type.instance.compose(sourceUserTypeName));
151+
}
152+
}
153+
154+
if (!missingUserTypes.isEmpty())
155+
throw ire("UDTs %s do not exist in target keyspace '%s'.",
156+
missingUserTypes.stream().sorted().collect(Collectors.joining(", ")),
157+
targetKeyspace);
158+
}
125159

126160
// Guardrail on columns per table
127161
Guardrails.columnsPerTable.guard(sourceTableMeta.columns().size(), targetTableName, false, state);
@@ -130,7 +164,7 @@ public Keyspaces apply(ClusterMetadata metadata)
130164
if (columnMetadata.type.isVector())
131165
{
132166
Guardrails.vectorTypeEnabled.ensureEnabled(columnMetadata.name.toString(), state);
133-
int dimensions = ((VectorType)columnMetadata.type).dimension;
167+
int dimensions = ((VectorType) columnMetadata.type).dimension;
134168
Guardrails.vectorDimensions.guard(dimensions, columnMetadata.name.toString(), false, state);
135169
}
136170
});

src/java/org/apache/cassandra/db/marshal/UserType.java

+8
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,14 @@ private boolean equalsWithoutTypes(UserType other)
370370
&& isMultiCell == other.isMultiCell;
371371
}
372372

373+
public boolean equalsWithOutKs(UserType other)
374+
{
375+
return name.equals(other.name)
376+
&& fieldNames.equals(other.fieldNames)
377+
&& types.equals(other.types)
378+
&& isMultiCell == other.isMultiCell;
379+
}
380+
373381
public Optional<Difference> compare(UserType other)
374382
{
375383
if (!equalsWithoutTypes(other))

0 commit comments

Comments
 (0)