diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 index 335576660f6b00..d8d22d76b0f773 100644 --- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 +++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 @@ -50,7 +50,7 @@ statement (ROLLUP LEFT_PAREN rollupDefs RIGHT_PAREN)? propertyClause? (AS query)? #createTable - | explain? INSERT (INTO | OVERWRITE TABLE) tableName=multipartIdentifier + | explain? INSERT IGNORE? (INTO | OVERWRITE TABLE) tableName=multipartIdentifier (PARTITION partition=identifierList)? // partition define (WITH LABEL labelName=identifier)? cols=identifierList? // label and columns define (LEFT_BRACKET hints=identifierSeq RIGHT_BRACKET)? // hint define diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundOlapTableSink.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundOlapTableSink.java index 1880581143ad37..25fc4f44e77559 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundOlapTableSink.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundOlapTableSink.java @@ -48,21 +48,29 @@ public class UnboundOlapTableSink extends LogicalSink partitions; private final boolean isPartialUpdate; private final boolean isFromNativeInsertStmt; + private final boolean isIgnoreMode; public UnboundOlapTableSink(List nameParts, List colNames, List hints, List partitions, CHILD_TYPE child) { - this(nameParts, colNames, hints, partitions, false, false, Optional.empty(), Optional.empty(), child); + this(nameParts, colNames, hints, partitions, false, false, false, Optional.empty(), Optional.empty(), child); } public UnboundOlapTableSink(List nameParts, List colNames, List hints, List partitions, boolean isPartialUpdate, CHILD_TYPE child) { - this(nameParts, colNames, hints, partitions, isPartialUpdate, false, + this(nameParts, colNames, hints, partitions, isPartialUpdate, false, false, Optional.empty(), Optional.empty(), child); } public UnboundOlapTableSink(List nameParts, List colNames, List hints, List partitions, boolean isPartialUpdate, boolean isFromNativeInsertStmt, CHILD_TYPE child) { - this(nameParts, colNames, hints, partitions, isPartialUpdate, isFromNativeInsertStmt, + this(nameParts, colNames, hints, partitions, isPartialUpdate, isFromNativeInsertStmt, false, + Optional.empty(), Optional.empty(), child); + } + + public UnboundOlapTableSink(List nameParts, List colNames, List hints, + List partitions, boolean isPartialUpdate, boolean isFromNativeInsertStmt, boolean isIgnoreMode, + CHILD_TYPE child) { + this(nameParts, colNames, hints, partitions, isPartialUpdate, isFromNativeInsertStmt, isIgnoreMode, Optional.empty(), Optional.empty(), child); } @@ -70,7 +78,7 @@ public UnboundOlapTableSink(List nameParts, List colNames, List< * constructor */ public UnboundOlapTableSink(List nameParts, List colNames, List hints, - List partitions, boolean isPartialUpdate, boolean isFromNativeInsertStmt, + List partitions, boolean isPartialUpdate, boolean isFromNativeInsertStmt, boolean isIgnoreMode, Optional groupExpression, Optional logicalProperties, CHILD_TYPE child) { super(PlanType.LOGICAL_UNBOUND_OLAP_TABLE_SINK, ImmutableList.of(), groupExpression, logicalProperties, child); @@ -80,6 +88,7 @@ public UnboundOlapTableSink(List nameParts, List colNames, List< this.partitions = Utils.copyRequiredList(partitions); this.isPartialUpdate = isPartialUpdate; this.isFromNativeInsertStmt = isFromNativeInsertStmt; + this.isIgnoreMode = isIgnoreMode; } public List getColNames() { @@ -106,11 +115,16 @@ public boolean isFromNativeInsertStmt() { return isFromNativeInsertStmt; } + public boolean isIgnoreMode() { + return isIgnoreMode; + } + @Override public Plan withChildren(List children) { Preconditions.checkArgument(children.size() == 1, "UnboundOlapTableSink only accepts one child"); return new UnboundOlapTableSink<>(nameParts, colNames, hints, partitions, isPartialUpdate, - isFromNativeInsertStmt, groupExpression, Optional.of(getLogicalProperties()), children.get(0)); + isFromNativeInsertStmt, isIgnoreMode, groupExpression, Optional.of(getLogicalProperties()), + children.get(0)); } @Override @@ -146,14 +160,15 @@ public int hashCode() { @Override public Plan withGroupExpression(Optional groupExpression) { return new UnboundOlapTableSink<>(nameParts, colNames, hints, partitions, isPartialUpdate, - isFromNativeInsertStmt, groupExpression, Optional.of(getLogicalProperties()), child()); + isFromNativeInsertStmt, isIgnoreMode, groupExpression, Optional.of(getLogicalProperties()), child()); } @Override public Plan withGroupExprLogicalPropChildren(Optional groupExpression, Optional logicalProperties, List children) { return new UnboundOlapTableSink<>(nameParts, colNames, hints, partitions, - isPartialUpdate, isFromNativeInsertStmt, groupExpression, logicalProperties, children.get(0)); + isPartialUpdate, isFromNativeInsertStmt, isIgnoreMode, groupExpression, + logicalProperties, children.get(0)); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java index a9b50c8bf1ebc1..e2226dc084831f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java @@ -402,6 +402,7 @@ public LogicalPlan visitStatementDefault(StatementDefaultContext ctx) { @Override public LogicalPlan visitInsertIntoQuery(InsertIntoQueryContext ctx) { boolean isOverwrite = ctx.INTO() == null; + boolean isIgnoreMode = ctx.IGNORE() != null; List tableName = visitMultipartIdentifier(ctx.tableName); String labelName = ctx.labelName == null ? null : ctx.labelName.getText(); List colNames = ctx.cols == null ? ImmutableList.of() : visitIdentifierList(ctx.cols); @@ -413,6 +414,7 @@ public LogicalPlan visitInsertIntoQuery(InsertIntoQueryContext ctx) { partitions, ConnectContext.get().getSessionVariable().isEnableUniqueKeyPartialUpdate(), true, + isIgnoreMode, visitQuery(ctx.query())); if (ctx.explain() != null) { return withExplain(sink, ctx.explain()); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSink.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSink.java index b8400caaebdd86..3a7f2d9bb5932c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSink.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSink.java @@ -21,6 +21,7 @@ import org.apache.doris.catalog.Column; import org.apache.doris.catalog.Database; import org.apache.doris.catalog.DatabaseIf; +import org.apache.doris.catalog.KeysType; import org.apache.doris.catalog.OlapTable; import org.apache.doris.catalog.Partition; import org.apache.doris.catalog.TableIf; @@ -75,6 +76,20 @@ public List buildRules() { LogicalPlan child = ((LogicalPlan) sink.child()); + if (sink.isIgnoreMode()) { + if (table.getKeysType() != KeysType.UNIQUE_KEYS + || !table.getEnableUniqueKeyMergeOnWrite()) { + throw new AnalysisException("ignore mode can only be enabled if the target" + + " table is a unique table with merge-on-write enabled."); + } else if (sink.isPartialUpdate()) { + throw new AnalysisException("ignore mode can't be used in partial update."); + } else if (table.hasSequenceCol()) { + throw new AnalysisException("ignore mode can't be used if the target table has" + + " sequence column, but table[" + table.getName() + + "] has sequnce column."); + } + } + LogicalOlapTableSink boundSink = new LogicalOlapTableSink<>( database, table, @@ -85,6 +100,7 @@ public List buildRules() { .collect(ImmutableList.toImmutableList()), sink.isPartialUpdate(), sink.isFromNativeInsertStmt(), + sink.isIgnoreMode(), sink.child()); // we need to insert all the columns of the target table diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalOlapTableSinkToPhysicalOlapTableSink.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalOlapTableSinkToPhysicalOlapTableSink.java index 2c727ebb8bde45..35331a101b3526 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalOlapTableSinkToPhysicalOlapTableSink.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalOlapTableSinkToPhysicalOlapTableSink.java @@ -42,6 +42,7 @@ public Rule build() { ctx.connectContext.getSessionVariable().isEnableSingleReplicaInsert(), sink.isPartialUpdate(), sink.isFromNativeInsertStmt(), + sink.isIgnoreMode(), Optional.empty(), sink.getLogicalProperties(), sink.child()); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/InsertIntoTableCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/InsertIntoTableCommand.java index e6affcb545ffda..9a9d49f3b9b03f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/InsertIntoTableCommand.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/InsertIntoTableCommand.java @@ -155,7 +155,7 @@ public void run(ConnectContext ctx, StmtExecutor executor) throws Exception { ctx.getSessionVariable().getSendBatchParallelism(), false, isStrictMode, - false); + physicalOlapTableSink.isIgnoreMode()); sink.complete(new Analyzer(Env.getCurrentEnv(), ctx)); TransactionState state = Env.getCurrentGlobalTransactionMgr().getTransactionState( diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapTableSink.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapTableSink.java index d7d890dda618e7..d6bf26bc8695ac 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapTableSink.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapTableSink.java @@ -47,20 +47,28 @@ public class LogicalOlapTableSink extends LogicalSink partitionIds; private final boolean isPartialUpdate; private final boolean isFromNativeInsertStmt; + private final boolean isIgnoreMode; public LogicalOlapTableSink(Database database, OlapTable targetTable, List cols, List partitionIds, List outputExprs, boolean isPartialUpdate, boolean isFromNativeInsertStmt, CHILD_TYPE child) { - this(database, targetTable, cols, partitionIds, outputExprs, isPartialUpdate, isFromNativeInsertStmt, + this(database, targetTable, cols, partitionIds, outputExprs, isPartialUpdate, isFromNativeInsertStmt, false, Optional.empty(), Optional.empty(), child); } + public LogicalOlapTableSink(Database database, OlapTable targetTable, List cols, List partitionIds, + List outputExprs, boolean isPartialUpdate, boolean isFromNativeInsertStmt, + boolean isIgnoreMode, CHILD_TYPE child) { + this(database, targetTable, cols, partitionIds, outputExprs, isPartialUpdate, isFromNativeInsertStmt, + isIgnoreMode, Optional.empty(), Optional.empty(), child); + } + /** * constructor */ public LogicalOlapTableSink(Database database, OlapTable targetTable, List cols, List partitionIds, List outputExprs, boolean isPartialUpdate, - boolean isFromNativeInsertStmt, Optional groupExpression, + boolean isFromNativeInsertStmt, boolean isIgnoreMode, Optional groupExpression, Optional logicalProperties, CHILD_TYPE child) { super(PlanType.LOGICAL_OLAP_TABLE_SINK, outputExprs, groupExpression, logicalProperties, child); this.database = Objects.requireNonNull(database, "database != null in LogicalOlapTableSink"); @@ -69,6 +77,7 @@ public LogicalOlapTableSink(Database database, OlapTable targetTable, List(database, targetTable, cols, partitionIds, output, isPartialUpdate, - isFromNativeInsertStmt, Optional.empty(), Optional.empty(), child); + isFromNativeInsertStmt, isIgnoreMode, Optional.empty(), Optional.empty(), child); } @Override public Plan withChildren(List children) { Preconditions.checkArgument(children.size() == 1, "LogicalOlapTableSink only accepts one child"); return new LogicalOlapTableSink<>(database, targetTable, cols, partitionIds, outputExprs, isPartialUpdate, - isFromNativeInsertStmt, Optional.empty(), Optional.empty(), children.get(0)); + isFromNativeInsertStmt, isIgnoreMode, Optional.empty(), Optional.empty(), children.get(0)); } public Database getDatabase() { @@ -110,6 +119,10 @@ public boolean isFromNativeInsertStmt() { return isFromNativeInsertStmt; } + public boolean isIgnoreMode() { + return isIgnoreMode; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -123,6 +136,7 @@ public boolean equals(Object o) { } LogicalOlapTableSink that = (LogicalOlapTableSink) o; return isPartialUpdate == that.isPartialUpdate && isFromNativeInsertStmt == that.isFromNativeInsertStmt + && isIgnoreMode == that.isIgnoreMode && Objects.equals(database, that.database) && Objects.equals(targetTable, that.targetTable) && Objects.equals(cols, that.cols) && Objects.equals(partitionIds, that.partitionIds); @@ -131,7 +145,7 @@ public boolean equals(Object o) { @Override public int hashCode() { return Objects.hash(super.hashCode(), database, targetTable, cols, partitionIds, - isPartialUpdate, isFromNativeInsertStmt); + isPartialUpdate, isFromNativeInsertStmt, isIgnoreMode); } @Override @@ -143,7 +157,8 @@ public String toString() { "cols", cols, "partitionIds", partitionIds, "isPartialUpdate", isPartialUpdate, - "isFromNativeInsertStmt", isFromNativeInsertStmt + "isFromNativeInsertStmt", isFromNativeInsertStmt, + "isIgnoreMode", isIgnoreMode ); } @@ -155,13 +170,13 @@ public R accept(PlanVisitor visitor, C context) { @Override public Plan withGroupExpression(Optional groupExpression) { return new LogicalOlapTableSink<>(database, targetTable, cols, partitionIds, outputExprs, isPartialUpdate, - isFromNativeInsertStmt, groupExpression, Optional.of(getLogicalProperties()), child()); + isFromNativeInsertStmt, isIgnoreMode, groupExpression, Optional.of(getLogicalProperties()), child()); } @Override public Plan withGroupExprLogicalPropChildren(Optional groupExpression, Optional logicalProperties, List children) { return new LogicalOlapTableSink<>(database, targetTable, cols, partitionIds, outputExprs, isPartialUpdate, - isFromNativeInsertStmt, groupExpression, logicalProperties, children.get(0)); + isFromNativeInsertStmt, isIgnoreMode, groupExpression, logicalProperties, children.get(0)); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapTableSink.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapTableSink.java index 3c0a7177fc4116..f29d5029e5006c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapTableSink.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapTableSink.java @@ -61,16 +61,17 @@ public class PhysicalOlapTableSink extends PhysicalSink private final boolean singleReplicaLoad; private final boolean isPartialUpdate; private final boolean isFromNativeInsertStmt; + private final boolean isIgnoreMode; /** * Constructor */ public PhysicalOlapTableSink(Database database, OlapTable targetTable, List cols, List partitionIds, List outputExprs, boolean singleReplicaLoad, - boolean isPartialUpdate, boolean isFromNativeInsertStmt, + boolean isPartialUpdate, boolean isFromNativeInsertStmt, boolean isIgnoreMode, Optional groupExpression, LogicalProperties logicalProperties, CHILD_TYPE child) { this(database, targetTable, cols, partitionIds, outputExprs, - singleReplicaLoad, isPartialUpdate, isFromNativeInsertStmt, + singleReplicaLoad, isPartialUpdate, isFromNativeInsertStmt, isIgnoreMode, groupExpression, logicalProperties, PhysicalProperties.GATHER, null, child); } @@ -79,7 +80,7 @@ public PhysicalOlapTableSink(Database database, OlapTable targetTable, List cols, List partitionIds, List outputExprs, boolean singleReplicaLoad, - boolean isPartialUpdate, boolean isFromNativeInsertStmt, + boolean isPartialUpdate, boolean isFromNativeInsertStmt, boolean isIgnoreMode, Optional groupExpression, LogicalProperties logicalProperties, PhysicalProperties physicalProperties, Statistics statistics, CHILD_TYPE child) { super(PlanType.PHYSICAL_OLAP_TABLE_SINK, outputExprs, groupExpression, @@ -91,6 +92,7 @@ public PhysicalOlapTableSink(Database database, OlapTable targetTable, List children) { Preconditions.checkArgument(children.size() == 1, "PhysicalOlapTableSink only accepts one child"); return new PhysicalOlapTableSink<>(database, targetTable, cols, partitionIds, outputExprs, - singleReplicaLoad, isPartialUpdate, isFromNativeInsertStmt, groupExpression, + singleReplicaLoad, isPartialUpdate, isFromNativeInsertStmt, isIgnoreMode, groupExpression, getLogicalProperties(), physicalProperties, statistics, children.get(0)); } @@ -141,6 +147,7 @@ public boolean equals(Object o) { return singleReplicaLoad == that.singleReplicaLoad && isPartialUpdate == that.isPartialUpdate && isFromNativeInsertStmt == that.isFromNativeInsertStmt + && isIgnoreMode == that.isIgnoreMode && Objects.equals(database, that.database) && Objects.equals(targetTable, that.targetTable) && Objects.equals(cols, that.cols) @@ -150,7 +157,7 @@ public boolean equals(Object o) { @Override public int hashCode() { return Objects.hash(database, targetTable, cols, partitionIds, singleReplicaLoad, - isPartialUpdate, isFromNativeInsertStmt); + isPartialUpdate, isFromNativeInsertStmt, isIgnoreMode); } @Override @@ -163,7 +170,8 @@ public String toString() { "partitionIds", partitionIds, "singleReplicaLoad", singleReplicaLoad, "isPartialUpdate", isPartialUpdate, - "isFromNativeInsertStmt", isFromNativeInsertStmt + "isFromNativeInsertStmt", isFromNativeInsertStmt, + "isIgnoreMode", isIgnoreMode ); } @@ -193,20 +201,22 @@ public List getExpressions() { @Override public Plan withGroupExpression(Optional groupExpression) { return new PhysicalOlapTableSink<>(database, targetTable, cols, partitionIds, outputExprs, singleReplicaLoad, - isPartialUpdate, isFromNativeInsertStmt, groupExpression, getLogicalProperties(), child()); + isPartialUpdate, isFromNativeInsertStmt, isIgnoreMode, groupExpression, + getLogicalProperties(), child()); } @Override public Plan withGroupExprLogicalPropChildren(Optional groupExpression, Optional logicalProperties, List children) { return new PhysicalOlapTableSink<>(database, targetTable, cols, partitionIds, outputExprs, singleReplicaLoad, - isPartialUpdate, isFromNativeInsertStmt, groupExpression, logicalProperties.get(), children.get(0)); + isPartialUpdate, isFromNativeInsertStmt, isIgnoreMode, groupExpression, + logicalProperties.get(), children.get(0)); } @Override public PhysicalPlan withPhysicalPropertiesAndStats(PhysicalProperties physicalProperties, Statistics statistics) { return new PhysicalOlapTableSink<>(database, targetTable, cols, partitionIds, outputExprs, singleReplicaLoad, - isPartialUpdate, isFromNativeInsertStmt, groupExpression, getLogicalProperties(), + isPartialUpdate, isFromNativeInsertStmt, isIgnoreMode, groupExpression, getLogicalProperties(), physicalProperties, statistics, child()); } @@ -247,7 +257,7 @@ public PhysicalProperties getRequirePhysicalProperties() { @Override public PhysicalOlapTableSink resetLogicalProperties() { return new PhysicalOlapTableSink<>(database, targetTable, cols, partitionIds, outputExprs, singleReplicaLoad, - isPartialUpdate, isFromNativeInsertStmt, groupExpression, + isPartialUpdate, isFromNativeInsertStmt, isIgnoreMode, groupExpression, null, physicalProperties, statistics, child()); } } diff --git a/regression-test/data/nereids_p0/insert_into_table/insert_ignore.out b/regression-test/data/nereids_p0/insert_into_table/insert_ignore.out new file mode 100644 index 00000000000000..bb38f60c9cc4be --- /dev/null +++ b/regression-test/data/nereids_p0/insert_into_table/insert_ignore.out @@ -0,0 +1,36 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !origin_data -- +1 kevin 18 shenzhen 400 +2 bob 20 beijing 500 +3 alice 22 shanghai 600 +4 jack 24 hangzhou 700 +5 tom 26 guanzhou 800 + +-- !after_insert_ignore -- +1 kevin 18 shenzhen 400 +2 bob 20 beijing 500 +3 alice 22 shanghai 600 +4 jack 24 hangzhou 700 +5 tom 26 guanzhou 800 +10 alex 28 shenzhen 1111 +20 leo 30 beijing 2222 +30 sam 32 shanghai 3333 +40 Ruth 34 hangzhou 4444 +50 cynthia 36 guanzhou 8000 + +-- !origin_data -- +1 1 + +-- !delete_a_row -- + +-- !after_insert_ignore -- +1 3 + +-- !sql -- +1 10 + +-- !delete_a_row -- + +-- !after_insert_ignore -- +1 1 + diff --git a/regression-test/suites/insert_p0/insert_ignore.groovy b/regression-test/suites/insert_p0/insert_ignore.groovy index 37cd7707f2e4eb..f6f5040089227e 100644 --- a/regression-test/suites/insert_p0/insert_ignore.groovy +++ b/regression-test/suites/insert_p0/insert_ignore.groovy @@ -16,6 +16,9 @@ // under the License. suite("test_insert_ignore") { + sql "set enable_nereids_dml=false;" + sql "set experimental_enable_nereids_planner=false;" + sql "sync;" def tableName = "test_insert_ignore1" sql """ DROP TABLE IF EXISTS ${tableName} FORCE;""" @@ -111,6 +114,7 @@ suite("test_insert_ignore") { sql "insert ignore into ${tableName3} values(1,3);" exception "ignore mode can only be enabled if the target table is a unique table with merge-on-write enabled." } + sql """ DROP TABLE IF EXISTS ${tableName3}; """ def tableName4 = "test_insert_ignore4" sql """ DROP TABLE IF EXISTS ${tableName4} FORCE; """ @@ -129,4 +133,5 @@ suite("test_insert_ignore") { sql "insert ignore into ${tableName4} values(1,3);" exception "ignore mode can't be used if the target table has sequence column, but table[${tableName4}] has sequnce column." } + sql """ DROP TABLE IF EXISTS ${tableName4}; """ } diff --git a/regression-test/suites/nereids_p0/insert_into_table/insert_ignore.groovy b/regression-test/suites/nereids_p0/insert_into_table/insert_ignore.groovy new file mode 100644 index 00000000000000..6df6ab0b227b96 --- /dev/null +++ b/regression-test/suites/nereids_p0/insert_into_table/insert_ignore.groovy @@ -0,0 +1,138 @@ +// 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. + +suite("test_nereids_insert_ignore") { + sql "set enable_nereids_dml=true;" + sql "set experimental_enable_nereids_planner=true;" + sql "set enable_fallback_to_original_planner=false;" + sql "sync;" + + def tableName = "test_nereids_insert_ignore1" + sql """ DROP TABLE IF EXISTS ${tableName} FORCE;""" + sql """ + CREATE TABLE ${tableName} ( + `id` int(11) NULL, + `name` varchar(10) NULL, + `age` int(11) NULL DEFAULT "20", + `city` varchar(10) NOT NULL DEFAULT "beijing", + `balance` decimalv3(9, 0) NULL + ) ENGINE = OLAP UNIQUE KEY(`id`) + COMMENT 'OLAP' DISTRIBUTED BY HASH(`id`) BUCKETS 1 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1", + "storage_format" = "V2", + "enable_unique_key_merge_on_write" = "true", + "light_schema_change" = "true", + "disable_auto_compaction" = "false", + "enable_single_replica_compaction" = "false" + ); + """ + sql """insert into ${tableName} values + (1,"kevin",18,"shenzhen",400), + (2,"bob",20,"beijing",500), + (3,"alice",22,"shanghai",600), + (4,"jack",24,"hangzhou",700), + (5,"tom",26,"guanzhou",800);""" + qt_origin_data "select * from ${tableName} order by id;" + + // some rows are with existing keys, some are not + sql """insert ignore into ${tableName} values + (1,"kevin",18,"shenzhen",4000), + (10,"alex",28,"shenzhen",1111), + (2,"bob",20,"beijing",5000), + (20,"leo",30,"beijing",2222), + (30,"sam",32,"shanghai",3333), + (3,"alice",22,"shanghai",6000), + (4,"jack",24,"hangzhou",7000), + (40,"Ruth",34,"hangzhou",4444), + (5,"tom",26,"guanzhou",8000), + (50,"cynthia",36,"guanzhou",8000);""" + + qt_after_insert_ignore "select * from ${tableName} order by id;" + sql """ DROP TABLE IF EXISTS ${tableName};""" + + def tableName2 = "test_nereids_insert_ignore2" + sql """ DROP TABLE IF EXISTS ${tableName2} FORCE; """ + sql """CREATE TABLE IF NOT EXISTS ${tableName2} ( + `uid` BIGINT NULL, + `v1` BIGINT NULL + ) + UNIQUE KEY(uid) + DISTRIBUTED BY HASH(uid) BUCKETS 1 + PROPERTIES ( + "enable_unique_key_merge_on_write" = "true", + "replication_num" = "1" + );""" + + sql "insert into ${tableName2} values(1,1);" + qt_origin_data "select * from ${tableName2} order by uid;" + + sql "insert into ${tableName2}(uid, v1, __DORIS_DELETE_SIGN__) values(1, 2, 1);" + qt_delete_a_row "select * from ${tableName2} order by uid;" + + sql "insert ignore into ${tableName2} values(1,3);" + qt_after_insert_ignore "select * from ${tableName2} order by uid;" + + sql "insert into ${tableName2} values(1,10);" + qt_sql "select * from ${tableName2} order by uid;" + + sql "insert into ${tableName2}(uid, v1, __DORIS_DELETE_SIGN__) values(1, 1, 1);" + qt_delete_a_row "select * from ${tableName2} order by uid;" + + sql "insert ignore into ${tableName2} values(1,1);" + qt_after_insert_ignore "select * from ${tableName2} order by uid;" + sql """ DROP TABLE IF EXISTS ${tableName2}; """ + + + // test illigal cases + def tableName3 = "test_nereids_insert_ignore3" + sql """ DROP TABLE IF EXISTS ${tableName3} FORCE; """ + sql """CREATE TABLE IF NOT EXISTS ${tableName3} ( + `uid` BIGINT NULL, + `v1` BIGINT NULL + ) UNIQUE KEY(uid) + DISTRIBUTED BY HASH(uid) BUCKETS 1 + PROPERTIES ( + "enable_unique_key_merge_on_write" = "false", + "replication_num" = "1" + );""" + sql "insert into ${tableName3} values(1,1);" + test { + sql "insert ignore into ${tableName3} values(1,3);" + exception "ignore mode can only be enabled if the target table is a unique table with merge-on-write enabled." + } + sql """ DROP TABLE IF EXISTS ${tableName3}; """ + + def tableName4 = "test_nereids_insert_ignore4" + sql """ DROP TABLE IF EXISTS ${tableName4} FORCE; """ + sql """CREATE TABLE IF NOT EXISTS ${tableName4} ( + `uid` BIGINT NULL, + `v1` BIGINT NULL + ) UNIQUE KEY(uid) + DISTRIBUTED BY HASH(uid) BUCKETS 1 + PROPERTIES ( + "enable_unique_key_merge_on_write" = "true", + "replication_num" = "1", + "function_column.sequence_col" = 'v1' + );""" + sql "insert into ${tableName4} values(1,1);" + test { + sql "insert ignore into ${tableName4} values(1,3);" + exception "ignore mode can't be used if the target table has sequence column, but table[${tableName4}] has sequnce column." + } + sql """ DROP TABLE IF EXISTS ${tableName4}; """ +}