feat: rewrite sqlserver meta provider

This commit is contained in:
vran 2022-05-09 13:36:33 +08:00
parent bab82d43df
commit 66ee6405e2
5 changed files with 303 additions and 2 deletions

View File

@ -2,6 +2,9 @@ package com.databasir.core.meta.provider;
import com.databasir.core.meta.provider.jdbc.*;
import com.databasir.core.meta.provider.mysql.MysqlTableTriggerMetaProvider;
import com.databasir.core.meta.provider.sqlserver.SqlServerColumnMetaProvider;
import com.databasir.core.meta.provider.sqlserver.SqlServerTableMetaProvider;
import com.databasir.core.meta.provider.sqlserver.SqlServerTriggerMetaProvider;
import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
@ -35,7 +38,7 @@ public class MetaProviders {
return jdbc();
}
if (url.contains(":sqlserver:")) {
return jdbc();
return sqlServer();
}
if (url.contains(":mysql:")) {
return mysql();
@ -57,4 +60,17 @@ public class MetaProviders {
return new JdbcDatabaseMetaProvider(tableMetaProvider);
}
private static DatabaseMetaProvider sqlServer() {
var columnMetaProvider = new SqlServerColumnMetaProvider();
var foreignKeyMetaProvider = new JdbcForeignKeyMetaProvider();
var indexMetaProvider = new JdbcIndexMetaProvider();
var triggerMetaProvider = new SqlServerTriggerMetaProvider();
var tableMetaProvider = new SqlServerTableMetaProvider(
columnMetaProvider,
indexMetaProvider,
foreignKeyMetaProvider,
triggerMetaProvider
);
return new JdbcDatabaseMetaProvider(tableMetaProvider);
}
}

View File

@ -61,7 +61,7 @@ public class MysqlTableTriggerMetaProvider implements TriggerMetaProvider {
}
return triggers;
} catch (SQLException e) {
log.warn("create trigger doc failed", e);
log.warn("get trigger meta failed", e);
return Collections.emptyList();
}
}

View File

@ -0,0 +1,78 @@
package com.databasir.core.meta.provider.sqlserver;
import com.databasir.core.meta.data.ColumnMeta;
import com.databasir.core.meta.provider.ColumnMetaProvider;
import com.databasir.core.meta.provider.condition.TableCondition;
import com.databasir.core.meta.provider.jdbc.JdbcColumnMetaProvider;
import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
public class SqlServerColumnMetaProvider implements ColumnMetaProvider {
private final ColumnMetaProvider columnMetaProvider = new JdbcColumnMetaProvider();
@Override
public List<ColumnMeta> selectColumns(Connection connection, TableCondition condition) {
Map<String, String> columnRemarksMap = getColumnRemarks(connection, condition);
return columnMetaProvider.selectColumns(connection, condition)
.stream()
.map(column -> {
String remark = columnRemarksMap.getOrDefault(column.getName(), "");
column.setComment(remark);
return column;
})
.collect(Collectors.toList());
}
private Map<String, String> getColumnRemarks(Connection connection,
TableCondition condition) {
String sql = "SELECT col.name AS COLUMN_NAME,\n" +
" ep.value AS REMARKS\n" +
"FROM sys.tables AS tab\n" +
" INNER JOIN sys.columns AS col\n" +
" ON tab.object_id = col.object_id\n" +
" LEFT JOIN sys.extended_properties AS ep " +
"ON ep.major_id = col.object_id AND ep.minor_id = col.column_id\n" +
"WHERE tab.name LIKE ?\n" +
" AND SCHEMA_NAME(tab.schema_id) LIKE ?\n" +
"ORDER BY tab.name, column_id;";
Map<String, String> map = new HashMap<>();
PreparedStatement preparedStatement = null;
try {
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, condition.getTableName());
preparedStatement.setString(2, condition.getSchemaName());
ResultSet result = preparedStatement.executeQuery();
while (result.next()) {
String name = result.getString("COLUMN_NAME");
String remarks = result.getString("REMARKS");
if (name == null || remarks == null) {
continue;
} else {
map.put(name, remarks);
}
}
} catch (SQLException e) {
log.error("", e);
} finally {
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
// ignore
}
}
}
return map;
}
}

View File

