Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(logicaldatabase): logical table expression parser #2274

Merged
merged 20 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@
public class SyntaxErrorException extends ParseCancellationException {

private final int start;
private final int stop;
private final String text;

public SyntaxErrorException(@NonNull Recognizer<?, ?> recognizer, @NonNull RecognitionException e) {
super(buildErrorMessage(recognizer, e), e);
if (recognizer instanceof Parser) {
Token token = e.getOffendingToken();
this.start = token.getStartIndex();
this.stop = token.getStopIndex();
TokenStream tokens = (CommonTokenStream) recognizer.getInputStream();
if (tokens == null) {
this.text = null;
Expand All @@ -57,6 +59,7 @@ public SyntaxErrorException(@NonNull Recognizer<?, ?> recognizer, @NonNull Recog
} else {
CharStream text = (CharStream) recognizer.getInputStream();
this.start = text.index();
this.stop = text.index();
this.text = text.toString();
}
}
Expand Down
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
<flowable.version>6.3.1</flowable.version>
<maven-antrun-plugin.version>3.1.0</maven-antrun-plugin.version>
<maven-pmd-plugin.version>3.21.0</maven-pmd-plugin.version>
<antlr4-maven-plugin.version>4.9.1</antlr4-maven-plugin.version>

<!-- default test profile for unit testing-->
<spring.profiles.active>clientMode,test,jdbc</spring.profiles.active>
Expand Down Expand Up @@ -1218,6 +1219,11 @@
<artifactId>maven-pmd-plugin</artifactId>
<version>${maven-pmd-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>${antlr4-maven-plugin.version}</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2023 OceanBase.
*
* Licensed 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 com.oceanbase.odc.service.connection.logicaldatabase;

import java.util.List;

import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import com.oceanbase.odc.ServiceTestEnv;
import com.oceanbase.odc.common.util.StringUtils;
import com.oceanbase.odc.common.util.YamlUtils;
import com.oceanbase.odc.service.connection.logicaldatabase.model.DataNode;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* @Author: Lebie
* @Date: 2024/4/23 11:49
* @Description: []
*/
public class LogicalTableServiceTest extends ServiceTestEnv {
private static final String TEST_RESOURCE_VALID_EXPRESSION_FILE_PATH =
"connection/logicaldatabase/valid_logical_table_expression_resolve.yaml";
private static final String TEST_RESOURCE_INVALID_EXPRESSION_FILE_PATH =
"connection/logicaldatabase/invalid_logical_table_expression_resolve.yaml";

@Autowired
private LogicalTableService logicalTableService;

@Test
public void testResolve_ValidExpression() {
List<LogicalTableExpressionResolveTestCase> testCases =
YamlUtils.fromYamlList(TEST_RESOURCE_VALID_EXPRESSION_FILE_PATH,
LogicalTableExpressionResolveTestCase.class);
for (LogicalTableExpressionResolveTestCase testCase : testCases) {
List<DataNode> actual = logicalTableService.resolve(testCase.getExpression());
List<DataNode> expected = testCase.getDataNodes();
Assert.assertEquals(String.format("test case id = %d", testCase.getId()), expected.size(), actual.size());
for (int i = 0; i < expected.size(); i++) {
DataNode expectedDataNode = expected.get(i);
DataNode actualDataNode = actual.get(i);
Assert.assertEquals(String.format("test case id = %d", testCase.getId()),
expectedDataNode.getSchemaName(),
actualDataNode.getSchemaName());
Assert.assertEquals(String.format("test case id = %d", testCase.getId()),
expectedDataNode.getTableName(),
actualDataNode.getTableName());
}
}
}

@Test
public void testResolve_InvalidExpression() {
List<LogicalTableExpressionResolveTestCase> testCases =
YamlUtils.fromYamlList(TEST_RESOURCE_INVALID_EXPRESSION_FILE_PATH,
LogicalTableExpressionResolveTestCase.class);
for (LogicalTableExpressionResolveTestCase testCase : testCases) {
try {
logicalTableService.resolve(testCase.getExpression());
} catch (Exception ex) {
Assert.assertTrue(
String.format("test case id = %d, expected = %s, actual = %s", testCase.getId(),
testCase.getErrorMessageAbstract(), ex.getMessage()),
StringUtils.containsIgnoreCase(ex.getMessage(), testCase.getErrorMessageAbstract()));
continue;
}
Assert.fail(String.format("test case id = %d, exception expected but not thrown", testCase.getId()));
}
}

@Data
@NoArgsConstructor
@AllArgsConstructor
static class LogicalTableExpressionResolveTestCase {
private Long id;
private String expression;
private List<DataNode> dataNodes;
private String errorMessageAbstract;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
- id: 1
expression: "db.tb[0-3"
error_message_abstract: "db.tb[0-3"

- id: 2
expression: "db[].tb[0-3]"
error_message_abstract: "db[]"

- id: 3
expression: "db[1-3]"
error_message_abstract: "db[1-3]"

- id: 4
expression: "db[[1-3]].tb_[1-3]"
error_message_abstract: "db[["

- id: 5
expression: "db_[0-3].tb_[0-2]"
error_message_abstract: "The number of tables 3 cannot be evenly divided by the number of databases 4. Please ensure that tables can be evenly distributed across databases and try again."

- id: 6
expression: "db_[0-3].tb_[0-3],"
error_message_abstract: "tb_[0-3],"

- id: 7
expression: "db_[0-3].tb_[0-3], bad_db"
error_message_abstract: "bad_db"

- id: 8
expression: "db_[1,2,3].tb_[1,2,3,4,5,6], bad_db.tb_[]"
error_message_abstract: "tb_[]"

- id: 9
expression: "db.tb_[2-1]"
error_message_abstract: "The start value 2 for [2-1] in your expression cannot be greater than the end value 1, please modify it and try again."

- id: 10
expression: "db.tb_[1-2:0]"
error_message_abstract: "The step 0 in your expression for [1-2:0] must be a positive number, please modify it and try again."

- id: 11
expression: "db.tb_[1-2147483648:1]"
error_message_abstract: "In your expression, the range for [1-2147483648:1] must consist of valid positive integers."
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
- id: 1
expression: "db.tb"
data_nodes:
- table_name: "tb"
schema_name: "db"

- id: 2
expression: "db.tb_[0-3]"
data_nodes:
- table_name: "tb_0"
schema_name: "db"
- table_name: "tb_1"
schema_name: "db"
- table_name: "tb_2"
schema_name: "db"
- table_name: "tb_3"
schema_name: "db"

- id: 3
expression: "db.tb_[0-6:2]"
data_nodes:
- table_name: "tb_0"
schema_name: "db"
- table_name: "tb_2"
schema_name: "db"
- table_name: "tb_4"
schema_name: "db"
- table_name: "tb_6"
schema_name: "db"

- id: 4
expression: "db.tb_[1,3,9]"
data_nodes:
- table_name: "tb_1"
schema_name: "db"
- table_name: "tb_3"
schema_name: "db"
- table_name: "tb_9"
schema_name: "db"

- id: 5
expression: "db.tb_[000-003]_[1-2]"
data_nodes:
- table_name: "tb_000_1"
schema_name: "db"
- table_name: "tb_000_2"
schema_name: "db"
- table_name: "tb_001_1"
schema_name: "db"
- table_name: "tb_001_2"
schema_name: "db"
- table_name: "tb_002_1"
schema_name: "db"
- table_name: "tb_002_2"
schema_name: "db"
- table_name: "tb_003_1"
schema_name: "db"
- table_name: "tb_003_2"
schema_name: "db"

- id: 6
expression: "db_[0-3].tb_[000-003]"
data_nodes:
- table_name: "tb_000"
schema_name: "db_0"
- table_name: "tb_001"
schema_name: "db_1"
- table_name: "tb_002"
schema_name: "db_2"
- table_name: "tb_003"
schema_name: "db_3"

- id: 7
expression: "db_[0-3].tb_[000-003]_[1-3:2]"
data_nodes:
- table_name: "tb_000_1"
schema_name: "db_0"
- table_name: "tb_000_3"
schema_name: "db_0"
- table_name: "tb_001_1"
schema_name: "db_1"
- table_name: "tb_001_3"
schema_name: "db_1"
- table_name: "tb_002_1"
schema_name: "db_2"
- table_name: "tb_002_3"
schema_name: "db_2"
- table_name: "tb_003_1"
schema_name: "db_3"
- table_name: "tb_003_3"
schema_name: "db_3"

- id: 8
expression: "db_[0-3].tb_[[01-02]]"
data_nodes:
- table_name: "tb_01"
schema_name: "db_0"
- table_name: "tb_02"
schema_name: "db_0"
- table_name: "tb_01"
schema_name: "db_1"
- table_name: "tb_02"
schema_name: "db_1"
- table_name: "tb_01"
schema_name: "db_2"
- table_name: "tb_02"
schema_name: "db_2"
- table_name: "tb_01"
schema_name: "db_3"
- table_name: "tb_02"
schema_name: "db_3"

- id: 9
expression: "db_[0-3]_[0-1].tb_[001-008]"
data_nodes:
- table_name: "tb_001"
schema_name: "db_0_0"
- table_name: "tb_002"
schema_name: "db_0_1"
- table_name: "tb_003"
schema_name: "db_1_0"
- table_name: "tb_004"
schema_name: "db_1_1"
- table_name: "tb_005"
schema_name: "db_2_0"
- table_name: "tb_006"
schema_name: "db_2_1"
- table_name: "tb_007"
schema_name: "db_3_0"
- table_name: "tb_008"
schema_name: "db_3_1"

- id: 10
expression: "db_[1,3,100].tb"
data_nodes:
- table_name: "tb"
schema_name: "db_1"
- table_name: "tb"
schema_name: "db_3"
- table_name: "tb"
schema_name: "db_100"

- id: 11
expression: "db_[1,3,5].tb_[1-3],db_[2,4,6].tb_[4-6]"
data_nodes:
- table_name: "tb_1"
schema_name: "db_1"
- table_name: "tb_2"
schema_name: "db_3"
- table_name: "tb_3"
schema_name: "db_5"
- table_name: "tb_4"
schema_name: "db_2"
- table_name: "tb_5"
schema_name: "db_4"
- table_name: "tb_6"
schema_name: "db_6"

- id: 12
expression: "db_[1,3,5].tb_[1-3], db_[2,4,6].tb_[4-6]"
data_nodes:
- table_name: "tb_1"
schema_name: "db_1"
- table_name: "tb_2"
schema_name: "db_3"
- table_name: "tb_3"
schema_name: "db_5"
- table_name: "tb_4"
schema_name: "db_2"
- table_name: "tb_5"
schema_name: "db_4"
- table_name: "tb_6"
schema_name: "db_6"

- id: 13
expression: "db_[0-3].tb_[[01-02]]_[2024-2025]"
data_nodes:
- table_name: "tb_01_2024"
schema_name: "db_0"
- table_name: "tb_01_2025"
schema_name: "db_0"
- table_name: "tb_02_2024"
schema_name: "db_0"
- table_name: "tb_02_2025"
schema_name: "db_0"
- table_name: "tb_01_2024"
schema_name: "db_1"
- table_name: "tb_01_2025"
schema_name: "db_1"
- table_name: "tb_02_2024"
schema_name: "db_1"
- table_name: "tb_02_2025"
schema_name: "db_1"
- table_name: "tb_01_2024"
schema_name: "db_2"
- table_name: "tb_01_2025"
schema_name: "db_2"
- table_name: "tb_02_2024"
schema_name: "db_2"
- table_name: "tb_02_2025"
schema_name: "db_2"
- table_name: "tb_01_2024"
schema_name: "db_3"
- table_name: "tb_01_2025"
schema_name: "db_3"
- table_name: "tb_02_2024"
schema_name: "db_3"
- table_name: "tb_02_2025"
schema_name: "db_3"
Loading
Loading