Skip to content

Commit

Permalink
[+]实现服务器模块 (#19)
Browse files Browse the repository at this point in the history
* 将接口、mock改成普通类

* 将接口、mock改成普通类

* 使用访问者模式替代原先的switch匹配

* 去除visitor, 重构表管理

* 去除visitor, 重构表管理

* 重写jbbp解析方法,增加测试

* 增加表配置信息操作

* 增加表加载测试

* 增加系统表和测试

* 完成Select语句的语法树定义

* 完成Insert语句的语法树定义

* 完成Update语句的语法树定义

* 完成Delete语句的语法树定义

* 完成Create table语句的语法树定义

* 完成Create index语句的语法树定义

* 格式化代码

* 增加空字段,增加field的方法

* 增加query模块

* 更新测试用例的序列化格式

* 修复空值Condition

* 增加创建索引测试

* 更改测试文件路径

* 完成服务器程序基本框架

* 字符串解析增加单引号

* 完成echo服务器

* 增加增删改、创建表的执行测试

* 更改测试路径

* 实现访问者模式处理sql语句

* 改进select语句解析

* 完善语句解析的返回值,使用泛型

* 完成语句执行逻辑

* 增加select测试

* 修复delete测试

* 实现指令解析,完成当前所有指令运行的测试

* 将mock换为RecordManager

* 完成自动提交

* 完成todo/fixme

* 增加获取所有文件路径的api

* 修正测试文件路径

* 增加field加载时的索引重建

* 修复未抛出的异常

* 修正执行的系列错误

* 修正自动提交事务上下文更改的问题

* 修正ci重复进行测试

* 修复投影获得空列表的bug

* 修复列未空的插入请求

* 修正select输出格式

* 修复metadata写入bug

* unpin遗漏

* 增加CreateIndex时的表结构序列化

* 修复物理记录查找问题

* 修复错误@nonnull的问题

* 更新dummy

* 修正一系列select解析问题

* 修正between计算问题

* 增加插入列检查

* record提供路径名

* 更改文件目录

* 创建数据文件夹

* 增加flush、exec语句

* 修正null值错误处理

* 通过记录来保存数据字典

* flush错误处理

* 修正系列问题,增加recordapi

* 修正测试用例编译

* 修复metadata加载问题

* 修复metadata加载问题

* 修正一处forEach

* 修复列persist标志位

* metadata加载的空指针问题

* 修改测试用例

* 修正若干错误测试用例

* 修正表模块单元测试路径

* 统一单元测试文件路径

Co-authored-by: Kevin Axel Manjaro <kevinaxel@163.com>
  • Loading branch information
kaaass and KveinAxel authored Jan 17, 2021
1 parent dbd35e2 commit 20d8039
Show file tree
Hide file tree
Showing 68 changed files with 2,218 additions and 866 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ dist: trusty
group: edge

script:
- ./gradlew check
- ./gradlew build --scan -s
14 changes: 13 additions & 1 deletion src/main/java/net/kaaass/rumbase/Main.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.kaaass.rumbase;

import lombok.extern.slf4j.Slf4j;
import net.kaaass.rumbase.server.Server;

/**
* 入口类
Expand All @@ -11,6 +12,17 @@
public class Main {

public static void main(String[] args) {
log.debug("Rumbase");
log.info("Rumbase DBMS");
// 启动
log.info("Start preparing...");
Server.getInstance().prepare();
// 注册程序退出事件
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
log.info("Shutdown...");
Server.getInstance().shutdown();
}, "Shutdown-thread"));
// 运行
log.info("Starting server...");
Server.getInstance().run();
}
}
39 changes: 20 additions & 19 deletions src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,27 +98,28 @@ public static IItemStorage ofFile(String fileName) throws FileException, PageExc
var pageStorage = PageManager.fromFile(fileName);
var header = pageStorage.get(0);
header.pin();
if (checkTableHeader(header)) {
// 如果表头标志存在,就解析对应表头信息
var h = parseHeader(header);
header.unpin();
return new ItemStorage(fileName, h.tempFreePage, h.headerUuid, pageStorage);
} else {
// 若表头标志不存在,就初始化对应的表信息。
// 只初始化headerFlag和tempFreePage,表头信息位置统一由setMetadata来实现
byte[] bytes;
try {
bytes = JBBPOut.BeginBin().
Byte(1, 2, 3, 4).
Int(1).
End().toByteArray();
} catch (IOException e) {
header.unpin();
throw new PageCorruptedException(1, e);
try {
if (checkTableHeader(header)) {
// 如果表头标志存在,就解析对应表头信息
var h = parseHeader(header);
return new ItemStorage(fileName, h.tempFreePage, h.headerUuid, pageStorage);
} else {
// 若表头标志不存在,就初始化对应的表信息。
// 只初始化headerFlag和tempFreePage,表头信息位置统一由setMetadata来实现
byte[] bytes;
try {
bytes = JBBPOut.BeginBin().
Byte(1, 2, 3, 4).
Int(1).
End().toByteArray();
} catch (IOException e) {
throw new PageCorruptedException(1, e);
}
header.patchData(0, bytes);
return new ItemStorage(fileName, 1, 0, pageStorage);
}
header.patchData(0, bytes);
} finally {
header.unpin();
return new ItemStorage(fileName, 1, 0, pageStorage);
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/net/kaaass/rumbase/page/RumPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ public void flush() throws FileException {
throw new FileException(2);
}
out.close();
} catch (FileException e) {
throw e;
} catch (Exception e) {
e.printStackTrace();
}
Expand Down
11 changes: 8 additions & 3 deletions src/main/java/net/kaaass/rumbase/parse/ConditionExpression.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import net.kaaass.rumbase.parse.exception.EvaluationException;
import net.kaaass.rumbase.parse.parser.ParserUtil;
import net.kaaass.rumbase.parse.parser.jsqlp.ParserUtil;
import net.sf.jsqlparser.expression.*;
import net.sf.jsqlparser.expression.operators.arithmetic.*;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
Expand All @@ -24,7 +24,6 @@ public class ConditionExpression {

public static double PRECISION = 0.00001;

@NonNull
private final Expression expression;

@NonNull
Expand All @@ -38,6 +37,9 @@ public class ConditionExpression {
* @param paramMap 参数列表,其中参数必须是原生类型的装箱对象,如Integer、String
*/
public boolean evaluate(Map<ColumnIdentifier, Object> paramMap) {
if (expression == null) {
return true;
}
updateParam();
var parser = new DeParser(paramMap);
expression.accept(parser);
Expand All @@ -58,6 +60,9 @@ public boolean evaluate(Map<ColumnIdentifier, Object> paramMap) {
* 获得表达式求值需要的参数
*/
public List<ColumnIdentifier> getParams() {
if (expression == null) {
return List.of();
}
updateParam();
return List.copyOf(paramColumn.values());
}
Expand Down Expand Up @@ -205,7 +210,7 @@ public void visit(Between between) {
var b = stack.pop();
var a = stack.pop();
Comparator cmp = Comparator.naturalOrder();
stack.push(cmp.compare(a, b) <= 0 && cmp.compare(b, c) < 0);
stack.push(cmp.compare(b, a) <= 0 && cmp.compare(a, c) < 0);
}

@Override
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/net/kaaass/rumbase/parse/ISqlStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
* @author kaaass
*/
public interface ISqlStatement {

<T> T accept(ISqlStatementVisitor<T> visitor);
}
37 changes: 37 additions & 0 deletions src/main/java/net/kaaass/rumbase/parse/ISqlStatementVisitor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package net.kaaass.rumbase.parse;

import net.kaaass.rumbase.parse.stmt.*;

/**
* SQL语句访问者,用于处理对应SQL语句
*
* @author kaaass
*/
public interface ISqlStatementVisitor<T> {

T visit(SelectStatement statement);

T visit(InsertStatement statement);

T visit(UpdateStatement statement);

T visit(DeleteStatement statement);

T visit(CreateIndexStatement statement);

T visit(CreateTableStatement statement);

T visit(StartTransactionStatement statement);

T visit(CommitStatement statement);

T visit(RollbackStatement statement);

T visit(ExitStatement statement);

T visit(ShutdownStatement statement);

T visit(FlushStatement statement);

T visit(ExecStatement statement);
}
27 changes: 23 additions & 4 deletions src/main/java/net/kaaass/rumbase/parse/SqlParser.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package net.kaaass.rumbase.parse;

import net.kaaass.rumbase.parse.exception.SqlSyntaxException;
import net.kaaass.rumbase.parse.parser.*;
import net.kaaass.rumbase.parse.parser.CommandStatementParser;
import net.kaaass.rumbase.parse.parser.JsqlpStatementParser;
import net.kaaass.rumbase.parse.parser.command.ExecStatementParser;
import net.kaaass.rumbase.parse.parser.jsqlp.*;
import net.kaaass.rumbase.parse.stmt.*;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
Expand All @@ -16,7 +20,17 @@
*/
public class SqlParser {

private static List<JsqlpStatementParser> jsqlpStatementParsers = new ArrayList<>() {{
private static final List<StatementParser<String>> STRING_STATEMENT_PARSERS = new ArrayList<>() {{
add(new CommandStatementParser(StartTransactionStatement.class, "start transaction"));
add(new CommandStatementParser(CommitStatement.class, "commit"));
add(new CommandStatementParser(RollbackStatement.class, "rollback"));
add(new CommandStatementParser(ExitStatement.class, "exit"));
add(new CommandStatementParser(ShutdownStatement.class, "shutdown"));
add(new CommandStatementParser(FlushStatement.class, "flush"));
add(new ExecStatementParser());
}};

private static final List<JsqlpStatementParser> JSQLP_STATEMENT_PARSERS = new ArrayList<>() {{
add(new SelectStatementParser());
add(new InsertStatementParser());
add(new UpdateStatementParser());
Expand All @@ -29,15 +43,20 @@ public class SqlParser {
* 将语句解析为SQL语法树
*/
public static ISqlStatement parseStatement(String sql) throws SqlSyntaxException {
// TODO
// 尝试字符串解析器解析
for (var parser : STRING_STATEMENT_PARSERS) {
if (parser.checkStatement(sql)) {
return parser.parse(sql);
}
}
// 尝试 JSqlParser 解析
Statement stmt;
try {
stmt = CCJSqlParserUtil.parse(sql);
} catch (JSQLParserException e) {
throw new SqlSyntaxException(1, e);
}
for (var parser : jsqlpStatementParsers) {
for (var parser : JSQLP_STATEMENT_PARSERS) {
if (parser.checkStatement(stmt)) {
return parser.parse(stmt);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* <p>
* E1001-1 SQL语句语法错误
* E1001-2 不支持的SQL语句
* E1001-3 语句生成错误,请检查服务器日志
*
* @author kaaass
*/
Expand All @@ -18,12 +19,17 @@ public class SqlSyntaxException extends RumbaseException {
public static final Map<Integer, String> REASONS = new HashMap<>() {{
put(1, "SQL语句语法错误");
put(2, "不支持的SQL语句");
put(3, "语句生成错误,请检查服务器日志");
}};

public SqlSyntaxException(int subId) {
super(5001, subId, REASONS.get(subId));
}

public SqlSyntaxException(int subId, String subReason) {
super(5001, subId, REASONS.get(subId) + ":" + subReason);
}

public SqlSyntaxException(int subId, Throwable e) {
super(5001, subId, REASONS.get(subId), e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package net.kaaass.rumbase.parse.parser;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.kaaass.rumbase.parse.ISqlStatement;
import net.kaaass.rumbase.parse.SqlParser;
import net.kaaass.rumbase.parse.exception.SqlSyntaxException;

import java.lang.reflect.InvocationTargetException;

/**
* 字符串指令解析器
* @author kaaass
*/
@Slf4j
@RequiredArgsConstructor
public class CommandStatementParser implements SqlParser.StatementParser<String> {

/**
* 语句解析结果的类
*/
private final Class<? extends ISqlStatement> stmtClazz;

/**
* 指令格式
*/
private final String command;

@Override
public ISqlStatement parse(String input) throws SqlSyntaxException {
try {
return stmtClazz.getDeclaredConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
log.error("无法生成指令对象 {}", input, e);
throw new SqlSyntaxException(3, e);
}
}

@Override
public boolean checkStatement(String input) {
// 忽略逗号
if (input.charAt(input.length() - 1) == ';') {
input = input.substring(0, input.length() - 1);
}
return command.compareToIgnoreCase(input) == 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package net.kaaass.rumbase.parse.parser.command;

import net.kaaass.rumbase.parse.ISqlStatement;
import net.kaaass.rumbase.parse.SqlParser;
import net.kaaass.rumbase.parse.stmt.ExecStatement;

/**
* 将执行SQL文件语句解释为对应语法树
*
* @author kaaass
*/
public class ExecStatementParser implements SqlParser.StatementParser<String> {
@Override
public ISqlStatement parse(String input) {
return new ExecStatement(input.substring(5).trim());
}

@Override
public boolean checkStatement(String input) {
return input.startsWith("exec ") || input.startsWith("EXEC ");
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package net.kaaass.rumbase.parse.parser;
package net.kaaass.rumbase.parse.parser.jsqlp;

import net.kaaass.rumbase.parse.ColumnIdentifier;
import net.kaaass.rumbase.parse.ISqlStatement;
import net.kaaass.rumbase.parse.parser.JsqlpStatementParser;
import net.kaaass.rumbase.parse.stmt.CreateIndexStatement;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.create.index.CreateIndex;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package net.kaaass.rumbase.parse.parser;
package net.kaaass.rumbase.parse.parser.jsqlp;

import net.kaaass.rumbase.parse.ISqlStatement;
import net.kaaass.rumbase.parse.exception.SqlSyntaxException;
import net.kaaass.rumbase.parse.parser.JsqlpStatementParser;
import net.kaaass.rumbase.parse.stmt.CreateTableStatement;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.create.table.ColDataType;
Expand All @@ -16,11 +18,14 @@
*/
public class CreateTableStatementParser implements JsqlpStatementParser {
@Override
public ISqlStatement parse(Statement input) {
public ISqlStatement parse(Statement input) throws SqlSyntaxException {
var stmt = (CreateTable) input;
// 解析表名
var tableName = stmt.getTable().getName();
// 解析字段定义
if (stmt.getColumnDefinitions() == null) {
throw new SqlSyntaxException(1, "表字段不能为空");
}
var columnDefs = stmt.getColumnDefinitions().stream()
.map(def -> new CreateTableStatement.ColumnDefinition(
mapColType(def.getColDataType()),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package net.kaaass.rumbase.parse.parser;
package net.kaaass.rumbase.parse.parser.jsqlp;

import net.kaaass.rumbase.parse.ConditionExpression;
import net.kaaass.rumbase.parse.ISqlStatement;
import net.kaaass.rumbase.parse.parser.JsqlpStatementParser;
import net.kaaass.rumbase.parse.stmt.DeleteStatement;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.delete.Delete;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package net.kaaass.rumbase.parse.parser;
package net.kaaass.rumbase.parse.parser.jsqlp;

import net.kaaass.rumbase.parse.ColumnIdentifier;
import net.kaaass.rumbase.parse.ISqlStatement;
import net.kaaass.rumbase.parse.parser.JsqlpStatementParser;
import net.kaaass.rumbase.parse.stmt.InsertStatement;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.ItemsListVisitorAdapter;
Expand Down Expand Up @@ -37,6 +38,7 @@ public ISqlStatement parse(Statement input) {
public void visit(ExpressionList expressionList) {
expressionList.getExpressions().stream()
.map(Objects::toString)
.map(s -> "NULL".equals(s) ? null : s)
.forEach(values::add);
}
});
Expand Down
Loading

0 comments on commit 20d8039

Please sign in to comment.