This is an automated email from the ASF dual-hosted git repository.
morrysnow pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 4c7d4d1c3d1 [feat](Nereids) persist constraint in table (#29767)
4c7d4d1c3d1 is described below
commit 4c7d4d1c3d121f17128efa05d324824a2a287982
Author: 谢健 <[email protected]>
AuthorDate: Tue Jan 16 18:21:40 2024 +0800
[feat](Nereids) persist constraint in table (#29767)
---
.../org/apache/doris/common/FeMetaVersion.java | 4 +-
.../main/java/org/apache/doris/catalog/Table.java | 20 +-
.../org/apache/doris/catalog/TableAttributes.java | 53 ++++
.../java/org/apache/doris/catalog/TableIf.java | 34 ++-
.../doris/catalog/constraint/Constraint.java | 31 ++-
.../catalog/constraint/ForeignKeyConstraint.java | 12 +-
.../catalog/constraint/PrimaryKeyConstraint.java | 9 +-
.../doris/catalog/constraint/TableIdentifier.java | 26 +-
.../doris/catalog/constraint/UniqueConstraint.java | 8 +-
.../doris/catalog/external/ExternalTable.java | 10 +
.../doris/datasource/ExternalSchemaCache.java | 5 +
.../org/apache/doris/journal/JournalEntity.java | 7 +
.../nereids/exceptions/MetaNotFoundException.java | 74 +++++
.../trees/plans/commands/AddConstraintCommand.java | 15 +-
.../plans/commands/DropConstraintCommand.java | 9 +-
.../plans/commands/ShowConstraintsCommand.java | 2 +-
.../apache/doris/persist/AlterConstraintLog.java | 61 +++++
.../java/org/apache/doris/persist/EditLog.java | 18 ++
.../org/apache/doris/persist/OperationType.java | 3 +
.../org/apache/doris/persist/gson/GsonUtils.java | 11 +
.../catalog/constraint/ConstraintPersistTest.java | 305 +++++++++++++++++++++
.../apache/doris/utframe/TestWithFeService.java | 11 +
22 files changed, 683 insertions(+), 45 deletions(-)
diff --git
a/fe/fe-common/src/main/java/org/apache/doris/common/FeMetaVersion.java
b/fe/fe-common/src/main/java/org/apache/doris/common/FeMetaVersion.java
index 650a831640b..387ce91e2c6 100644
--- a/fe/fe-common/src/main/java/org/apache/doris/common/FeMetaVersion.java
+++ b/fe/fe-common/src/main/java/org/apache/doris/common/FeMetaVersion.java
@@ -72,9 +72,11 @@ public final class FeMetaVersion {
public static final int VERSION_125 = 125;
// For write/read function nullable mode info
public static final int VERSION_126 = 126;
+ // For constraints
+ public static final int VERSION_127 = 127;
// note: when increment meta version, should assign the latest version to
VERSION_CURRENT
- public static final int VERSION_CURRENT = VERSION_126;
+ public static final int VERSION_CURRENT = VERSION_127;
// all logs meta version should >= the minimum version, so that we could
remove many if clause, for example
// if (FE_METAVERSION < VERSION_94) ...
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java
index 3395da6b58e..783016e7d80 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java
@@ -22,12 +22,14 @@ import org.apache.doris.catalog.constraint.Constraint;
import org.apache.doris.common.Config;
import org.apache.doris.common.DdlException;
import org.apache.doris.common.ErrorCode;
+import org.apache.doris.common.FeMetaVersion;
import org.apache.doris.common.MetaNotFoundException;
import org.apache.doris.common.io.Text;
import org.apache.doris.common.io.Writable;
import org.apache.doris.common.util.QueryableReentrantReadWriteLock;
import org.apache.doris.common.util.SqlUtils;
import org.apache.doris.common.util.Util;
+import org.apache.doris.persist.gson.GsonUtils;
import org.apache.doris.statistics.AnalysisInfo;
import org.apache.doris.statistics.BaseAnalysisTask;
import org.apache.doris.statistics.ColumnStatistic;
@@ -50,7 +52,6 @@ import java.io.DataOutput;
import java.io.IOException;
import java.time.Instant;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -116,8 +117,8 @@ public abstract class Table extends MetaObject implements
Writable, TableIf {
@SerializedName(value = "comment")
protected String comment = "";
- @SerializedName(value = "constraints")
- private HashMap<String, Constraint> constraintsMap = new HashMap<>();
+ @SerializedName(value = "ta")
+ private TableAttributes tableAttributes = new TableAttributes();
// check read lock leaky
private Map<Long, String> readLockThreads = null;
@@ -334,12 +335,12 @@ public abstract class Table extends MetaObject implements
Writable, TableIf {
}
public Constraint getConstraint(String name) {
- return constraintsMap.get(name);
+ return getConstraintsMap().get(name);
}
@Override
public Map<String, Constraint> getConstraintsMapUnsafe() {
- return constraintsMap;
+ return tableAttributes.getConstraintsMap();
}
public TableType getType() {
@@ -455,9 +456,9 @@ public abstract class Table extends MetaObject implements
Writable, TableIf {
for (Column column : fullSchema) {
column.write(out);
}
-
Text.writeString(out, comment);
-
+ // write table attributes
+ Text.writeString(out, GsonUtils.GSON.toJson(tableAttributes));
// write create time
out.writeLong(createTime);
}
@@ -488,7 +489,12 @@ public abstract class Table extends MetaObject implements
Writable, TableIf {
hasCompoundKey = true;
}
comment = Text.readString(in);
+ // table attribute only support after version 127
+ if (FeMetaVersion.VERSION_127 <= Env.getCurrentEnvJournalVersion()) {
+ String json = Text.readString(in);
+ this.tableAttributes = GsonUtils.GSON.fromJson(json,
TableAttributes.class);
+ }
// read create time
this.createTime = in.readLong();
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableAttributes.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableAttributes.java
new file mode 100644
index 00000000000..2ac86fada51
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableAttributes.java
@@ -0,0 +1,53 @@
+// 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.doris.catalog;
+
+import org.apache.doris.catalog.constraint.Constraint;
+import org.apache.doris.common.io.Text;
+import org.apache.doris.common.io.Writable;
+import org.apache.doris.persist.gson.GsonUtils;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * TableAttributes contains additional information about all table
+ */
+public class TableAttributes implements Writable {
+ @SerializedName(value = "constraints")
+ private final Map<String, Constraint> constraintsMap = new HashMap<>();
+
+
+ @Override
+ public void write(DataOutput out) throws IOException {
+ Text.writeString(out, GsonUtils.GSON.toJson(this));
+ }
+
+ public TableAttributes read(DataInput in) throws IOException {
+ return GsonUtils.GSON.fromJson(Text.readString(in),
TableAttributes.class);
+ }
+
+ public Map<String, Constraint> getConstraintsMap() {
+ return constraintsMap;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java
index bb6abcdd509..b59aedfdbf3 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java
@@ -183,7 +183,7 @@ public interface TableIf {
}
}
- default Map<String, Constraint> getConstraintMap() {
+ default Map<String, Constraint> getConstraintsMap() {
readLock();
try {
return ImmutableMap.copyOf(getConstraintsMapUnsafe());
@@ -236,25 +236,27 @@ public interface TableIf {
}
}
- default void addUniqueConstraint(String name, ImmutableList<String>
columns) {
+ default Constraint addUniqueConstraint(String name, ImmutableList<String>
columns) {
writeLock();
try {
Map<String, Constraint> constraintMap = getConstraintsMapUnsafe();
UniqueConstraint uniqueConstraint = new UniqueConstraint(name,
ImmutableSet.copyOf(columns));
checkConstraintNotExistence(name, uniqueConstraint, constraintMap);
constraintMap.put(name, uniqueConstraint);
+ return uniqueConstraint;
} finally {
writeUnlock();
}
}
- default void addPrimaryKeyConstraint(String name, ImmutableList<String>
columns) {
+ default Constraint addPrimaryKeyConstraint(String name,
ImmutableList<String> columns) {
writeLock();
try {
Map<String, Constraint> constraintMap = getConstraintsMapUnsafe();
PrimaryKeyConstraint primaryKeyConstraint = new
PrimaryKeyConstraint(name, ImmutableSet.copyOf(columns));
checkConstraintNotExistence(name, primaryKeyConstraint,
constraintMap);
constraintMap.put(name, primaryKeyConstraint);
+ return primaryKeyConstraint;
} finally {
writeUnlock();
}
@@ -277,7 +279,7 @@ public interface TableIf {
}
}
- default void addForeignConstraint(String name, ImmutableList<String>
columns,
+ default Constraint addForeignConstraint(String name, ImmutableList<String>
columns,
TableIf referencedTable, ImmutableList<String> referencedColumns) {
writeLock();
try {
@@ -289,12 +291,32 @@ public interface TableIf {
foreignKeyConstraint.getReferencedColumnNames());
updatePrimaryKeyForForeignKey(requirePrimaryKey, referencedTable);
constraintMap.put(name, foreignKeyConstraint);
+ return foreignKeyConstraint;
} finally {
writeUnlock();
}
}
- default void dropConstraint(String name) {
+ default void replayAddConstraint(Constraint constraint) {
+ if (constraint instanceof UniqueConstraint) {
+ UniqueConstraint uniqueConstraint = (UniqueConstraint) constraint;
+ this.addUniqueConstraint(constraint.getName(),
+
ImmutableList.copyOf(uniqueConstraint.getUniqueColumnNames()));
+ } else if (constraint instanceof PrimaryKeyConstraint) {
+ PrimaryKeyConstraint primaryKeyConstraint = (PrimaryKeyConstraint)
constraint;
+ this.addPrimaryKeyConstraint(primaryKeyConstraint.getName(),
+
ImmutableList.copyOf(primaryKeyConstraint.getPrimaryKeyNames()));
+ } else if (constraint instanceof ForeignKeyConstraint) {
+ ForeignKeyConstraint foreignKey = (ForeignKeyConstraint)
constraint;
+ this.addForeignConstraint(foreignKey.getName(),
+ ImmutableList.copyOf(foreignKey.getForeignKeyNames()),
+ foreignKey.getReferencedTable(),
+
ImmutableList.copyOf(foreignKey.getReferencedColumnNames()));
+ }
+ }
+
+ default Constraint dropConstraint(String name) {
+ Constraint dropConstraint;
writeLock();
try {
Map<String, Constraint> constraintMap = getConstraintsMapUnsafe();
@@ -308,9 +330,11 @@ public interface TableIf {
((PrimaryKeyConstraint) constraint).getForeignTables()
.forEach(t -> t.dropFKReferringPK(this,
(PrimaryKeyConstraint) constraint));
}
+ dropConstraint = constraint;
} finally {
writeUnlock();
}
+ return dropConstraint;
}
default void dropFKReferringPK(TableIf table, PrimaryKeyConstraint
constraint) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/Constraint.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/Constraint.java
index 9faa80f8c1e..01686aadaac 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/Constraint.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/Constraint.java
@@ -17,15 +17,25 @@
package org.apache.doris.catalog.constraint;
-public abstract class Constraint {
+import org.apache.doris.common.io.Text;
+import org.apache.doris.common.io.Writable;
+import org.apache.doris.persist.gson.GsonUtils;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+public abstract class Constraint implements Writable {
public enum ConstraintType {
FOREIGN_KEY("FOREIGN KEY"),
PRIMARY_KEY("PRIMARY KEY"),
UNIQUE("UNIQUE");
-
+ @SerializedName(value = "tn")
private final String name;
- private ConstraintType(String stringValue) {
+ ConstraintType(String stringValue) {
this.name = stringValue;
}
@@ -34,7 +44,9 @@ public abstract class Constraint {
}
}
+ @SerializedName(value = "n")
private final String name;
+ @SerializedName(value = "ty")
private final ConstraintType type;
@@ -50,4 +62,17 @@ public abstract class Constraint {
public ConstraintType getType() {
return type;
}
+
+ @Override
+ public void write(DataOutput out) throws IOException {
+ Text.writeString(out, GsonUtils.GSON.toJson(this));
+ }
+
+ /**
+ * Read Constraint.
+ **/
+ public static Constraint read(DataInput in) throws IOException {
+ String json = Text.readString(in);
+ return GsonUtils.GSON.fromJson(json, Constraint.class);
+ }
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/ForeignKeyConstraint.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/ForeignKeyConstraint.java
index 01dc00052b9..66d8e0a3706 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/ForeignKeyConstraint.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/ForeignKeyConstraint.java
@@ -24,13 +24,17 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.ImmutableSet;
+import com.google.gson.annotations.SerializedName;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
public class ForeignKeyConstraint extends Constraint {
- private final ImmutableMap<String, String> foreignToReference;
+ @SerializedName(value = "ftr")
+ private final Map<String, String> foreignToReference;
+ @SerializedName(value = "rt")
private final TableIdentifier referencedTable;
public ForeignKeyConstraint(String name, List<String> columns,
@@ -50,11 +54,11 @@ public class ForeignKeyConstraint extends Constraint {
this.foreignToReference = builder.build();
}
- public ImmutableSet<String> getForeignKeyNames() {
+ public Set<String> getForeignKeyNames() {
return foreignToReference.keySet();
}
- public ImmutableSet<String> getReferencedColumnNames() {
+ public Set<String> getReferencedColumnNames() {
return ImmutableSet.copyOf(foreignToReference.values());
}
@@ -62,7 +66,7 @@ public class ForeignKeyConstraint extends Constraint {
return foreignToReference.get(column);
}
- public ImmutableMap<String, String> getForeignToReference() {
+ public Map<String, String> getForeignToReference() {
return foreignToReference;
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/PrimaryKeyConstraint.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/PrimaryKeyConstraint.java
index c868d3a84f8..47c822ad597 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/PrimaryKeyConstraint.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/PrimaryKeyConstraint.java
@@ -23,15 +23,18 @@ import org.apache.doris.catalog.TableIf;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.gson.annotations.SerializedName;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class PrimaryKeyConstraint extends Constraint {
- private final ImmutableSet<String> columns;
+ @SerializedName(value = "cols")
+ private final Set<String> columns;
// record the foreign table which references the primary key
+ @SerializedName(value = "ft")
private final Set<TableIdentifier> foreignTables = new HashSet<>();
public PrimaryKeyConstraint(String name, Set<String> columns) {
@@ -39,11 +42,11 @@ public class PrimaryKeyConstraint extends Constraint {
this.columns = ImmutableSet.copyOf(columns);
}
- public ImmutableSet<String> getPrimaryKeyNames() {
+ public Set<String> getPrimaryKeyNames() {
return columns;
}
- public ImmutableSet<Column> getPrimaryKeys(TableIf table) {
+ public Set<Column> getPrimaryKeys(TableIf table) {
return
columns.stream().map(table::getColumn).collect(ImmutableSet.toImmutableSet());
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/TableIdentifier.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/TableIdentifier.java
index c4db65c14e8..2688fd5784d 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/TableIdentifier.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/TableIdentifier.java
@@ -20,30 +20,42 @@ package org.apache.doris.catalog.constraint;
import org.apache.doris.catalog.DatabaseIf;
import org.apache.doris.catalog.Env;
import org.apache.doris.catalog.TableIf;
+import org.apache.doris.datasource.CatalogIf;
+import org.apache.doris.nereids.exceptions.MetaNotFoundException;
import com.google.common.base.Preconditions;
+import com.google.gson.annotations.SerializedName;
import java.util.Objects;
-class TableIdentifier {
+public class TableIdentifier {
+ @SerializedName(value = "dbId")
private final long databaseId;
+ @SerializedName(value = "tId")
private final long tableId;
+ @SerializedName(value = "cId")
+ private final long catalogId;
- TableIdentifier(TableIf tableIf) {
+ public TableIdentifier(TableIf tableIf) {
Preconditions.checkArgument(tableIf != null,
"Table can not be null in constraint");
- databaseId = tableIf.getDatabase().getId();
tableId = tableIf.getId();
+ databaseId = tableIf.getDatabase().getId();
+ catalogId = tableIf.getDatabase().getCatalog().getId();
}
- TableIf toTableIf() {
- DatabaseIf databaseIf =
Env.getCurrentEnv().getCurrentCatalog().getDbNullable(databaseId);
+ public TableIf toTableIf() {
+ CatalogIf<?> catalogIf =
Env.getCurrentEnv().getCatalogMgr().getCatalog(catalogId);
+ if (catalogIf == null) {
+ throw new MetaNotFoundException(String.format("Can not find
catalog %s in constraint", catalogId));
+ }
+ DatabaseIf<?> databaseIf = catalogIf.getDbNullable(databaseId);
if (databaseIf == null) {
- throw new RuntimeException(String.format("Can not find database %s
in constraint", databaseId));
+ throw new MetaNotFoundException(String.format("Can not find
database %s in constraint", databaseId));
}
TableIf tableIf = databaseIf.getTableNullable(tableId);
if (tableIf == null) {
- throw new RuntimeException(String.format("Can not find table %s in
constraint", databaseId));
+ throw new MetaNotFoundException(String.format("Can not find table
%s in constraint", databaseId));
}
return tableIf;
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/UniqueConstraint.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/UniqueConstraint.java
index 3e8042dc8e0..0b54f13bdee 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/UniqueConstraint.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/UniqueConstraint.java
@@ -22,22 +22,24 @@ import org.apache.doris.catalog.TableIf;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
+import com.google.gson.annotations.SerializedName;
import java.util.Set;
public class UniqueConstraint extends Constraint {
- private final ImmutableSet<String> columns;
+ @SerializedName(value = "cols")
+ private final Set<String> columns;
public UniqueConstraint(String name, Set<String> columns) {
super(ConstraintType.UNIQUE, name);
this.columns = ImmutableSet.copyOf(columns);
}
- public ImmutableSet<String> getUniqueColumnNames() {
+ public Set<String> getUniqueColumnNames() {
return columns;
}
- public ImmutableSet<Column> getUniqueKeys(TableIf table) {
+ public Set<Column> getUniqueKeys(TableIf table) {
return
columns.stream().map(table::getColumn).collect(ImmutableSet.toImmutableSet());
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/external/ExternalTable.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/external/ExternalTable.java
index 49bf2858905..1af013fcbfe 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/catalog/external/ExternalTable.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/external/ExternalTable.java
@@ -21,7 +21,9 @@ import org.apache.doris.alter.AlterCancelException;
import org.apache.doris.catalog.Column;
import org.apache.doris.catalog.DatabaseIf;
import org.apache.doris.catalog.Env;
+import org.apache.doris.catalog.TableAttributes;
import org.apache.doris.catalog.TableIf;
+import org.apache.doris.catalog.constraint.Constraint;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.DdlException;
import org.apache.doris.common.ErrorCode;
@@ -77,6 +79,9 @@ public class ExternalTable implements TableIf, Writable,
GsonPostProcessable {
protected long timestamp;
@SerializedName(value = "dbName")
protected String dbName;
+ @SerializedName(value = "ta")
+ private final TableAttributes tableAttributes = new TableAttributes();
+
// this field will be refreshed after reloading schema
protected volatile long schemaUpdateTime;
@@ -272,6 +277,11 @@ public class ExternalTable implements TableIf, Writable,
GsonPostProcessable {
return null;
}
+ @Override
+ public Map<String, Constraint> getConstraintsMapUnsafe() {
+ return tableAttributes.getConstraintsMap();
+ }
+
@Override
public String getEngine() {
return getType().toEngineName();
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalSchemaCache.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalSchemaCache.java
index 3eab6028d46..962f9d977c9 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalSchemaCache.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalSchemaCache.java
@@ -94,6 +94,11 @@ public class ExternalSchemaCache {
}
}
+ public void addSchemaForTest(String dbName, String tblName,
ImmutableList<Column> schema) {
+ SchemaCacheKey key = new SchemaCacheKey(dbName, tblName);
+ schemaCache.put(key, schema);
+ }
+
public void invalidateTableCache(String dbName, String tblName) {
SchemaCacheKey key = new SchemaCacheKey(dbName, tblName);
schemaCache.invalidate(key);
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/journal/JournalEntity.java
b/fe/fe-core/src/main/java/org/apache/doris/journal/JournalEntity.java
index 6f6bc945096..1bedda0a7e9 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/journal/JournalEntity.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/journal/JournalEntity.java
@@ -58,6 +58,7 @@ import org.apache.doris.load.loadv2.LoadJobFinalOperation;
import org.apache.doris.load.routineload.RoutineLoadJob;
import org.apache.doris.load.sync.SyncJob;
import org.apache.doris.mysql.privilege.UserPropertyInfo;
+import org.apache.doris.persist.AlterConstraintLog;
import org.apache.doris.persist.AlterDatabasePropertyInfo;
import org.apache.doris.persist.AlterLightSchemaChangeInfo;
import org.apache.doris.persist.AlterMTMV;
@@ -793,6 +794,12 @@ public class JournalEntity implements Writable {
isRead = true;
break;
}
+ case OperationType.OP_DROP_CONSTRAINT:
+ case OperationType.OP_ADD_CONSTRAINT: {
+ data = AlterConstraintLog.read(in);
+ isRead = true;
+ break;
+ }
case OperationType.OP_ALTER_USER: {
data = AlterUserOperationLog.read(in);
isRead = true;
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/exceptions/MetaNotFoundException.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/exceptions/MetaNotFoundException.java
new file mode 100644
index 00000000000..f7d19c3f844
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/exceptions/MetaNotFoundException.java
@@ -0,0 +1,74 @@
+// 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.doris.nereids.exceptions;
+
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+
+import java.util.Optional;
+
+/** Nereids's AnalysisException. */
+public class MetaNotFoundException extends RuntimeException {
+ private final String message;
+ private final Optional<Integer> line;
+ private final Optional<Integer> startPosition;
+ private final Optional<LogicalPlan> plan;
+
+ public MetaNotFoundException(String message, Throwable cause,
Optional<Integer> line,
+ Optional<Integer> startPosition, Optional<LogicalPlan> plan) {
+ super(message, cause);
+ this.message = message;
+ this.line = line;
+ this.startPosition = startPosition;
+ this.plan = plan;
+ }
+
+ public MetaNotFoundException(String message, Optional<Integer> line,
+ Optional<Integer> startPosition, Optional<LogicalPlan> plan) {
+ super(message);
+ this.message = message;
+ this.line = line;
+ this.startPosition = startPosition;
+ this.plan = plan;
+ }
+
+ public MetaNotFoundException(String message, Throwable cause) {
+ this(message, cause, Optional.empty(), Optional.empty(),
Optional.empty());
+ }
+
+ public MetaNotFoundException(String message) {
+ this(message, Optional.empty(), Optional.empty(), Optional.empty());
+ }
+
+ @Override
+ public String getMessage() {
+ String planAnnotation = plan.map(p -> ";\n" +
p.treeString()).orElse("");
+ return getSimpleMessage() + planAnnotation;
+ }
+
+ private String getSimpleMessage() {
+ if (line.isPresent() || startPosition.isPresent()) {
+ String lineAnnotation = line.map(l -> "line " + l).orElse("");
+ String positionAnnotation = startPosition.map(s -> " pos " +
s).orElse("");
+ return message + ";" + lineAnnotation + positionAnnotation;
+ } else {
+ return message;
+ }
+ }
+
+ // TODO: support ErrorCode
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AddConstraintCommand.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AddConstraintCommand.java
index 4086758e74f..8c90bc0f914 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AddConstraintCommand.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AddConstraintCommand.java
@@ -17,7 +17,7 @@
package org.apache.doris.nereids.trees.plans.commands;
-import org.apache.doris.catalog.Table;
+import org.apache.doris.catalog.Env;
import org.apache.doris.catalog.TableIf;
import org.apache.doris.common.Pair;
import org.apache.doris.nereids.NereidsPlanner;
@@ -30,6 +30,7 @@ import
org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel
import org.apache.doris.nereids.trees.plans.logical.LogicalCatalogRelation;
import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
+import org.apache.doris.persist.AlterConstraintLog;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.StmtExecutor;
@@ -46,6 +47,7 @@ import java.util.Set;
public class AddConstraintCommand extends Command implements ForwardWithSync {
public static final Logger LOG =
LogManager.getLogger(AddConstraintCommand.class);
+
private final String name;
private final Constraint constraint;
@@ -61,16 +63,19 @@ public class AddConstraintCommand extends Command
implements ForwardWithSync {
@Override
public void run(ConnectContext ctx, StmtExecutor executor) throws
Exception {
Pair<ImmutableList<String>, TableIf> columnsAndTable =
extractColumnsAndTable(ctx, constraint.toProject());
+ org.apache.doris.catalog.constraint.Constraint catalogConstraint =
null;
if (constraint.isForeignKey()) {
Pair<ImmutableList<String>, TableIf> referencedColumnsAndTable
= extractColumnsAndTable(ctx,
constraint.toReferenceProject());
- columnsAndTable.second.addForeignConstraint(name,
columnsAndTable.first,
+ catalogConstraint =
columnsAndTable.second.addForeignConstraint(name, columnsAndTable.first,
referencedColumnsAndTable.second,
referencedColumnsAndTable.first);
} else if (constraint.isPrimaryKey()) {
- columnsAndTable.second.addPrimaryKeyConstraint(name,
columnsAndTable.first);
+ catalogConstraint =
columnsAndTable.second.addPrimaryKeyConstraint(name, columnsAndTable.first);
} else if (constraint.isUnique()) {
- columnsAndTable.second.addUniqueConstraint(name,
columnsAndTable.first);
+ catalogConstraint =
columnsAndTable.second.addUniqueConstraint(name, columnsAndTable.first);
}
+ Env.getCurrentEnv().getEditLog().logAddConstraint(
+ new AlterConstraintLog(catalogConstraint,
columnsAndTable.second));
}
private Pair<ImmutableList<String>, TableIf>
extractColumnsAndTable(ConnectContext ctx, LogicalPlan plan) {
@@ -82,8 +87,6 @@ public class AddConstraintCommand extends Command implements
ForwardWithSync {
throw new AnalysisException("Can not found table in constraint " +
constraint.toString());
}
LogicalCatalogRelation catalogRelation =
logicalCatalogRelationSet.iterator().next();
- Preconditions.checkArgument(catalogRelation.getTable() instanceof
Table,
- "We only support table now but we meet ",
catalogRelation.getTable());
ImmutableList<String> columns = analyzedPlan.getOutput().stream()
.map(s -> {
Preconditions.checkArgument(s instanceof SlotReference
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/DropConstraintCommand.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/DropConstraintCommand.java
index 202f53197d2..84143f234c3 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/DropConstraintCommand.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/DropConstraintCommand.java
@@ -17,7 +17,7 @@
package org.apache.doris.nereids.trees.plans.commands;
-import org.apache.doris.catalog.Table;
+import org.apache.doris.catalog.Env;
import org.apache.doris.catalog.TableIf;
import org.apache.doris.nereids.NereidsPlanner;
import org.apache.doris.nereids.exceptions.AnalysisException;
@@ -28,10 +28,10 @@ import
org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel
import org.apache.doris.nereids.trees.plans.logical.LogicalCatalogRelation;
import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
+import org.apache.doris.persist.AlterConstraintLog;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.StmtExecutor;
-import com.google.common.base.Preconditions;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -58,7 +58,8 @@ public class DropConstraintCommand extends Command implements
ForwardWithSync {
@Override
public void run(ConnectContext ctx, StmtExecutor executor) throws
Exception {
TableIf table = extractTable(ctx, plan);
- table.dropConstraint(name);
+ org.apache.doris.catalog.constraint.Constraint catalogConstraint =
table.dropConstraint(name);
+ Env.getCurrentEnv().getEditLog().logDropConstraint(new
AlterConstraintLog(catalogConstraint, table));
}
private TableIf extractTable(ConnectContext ctx, LogicalPlan plan) {
@@ -70,8 +71,6 @@ public class DropConstraintCommand extends Command implements
ForwardWithSync {
throw new AnalysisException("Can not found table when dropping
constraint");
}
LogicalCatalogRelation catalogRelation =
logicalCatalogRelationSet.iterator().next();
- Preconditions.checkArgument(catalogRelation.getTable() instanceof
Table,
- "Don't support table ", catalogRelation.getTable());
return catalogRelation.getTable();
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowConstraintsCommand.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowConstraintsCommand.java
index 32950308e01..13d1f0c5f6d 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowConstraintsCommand.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowConstraintsCommand.java
@@ -51,7 +51,7 @@ public class ShowConstraintsCommand extends Command
implements NoForward {
public void run(ConnectContext ctx, StmtExecutor executor) throws
Exception {
TableIf tableIf = RelationUtil.getDbAndTable(
RelationUtil.getQualifierName(ctx, nameParts),
ctx.getEnv()).value();
- List<List<String>> res = tableIf.getConstraintMap().entrySet().stream()
+ List<List<String>> res =
tableIf.getConstraintsMap().entrySet().stream()
.map(e -> Lists.newArrayList(e.getKey(),
e.getValue().getType().getName(),
e.getValue().toString()))
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/persist/AlterConstraintLog.java
b/fe/fe-core/src/main/java/org/apache/doris/persist/AlterConstraintLog.java
new file mode 100644
index 00000000000..eef8b2cd2b5
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/AlterConstraintLog.java
@@ -0,0 +1,61 @@
+// 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.doris.persist;
+
+import org.apache.doris.catalog.TableIf;
+import org.apache.doris.catalog.constraint.Constraint;
+import org.apache.doris.catalog.constraint.TableIdentifier;
+import org.apache.doris.common.io.Text;
+import org.apache.doris.common.io.Writable;
+import org.apache.doris.persist.gson.GsonUtils;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+public class AlterConstraintLog implements Writable {
+ @SerializedName("ct")
+ final Constraint constraint;
+ @SerializedName("tid")
+ final TableIdentifier tableIdentifier;
+
+ public AlterConstraintLog(Constraint constraint, TableIf table) {
+ this.constraint = constraint;
+ this.tableIdentifier = new TableIdentifier(table);
+ }
+
+ public TableIf getTableIf() {
+ return tableIdentifier.toTableIf();
+ }
+
+ public Constraint getConstraint() {
+ return constraint;
+ }
+
+ @Override
+ public void write(DataOutput out) throws IOException {
+ Text.writeString(out, GsonUtils.GSON.toJson(this));
+ }
+
+ public static AlterConstraintLog read(DataInput in) throws IOException {
+ String json = Text.readString(in);
+ return GsonUtils.GSON.fromJson(json, AlterConstraintLog.class);
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java
b/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java
index 6eae5a68864..fb97c02b00c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java
@@ -973,6 +973,16 @@ public class EditLog {
case OperationType.OP_ALTER_MTMV_STMT: {
break;
}
+ case OperationType.OP_ADD_CONSTRAINT: {
+ final AlterConstraintLog log = (AlterConstraintLog)
journal.getData();
+ log.getTableIf().replayAddConstraint(log.getConstraint());
+ break;
+ }
+ case OperationType.OP_DROP_CONSTRAINT: {
+ final AlterConstraintLog log = (AlterConstraintLog)
journal.getData();
+
log.getTableIf().dropConstraint(log.getConstraint().getName());
+ break;
+ }
case OperationType.OP_ALTER_USER: {
final AlterUserOperationLog log = (AlterUserOperationLog)
journal.getData();
env.getAuth().replayAlterUser(log);
@@ -1969,6 +1979,14 @@ public class EditLog {
}
+ public void logAddConstraint(AlterConstraintLog log) {
+ logEdit(OperationType.OP_ADD_CONSTRAINT, log);
+ }
+
+ public void logDropConstraint(AlterConstraintLog log) {
+ logEdit(OperationType.OP_DROP_CONSTRAINT, log);
+ }
+
public void logInsertOverwrite(InsertOverwriteLog log) {
logEdit(OperationType.OP_INSERT_OVERWRITE, log);
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/persist/OperationType.java
b/fe/fe-core/src/main/java/org/apache/doris/persist/OperationType.java
index d26ddc12f49..42312297b91 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/persist/OperationType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/OperationType.java
@@ -285,6 +285,8 @@ public class OperationType {
public static final short OP_CHANGE_MTMV_TASK = 342;
@Deprecated
public static final short OP_ALTER_MTMV_STMT = 345;
+ public static final short OP_ADD_CONSTRAINT = 346;
+ public static final short OP_DROP_CONSTRAINT = 347;
public static final short OP_DROP_EXTERNAL_TABLE = 350;
public static final short OP_DROP_EXTERNAL_DB = 351;
@@ -355,6 +357,7 @@ public class OperationType {
public static final short OP_INSERT_OVERWRITE = 461;
+
/**
* Get opcode name by op code.
**/
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/persist/gson/GsonUtils.java
b/fe/fe-core/src/main/java/org/apache/doris/persist/gson/GsonUtils.java
index db49ecdc992..54c109b61a5 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/persist/gson/GsonUtils.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/gson/GsonUtils.java
@@ -44,6 +44,10 @@ import org.apache.doris.catalog.SinglePartitionInfo;
import org.apache.doris.catalog.SparkResource;
import org.apache.doris.catalog.StructType;
import org.apache.doris.catalog.TableIf;
+import org.apache.doris.catalog.constraint.Constraint;
+import org.apache.doris.catalog.constraint.ForeignKeyConstraint;
+import org.apache.doris.catalog.constraint.PrimaryKeyConstraint;
+import org.apache.doris.catalog.constraint.UniqueConstraint;
import org.apache.doris.catalog.external.EsExternalDatabase;
import org.apache.doris.catalog.external.EsExternalTable;
import org.apache.doris.catalog.external.ExternalDatabase;
@@ -202,6 +206,12 @@ public class GsonUtils {
Policy.class, "clazz").registerSubtype(RowPolicy.class,
RowPolicy.class.getSimpleName())
.registerSubtype(StoragePolicy.class,
StoragePolicy.class.getSimpleName());
+ private static RuntimeTypeAdapterFactory<Constraint>
constraintTypeAdapterFactory = RuntimeTypeAdapterFactory.of(
+ Constraint.class, "clazz")
+ .registerSubtype(PrimaryKeyConstraint.class,
PrimaryKeyConstraint.class.getSimpleName())
+ .registerSubtype(ForeignKeyConstraint.class,
ForeignKeyConstraint.class.getSimpleName())
+ .registerSubtype(UniqueConstraint.class,
UniqueConstraint.class.getSimpleName());
+
private static RuntimeTypeAdapterFactory<CatalogIf> dsTypeAdapterFactory =
RuntimeTypeAdapterFactory.of(
CatalogIf.class, "clazz")
.registerSubtype(InternalCatalog.class,
InternalCatalog.class.getSimpleName())
@@ -287,6 +297,7 @@ public class GsonUtils {
.registerTypeAdapterFactory(hbResponseTypeAdapterFactory)
.registerTypeAdapterFactory(rdsTypeAdapterFactory)
.registerTypeAdapterFactory(jobExecutorRuntimeTypeAdapterFactory)
+ .registerTypeAdapterFactory(constraintTypeAdapterFactory)
.registerTypeAdapter(ImmutableMap.class, new
ImmutableMapDeserializer())
.registerTypeAdapter(AtomicBoolean.class, new
AtomicBooleanAdapter())
.registerTypeAdapter(PartitionKey.class, new
PartitionKey.PartitionKeySerializer())
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/catalog/constraint/ConstraintPersistTest.java
b/fe/fe-core/src/test/java/org/apache/doris/catalog/constraint/ConstraintPersistTest.java
new file mode 100644
index 00000000000..64f3db583ad
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/catalog/constraint/ConstraintPersistTest.java
@@ -0,0 +1,305 @@
+// 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.doris.catalog.constraint;
+
+import org.apache.doris.catalog.Column;
+import org.apache.doris.catalog.DatabaseIf;
+import org.apache.doris.catalog.Env;
+import org.apache.doris.catalog.PrimitiveType;
+import org.apache.doris.catalog.Table;
+import org.apache.doris.catalog.TableIf;
+import org.apache.doris.catalog.external.EsExternalDatabase;
+import org.apache.doris.catalog.external.EsExternalTable;
+import org.apache.doris.catalog.external.ExternalTable;
+import org.apache.doris.common.Config;
+import org.apache.doris.datasource.EsExternalCatalog;
+import org.apache.doris.journal.JournalEntity;
+import org.apache.doris.nereids.util.PlanPatternMatchSupported;
+import org.apache.doris.nereids.util.RelationUtil;
+import org.apache.doris.persist.AlterConstraintLog;
+import org.apache.doris.persist.EditLog;
+import org.apache.doris.persist.OperationType;
+import org.apache.doris.utframe.TestWithFeService;
+
+import com.google.common.collect.ImmutableList;
+import mockit.Mock;
+import mockit.MockUp;
+import org.apache.hadoop.util.Lists;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+class ConstraintPersistTest extends TestWithFeService implements
PlanPatternMatchSupported {
+
+ @Override
+ public void runBeforeAll() throws Exception {
+ createDatabase("test");
+ connectContext.setDatabase("test");
+ createTable("create table t1 (\n"
+ + " k1 int,\n"
+ + " k2 int\n"
+ + ")\n"
+ + "unique key(k1, k2)\n"
+ + "distributed by hash(k1) buckets 4\n"
+ + "properties(\n"
+ + " \"replication_num\"=\"1\"\n"
+ + ")");
+ createTable("create table t2 (\n"
+ + " k1 int,\n"
+ + " k2 int\n"
+ + ")\n"
+ + "unique key(k1, k2)\n"
+ + "distributed by hash(k1) buckets 4\n"
+ + "properties(\n"
+ + " \"replication_num\"=\"1\"\n"
+ + ")");
+ }
+
+ @Test
+ void addConstraintLogPersistTest() throws Exception {
+ Config.edit_log_type = "local";
+ addConstraint("alter table t1 add constraint pk primary key (k1)");
+ addConstraint("alter table t2 add constraint pk primary key (k1)");
+ addConstraint("alter table t1 add constraint uk unique (k1)");
+ addConstraint("alter table t1 add constraint fk foreign key (k1)
references t2(k1)");
+ TableIf tableIf = RelationUtil.getTable(
+ RelationUtil.getQualifierName(connectContext,
Lists.newArrayList("test", "t1")),
+ connectContext.getEnv());
+ Map<String, Constraint> constraintMap = tableIf.getConstraintsMap();
+ tableIf.getConstraintsMapUnsafe().clear();
+ Assertions.assertTrue(tableIf.getConstraintsMap().isEmpty());
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ DataOutput output = new DataOutputStream(outputStream);
+ for (Constraint value : constraintMap.values()) {
+ JournalEntity journalEntity = new JournalEntity();
+ journalEntity.setData(new AlterConstraintLog(value, tableIf));
+ journalEntity.setOpCode(OperationType.OP_ADD_CONSTRAINT);
+ journalEntity.write(output);
+ }
+ InputStream inputStream = new
ByteArrayInputStream(outputStream.toByteArray());
+ DataInput input = new DataInputStream(inputStream);
+ for (int i = 0; i < constraintMap.values().size(); i++) {
+ JournalEntity journalEntity = new JournalEntity();
+ journalEntity.readFields(input);
+ EditLog.loadJournal(Env.getCurrentEnv(), 0L, journalEntity);
+ }
+ Assertions.assertEquals(tableIf.getConstraintsMap(), constraintMap);
+ dropConstraint("alter table t1 drop constraint fk");
+ dropConstraint("alter table t1 drop constraint pk");
+ dropConstraint("alter table t2 drop constraint pk");
+ dropConstraint("alter table t1 drop constraint uk");
+ }
+
+ @Test
+ void dropConstraintLogPersistTest() throws Exception {
+ Config.edit_log_type = "local";
+ addConstraint("alter table t1 add constraint pk primary key (k1)");
+ addConstraint("alter table t2 add constraint pk primary key (k1)");
+ addConstraint("alter table t1 add constraint uk unique (k1)");
+ addConstraint("alter table t1 add constraint fk foreign key (k1)
references t2(k1)");
+ TableIf tableIf = RelationUtil.getTable(
+ RelationUtil.getQualifierName(connectContext,
Lists.newArrayList("test", "t1")),
+ connectContext.getEnv());
+ Map<String, Constraint> constraintMap = tableIf.getConstraintsMap();
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ DataOutput output = new DataOutputStream(outputStream);
+ for (Constraint value : constraintMap.values()) {
+ JournalEntity journalEntity = new JournalEntity();
+ journalEntity.setData(new AlterConstraintLog(value, tableIf));
+ journalEntity.setOpCode(OperationType.OP_DROP_CONSTRAINT);
+ journalEntity.write(output);
+ }
+ InputStream inputStream = new
ByteArrayInputStream(outputStream.toByteArray());
+ DataInput input = new DataInputStream(inputStream);
+ for (int i = 0; i < constraintMap.values().size(); i++) {
+ JournalEntity journalEntity = new JournalEntity();
+ journalEntity.readFields(input);
+ EditLog.loadJournal(Env.getCurrentEnv(), 0L, journalEntity);
+ }
+ Assertions.assertTrue(tableIf.getConstraintsMap().isEmpty());
+ }
+
+ @Test
+ void constraintWithTablePersistTest() throws Exception {
+ addConstraint("alter table t1 add constraint pk primary key (k1)");
+ addConstraint("alter table t2 add constraint pk primary key (k1)");
+ addConstraint("alter table t1 add constraint uk unique (k1)");
+ addConstraint("alter table t1 add constraint fk foreign key (k1)
references t2(k1)");
+ TableIf tableIf = RelationUtil.getTable(
+ RelationUtil.getQualifierName(connectContext,
Lists.newArrayList("test", "t1")),
+ connectContext.getEnv());
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ DataOutput output = new DataOutputStream(outputStream);
+ tableIf.write(output);
+ InputStream inputStream = new
ByteArrayInputStream(outputStream.toByteArray());
+ DataInput input = new DataInputStream(inputStream);
+ TableIf loadTable = Table.read(input);
+ Assertions.assertEquals(loadTable.getConstraintsMap(),
tableIf.getConstraintsMap());
+ dropConstraint("alter table t1 drop constraint fk");
+ dropConstraint("alter table t1 drop constraint pk");
+ dropConstraint("alter table t2 drop constraint pk");
+ dropConstraint("alter table t1 drop constraint uk");
+ }
+
+ @Test
+ void externalTableTest() throws Exception {
+ ExternalTable externalTable = new ExternalTable();
+ externalTable.addPrimaryKeyConstraint("pk", ImmutableList.of("col"));
+
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ DataOutput output = new DataOutputStream(outputStream);
+ externalTable.write(output);
+ InputStream inputStream = new
ByteArrayInputStream(outputStream.toByteArray());
+ DataInput input = new DataInputStream(inputStream);
+ TableIf loadTable = ExternalTable.read(input);
+ Assertions.assertEquals(1, loadTable.getConstraintsMap().size());
+ }
+
+ @Test
+ void addConstraintLogPersistForExternalTableTest() throws Exception {
+ Config.edit_log_type = "local";
+ createCatalog("create catalog es properties('type' = 'es',
'elasticsearch.hosts' = 'http://192.168.0.1',"
+ + " 'elasticsearch.username' = 'user1');");
+
+ Env.getCurrentEnv().changeCatalog(connectContext, "es");
+ EsExternalCatalog esCatalog = (EsExternalCatalog) getCatalog("es");
+ EsExternalDatabase db = new EsExternalDatabase(esCatalog, 10002,
"es_db1");
+ EsExternalTable tbl = new EsExternalTable(10003, "es_tbl1", "es_db1",
esCatalog);
+ ImmutableList<Column> schema = ImmutableList.of(new Column("k1",
PrimitiveType.INT));
+ tbl.setNewFullSchema(schema);
+ db.addTableForTest(tbl);
+ esCatalog.addDatabaseForTest(db);
+
Env.getCurrentEnv().getExtMetaCacheMgr().getSchemaCache(esCatalog).addSchemaForTest(db.getFullName(),
tbl.getName(), schema);
+ new MockUp<RelationUtil>() {
+ @Mock
+ public TableIf getTable(List<String> qualifierName, Env env) {
+ return tbl;
+ }
+ };
+
+ new MockUp<ExternalTable>() {
+ @Mock
+ public DatabaseIf getDatabase() {
+ return db;
+ }
+ };
+
+ new MockUp<TableIdentifier>() {
+ @Mock
+ public TableIf toTableIf() {
+ return tbl;
+ }
+ };
+
+ addConstraint("alter table es.es_db1.es_tbl1 add constraint pk primary
key (k1)");
+ addConstraint("alter table es.es_db1.es_tbl1 add constraint uk unique
(k1)");
+ TableIf tableIf = RelationUtil.getTable(
+ RelationUtil.getQualifierName(connectContext,
Lists.newArrayList("test", "t1")),
+ connectContext.getEnv());
+ Map<String, Constraint> constraintMap = tableIf.getConstraintsMap();
+ tableIf.getConstraintsMapUnsafe().clear();
+ Assertions.assertTrue(tableIf.getConstraintsMap().isEmpty());
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ DataOutput output = new DataOutputStream(outputStream);
+ for (Constraint value : new ArrayList<>(constraintMap.values())) {
+ JournalEntity journalEntity = new JournalEntity();
+ journalEntity.setData(new AlterConstraintLog(value, tableIf));
+ journalEntity.setOpCode(OperationType.OP_ADD_CONSTRAINT);
+ journalEntity.write(output);
+ }
+ InputStream inputStream = new
ByteArrayInputStream(outputStream.toByteArray());
+ DataInput input = new DataInputStream(inputStream);
+ for (int i = 0; i < constraintMap.values().size(); i++) {
+ JournalEntity journalEntity = new JournalEntity();
+ journalEntity.readFields(input);
+ EditLog.loadJournal(Env.getCurrentEnv(), 0L, journalEntity);
+ }
+ Assertions.assertEquals(tableIf.getConstraintsMap(), constraintMap);
+ Env.getCurrentEnv().changeCatalog(connectContext, "internal");
+ }
+
+ @Test
+ void dropConstraintLogPersistForExternalTest() throws Exception {
+ Config.edit_log_type = "local";
+ createCatalog("create catalog es2 properties('type' = 'es',
'elasticsearch.hosts' = 'http://192.168.0.1',"
+ + " 'elasticsearch.username' = 'user1');");
+
+ Env.getCurrentEnv().changeCatalog(connectContext, "es2");
+ EsExternalCatalog esCatalog = (EsExternalCatalog) getCatalog("es2");
+ EsExternalDatabase db = new EsExternalDatabase(esCatalog, 10002,
"es_db1");
+ EsExternalTable tbl = new EsExternalTable(10003, "es_tbl1", "es_db1",
esCatalog);
+ ImmutableList<Column> schema = ImmutableList.of(new Column("k1",
PrimitiveType.INT));
+ tbl.setNewFullSchema(schema);
+ db.addTableForTest(tbl);
+ esCatalog.addDatabaseForTest(db);
+
Env.getCurrentEnv().getExtMetaCacheMgr().getSchemaCache(esCatalog).addSchemaForTest(db.getFullName(),
tbl.getName(), schema);
+ new MockUp<RelationUtil>() {
+ @Mock
+ public TableIf getTable(List<String> qualifierName, Env env) {
+ return tbl;
+ }
+ };
+
+ new MockUp<ExternalTable>() {
+ @Mock
+ public DatabaseIf getDatabase() {
+ return db;
+ }
+ };
+
+ new MockUp<TableIdentifier>() {
+ @Mock
+ public TableIf toTableIf() {
+ return tbl;
+ }
+ };
+ addConstraint("alter table es.es_db1.es_tbl1 add constraint pk primary
key (k1)");
+ addConstraint("alter table es.es_db1.es_tbl1 add constraint uk unique
(k1)");
+ TableIf tableIf = RelationUtil.getTable(
+ RelationUtil.getQualifierName(connectContext,
Lists.newArrayList("test", "t1")),
+ connectContext.getEnv());
+ Map<String, Constraint> constraintMap = tableIf.getConstraintsMap();
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ DataOutput output = new DataOutputStream(outputStream);
+ for (Constraint value : constraintMap.values()) {
+ JournalEntity journalEntity = new JournalEntity();
+ journalEntity.setData(new AlterConstraintLog(value, tableIf));
+ journalEntity.setOpCode(OperationType.OP_DROP_CONSTRAINT);
+ journalEntity.write(output);
+ }
+ InputStream inputStream = new
ByteArrayInputStream(outputStream.toByteArray());
+ DataInput input = new DataInputStream(inputStream);
+ for (int i = 0; i < constraintMap.values().size(); i++) {
+ JournalEntity journalEntity = new JournalEntity();
+ journalEntity.readFields(input);
+ EditLog.loadJournal(Env.getCurrentEnv(), 0L, journalEntity);
+ }
+ Assertions.assertTrue(tableIf.getConstraintsMap().isEmpty());
+ Env.getCurrentEnv().changeCatalog(connectContext, "internal");
+ }
+}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java
b/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java
index 85f6e22e6f4..1f57040d305 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java
@@ -21,6 +21,7 @@ import org.apache.doris.alter.AlterJobV2;
import org.apache.doris.analysis.AlterSqlBlockRuleStmt;
import org.apache.doris.analysis.AlterTableStmt;
import org.apache.doris.analysis.Analyzer;
+import org.apache.doris.analysis.CreateCatalogStmt;
import org.apache.doris.analysis.CreateDbStmt;
import org.apache.doris.analysis.CreateFunctionStmt;
import org.apache.doris.analysis.CreateMaterializedViewStmt;
@@ -55,6 +56,7 @@ import org.apache.doris.common.DdlException;
import org.apache.doris.common.FeConstants;
import org.apache.doris.common.MetaNotFoundException;
import org.apache.doris.common.util.SqlParserUtils;
+import org.apache.doris.datasource.CatalogIf;
import org.apache.doris.nereids.CascadesContext;
import org.apache.doris.nereids.StatementContext;
import org.apache.doris.nereids.glue.LogicalPlanAdapter;
@@ -650,6 +652,15 @@ public abstract class TestWithFeService {
Env.getCurrentEnv().createTableAsSelect(createTableAsSelectStmt);
}
+ public void createCatalog(String sql) throws Exception {
+ CreateCatalogStmt stmt = (CreateCatalogStmt) parseAndAnalyzeStmt(sql,
connectContext);
+ Env.getCurrentEnv().getCatalogMgr().createCatalog(stmt);
+ }
+
+ public CatalogIf getCatalog(String name) throws Exception {
+ return Env.getCurrentEnv().getCatalogMgr().getCatalog(name);
+ }
+
public void createTables(String... sqls) throws Exception {
createTables(false, sqls);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]