@ -0,0 +1,107 @@
package com.databasir.core.meta.provider.sqlserver;
import com.databasir.core.meta.data.ColumnMeta;
import com.databasir.core.meta.data.TableMeta;
import com.databasir.core.meta.provider.*;
import com.databasir.core.meta.provider.condition.Condition;
import com.databasir.core.meta.provider.condition.TableCondition;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@RequiredArgsConstructor
@Slf4j
public class SqlServerTableMetaProvider implements TableMetaProvider {
private final ColumnMetaProvider columnMetaProvider;
private final IndexMetaProvider indexMetaProvider;
private final ForeignKeyMetaProvider foreignKeyMetaProvider;
private final TriggerMetaProvider triggerMetaProvider;
@Override
public List<TableMeta> selectTables(Connection connection, Condition condition) {
String sql = "SELECT sys.objects.name AS TABLE_NAME,\n" +
" sys.objects.type_desc AS TABLE_TYPE,\n" +
" CAST(extended_properties.value AS NVARCHAR(500)) AS REMARKS\n" +
"FROM sys.objects\n" +
" LEFT JOIN sys.schemas ON sys.objects.schema_id = sys.schemas.schema_id\n" +
" LEFT JOIN sys.extended_properties " +
"ON sys.objects.object_id = sys.extended_properties.major_id\n" +
"WHERE (type = 'U' OR type = 'V')\n" +
" AND sys.extended_properties.minor_id = 0\n" +
" AND sys.schemas.name LIKE ?;\n";
PreparedStatement preparedStatement = null;
try {
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, condition.getSchemaName());
ResultSet results = preparedStatement.executeQuery();
return doSelect(results, connection, condition);
} catch (SQLException e) {
log.warn("get table meta failed {}", e.getMessage());
if (log.isDebugEnabled()) {
log.debug("get table meta failed", e);
}
return Collections.emptyList();
} finally {
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
// ignore
}
}
}
}
private List<TableMeta> doSelect(ResultSet tablesResult,
Connection connection,
Condition condition) throws SQLException {
List<TableMeta> tableMetas = new ArrayList<>();
try {
while (tablesResult.next()) {
String tableName = tablesResult.getString("TABLE_NAME");
if (condition.tableIsIgnored(tableName)) {
if (log.isWarnEnabled()) {
log.warn("ignored table: " + condition.getSchemaName() + "." + tableName);
}
} else {
String tableType = tablesResult.getString("TABLE_TYPE");
String tableComment = tablesResult.getString("REMARKS");
TableCondition tableCondition = TableCondition.of(condition, tableName);
List<ColumnMeta> columns = columnMetaProvider.selectColumns(connection, tableCondition);
if (columns.isEmpty()) {
if (log.isWarnEnabled()) {
log.warn("ignored table: " + condition.getSchemaName() + "." + tableName
+ ", caused by get empty columns");
}
continue;
}
TableMeta tableMeta = TableMeta.builder()
.name(tableName)
.type(tableType)
.comment(tableComment)
.columns(columns)
.foreignKeys(foreignKeyMetaProvider.selectForeignKeys(connection, tableCondition))
.indexes(indexMetaProvider.selectIndexes(connection, tableCondition))
.triggers(triggerMetaProvider.selectTriggers(connection, tableCondition))
.build();
tableMetas.add(tableMeta);
}
}
} finally {
tablesResult.close();
}
return tableMetas;
}
}

View File

@ -0,0 +1,100 @@
package com.databasir.core.meta.provider.sqlserver;
import com.databasir.core.meta.data.TriggerMeta;
import com.databasir.core.meta.provider.TriggerMetaProvider;
import com.databasir.core.meta.provider.condition.TableCondition;
import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
public class SqlServerTriggerMetaProvider implements TriggerMetaProvider {
private static final Pattern DATE_TIME_PATTERN =
Pattern.compile("(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})(.*)");
@Override
public List<TriggerMeta> selectTriggers(Connection connection, TableCondition condition) {
String sql = "SELECT SCHEMA_NAME(tab.schema_id) + '.' + tab.name AS table_name,\n" +
" trig.name AS trigger_name,\n" +
" trig.create_date AS create_date,\n" +
" CASE\n" +
" WHEN is_instead_of_trigger = 1 THEN 'Instead of'\n" +
" ELSE 'After' END AS timing,\n" +
" (CASE\n" +
" WHEN OBJECTPROPERTY(trig.object_id, 'ExecIsUpdateTrigger') = 1\n" +
" THEN 'Update '\n" +
" ELSE '' END\n" +
" + CASE\n" +
" WHEN OBJECTPROPERTY(trig.object_id, 'ExecIsDeleteTrigger') = 1\n" +
" THEN 'Delete '\n" +
" ELSE '' END\n" +
" + CASE\n" +
" WHEN OBJECTPROPERTY(trig.object_id, 'ExecIsInsertTrigger') = 1\n" +
" THEN 'Insert '\n" +
" ELSE '' END\n" +
" ) AS manipulation,\n" +
" CASE\n" +
" WHEN trig.[type] = 'TA' THEN 'Assembly (CLR) trigger'\n" +
" WHEN trig.[type] = 'TR' THEN 'SQL trigger'\n" +
" ELSE '' END AS [TYPE],\n" +
" CASE\n" +
" WHEN is_disabled = 1 THEN 'Disabled'\n" +
" ELSE 'Active' END AS [status],\n" +
" OBJECT_DEFINITION(trig.object_id) AS STATEMENT\n" +
"FROM sys.triggers trig\n" +
" INNER JOIN sys.objects tab\n" +
" ON trig.parent_id = tab.object_id\n" +
"WHERE SCHEMA_NAME(tab.schema_id) = ? AND tab.name = ?";
PreparedStatement preparedStatement = null;
List<TriggerMeta> triggerMetas = new ArrayList<>();
try {
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, condition.getSchemaName());
preparedStatement.setString(2, condition.getTableName());
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
String triggerName = resultSet.getString("trigger_name");
String timing = resultSet.getString("timing");
String manipulation = resultSet.getString("manipulation");
String statement = resultSet.getString("statement");
Matcher matcher = DATE_TIME_PATTERN.matcher(resultSet.getString("create_date"));
String createAt;
if (matcher.matches()) {
createAt = matcher.group(1);
} else {
createAt = "1970-01-01 00:00:00";
}
triggerMetas.add(TriggerMeta.builder()
.name(triggerName)
.timing(timing)
.manipulation(manipulation)
.statement(statement)
.createAt(createAt)
.build());
}
} catch (SQLException e) {
log.warn("ignore trigger meta by error {}", e.getMessage());
if (log.isDebugEnabled()) {
log.debug("ignore trigger meta by error ", e);
}
} finally {
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
// ignore
}
}
}
return triggerMetas;
}
}