Skip to content

Commit

Permalink
[BugFix] Fix the bug that partition by range(str2date) does not check…
Browse files Browse the repository at this point in the history
… parameters (StarRocks#45838)

Signed-off-by: HangyuanLiu <[email protected]>
  • Loading branch information
HangyuanLiu authored May 20, 2024
1 parent 5272aeb commit 8ae5186
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,7 @@ private void checkPartitionColumnExprs(CreateMaterializedViewStatement statement
// e.g. partition by date_trunc('month', dt)
FunctionCallExpr functionCallExpr = (FunctionCallExpr) expressionPartitionDesc.getExpr();
String functionName = functionCallExpr.getFnName().getFunction();
if (!MaterializedViewPartitionFunctionChecker.FN_NAME_TO_PATTERN.containsKey(functionName)) {
if (!PartitionFunctionChecker.FN_NAME_TO_PATTERN.containsKey(functionName)) {
throw new SemanticException("Materialized view partition function " +
functionCallExpr.getFnName().getFunction() +
" is not supported yet.", functionCallExpr.getPos());
Expand Down Expand Up @@ -740,8 +740,8 @@ private void checkPartitionExpPatterns(CreateMaterializedViewStatement statement
if (expr instanceof FunctionCallExpr) {
FunctionCallExpr functionCallExpr = ((FunctionCallExpr) expr);
String functionName = functionCallExpr.getFnName().getFunction();
MaterializedViewPartitionFunctionChecker.CheckPartitionFunction checkPartitionFunction =
MaterializedViewPartitionFunctionChecker.FN_NAME_TO_PATTERN.get(functionName);
PartitionFunctionChecker.CheckPartitionFunction checkPartitionFunction =
PartitionFunctionChecker.FN_NAME_TO_PATTERN.get(functionName);
if (checkPartitionFunction == null) {
throw new SemanticException("Materialized view partition function " +
functionName + " is not support: " + expr.toSqlWithoutTbl(), functionCallExpr.getPos());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

import static com.starrocks.sql.common.TimeUnitUtils.TIME_MAP;

public class MaterializedViewPartitionFunctionChecker {
public class PartitionFunctionChecker {
@FunctionalInterface
public interface CheckPartitionFunction {
boolean check(Expr expr);
Expand All @@ -41,8 +41,8 @@ public interface CheckPartitionFunction {
static {
FN_NAME_TO_PATTERN = Maps.newHashMap();
// can add some other functions
FN_NAME_TO_PATTERN.put("date_trunc", MaterializedViewPartitionFunctionChecker::checkDateTrunc);
FN_NAME_TO_PATTERN.put("str2date", MaterializedViewPartitionFunctionChecker::checkStr2date);
FN_NAME_TO_PATTERN.put("date_trunc", PartitionFunctionChecker::checkDateTrunc);
FN_NAME_TO_PATTERN.put("str2date", PartitionFunctionChecker::checkStr2date);
}

public static boolean checkDateTrunc(Expr expr) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@
import com.starrocks.common.DdlException;
import com.starrocks.sql.analyzer.AnalyzerUtils;
import com.starrocks.sql.analyzer.PartitionExprAnalyzer;
import com.starrocks.sql.analyzer.PartitionFunctionChecker;
import com.starrocks.sql.analyzer.SemanticException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class ExpressionPartitionDesc extends PartitionDesc {

Expand All @@ -48,6 +51,9 @@ public class ExpressionPartitionDesc extends PartitionDesc {
// range partition desc == null means this must be materialized view
private RangePartitionDesc rangePartitionDesc = null;

private static final List<String> AUTO_PARTITION_SUPPORT_FUNCTIONS =
Lists.newArrayList(FunctionSet.TIME_SLICE, FunctionSet.DATE_TRUNC);

public ExpressionPartitionDesc(RangePartitionDesc rangePartitionDesc, Expr expr) {
super(expr.getPos());
this.rangePartitionDesc = rangePartitionDesc;
Expand Down Expand Up @@ -97,6 +103,12 @@ public void analyze(List<ColumnDef> columnDefs, Map<String, String> otherPropert
if (rangePartitionDesc.isAutoPartitionTable) {
rangePartitionDesc.setAutoPartitionTable(true);
slotRef = AnalyzerUtils.getSlotRefFromFunctionCall(expr);
if (expr instanceof FunctionCallExpr) {
FunctionCallExpr functionCallExpr = (FunctionCallExpr) expr;
if (!AUTO_PARTITION_SUPPORT_FUNCTIONS.contains(functionCallExpr.getFnName().getFunction())) {
throw new SemanticException("Only support date_trunc and time_slice as partition expression");
}
}
} else {
// for partition by range expr table
// The type of the partition field may be different from the type after the expression
Expand All @@ -105,9 +117,19 @@ public void analyze(List<ColumnDef> columnDefs, Map<String, String> otherPropert
partitionType = ((CastExpr) expr).getTargetTypeDef().getType();
} else if (expr instanceof FunctionCallExpr) {
slotRef = AnalyzerUtils.getSlotRefFromFunctionCall(expr);

Optional<ColumnDef> columnDef = columnDefs.stream()
.filter(c -> c.getName().equals(slotRef.getColumnName())).findFirst();
Preconditions.checkState(columnDef.isPresent());
slotRef.setType(columnDef.get().getType());

String functionName = ((FunctionCallExpr) expr).getFnName().getFunction().toLowerCase();
if (functionName.equals(FunctionSet.STR2DATE)) {
partitionType = Type.DATE;
if (!PartitionFunctionChecker.checkStr2date(expr)) {
throw new SemanticException("partition function check fail, only supports the result " +
"of the function str2date(VARCHAR str, VARCHAR format) as a strict DATE type");
}
}
} else {
throw new AnalysisException("Unsupported expr:" + expr.toSql());
Expand Down
13 changes: 12 additions & 1 deletion test/sql/test_partition_by_expr/R/test_expr_str2date
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ insert into partition_str2date values('2021-01-05','1',1.1,1);
insert into partition_str2date values('2021-01-06','1',1.1,1);
-- result:
-- !result
select * from partition_str2date;
select * from partition_str2date order by create_time;
-- result:
2021-01-04 1 1 1
2021-01-05 1 1 1
Expand All @@ -162,3 +162,14 @@ select * from partition_str2date where create_time>='2021-01-05';
2021-01-05 1 1 1
2021-01-06 1 1 1
-- !result
create table t1 (dt varchar(20), id int) partition by range(str2date(dt, "%Y-%m-%d")) (start ("2021-01-01") end ("2021-01-10") every (interval 1 day));
-- result:
-- !result
create table t2 (dt varchar(20), id int) partition by range(str2date(dt, "%Y-%m")) (start ("2021-01-01") end ("2021-01-10") every (interval 1 day));
-- result:
E: (1064, 'Getting analyzing error. Detail message: partition function check fail, only supports the result of the function str2date(VARCHAR str, VARCHAR format) as a strict DATE type.')
-- !result
create table t3 (dt varchar(20), id int) partition by str2date(dt, "%Y-%m-%d");
-- result:
E: (1064, 'Getting analyzing error. Detail message: Only support date_trunc and time_slice as partition expression.')
-- !result
6 changes: 5 additions & 1 deletion test/sql/test_partition_by_expr/T/test_expr_str2date
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,12 @@ START ("2021-01-01") END ("2021-01-10") EVERY (INTERVAL 1 DAY)
insert into partition_str2date values('2021-01-04','1',1.1,1);
insert into partition_str2date values('2021-01-05','1',1.1,1);
insert into partition_str2date values('2021-01-06','1',1.1,1);
select * from partition_str2date;
select * from partition_str2date order by create_time;
select * from partition_str2date where create_time='2021-01-05';
explain select * from partition_str2date where create_time='2021-01-05';
select * from partition_str2date where '2021-01-05'=create_time;
select * from partition_str2date where create_time>='2021-01-05';

create table t1 (dt varchar(20), id int) partition by range(str2date(dt, "%Y-%m-%d")) (start ("2021-01-01") end ("2021-01-10") every (interval 1 day));
create table t2 (dt varchar(20), id int) partition by range(str2date(dt, "%Y-%m")) (start ("2021-01-01") end ("2021-01-10") every (interval 1 day));
create table t3 (dt varchar(20), id int) partition by str2date(dt, "%Y-%m-%d");

0 comments on commit 8ae5186

Please sign in to comment.