diff --git a/common/src/main/java/io/mycat/DataSourceNearness.java b/common/src/main/java/io/mycat/DataSourceNearness.java index 77e45de31..187d77188 100644 --- a/common/src/main/java/io/mycat/DataSourceNearness.java +++ b/common/src/main/java/io/mycat/DataSourceNearness.java @@ -8,7 +8,5 @@ public interface DataSourceNearness { public void setLoadBalanceStrategy(String loadBalanceStrategy); - public void setUpdate(boolean update); - public void clear(); } \ No newline at end of file diff --git a/common/src/main/java/io/mycat/beans/mycat/ResultSetBuilder.java b/common/src/main/java/io/mycat/beans/mycat/ResultSetBuilder.java index 071950c37..bfb56f963 100644 --- a/common/src/main/java/io/mycat/beans/mycat/ResultSetBuilder.java +++ b/common/src/main/java/io/mycat/beans/mycat/ResultSetBuilder.java @@ -173,4 +173,12 @@ public void close() { } } + + /** + * 跳过头部的null + * @return + */ + public List getColumnInfos() { + return columnInfos.subList(1,columnInfos.size()); + } } \ No newline at end of file diff --git a/common/src/main/java/io/mycat/beans/mysql/InformationSchema.java b/common/src/main/java/io/mycat/beans/mysql/InformationSchema.java index c8fee6952..ae4365f93 100644 --- a/common/src/main/java/io/mycat/beans/mysql/InformationSchema.java +++ b/common/src/main/java/io/mycat/beans/mysql/InformationSchema.java @@ -10,7 +10,7 @@ */ @NoArgsConstructor @Data -public class InformationSchema { +public class InformationSchema implements Cloneable { public TABLES_TABLE_OBJECT[] TABLES = new TABLES_TABLE_OBJECT[]{}; @@ -2253,4 +2253,9 @@ public static class ROUTINES_TABLE_OBJECT { public String DATABASE_COLLATION; } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } } \ No newline at end of file diff --git a/common/src/main/java/io/mycat/beans/mysql/packet/ColumnDefPacketImpl.java b/common/src/main/java/io/mycat/beans/mysql/packet/ColumnDefPacketImpl.java index d21af8ead..83aaa65e6 100644 --- a/common/src/main/java/io/mycat/beans/mysql/packet/ColumnDefPacketImpl.java +++ b/common/src/main/java/io/mycat/beans/mysql/packet/ColumnDefPacketImpl.java @@ -18,6 +18,7 @@ import io.mycat.beans.mycat.MycatRowMetaData; import io.mycat.beans.mysql.MySQLFieldInfo; import io.mycat.beans.mysql.MySQLFieldsType; +import io.mycat.util.StringUtil; import java.sql.ResultSetMetaData; import java.util.Arrays; @@ -71,7 +72,11 @@ byte[] getBytes(String text){ } public ColumnDefPacketImpl(final MycatRowMetaData resultSetMetaData, int columnIndex) { try { - this.columnSchema = getBytes(resultSetMetaData.getSchemaName(columnIndex)); + String schemaName = resultSetMetaData.getSchemaName(columnIndex); + if (StringUtil.isEmpty(schemaName )){ + schemaName = "UNKNOWN";//mysql workbench 该字段不能为长度0 + } + this.columnSchema = getBytes(schemaName); this.columnName = getBytes(resultSetMetaData.getColumnLabel(columnIndex)); this.columnOrgName = getBytes(resultSetMetaData.getColumnName(columnIndex)); this.columnNextLength = 0xC; diff --git a/datasource/pom.xml b/datasource/pom.xml index e66c450de..fe0629e20 100644 --- a/datasource/pom.xml +++ b/datasource/pom.xml @@ -82,7 +82,7 @@ org.apache.calcite calcite-core - 1.22.0 + 1.23.0 \ No newline at end of file diff --git a/datasource/src/main/java/io/mycat/datasource/jdbc/transactionSession/TransactionSessionTemplate.java b/datasource/src/main/java/io/mycat/datasource/jdbc/transactionSession/TransactionSessionTemplate.java index 7006e8378..aab6c0715 100644 --- a/datasource/src/main/java/io/mycat/datasource/jdbc/transactionSession/TransactionSessionTemplate.java +++ b/datasource/src/main/java/io/mycat/datasource/jdbc/transactionSession/TransactionSessionTemplate.java @@ -15,7 +15,7 @@ public abstract class TransactionSessionTemplate implements TransactionSession { protected final Map updateConnectionMap = new HashMap<>(); - protected final DataSourceNearness dataSourceNearness = new DataSourceNearnessImpl(); + protected final DataSourceNearness dataSourceNearness = new DataSourceNearnessImpl(this); final MycatDataContext dataContext; protected final ConcurrentLinkedQueue closeResourceQueue = new ConcurrentLinkedQueue<>(); @@ -78,8 +78,6 @@ public void doAction() { if (!isAutocommit()) { begin(); } - - dataSourceNearness.setUpdate(isInTransaction()); } abstract protected void callBackBegin(); diff --git a/example/src/test/java/io/mycat/example/sharding/ShardingExample.java b/example/src/test/java/io/mycat/example/sharding/ShardingExample.java index fb3837454..73c8ad757 100644 --- a/example/src/test/java/io/mycat/example/sharding/ShardingExample.java +++ b/example/src/test/java/io/mycat/example/sharding/ShardingExample.java @@ -97,7 +97,7 @@ public void test() throws Exception { for (int i = 0; i < 10; i++) { set.add(TestUtil.getString(statement.executeQuery( "explain select * from travelrecord" - ))); + )).replaceAll("id=\\[\\d+\\]","")); } Assert.assertTrue(set.size() == 1);//验证有事务的情况下,不读写分离 } @@ -109,7 +109,7 @@ public void test() throws Exception { for (int i = 0; i < 10; i++) { set.add(TestUtil.getString(statement.executeQuery( "explain select * from travelrecord" - ))); + )).replaceAll("id=\\[\\d+\\]","")); } Assert.assertEquals(1, set.size());//验证无事务的情况下但是set autocommit = 0,不读写分离 } @@ -126,7 +126,7 @@ public void test() throws Exception { for (int i = 0; i < 10; i++) { set.add(TestUtil.getString(statement.executeQuery( " select * from travelrecord" - ))); + )).replaceAll("id=\\[\\d+\\]","")); } Assert.assertEquals(1, set.size());//验证无事务的情况下但是set autocommit = 1,读写分离 } @@ -144,7 +144,7 @@ public void test() throws Exception { for (int i = 0; i < 10; i++) { set.add(TestUtil.getString(statement.executeQuery( "explain select * from travelrecord" - ))); + )).replaceAll("id=\\[\\d+\\]","")); } Assert.assertTrue(set.size() == 1);//验证有事务的情况下,不读写分离 } diff --git a/example/src/test/java/io/mycat/example/shardingRw/ShardingRwExample.java b/example/src/test/java/io/mycat/example/shardingRw/ShardingRwExample.java index cff4fff5c..cfa636f08 100644 --- a/example/src/test/java/io/mycat/example/shardingRw/ShardingRwExample.java +++ b/example/src/test/java/io/mycat/example/shardingRw/ShardingRwExample.java @@ -103,7 +103,7 @@ public void test() throws Exception { for (int i = 0; i < 10; i++) { set.add(TestUtil.getString(statement.executeQuery( "explain select * from travelrecord" - ))); + )).replaceAll("id=\\[\\d+\\]","")); } Assert.assertTrue(set.size() == 1);//验证有事务的情况下,不读写分离 } @@ -115,7 +115,7 @@ public void test() throws Exception { for (int i = 0; i < 10; i++) { set.add(TestUtil.getString(statement.executeQuery( "explain select * from travelrecord" - ))); + )).replaceAll("id=\\[\\d+\\]","")); } Assert.assertEquals(1, set.size());//验证无事务的情况下但是set autocommit = 0,不读写分离 } diff --git a/example/src/test/java/io/mycat/example/sharingXA/ShardingXAExample.java b/example/src/test/java/io/mycat/example/sharingXA/ShardingXAExample.java index 1553963e1..db14f1845 100644 --- a/example/src/test/java/io/mycat/example/sharingXA/ShardingXAExample.java +++ b/example/src/test/java/io/mycat/example/sharingXA/ShardingXAExample.java @@ -97,7 +97,7 @@ public void test() throws Exception { for (int i = 0; i < 10; i++) { set.add(TestUtil.getString(statement.executeQuery( "explain select * from travelrecord" - ))); + )).replaceAll("id=\\[\\d+\\]","")); } Assert.assertTrue(set.size() == 1);//验证有事务的情况下,不读写分离 } @@ -109,7 +109,7 @@ public void test() throws Exception { for (int i = 0; i < 10; i++) { set.add(TestUtil.getString(statement.executeQuery( "explain select * from travelrecord" - ))); + )).replaceAll("id=\\[\\d+\\]","")); } Assert.assertEquals(1, set.size());//验证无事务的情况下但是set autocommit = 0,不读写分离 } @@ -144,7 +144,7 @@ public void test() throws Exception { for (int i = 0; i < 10; i++) { set.add(TestUtil.getString(statement.executeQuery( "explain select * from travelrecord" - ))); + )).replaceAll("id=\\[\\d+\\]","")); } Assert.assertTrue(set.size() == 1);//验证有事务的情况下,不读写分离 } diff --git a/hbt/pom.xml b/hbt/pom.xml index 2aa0aa54d..149c0bd72 100644 --- a/hbt/pom.xml +++ b/hbt/pom.xml @@ -62,7 +62,7 @@ org.apache.calcite calcite-core - 1.22.0 + 1.23.0 diff --git a/hbt/src/main/java/io/mycat/calcite/CalciteRunners.java b/hbt/src/main/java/io/mycat/calcite/CalciteRunners.java index 3dd642735..7cf701820 100644 --- a/hbt/src/main/java/io/mycat/calcite/CalciteRunners.java +++ b/hbt/src/main/java/io/mycat/calcite/CalciteRunners.java @@ -5,6 +5,7 @@ import io.mycat.calcite.prepare.MycatCalcitePlanner; import io.mycat.calcite.resultset.EnumeratorRowIterator; import io.mycat.calcite.resultset.MyCatResultSetEnumerator; +import io.mycat.calcite.rules.StreamUnionRule; import io.mycat.calcite.table.SingeTargetSQLTable; import io.mycat.datasource.jdbc.JdbcRuntime; import io.mycat.upondb.MycatDBContext; @@ -13,6 +14,8 @@ import org.apache.calcite.linq4j.AbstractEnumerable; import org.apache.calcite.linq4j.Enumerable; import org.apache.calcite.linq4j.Enumerator; +import org.apache.calcite.plan.hep.HepPlanner; +import org.apache.calcite.plan.hep.HepProgramBuilder; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.RelShuttleImpl; import org.apache.calcite.rel.core.TableScan; @@ -21,6 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.StringWriter; import java.util.*; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -30,37 +34,28 @@ public class CalciteRunners { private final static Logger LOGGER = LoggerFactory.getLogger(CalciteRunners.class); @SneakyThrows - public static RelNode complie(MycatCalcitePlanner planner, String sql, boolean forUpdate) { + public static RelNode compile(MycatCalcitePlanner planner, String sql, boolean forUpdate) { SqlNode sqlNode = planner.parse(sql); SqlNode validate = planner.validate(sqlNode); RelNode relNode = planner.convert(validate); - return complie(planner, relNode, forUpdate); + return compile(planner, relNode, forUpdate); } - public static RelNode complie(MycatCalcitePlanner planner, RelNode relNode, boolean forUpdate) { - return planner.pushDownBySQL(planner.eliminateLogicTable(relNode), forUpdate); + public static RelNode compile(MycatCalcitePlanner planner, RelNode relNode, boolean forUpdate) { + try { + relNode = planner.eliminateLogicTable(relNode); + relNode = planner.pullUpUnion(relNode); + relNode = planner.pushDownBySQL(relNode, forUpdate); + return relNode; + }catch (Throwable e){ + LOGGER.error("",e); + } + return null; } @SneakyThrows public static RowBaseIterator run(MycatCalciteDataContext calciteDataContext, RelNode relNode) { - Future submit = JdbcRuntime.INSTANCE.getFetchDataExecutorService().submit(new Runnable() { - @Override - @SneakyThrows - public void run() { - fork(calciteDataContext, relNode); - } - }); - - ArrayBindable bindable1 = Interpreters.bindable(relNode); - submit.get(1, TimeUnit.MINUTES); - Enumerable bind = bindable1.bind(calciteDataContext); - - Enumerator enumerator = bind.enumerator(); - return new EnumeratorRowIterator(CalciteConvertors.getMycatRowMetaData(relNode.getRowType()), enumerator); - } - - private static void fork(MycatCalciteDataContext calciteDataContext, RelNode relNode) throws IllegalAccessException { Map> map = new HashMap<>(); relNode.accept(new RelShuttleImpl() { @Override @@ -73,6 +68,23 @@ public RelNode visit(TableScan scan) { return super.visit(scan); } }); + + HepProgramBuilder hepProgramBuilder = new HepProgramBuilder(); + hepProgramBuilder.addMatchLimit(64); + + hepProgramBuilder.addRuleInstance(StreamUnionRule.INSTANCE); + final HepPlanner planner2 = new HepPlanner(hepProgramBuilder.build()); + planner2.setRoot(relNode); + relNode = planner2.findBestExp(); + fork(calciteDataContext, map); + ArrayBindable bindable1 = Interpreters.bindable(relNode); + Enumerable bind = bindable1.bind(calciteDataContext); + + Enumerator enumerator = bind.enumerator(); + return new EnumeratorRowIterator(CalciteConvertors.getMycatRowMetaData(relNode.getRowType()), enumerator); + } + + private static void fork(MycatCalciteDataContext calciteDataContext, Map> map) throws IllegalAccessException { MycatDBContext uponDBContext = calciteDataContext.getUponDBContext(); AtomicBoolean cancelFlag = uponDBContext.cancelFlag(); if (uponDBContext.isInTransaction()) { @@ -87,15 +99,16 @@ public RelNode visit(TableScan scan) { if (list.size() > 1) { throw new IllegalAccessException("该执行计划重复拉取同一个数据源的数据"); } + Future submit = JdbcRuntime.INSTANCE.getFetchDataExecutorService() + .submit(() -> connection.executeQuery(table.getMetaData(), table.getSql())); table.setEnumerable(new AbstractEnumerable() { @Override @SneakyThrows public Enumerator enumerator() { - return new MyCatResultSetEnumerator(cancelFlag, connection.executeQuery(table.getMetaData(), table.getSql())); + return new MyCatResultSetEnumerator(cancelFlag, submit.get(1, TimeUnit.MINUTES)); } }); } - } else { Iterator iterator = map.entrySet().stream() .flatMap(i -> i.getValue().stream()) @@ -113,7 +126,7 @@ public Enumerator enumerator() { @Override @SneakyThrows public Enumerator enumerator() { - LOGGER.info("------!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + LOGGER.info("拉取数据"+v.getTargetName()+" sql:"+v.getSql()); return new MyCatResultSetEnumerator(cancelFlag, submit.get()); } }; diff --git a/hbt/src/main/java/io/mycat/calcite/CalciteUtls.java b/hbt/src/main/java/io/mycat/calcite/CalciteUtls.java index 245d49a64..d83f38699 100644 --- a/hbt/src/main/java/io/mycat/calcite/CalciteUtls.java +++ b/hbt/src/main/java/io/mycat/calcite/CalciteUtls.java @@ -23,6 +23,8 @@ import io.mycat.queryCondition.DataMappingEvaluator; import io.mycat.queryCondition.SimpleColumnInfo; import org.apache.calcite.DataContext; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.core.Union; import org.apache.calcite.rel.rel2sql.SqlImplementor; import org.apache.calcite.rex.*; import org.apache.calcite.sql.SqlIdentifier; @@ -57,13 +59,23 @@ public static List getQueryBackendTasks(ShardingTableHandler t List list = new ArrayList<>(); for (BackendTableInfo backendTableInfo : calculate) { String backendTaskSQL = getBackendTaskSQL(filters, rawColumnList, projectColumnList, backendTableInfo); - QueryBackendTask queryBackendTask = new QueryBackendTask( backendTableInfo.getTargetName(),backendTaskSQL); + QueryBackendTask queryBackendTask = new QueryBackendTask(backendTableInfo.getTargetName(), backendTaskSQL); list.add(queryBackendTask); } return list; } + public static void collect(Union e, List unions) { + for (RelNode input : e.getInputs()) { + if (input instanceof Union){ + collect((Union)input,unions); + }else { + unions.add(input); + } + } + } + public static List getBackendTableInfos(ShardingTableHandler table, List filters) { LOGGER.info("origin filters:{}", filters); DataMappingEvaluator record = new DataMappingEvaluator(); @@ -132,8 +144,8 @@ public SqlNode field(int ordinal) { }; try { return " where " + context.toSql(null, rexNode).toSqlString(MysqlSqlDialect.DEFAULT).getSql(); - }catch (Exception e){ - LOGGER.warn("不能生成对应的sql",e); + } catch (Exception e) { + LOGGER.warn("不能生成对应的sql", e); } return ""; } @@ -163,13 +175,13 @@ public static boolean addFilter(ShardingTableHandler table, DataMappingEvaluator RexNode left = operands.get(i); RexNode right = operands.get(j); if (left instanceof RexCall && right instanceof RexCall) { - if ((left.isA(SqlKind.GREATER_THAN_OR_EQUAL)||left.isA(SqlKind.GREATER_THAN)) && (right.isA(SqlKind.LESS_THAN_OR_EQUAL)||right.isA(SqlKind.LESS_THAN))) { + if ((left.isA(SqlKind.GREATER_THAN_OR_EQUAL) || left.isA(SqlKind.GREATER_THAN)) && (right.isA(SqlKind.LESS_THAN_OR_EQUAL) || right.isA(SqlKind.LESS_THAN))) { RexNode fisrtExpr = unCastWrapper(((RexCall) left).getOperands().get(0)); - RexNode secondExpr =unCastWrapper(((RexCall) right).getOperands().get(0)); + RexNode secondExpr = unCastWrapper(((RexCall) right).getOperands().get(0)); if (fisrtExpr instanceof RexInputRef && secondExpr instanceof RexInputRef) { int index = ((RexInputRef) fisrtExpr).getIndex(); if (index == ((RexInputRef) secondExpr).getIndex()) { - RexNode start =unCastWrapper( ((RexCall) left).getOperands().get(1)); + RexNode start = unCastWrapper(((RexCall) left).getOperands().get(1)); RexNode end = unCastWrapper(((RexCall) right).getOperands().get(1)); if (start instanceof RexLiteral && end instanceof RexLiteral) { String startValue = ((RexLiteral) start).getValue2().toString(); @@ -199,10 +211,6 @@ public static boolean addFilter(ShardingTableHandler table, DataMappingEvaluator left = unCastWrapper(left); - - - - RexNode right = call.getOperands().get(1); right = unCastWrapper(right); if (left instanceof RexInputRef && right instanceof RexLiteral) { diff --git a/hbt/src/main/java/io/mycat/calcite/MycatCalciteDataContext.java b/hbt/src/main/java/io/mycat/calcite/MycatCalciteDataContext.java index b86a57aa5..a98b3b5c4 100644 --- a/hbt/src/main/java/io/mycat/calcite/MycatCalciteDataContext.java +++ b/hbt/src/main/java/io/mycat/calcite/MycatCalciteDataContext.java @@ -38,6 +38,7 @@ import org.apache.calcite.schema.impl.AbstractSchema; import org.apache.calcite.sql.SqlOperatorTable; import org.apache.calcite.sql.parser.SqlParser; +import org.apache.calcite.sql.validate.SqlValidator; import org.apache.calcite.sql2rel.SqlRexConvertletTable; import org.apache.calcite.sql2rel.SqlToRelConverter; import org.apache.calcite.tools.FrameworkConfig; @@ -86,14 +87,12 @@ private ImmutableMap getCalciteLocalVariable() { public SchemaPlus getRootSchema() { MycatDBSharedServer uponDBSharedServer = uponDBContext.getUponDBSharedServer(); - Function function = new Function() { - @Override - public SchemaPlus apply(Byte aByte) { - return getSchema(uponDBContext); - } - }; - SchemaPlus component = uponDBSharedServer.getComponent(Components.SCHEMA,function); - return component; + Function function = aByte -> getSchema(uponDBContext); + if (uponDBContext.config().isCache()) { + return uponDBSharedServer.getComponent(Components.SCHEMA, function); + } else { + return function.apply(Components.SCHEMA); + } } public JavaTypeFactory getTypeFactory() { @@ -160,6 +159,11 @@ public SqlParser.Config getParserConfig() { return MycatCalciteSupport.INSTANCE.config.getParserConfig(); } + @Override + public SqlValidator.Config getSqlValidatorConfig() { + return SqlValidator.Config.DEFAULT; + } + @Override public SqlToRelConverter.Config getSqlToRelConverterConfig() { return MycatCalciteSupport.INSTANCE.config.getSqlToRelConverterConfig(); @@ -179,7 +183,7 @@ public SchemaPlus getDefaultSchema() { public RexExecutor getExecutor() { return (rexBuilder, constExps, reducedValues) -> { RexExecutor executor = MycatCalciteSupport.INSTANCE.config.getExecutor(); - if (executor!=null) { + if (executor != null) { executor.reduce(rexBuilder, constExps, reducedValues); } }; @@ -244,29 +248,30 @@ public MycatLogicTable getLogicTable(String targetName, String schema, String ta String uniqueName = targetName + "." + schema + "." + table; SchemaPlus rootSchema = getRootSchema(); Set subSchemaNames = rootSchema.getSubSchemaNames(); - for (String subSchemaName :subSchemaNames) { + for (String subSchemaName : subSchemaNames) { SchemaPlus subSchema = rootSchema.getSubSchema(subSchemaName); - log.debug("schemaName:{}",subSchemaName); + log.debug("schemaName:{}", subSchemaName); Set tableNames = subSchema.getTableNames(); - log.debug("tableNames:{}",tableNames); + log.debug("tableNames:{}", tableNames); for (String tableName : tableNames) { Table table1 = subSchema.getTable(tableName); if (table1 instanceof MycatLogicTable) { Map dataNodeMap = ((MycatLogicTable) table1).getDataNodeMap(); - log.debug("dataNodeMap:{}",dataNodeMap); + log.debug("dataNodeMap:{}", dataNodeMap); if (dataNodeMap.containsKey(uniqueName)) { - return Objects.requireNonNull((MycatLogicTable)table1); + return Objects.requireNonNull((MycatLogicTable) table1); } } } } return null; } + final static Logger log = LoggerFactory.getLogger(MycatCalciteDataContext.class); - public AtomicBoolean getCancelFlag(){ - return DataContext.Variable.CANCEL_FLAG.get(this); - } + public AtomicBoolean getCancelFlag() { + return DataContext.Variable.CANCEL_FLAG.get(this); + } } \ No newline at end of file diff --git a/hbt/src/main/java/io/mycat/calcite/MycatCalciteSupport.java b/hbt/src/main/java/io/mycat/calcite/MycatCalciteSupport.java index bb33caf0b..585804189 100644 --- a/hbt/src/main/java/io/mycat/calcite/MycatCalciteSupport.java +++ b/hbt/src/main/java/io/mycat/calcite/MycatCalciteSupport.java @@ -26,10 +26,7 @@ import io.mycat.hbt.ast.base.Schema; import io.mycat.upondb.MycatDBContext; import io.mycat.util.Explains; -import org.apache.calcite.config.CalciteConnectionConfig; -import org.apache.calcite.config.CalciteConnectionConfigImpl; -import org.apache.calcite.config.CalciteConnectionProperty; -import org.apache.calcite.config.Lex; +import org.apache.calcite.config.*; import org.apache.calcite.jdbc.Driver; import org.apache.calcite.jdbc.JavaTypeFactoryImpl; import org.apache.calcite.plan.Context; @@ -51,11 +48,14 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.sql.parser.SqlAbstractParserImpl; import org.apache.calcite.sql.parser.SqlParser; +import org.apache.calcite.sql.type.SqlTypeCoercionRule; import org.apache.calcite.sql.type.SqlTypeFamily; import org.apache.calcite.sql.type.SqlTypeName; import org.apache.calcite.sql.validate.SqlConformance; import org.apache.calcite.sql.validate.SqlConformanceEnum; import org.apache.calcite.sql.validate.SqlNameMatcher; +import org.apache.calcite.sql.validate.SqlValidator; +import org.apache.calcite.sql.validate.implicit.TypeCoercionFactory; import org.apache.calcite.sql2rel.SqlRexConvertlet; import org.apache.calcite.sql2rel.SqlRexConvertletTable; import org.apache.calcite.sql2rel.SqlToRelConverter; @@ -126,6 +126,102 @@ public RelBuilder create(RelOptCluster cluster, RelOptSchema schema) { .withInSubQueryThreshold(Integer.MAX_VALUE) .withRelBuilderFactory(relBuilderFactory).build(); + public final SqlValidator.Config getValidatorConfig() { + return SqlValidator.Config.DEFAULT; +// .withSqlConformance(calciteConnectionConfig.conformance()); + } +// new SqlValidator.Config() { +// @Override +// public boolean callRewrite() { +// return false; +// } +// +// @Override +// public SqlValidator.Config withCallRewrite(boolean rewrite) { +// return this; +// } +// +// @Override +// public NullCollation defaultNullCollation() { +// return NullCollation.HIGH; +// } +// +// @Override +// public SqlValidator.Config withDefaultNullCollation(NullCollation nullCollation) { +// return this; +// } +// +// @Override +// public boolean columnReferenceExpansion() { +// return false; +// } +// +// @Override +// public SqlValidator.Config withColumnReferenceExpansion(boolean expand) { +// return this; +// } +// +// @Override +// public boolean identifierExpansion() { +// return false; +// } +// +// @Override +// public SqlValidator.Config withIdentifierExpansion(boolean expand) { +// return this; +// } +// +// @Override +// public boolean lenientOperatorLookup() { +// return true; +// } +// +// @Override +// public SqlValidator.Config withLenientOperatorLookup(boolean lenient) { +// return this; +// } +// +// @Override +// public boolean typeCoercionEnabled() { +// return false; +// } +// +// @Override +// public SqlValidator.Config withTypeCoercionEnabled(boolean enabled) { +// return this; +// } +// +// @Override +// public TypeCoercionFactory typeCoercionFactory() { +// return SqlValidator.Config.DEFAULT.typeCoercionFactory(); +// } +// +// @Override +// public SqlValidator.Config withTypeCoercionFactory(TypeCoercionFactory factory) { +// return this; +// } +// +// @Override +// public SqlTypeCoercionRule typeCoercionRules() { +// return SqlValidator.Config.DEFAULT.typeCoercionRules(); +// } +// +// @Override +// public SqlValidator.Config withTypeCoercionRules(SqlTypeCoercionRule rules) { +// return this; +// } +// +// @Override +// public SqlConformance sqlConformance() { +// return MycatCalciteSupport.INSTANCE.calciteConnectionConfig.conformance(); +// } +// +// @Override +// public SqlValidator.Config withSqlConformance(SqlConformance conformance) { +// return this; +// } +// }; + public MycatCalciteDataContext create(MycatDBContext uponDBContext) { return new MycatCalciteDataContext(uponDBContext); @@ -146,6 +242,7 @@ public MycatCalciteDataContext create(MycatDBContext uponDBContext) { map.put("IFNULL", SqlStdOperatorTable.COALESCE); build.put("SUBSTR", SqlStdOperatorTable.SUBSTRING); build.put("CURDATE", SqlStdOperatorTable.CURRENT_DATE); + build.put("CURRENT_DATE",SqlStdOperatorTable.CURRENT_DATE); build.put("NOW", SqlStdOperatorTable.LOCALTIMESTAMP); build.put("LOG", SqlStdOperatorTable.LOG10); build.put("PI",SqlStdOperatorTable.PI); diff --git a/hbt/src/main/java/io/mycat/calcite/MycatImplementor.java b/hbt/src/main/java/io/mycat/calcite/MycatImplementor.java index 31134aca4..bc826ad1f 100644 --- a/hbt/src/main/java/io/mycat/calcite/MycatImplementor.java +++ b/hbt/src/main/java/io/mycat/calcite/MycatImplementor.java @@ -17,18 +17,19 @@ import com.google.common.collect.ImmutableList; import io.mycat.SchemaInfo; import io.mycat.calcite.table.MycatPhysicalTable; +import org.apache.calcite.linq4j.Ord; +import org.apache.calcite.linq4j.tree.Expressions; import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.core.Aggregate; -import org.apache.calcite.rel.core.AggregateCall; -import org.apache.calcite.rel.core.Project; -import org.apache.calcite.rel.core.TableScan; +import org.apache.calcite.rel.core.*; import org.apache.calcite.rel.rel2sql.RelToSqlConverter; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.sql.*; import org.apache.calcite.sql.fun.SqlSingleValueAggFunction; import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.sql.parser.SqlParserPos; +import org.apache.calcite.tools.RelBuilder; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -43,7 +44,12 @@ public Result visit(TableScan e) { MycatPhysicalTable physicalTable = e.getTable().unwrap(MycatPhysicalTable.class); if (physicalTable != null) { SchemaInfo schemaInfo = physicalTable.getBackendTableInfo().getSchemaInfo(); - SqlIdentifier identifier = new SqlIdentifier(Arrays.asList(schemaInfo.getTargetSchema(),schemaInfo.getTargetTable()), SqlParserPos.ZERO); + SqlIdentifier identifier; + if (schemaInfo.getTargetSchema() == null) { + identifier = new SqlIdentifier(Collections.singletonList(schemaInfo.getTargetTable()), SqlParserPos.ZERO); + } else { + identifier = new SqlIdentifier(Arrays.asList(schemaInfo.getTargetSchema(), schemaInfo.getTargetTable()), SqlParserPos.ZERO); + } return result(identifier, ImmutableList.of(Clause.FROM), e, null); } else { return super.visit(e); @@ -72,6 +78,7 @@ public MycatImplementor(SqlDialect dialect) { // /** @see #dispatch */ // public Result visit(MycatTransientSQLTableScan scan) { // return scan.implement(); + // } public Result implement(RelNode node) { @@ -80,12 +87,13 @@ public Result implement(RelNode node) { /** * 1.修复生成的sql不带select items + * * @param e * @return */ @Override public Result visit(Project e) { - if (e.getProjects().isEmpty()){ + if (e.getProjects().isEmpty()) { Result x = visitChild(0, e.getInput()); final Builder builder = x.builder(e, Clause.SELECT); @@ -94,6 +102,41 @@ public Result visit(Project e) { } return super.visit(e); } + + /** + * 该union输入是超过2个节点的,union 别名 问题 + * @param e + * @return + */ +// @Override +// public Result visit(Union e) { +// if (!e.isDistinct()) { +// List unions =e.getInputs(); +// RelBuilder relBuilder = MycatCalciteSupport.INSTANCE.relBuilderFactory.create(e.getCluster(), null); +// relBuilder.pushAll(unions); +// relBuilder.union(e.all, unions.size()); +// e = (Union) relBuilder.build(); +// SqlNode node = null; +// for (Ord input : Ord.zip(e.getInputs())) { +// final Result result = visitChild(input.i, input.e); +// if (node == null) { +// node = result.asSelect().;//修改点 会添加别名??? +// } else { +// SqlSetOperator sqlSetOperator = e.all +// ? SqlStdOperatorTable.UNION_ALL +// : SqlStdOperatorTable.UNION; +// node = sqlSetOperator.createCall(POS, node, result.asSelect()); +// } +// } +// final List clauses = +// Expressions.list(Clause.SET_OP); +// return result(node, clauses, e, null); +// } +// return super.visit(e).qualifiedContext().implementor().setOpToSql().resetAlias(); +// } +// + + @Override protected Result buildAggregate(Aggregate e, Builder builder, List selectList, List groupByList) { @@ -103,7 +146,7 @@ protected Result buildAggregate(Aggregate e, Builder builder, SqlNode aggCallSqlNode = builder.context.toSql(aggCall); if (aggCall.getAggregation() instanceof SqlSingleValueAggFunction) { aggCallSqlNode = dialect.rewriteSingleValueExpr(aggCallSqlNode); - aggCallSqlNode= SqlStdOperatorTable.CAST.createCall(POS, + aggCallSqlNode = SqlStdOperatorTable.CAST.createCall(POS, aggCallSqlNode, dialect.getCastSpec(type)); } addSelect(selectList, aggCallSqlNode, e.getRowType()); diff --git a/hbt/src/main/java/io/mycat/calcite/MycatRelBuilder.java b/hbt/src/main/java/io/mycat/calcite/MycatRelBuilder.java index 0e5cd343f..3343404ed 100644 --- a/hbt/src/main/java/io/mycat/calcite/MycatRelBuilder.java +++ b/hbt/src/main/java/io/mycat/calcite/MycatRelBuilder.java @@ -52,6 +52,7 @@ * @author Junwen Chen **/ public class MycatRelBuilder extends RelBuilder { + int id = 0; public MycatRelBuilder(Context context, RelOptCluster cluster, RelOptSchema relOptSchema) { super(context, cluster, relOptSchema); } @@ -187,11 +188,12 @@ public RexNode literal(Object value) { public RelNode makeBySql(String targetName,RelDataType relDataType, String sql) { MycatConvention convention = MycatConvention.of(targetName, MysqlSqlDialect.DEFAULT); MycatSQLTableScan transientTable = new MycatSQLTableScan(convention,relDataType,sql); + id++; RelOptTable relOptTable = RelOptTableImpl.create( this.getRelOptSchema(), relDataType, transientTable, - ImmutableList.of(targetName, sql)); + ImmutableList.of(id +"$"+targetName, id+sql)); return new MycatTransientSQLTableScan(this.getCluster(), convention, relOptTable, () -> sql); } } \ No newline at end of file diff --git a/hbt/src/main/java/io/mycat/calcite/UnionResolver.java b/hbt/src/main/java/io/mycat/calcite/UnionResolver.java new file mode 100644 index 000000000..fdd95da71 --- /dev/null +++ b/hbt/src/main/java/io/mycat/calcite/UnionResolver.java @@ -0,0 +1,64 @@ +package io.mycat.calcite; + +import com.google.common.collect.ImmutableList; +import io.mycat.calcite.table.MycatSQLTableScan; +import io.mycat.calcite.table.StreamUnionTable; +import org.apache.calcite.plan.RelOptTable; +import org.apache.calcite.prepare.RelOptTableImpl; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.RelShuttleImpl; +import org.apache.calcite.rel.logical.LogicalTableScan; +import org.apache.calcite.rel.logical.LogicalUnion; +import org.apache.calcite.tools.RelBuilder; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class UnionResolver extends RelShuttleImpl { + public boolean change = true; + + @Override + public RelNode visit(LogicalUnion union) { + change = false; +// boolean inTransaction = calciteDataContext.getUponDBContext().isInTransaction(); + + //calcite的默认union执行器的输入不能超过2个 + + RelBuilder relBuilder = MycatCalciteSupport.INSTANCE.relBuilderFactory.create(union.getCluster(), null); + + ArrayList inputs = new ArrayList<>(); + CalciteUtls.collect(union, inputs); + //收集union的输入节点 + + +// //union并行化 +// if (inputs.stream().allMatch(p -> p.getTable() != null && p.getTable().unwrap(MycatSQLTableScan.class) != null)) { +// List relNodes = (List) +// (inputs.stream().map(p -> p.getTable().unwrap(MycatSQLTableScan.class)).collect(Collectors.toList())); +// StreamUnionTable scanOperator = new StreamUnionTable(relNodes); +// RelOptTable table = RelOptTableImpl.create( +// null, +// scanOperator.getRowType(MycatCalciteSupport.INSTANCE.TypeFactory), +// scanOperator, +// ImmutableList.of(union.toString())); +// change = true; +// return LogicalTableScan.create(union.getCluster(), table, ImmutableList.of()); +// } + + //不能并行的转换为执行器能运行的形状 + if (inputs.size() > 2) { + change = true; + return inputs.stream().reduce((relNode1, relNode2) -> { + relBuilder.clear(); + relBuilder.push(relNode1); + relBuilder.push(relNode2); + return relBuilder.union(!union.isDistinct()).build(); + }).get(); + } else { + change = false; + return union; + } + + } +} \ No newline at end of file diff --git a/hbt/src/main/java/io/mycat/calcite/prepare/MycatCalcitePlanner.java b/hbt/src/main/java/io/mycat/calcite/prepare/MycatCalcitePlanner.java index 645fb1d27..29aca8655 100644 --- a/hbt/src/main/java/io/mycat/calcite/prepare/MycatCalcitePlanner.java +++ b/hbt/src/main/java/io/mycat/calcite/prepare/MycatCalcitePlanner.java @@ -15,16 +15,19 @@ package io.mycat.calcite.prepare; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import io.mycat.calcite.MycatCalciteDataContext; import io.mycat.calcite.MycatCalciteSupport; import io.mycat.calcite.MycatRelBuilder; -import io.mycat.calcite.rules.PushDownLogicTable; +import io.mycat.calcite.rules.LimitPushRemoveRule; +import io.mycat.calcite.rules.PushDownLogicTableRule; import io.mycat.calcite.table.*; import io.mycat.upondb.MycatDBContext; import org.apache.calcite.adapter.enumerable.EnumerableConvention; import org.apache.calcite.interpreter.Bindables; import org.apache.calcite.jdbc.CalciteSchema; import org.apache.calcite.plan.*; +import org.apache.calcite.plan.hep.HepMatchOrder; import org.apache.calcite.plan.hep.HepPlanner; import org.apache.calcite.plan.hep.HepProgram; import org.apache.calcite.plan.hep.HepProgramBuilder; @@ -48,13 +51,14 @@ import org.apache.calcite.sql.SqlOperatorTable; import org.apache.calcite.sql.parser.SqlParseException; import org.apache.calcite.sql.type.SqlTypeFamily; -import org.apache.calcite.sql.validate.SqlConformance; import org.apache.calcite.sql.validate.SqlValidatorCatalogReader; import org.apache.calcite.sql.validate.SqlValidatorImpl; import org.apache.calcite.sql.validate.SqlValidatorUtil; import org.apache.calcite.sql2rel.SqlToRelConverter; import org.apache.calcite.tools.*; import org.apache.calcite.util.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.Reader; import java.util.*; @@ -69,7 +73,7 @@ * @author Junwen Chen **/ public class MycatCalcitePlanner implements Planner, RelOptTable.ViewExpander { - + private final static Logger LOGGER = LoggerFactory.getLogger(MycatCalcitePlanner.class); private final SchemaPlus rootSchema; private final PlannerImpl planner; CalciteCatalogReader reader = null; @@ -110,8 +114,7 @@ public SqlValidatorImpl getSqlValidator() { SqlOperatorTable opTab = MycatCalciteSupport.INSTANCE.config.getOperatorTable(); SqlValidatorCatalogReader catalogReader = createCalciteCatalogReader(); RelDataTypeFactory typeFactory = MycatCalciteSupport.INSTANCE.TypeFactory; - SqlConformance conformance = MycatCalciteSupport.INSTANCE.calciteConnectionConfig.conformance(); - return (SqlValidatorImpl) SqlValidatorUtil.newValidator(opTab, catalogReader, typeFactory, conformance); + return (SqlValidatorImpl) SqlValidatorUtil.newValidator(opTab, catalogReader, typeFactory, MycatCalciteSupport.INSTANCE.getValidatorConfig()); } public SqlToRelConverter createSqlToRelConverter() { @@ -136,49 +139,49 @@ public SqlToRelConverter createSqlToRelConverter() { // AggregateProjectPullUpConstantsRule.INSTANCE, // PushDownLogicTable.INSTANCE_FOR_PushDownFilterLogicTable // ); - +//目的是下推谓词,所以添加 Filter 相关 +static final ImmutableSet FILTER = ImmutableSet.of( + FilterAggregateTransposeRule.INSTANCE, + FilterCorrelateRule.INSTANCE, + FilterJoinRule.FILTER_ON_JOIN, + FilterMergeRule.INSTANCE, + FilterMultiJoinMergeRule.INSTANCE, + FilterProjectTransposeRule.INSTANCE, + FilterRemoveIsNotDistinctFromRule.INSTANCE, + FilterTableScanRule.INSTANCE, + FilterSetOpTransposeRule.INSTANCE, + FilterProjectTransposeRule.INSTANCE, + SemiJoinFilterTransposeRule.INSTANCE, +// ReduceExpressionsRule.FILTER_INSTANCE, +// ReduceExpressionsRule.JOIN_INSTANCE, + //https://issues.apache.org/jira/browse/CALCITE-4045 +// ReduceExpressionsRule.PROJECT_INSTANCE, + ProjectFilterTransposeRule.INSTANCE, + FilterTableScanRule.INSTANCE, + JoinPushTransitivePredicatesRule.INSTANCE, + JoinPushTransitivePredicatesRule.INSTANCE, + ProjectTableScanRule.INSTANCE, + JoinExtractFilterRule.INSTANCE, + Bindables.BINDABLE_TABLE_SCAN_RULE + +); public RelNode eliminateLogicTable(final RelNode bestExp) { - RelOptCluster cluster = bestExp.getCluster(); - HepProgramBuilder hepProgramBuilder = new HepProgramBuilder(); - PushDownLogicTable pushDownLogicTable = new PushDownLogicTable(); - Arrays.asList( - FilterProjectTransposeRule.INSTANCE, - Bindables.BINDABLE_TABLE_SCAN_RULE, - FilterTableScanRule.INSTANCE, - ProjectTableScanRule.INSTANCE, - FilterSetOpTransposeRule.INSTANCE, - JoinUnionTransposeRule.LEFT_UNION, - JoinUnionTransposeRule.RIGHT_UNION, - JoinExtractFilterRule.INSTANCE, - JoinPushTransitivePredicatesRule.INSTANCE, - AggregateUnionTransposeRule.INSTANCE, - AggregateUnionAggregateRule.AGG_ON_FIRST_INPUT, - AggregateUnionAggregateRule.AGG_ON_SECOND_INPUT, - AggregateUnionAggregateRule.INSTANCE, - AggregateProjectMergeRule.INSTANCE, - AggregateProjectPullUpConstantsRule.INSTANCE, - pushDownLogicTable, -// PushDownLogicTable.INSTANCE_FOR_PushDownFilterLogicTable, - AggregateValuesRule.INSTANCE - ).forEach(i -> hepProgramBuilder.addRuleInstance(i)); -// hepProgramBuilder.addRuleInstance(PushDownLogicTable.INSTANCE_FOR_PushDownLogicTable); - - final HepPlanner planner2 = new HepPlanner(hepProgramBuilder.build()); + HepProgramBuilder hepProgramBuilder = new HepProgramBuilder() + .addMatchLimit(FILTER.size()) + .addRuleCollection(FILTER); + HepPlanner planner2 = new HepPlanner(hepProgramBuilder.build()); planner2.setRoot(bestExp); - final RelNode bestExp1 = planner2.findBestExp(); + RelNode bestExp2 = planner2.findBestExp(); - RelShuttleImpl relShuttle = new RelShuttleImpl() { - @Override - public RelNode visit(TableScan scan) { - MycatLogicTable unwrap = scan.getTable().unwrap(MycatLogicTable.class); - if (unwrap != null) { - return pushDownLogicTable.toPhyTable(createRelBuilder(cluster), scan); - } - return super.visit(scan); - } - }; - final RelNode bestExp2 = bestExp1.accept(relShuttle); - return relShuttle.visit(bestExp2); + hepProgramBuilder= new HepProgramBuilder() + .addMatchLimit(FILTER.size()) + .addRuleCollection(ImmutableList.of( + PushDownLogicTableRule.BindableTableScan + )); + + planner2 = new HepPlanner(hepProgramBuilder.build()); + planner2.setRoot(bestExp2); + return planner2.findBestExp(); } public RelNode pushDownBySQL(RelNode bestExp, boolean forUpdate) { @@ -186,10 +189,13 @@ public RelNode pushDownBySQL(RelNode bestExp, boolean forUpdate) { } public RelNode pushDownBySQL(MycatRelBuilder relBuilder, final RelNode bestExp0, boolean forUpdate) { - HepProgram build = new HepProgramBuilder().build(); + HepProgramBuilder hepProgramBuilder = new HepProgramBuilder(); + hepProgramBuilder.addMatchLimit(3); + hepProgramBuilder.addMatchOrder(HepMatchOrder.TOP_DOWN); + hepProgramBuilder.addRuleInstance(LimitPushRemoveRule.INSTANCE); + HepProgram build = hepProgramBuilder.build(); RelOptPlanner planner = new HepPlanner(build); - RelOptUtil.registerDefaultRules(planner, true, true); planner.setRoot(bestExp0); final RelNode bestExp1 = planner.findBestExp(); @@ -197,7 +203,6 @@ public RelNode pushDownBySQL(MycatRelBuilder relBuilder, final RelNode bestExp0, IdentityHashMap cache = computePushDownInfo.getCache(); IdentityHashMap> margeList = computePushDownInfo.getMargeList(); - final RelNode bestExp3 = simplyAggreate(relBuilder, cache, margeList, bestExp1); //从根节点开始把变成SQL下推 RelHomogeneousShuttle relHomogeneousShuttle1 = new RelHomogeneousShuttle() { @Override @@ -215,12 +220,12 @@ public RelNode visit(RelNode other) { return super.visit(other); } }; - final RelNode bestExp4 = bestExp3.accept(relHomogeneousShuttle1); - return bestExp4; + return bestExp1.accept(relHomogeneousShuttle1); } /** * 测试单库分表与不同分片两个情况 + * * @param relBuilder * @param cache * @param margeList @@ -233,14 +238,14 @@ private RelNode simplyAggreate(MycatRelBuilder relBuilder, IdentityHashMap aggCallList = aggregate.getAggCallList(); - boolean allMatch = aggregate.getRowType().getFieldCount()==1&&aggCallList.stream().allMatch(new Predicate() { + boolean allMatch = aggregate.getRowType().getFieldCount() == 1 && aggCallList.stream().allMatch(new Predicate() { @Override public boolean test(AggregateCall aggregateCall) { return SUPPORTED_AGGREGATES.getOrDefault(aggregateCall.getAggregation().getKind(), false) && - aggregate.getRowType().getFieldList().stream().allMatch(i->i.getType().getSqlTypeName().getFamily()== SqlTypeFamily.NUMERIC); + aggregate.getRowType().getFieldList().stream().allMatch(i -> i.getType().getSqlTypeName().getFamily() == SqlTypeFamily.NUMERIC); } }); if (allMatch) { @@ -326,7 +331,7 @@ public RelOptCluster newCluster() { return RelOptCluster.create(planner, MycatCalciteSupport.INSTANCE.RexBuilder); } - private static final EnumMap SUPPORTED_AGGREGATES = new EnumMap<>(SqlKind.class); + public static final EnumMap SUPPORTED_AGGREGATES = new EnumMap<>(SqlKind.class); static { SUPPORTED_AGGREGATES.put(SqlKind.MIN, true); @@ -438,11 +443,62 @@ public RelNode visit(TableScan scan) { }); } + //目的是上拉union,所以添加 union 相关 + //目的是消除project,减少产生的子查询 所以添加 project 相关 + static final ImmutableSet PULL_RULES = ImmutableSet.of( + UnionEliminatorRule.INSTANCE, + UnionMergeRule.INTERSECT_INSTANCE, + UnionMergeRule.INTERSECT_INSTANCE, + UnionMergeRule.MINUS_INSTANCE, + UnionPullUpConstantsRule.INSTANCE, + UnionToDistinctRule.INSTANCE, + ProjectCorrelateTransposeRule.INSTANCE, + ProjectFilterTransposeRule.INSTANCE, + ProjectJoinJoinRemoveRule.INSTANCE, + ProjectJoinRemoveRule.INSTANCE, + ProjectJoinTransposeRule.INSTANCE, + ProjectMergeRule.INSTANCE, + ProjectMultiJoinMergeRule.INSTANCE, + ProjectRemoveRule.INSTANCE, + JoinUnionTransposeRule.LEFT_UNION, + JoinUnionTransposeRule.RIGHT_UNION, + AggregateProjectMergeRule.INSTANCE,//该类有效 + AggregateUnionTransposeRule.INSTANCE,//该实现可能有问题 + AggregateUnionAggregateRule.INSTANCE, + AggregateProjectMergeRule.INSTANCE, + AggregateRemoveRule.INSTANCE, + AggregateProjectPullUpConstantsRule.INSTANCE2, + ProjectSetOpTransposeRule.INSTANCE,//该实现可能有问题 + ProjectSortTransposeRule.INSTANCE, + AggregateCaseToFilterRule.INSTANCE, + AggregateFilterTransposeRule.INSTANCE, + AggregateValuesRule.INSTANCE, + //sort + SortJoinCopyRule.INSTANCE, + SortJoinTransposeRule.INSTANCE, + SortProjectTransposeRule.INSTANCE, + SortRemoveConstantKeysRule.INSTANCE, + SortRemoveRule.INSTANCE, + SortUnionTransposeRule.INSTANCE, + SortUnionTransposeRule.MATCH_NULL_FETCH, + SubQueryRemoveRule.FILTER, + SubQueryRemoveRule.JOIN, + SubQueryRemoveRule.PROJECT); + + public RelNode pullUpUnion(RelNode relNode1) { + HepProgramBuilder hepProgramBuilder = new HepProgramBuilder(); + hepProgramBuilder.addMatchLimit(PULL_RULES.size()); + hepProgramBuilder.addRuleCollection(PULL_RULES); + final HepPlanner planner2 = new HepPlanner(hepProgramBuilder.build()); + planner2.setRoot(relNode1); + return planner2.findBestExp(); + } + + private class ComputePushDownInfo { private RelNode bestExp1; private IdentityHashMap cache; private IdentityHashMap> margeList; - private RelNode bestExp2; public ComputePushDownInfo(RelNode bestExp1) { this.bestExp1 = bestExp1; @@ -456,9 +512,6 @@ public IdentityHashMap> getMargeList() { return margeList; } - public RelNode getBestExp2() { - return bestExp2; - } public ComputePushDownInfo invoke() { RelNode root = bestExp1; @@ -469,10 +522,15 @@ public ComputePushDownInfo invoke() { @Override public RelNode visit(RelNode other) { RelNode res = super.visit(other);//后续遍历 + + + List inputs = other.getInputs(); boolean isLeftNode = inputs == null || other.getInputs() != null && other.getInputs().isEmpty(); + if (!isLeftNode) { + ArrayList targetList = new ArrayList<>(); for (RelNode input : inputs) { targetList.addAll(margeList.getOrDefault(input, Collections.emptyList())); @@ -480,12 +538,16 @@ public RelNode visit(RelNode other) { Set distinct = new HashSet<>(targetList); margeList.put(other, targetList); boolean b = other instanceof Aggregate && other != root;//控制深度为2的关系表达式节点是否是Aggregate - if (other instanceof Correlate) { - cache.put(other, false);//关联子查询(mycat不支持)和 - } else { + +// if (other instanceof Correlate) { +// cache.put(other, false);//关联子查询(mycat不支持)和 +// } + + { boolean distinctValue = distinct.isEmpty() || distinct.size() == 1; cache.put(other, distinctValue); } + } else { MycatPhysicalTable mycatPhysicalTable = Optional.ofNullable(other.getTable()).map(i -> i.unwrap(MycatPhysicalTable.class)).orElse(null); if (mycatPhysicalTable != null) { @@ -495,10 +557,15 @@ public RelNode visit(RelNode other) { } cache.put(other, Boolean.TRUE); } + //修正,不能影响上面流程 + if(other instanceof Union){ + cache.put(other, false);//没有事务并行查询->总是并行查询 + return other; + } return other; } }; - bestExp2 = relHomogeneousShuttle.visit(bestExp1); + relHomogeneousShuttle.visit(bestExp1); return this; } } diff --git a/hbt/src/main/java/io/mycat/calcite/prepare/MycatSqlPlanner.java b/hbt/src/main/java/io/mycat/calcite/prepare/MycatSqlPlanner.java index ea2a11cce..31f38e5f9 100644 --- a/hbt/src/main/java/io/mycat/calcite/prepare/MycatSqlPlanner.java +++ b/hbt/src/main/java/io/mycat/calcite/prepare/MycatSqlPlanner.java @@ -47,7 +47,7 @@ public MycatSqlPlanner(MycatSQLPrepareObject prepare, String sql, MycatDBContext this.prepare = prepare; this.mycatCalciteDataContext = MycatCalciteSupport.INSTANCE.create(uponDBContext); MycatCalcitePlanner planner = MycatCalciteSupport.INSTANCE.createPlanner(mycatCalciteDataContext); - this.relNode = CalciteRunners.complie(planner, sql, prepare.isForUpdate()); + this.relNode = CalciteRunners.compile(planner, sql, prepare.isForUpdate()); } public List explain() { diff --git a/hbt/src/main/java/io/mycat/calcite/rules/GroupByPartitionRule.java b/hbt/src/main/java/io/mycat/calcite/rules/GroupByPartitionRule.java new file mode 100644 index 000000000..f8e774fbf --- /dev/null +++ b/hbt/src/main/java/io/mycat/calcite/rules/GroupByPartitionRule.java @@ -0,0 +1,89 @@ +package io.mycat.calcite.rules; + +import com.google.common.base.Predicate; +import io.mycat.calcite.table.MycatLogicTable; +import io.mycat.calcite.table.MycatPhysicalTable; +import io.mycat.metadata.ShardingTable; +import io.mycat.metadata.TableHandler; +import io.mycat.queryCondition.SimpleColumnInfo; +import org.apache.calcite.plan.RelOptRule; +import org.apache.calcite.plan.RelOptRuleCall; +import org.apache.calcite.plan.RelOptTable; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.core.Aggregate; +import org.apache.calcite.rel.core.TableScan; +import org.apache.calcite.rel.core.Union; +import org.apache.calcite.sql.SqlKind; +import org.apache.calcite.tools.RelBuilder; +import org.apache.calcite.util.ImmutableBitSet; + +import java.util.EnumMap; +import java.util.List; + +public class GroupByPartitionRule extends RelOptRule { + public static final EnumMap SUPPORTED_AGGREGATES = new EnumMap<>(SqlKind.class); + + static { + SUPPORTED_AGGREGATES.put(SqlKind.MIN, true); + SUPPORTED_AGGREGATES.put(SqlKind.MAX, true); + SUPPORTED_AGGREGATES.put(SqlKind.COUNT, true); + SUPPORTED_AGGREGATES.put(SqlKind.SUM, true); + SUPPORTED_AGGREGATES.put(SqlKind.SUM0, true); + } + + public GroupByPartitionRule() { + super(operandJ(Aggregate.class, null, GroupByPartitionRule::test, + operandJ(Union.class, null, r -> !r.isDistinct(), + operandJ(TableScan.class, null, (Predicate) input -> { + if (input != null) { + RelOptTable table = input.getTable(); + if (table != null) { + MycatPhysicalTable table1 = table.unwrap(MycatPhysicalTable.class); + MycatLogicTable logicTable = table1.getLogicTable(); + TableHandler tableHandler = logicTable.getTable(); + if (tableHandler instanceof ShardingTable) { + ShardingTable handler = (ShardingTable) tableHandler; + return logicTable.getDataNodes().size() > 1; + } + return false; + } + } + return false; + }, none())))); + } + + private static boolean test(Aggregate r) { + return r.getGroupCount() == 1 && r.getAggCallList().size() == 1 && + SUPPORTED_AGGREGATES.containsKey(r.getAggCallList().get(0).getAggregation().kind); + } + + @Override + public void onMatch(RelOptRuleCall call) { + final Aggregate aggregate = call.rel(0); + final Union union = call.rel(1); + final TableScan table = call.rel(2); + if (!test(aggregate)) { + return; + } + + ImmutableBitSet groupSet = aggregate.getGroupSet(); + Integer integer = groupSet.asList().get(0); + MycatPhysicalTable table1 = table.getTable().unwrap(MycatPhysicalTable.class); + + MycatLogicTable logicTable = table1.getLogicTable(); + TableHandler tableHandler = logicTable.getTable(); + if (tableHandler instanceof ShardingTable) { + ShardingTable handler = (ShardingTable) tableHandler; + List columns = handler.getColumns(); + if (integer < columns.size()) { + if (handler.getNatureTableColumnInfo().getColumnInfo().equals(columns.get(integer))) { + RelBuilder builder = call.builder(); + List inputs = union.getInputs(); + + + } + } + } + + } +} \ No newline at end of file diff --git a/hbt/src/main/java/io/mycat/calcite/rules/LimitPushRemoveRule.java b/hbt/src/main/java/io/mycat/calcite/rules/LimitPushRemoveRule.java new file mode 100644 index 000000000..217dbdb09 --- /dev/null +++ b/hbt/src/main/java/io/mycat/calcite/rules/LimitPushRemoveRule.java @@ -0,0 +1,123 @@ +/* + * 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. + */ +package io.mycat.calcite.rules; + +import com.google.common.base.Predicate; +import org.apache.calcite.plan.RelOptRule; +import org.apache.calcite.plan.RelOptRuleCall; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.core.RelFactories; +import org.apache.calcite.rel.core.Sort; +import org.apache.calcite.rel.core.Union; +import org.apache.calcite.rex.RexLiteral; +import org.apache.calcite.tools.RelBuilder; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.math.BigDecimal; +import java.util.ArrayList; + +/** + * chenjunwen + *

+ * EXPLAIN SELECT * FROM db1.travelrecord LIMIT 500 ,10000; + */ +public class LimitPushRemoveRule extends RelOptRule { + public static final LimitPushRemoveRule INSTANCE = new LimitPushRemoveRule(); + private static final Logger LOGGER = LoggerFactory.getLogger(LimitPushRemoveRule.class); + + public LimitPushRemoveRule() { + super( + operandJ(Sort.class, null, (Predicate) LimitPushRemoveRule::sortApply, + operandJ(Union.class, null, (Predicate) LimitPushRemoveRule::unionApply, any())), + RelFactories.LOGICAL_BUILDER, "LimitRemoveRule"); + } + + private static boolean unionApply(@Nullable Union union) { + if (union == null || union.isDistinct()) { + return false; + } + return !(union.getInput(0) instanceof Sort) && !(union.getInput(1) instanceof Sort); + } + + private static boolean sortApply(Sort call) { + if (call != null) { + if (call.isDistinct() || + (call.getChildExps() == null)) { + return false; + } + } + return true; + } + + @Override + public void onMatch(RelOptRuleCall call) { + + + final Sort sort = call.rel(0); + if (!sortApply(sort)) { + return; + } + + final Union union = call.rel(1); + if (!unionApply(union)) { + return; + } + RelBuilder builder = call.builder(); + + builder.clear(); + if (!union.isDistinct()) { + ArrayList newNodes = new ArrayList<>(); + if (sort.offset == null && sort.fetch != null) { + for (RelNode input : union.getInputs()) { + Sort pushSort = sort.copy(sort.getTraitSet(), input, sort.getCollation(), null, sort.fetch); + newNodes.add(pushSort); + } + } else if (sort.offset != null && sort.fetch != null) { + for (RelNode input : union.getInputs()) { + if (sort.offset instanceof RexLiteral && sort.fetch instanceof RexLiteral) { + Comparable start = ((RexLiteral) sort.offset).getValue(); + Comparable end = ((RexLiteral) sort.fetch).getValue(); + if (start instanceof Number && end instanceof Number) { + Sort pushSort = sort.copy( + sort.getTraitSet(), + input, + sort.getCollation(), + builder.literal(0), + builder.literal( + BigDecimal.valueOf(((Number) start).longValue()) + .add( + BigDecimal.valueOf(((Number) end).longValue())) + ) + ); + newNodes.add(pushSort); + continue; + } + } + } + } + if (!newNodes.isEmpty()) { + builder.pushAll(newNodes); + RelNode build = builder.union(true, newNodes.size()).build(); + Sort copy = sort.copy(sort.getTraitSet(), build, sort.getCollation()); + call.transformTo(copy); + } + } + + } +} diff --git a/hbt/src/main/java/io/mycat/calcite/rules/PushDownLogicTable.java b/hbt/src/main/java/io/mycat/calcite/rules/PushDownLogicTableRule.java similarity index 72% rename from hbt/src/main/java/io/mycat/calcite/rules/PushDownLogicTable.java rename to hbt/src/main/java/io/mycat/calcite/rules/PushDownLogicTableRule.java index 37f37ff0e..ec1a68fb1 100644 --- a/hbt/src/main/java/io/mycat/calcite/rules/PushDownLogicTable.java +++ b/hbt/src/main/java/io/mycat/calcite/rules/PushDownLogicTableRule.java @@ -28,10 +28,16 @@ import org.apache.calcite.rel.logical.LogicalTableScan; import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.rex.RexNode; +import org.apache.calcite.schema.FilterableTable; +import org.apache.calcite.schema.ProjectableFilterableTable; +import org.apache.calcite.schema.ScannableTable; import org.apache.calcite.tools.RelBuilder; import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; /** * @author Junwen Chen @@ -41,27 +47,41 @@ SubstitutionVisitor 物化结合 MaterializedViewSubstitutionVisitor */ -public class PushDownLogicTable extends RelOptRule { - final HashSet context = new HashSet<>(); - - public PushDownLogicTable() { - super(operand(Bindables.BindableTableScan.class, any()), "proj on filter on proj"); +public class PushDownLogicTableRule extends RelOptRule { + public static PushDownLogicTableRule LogicalTable = new PushDownLogicTableRule(LogicalTableScan.class); + public static PushDownLogicTableRule ScannableTable = new PushDownLogicTableRule(ScannableTable.class); + public static PushDownLogicTableRule FilterableTable = new PushDownLogicTableRule(FilterableTable.class); + public static PushDownLogicTableRule ProjectableFilterableTable = new PushDownLogicTableRule(ProjectableFilterableTable.class); + public static PushDownLogicTableRule BindableTableScan = new PushDownLogicTableRule( Bindables.BindableTableScan.class); + + public PushDownLogicTableRule(Class c) { + super(operand(c, none()), "PushDownLogicTable"); } + public static boolean canHandle(RelOptTable table) { + return table.unwrap(ScannableTable.class) != null + || table.unwrap(FilterableTable.class) != null + || table.unwrap(ProjectableFilterableTable.class) != null; + } + /** * @param call todo result set with order,backend */ @Override public void onMatch(RelOptRuleCall call) { TableScan judgeObject = (TableScan) call.rels[0]; - RelNode value = toPhyTable(call.builder(), judgeObject); - if (value != null) { - call.transformTo(value); + if (canHandle(judgeObject.getTable())) { + RelNode value = toPhyTable(call.builder(), judgeObject); + if (value != null) { + call.transformTo(value); + } } + } public RelNode toPhyTable(RelBuilder builder, TableScan judgeObject) { + Bindables.BindableTableScan bindableTableScan; if (judgeObject instanceof Bindables.BindableTableScan) { bindableTableScan = (Bindables.BindableTableScan) judgeObject; @@ -91,7 +111,11 @@ public RelNode toPhyTable(RelBuilder builder, TableScan judgeObject) { } @NotNull - private RelNode global(RelOptCluster cluster, Bindables.BindableTableScan bindableTableScan, RelOptSchema relOptSchema, MycatLogicTable logicTable) { + private RelNode global(RelOptCluster cluster, + Bindables.BindableTableScan bindableTableScan, + RelOptSchema relOptSchema, + MycatLogicTable logicTable) { + final HashSet context = new HashSet<>(); RelNode logicalTableScan; MycatPhysicalTable mycatPhysicalTable = logicTable.getMycatGlobalPhysicalTable(context); RelOptTable dataNode = RelOptTableImpl.create( @@ -99,7 +123,7 @@ private RelNode global(RelOptCluster cluster, Bindables.BindableTableScan bindab logicTable.getRowType(cluster.getTypeFactory()),//这里使用logicTable,避免类型不一致 mycatPhysicalTable, ImmutableList.of(mycatPhysicalTable.getBackendTableInfo().getUniqueName())); - logicalTableScan = LogicalTableScan.create(cluster, dataNode); + logicalTableScan = LogicalTableScan.create(cluster, dataNode, ImmutableList.of()); return RelOptUtil.createProject(RelOptUtil.createFilter(logicalTableScan, bindableTableScan.filters), bindableTableScan.projects); } @@ -113,39 +137,11 @@ private RelNode shardingTable(RelBuilder builder, Bindables.BindableTableScan bi //////////////////////////////////////////////////////////////////////////////////////////////// - - TreeMap> bindTableGroupMapByTargetName = new TreeMap<>(Comparator.comparing(x -> x)); + builder.clear(); for (BackendTableInfo backendTableInfo : backendTableInfos) { - String targetName = backendTableInfo.getTargetName(); - List queryBackendTasksList = bindTableGroupMapByTargetName.computeIfAbsent(targetName, (s) -> new ArrayList<>()); - queryBackendTasksList.add(getBindableTableScan(bindableTableScan, cluster, relOptSchema, backendTableInfo)); - } - - TreeMap relNodeGroup = new TreeMap<>(Comparator.comparing(x -> x)); - context.addAll(relNodeGroup.keySet()); - for (Map.Entry> entry : bindTableGroupMapByTargetName.entrySet()) { - if (entry.getValue().isEmpty()) { - continue; - } - RelNode relNode = entry.getValue().stream().reduce((relNode1, relNode2) -> { - builder.clear(); - return builder.push(relNode1).push(relNode2).union(true).build(); - }).get(); - relNodeGroup.put(entry.getKey(), relNode); - } - - if (relNodeGroup.size() == 1) { - value = relNodeGroup.entrySet().iterator().next().getValue(); - } else { - if (relNodeGroup.size() < 1) { - throw new AssertionError(); - } - Optional reduce = relNodeGroup.values().stream().reduce((relNode1, relNode2) -> { - builder.clear(); - return builder.push(relNode1).push(relNode2).union(true).build(); - }); - value = reduce.get(); + builder.push(getBindableTableScan(bindableTableScan, cluster, relOptSchema, backendTableInfo)); } + value = builder.union(true, backendTableInfos.size()).build(); return value; } @@ -159,7 +155,7 @@ private static RelNode getBindableTableScan(Bindables.BindableTableScan bindable mycatPhysicalTable.getRowType(cluster.getTypeFactory()), mycatPhysicalTable, ImmutableList.of(uniqueName)); - RelNode logicalTableScan = LogicalTableScan.create(cluster, dataNode); + RelNode logicalTableScan = LogicalTableScan.create(cluster, dataNode, ImmutableList.of()); return RelOptUtil.createProject(RelOptUtil.createFilter(logicalTableScan, bindableTableScan.filters), bindableTableScan.projects); } } \ No newline at end of file diff --git a/hbt/src/main/java/io/mycat/calcite/rules/SortLimitPushRule.java b/hbt/src/main/java/io/mycat/calcite/rules/SortLimitPushRule.java new file mode 100644 index 000000000..090d01534 --- /dev/null +++ b/hbt/src/main/java/io/mycat/calcite/rules/SortLimitPushRule.java @@ -0,0 +1,76 @@ +package io.mycat.calcite.rules; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableList; +import org.apache.calcite.plan.RelOptRule; +import org.apache.calcite.plan.RelOptRuleCall; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.core.RelFactories; +import org.apache.calcite.rel.core.Sort; +import org.apache.calcite.rel.core.Union; +import org.apache.calcite.tools.RelBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * chenjunwen + *

+ */ +public class SortLimitPushRule extends RelOptRule { + private static final Logger LOGGER = LoggerFactory.getLogger(SortLimitPushRule.class); + boolean apply = false; + public SortLimitPushRule() { + super( + operandJ(Sort.class,null, (Predicate) call -> { + if (call!=null) { + if ( call.isDistinct() || + (call.getChildExps() == null || call.getChildExps().isEmpty())) { + return false; + } + } + return true; + }, + operand(Union.class, any())), + RelFactories.LOGICAL_BUILDER, "SortLimitPushRule"); + } + + @Override + public void onMatch(RelOptRuleCall call) { + if (apply){ + return; + } + List parents = call.getParents(); + + final Sort sort = call.rel(0); + if (parents != null || sort.isDistinct() || + (sort.getChildExps() == null || sort.getChildExps().isEmpty())) { + return; + } + RelBuilder builder = call.builder(); + builder.clear(); + final Union union = call.rel(1); + if (!union.isDistinct()) { + int size = union.getInputs().size(); + if (!union.getInputs().isEmpty()){ + RelNode input = union.getInput(0); + if(input instanceof Sort) { + return; + } + } + ArrayList newNodes = new ArrayList<>(2); + for (RelNode input : union.getInputs()) { + newNodes.add(sort.copy(sort.getTraitSet(), ImmutableList.of(input))); + } + if (!newNodes.isEmpty()) { + builder.pushAll(newNodes); + builder.union(true, newNodes.size()); + call.transformTo(sort.copy(sort.getTraitSet(), ImmutableList.of(builder.build()))); + apply = true; + } + } + + } +} diff --git a/hbt/src/main/java/io/mycat/calcite/rules/StreamUnionRule.java b/hbt/src/main/java/io/mycat/calcite/rules/StreamUnionRule.java new file mode 100644 index 000000000..e379401de --- /dev/null +++ b/hbt/src/main/java/io/mycat/calcite/rules/StreamUnionRule.java @@ -0,0 +1,102 @@ +/** + * Copyright (C) <2019> + *

+ * This program is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License along with this program. If + * not, see . + */ +package io.mycat.calcite.rules; + +import com.google.common.collect.ImmutableList; +import io.mycat.calcite.MycatCalciteSupport; +import io.mycat.calcite.table.MycatSQLTableScan; +import io.mycat.calcite.table.StreamUnionTable; +import org.apache.calcite.plan.RelOptRule; +import org.apache.calcite.plan.RelOptRuleCall; +import org.apache.calcite.plan.RelOptTable; +import org.apache.calcite.plan.hep.HepRelVertex; +import org.apache.calcite.prepare.RelOptTableImpl; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.core.Union; +import org.apache.calcite.rel.logical.LogicalTableScan; +import org.apache.calcite.tools.RelBuilder; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Junwen Chen + **/ +/* + + */ +public class StreamUnionRule extends RelOptRule { + public static final StreamUnionRule INSTANCE = new StreamUnionRule(); + + public StreamUnionRule() { + super(operandJ(Union.class, null, input -> input.getInputs().size() > 2, any()), "UnionRule"); + } + + + /** + * @param call todo result set with order,backend + */ + @Override + public void onMatch(RelOptRuleCall call) { + + Union union = (Union) call.rels[0]; + List inputs = union.getInputs(); + int i = 0; + for (RelNode relNode : inputs) { + HepRelVertex relNode1 = (HepRelVertex) relNode; + relNode = relNode1.getCurrentRel(); + RelOptTable table = relNode.getTable(); + if (table!=null){ + MycatSQLTableScan unwrap = table.unwrap(MycatSQLTableScan.class); + if (unwrap!=null){ + if(!unwrap.existsEnumerable()){ + i++; + } + } + } + } + + if (i == inputs.size()){ + List collect = new ArrayList<>(inputs.size()); + for (RelNode relNode : inputs) { + HepRelVertex relNode1 = (HepRelVertex) relNode; + relNode = relNode1.getCurrentRel(); + RelOptTable table = relNode.getTable(); + if (table!=null){ + collect.add(table.unwrap(MycatSQLTableScan.class)); + } + } + StreamUnionTable streamUnionTable = new StreamUnionTable(collect); + RelOptTable relOptTable = RelOptTableImpl.create( + null, + streamUnionTable.getRowType(MycatCalciteSupport.INSTANCE.TypeFactory), + streamUnionTable, + ImmutableList.of(collect.toString())); + call.transformTo(LogicalTableScan.create(union.getCluster(),relOptTable,ImmutableList.of())); + return; + } + + if (inputs.size() > 2) { + RelBuilder builder = call.builder(); + RelNode relNode = inputs.stream().reduce((relNode1, relNode2) -> { + builder.clear(); + builder.push(relNode1); + builder.push(relNode2); + return builder.union(!union.isDistinct()).build(); + }).get(); + call.transformTo(relNode); + } + } +} \ No newline at end of file diff --git a/hbt/src/main/java/io/mycat/calcite/table/MycatLogicTable.java b/hbt/src/main/java/io/mycat/calcite/table/MycatLogicTable.java index aee347bdc..27cba59ee 100644 --- a/hbt/src/main/java/io/mycat/calcite/table/MycatLogicTable.java +++ b/hbt/src/main/java/io/mycat/calcite/table/MycatLogicTable.java @@ -197,7 +197,7 @@ public Enumerable scan(DataContext root, List filters, int[] @Override public RelNode toRel(RelOptTable.ToRelContext context, RelOptTable relOptTable) { - return LogicalTableScan.create(context.getCluster(), relOptTable); + return LogicalTableScan.create(context.getCluster(), relOptTable,ImmutableList.of()); } public MycatPhysicalTable getMycatGlobalPhysicalTable(Set context) { diff --git a/hbt/src/main/java/io/mycat/calcite/table/MycatPhysicalTable.java b/hbt/src/main/java/io/mycat/calcite/table/MycatPhysicalTable.java index aa19170a4..6ee73a4b1 100644 --- a/hbt/src/main/java/io/mycat/calcite/table/MycatPhysicalTable.java +++ b/hbt/src/main/java/io/mycat/calcite/table/MycatPhysicalTable.java @@ -14,6 +14,7 @@ */ package io.mycat.calcite.table; +import com.google.common.collect.ImmutableList; import io.mycat.BackendTableInfo; import io.mycat.MycatConnection; import io.mycat.SchemaInfo; @@ -127,7 +128,7 @@ public String getTargetName() { @Override public RelNode toRel(RelOptTable.ToRelContext context, RelOptTable relOptTable) { - return LogicalTableScan.create(context.getCluster(), relOptTable); + return LogicalTableScan.create(context.getCluster(), relOptTable, ImmutableList.of()); } @Override diff --git a/hbt/src/main/java/io/mycat/calcite/table/MycatTransientSQLTableScan.java b/hbt/src/main/java/io/mycat/calcite/table/MycatTransientSQLTableScan.java index 62d38cc6c..37634d7c6 100644 --- a/hbt/src/main/java/io/mycat/calcite/table/MycatTransientSQLTableScan.java +++ b/hbt/src/main/java/io/mycat/calcite/table/MycatTransientSQLTableScan.java @@ -30,11 +30,12 @@ public MycatTransientSQLTableScan(RelOptCluster cluster, MycatConvention convent }), relOptTable); this.convention = convention; this.sql = sql; + this.digest = convention.toString(); } @Override public RelWriter explainTerms(RelWriter pw) { - return pw.item("sql", getSql()); + return pw.item("id",id).item("targetName",this.convention.targetName).item("sql", getSql()); } @Override @@ -51,4 +52,5 @@ public String getSql() { private MycatConvention getMycatConvention() { return (MycatConvention) getConvention(); } + } \ No newline at end of file diff --git a/hbt/src/main/java/io/mycat/calcite/table/StreamUnionTable.java b/hbt/src/main/java/io/mycat/calcite/table/StreamUnionTable.java new file mode 100644 index 000000000..a287b3f4b --- /dev/null +++ b/hbt/src/main/java/io/mycat/calcite/table/StreamUnionTable.java @@ -0,0 +1,36 @@ +package io.mycat.calcite.table; + +import io.mycat.calcite.MycatCalciteSupport; +import io.mycat.calcite.table.EnumerableTable; +import io.mycat.calcite.table.MycatSQLTableScan; +import org.apache.calcite.DataContext; +import org.apache.calcite.linq4j.Enumerable; +import org.apache.calcite.linq4j.Linq4j; +import org.apache.calcite.rel.type.RelDataType; +import org.apache.calcite.rel.type.RelDataTypeFactory; + +import java.util.List; +import java.util.stream.Collectors; + +public class StreamUnionTable extends EnumerableTable { + private final List enumerableTables; + + public StreamUnionTable(List enumerableTables) { + this.enumerableTables = enumerableTables; + } + + @Override + public RelDataType getRowType(RelDataTypeFactory typeFactory) { + return enumerableTables.get(0).getRowType(MycatCalciteSupport.INSTANCE.TypeFactory); + } + + @Override + public Enumerable scan(DataContext root) { + return Linq4j.concat(enumerableTables.stream().map(i->i.scan(root)).collect(Collectors.toList())); + } + + @Override + public boolean existsEnumerable() { + return true; + } +} \ No newline at end of file diff --git a/hbt/src/main/java/io/mycat/hbt/HBTQueryConvertor.java b/hbt/src/main/java/io/mycat/hbt/HBTQueryConvertor.java index 17c5d1f75..55b179279 100644 --- a/hbt/src/main/java/io/mycat/hbt/HBTQueryConvertor.java +++ b/hbt/src/main/java/io/mycat/hbt/HBTQueryConvertor.java @@ -18,14 +18,12 @@ import com.alibaba.fastsql.sql.ast.SQLStatement; import com.google.common.collect.ImmutableList; import io.mycat.beans.mycat.JdbcRowMetaData; -import io.mycat.beans.mycat.MycatRowMetaData; import io.mycat.calcite.MycatCalciteDataContext; import io.mycat.calcite.MycatCalciteSupport; import io.mycat.calcite.MycatRelBuilder; import io.mycat.calcite.prepare.MycatCalcitePlanner; -import io.mycat.calcite.rules.PushDownLogicTable; +import io.mycat.calcite.rules.PushDownLogicTableRule; import io.mycat.calcite.table.MycatLogicTable; -import io.mycat.calcite.table.MycatPhysicalTable; import io.mycat.datasource.jdbc.JdbcRuntime; import io.mycat.datasource.jdbc.datasource.JdbcDataSource; import io.mycat.hbt.ast.HBTOp; @@ -206,8 +204,7 @@ public RelNode filterFromTable(FilterFromTableSchema input) { Filter build = (Filter) relBuilder.build(); Bindables.BindableTableScan bindableTableScan = Bindables.BindableTableScan.create(build.getCluster(), table, build.getChildExps(), TableScan.identity(table)); relBuilder.clear(); - PushDownLogicTable pushDownLogicTable = new PushDownLogicTable(); - return pushDownLogicTable.toPhyTable(relBuilder, bindableTableScan); + return PushDownLogicTableRule.BindableTableScan.toPhyTable(relBuilder, bindableTableScan); } private RelNode fromRelToSqlSchema(FromRelToSqlSchema input) { @@ -443,8 +440,7 @@ private RelNode fromTable(FromTableSchema input) { //消除逻辑表,变成物理表 if (unwrap!= null){ - PushDownLogicTable pushDownLogicTable = new PushDownLogicTable(); - return pushDownLogicTable.toPhyTable(relBuilder,(TableScan)build); + return PushDownLogicTableRule.BindableTableScan.toPhyTable(relBuilder,(TableScan)build); } return build; diff --git a/hbt/src/main/java/io/mycat/metadata/LogicTable.java b/hbt/src/main/java/io/mycat/metadata/LogicTable.java index d450fdf53..dba8a9736 100644 --- a/hbt/src/main/java/io/mycat/metadata/LogicTable.java +++ b/hbt/src/main/java/io/mycat/metadata/LogicTable.java @@ -9,6 +9,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Supplier; @Getter @@ -35,7 +36,7 @@ public LogicTable(LogicTableType type, String schemaName, this.schemaName = schemaName; this.tableName = tableName; this.rawColumns = rawColumns; - this.createTableSQL = createTableSQL; + this.createTableSQL = Objects.requireNonNull(createTableSQL, this.uniqueName+" createTableSQL is not existed"); ///////////////////////////////////////// this.autoIncrementColumn = rawColumns.stream().filter(i -> i.isAutoIncrement()).findFirst().orElse(null); ///////////////////////////////////////// diff --git a/hbt/src/main/java/io/mycat/metadata/MetadataManager.java b/hbt/src/main/java/io/mycat/metadata/MetadataManager.java index b1511730d..3d7e3ac8b 100644 --- a/hbt/src/main/java/io/mycat/metadata/MetadataManager.java +++ b/hbt/src/main/java/io/mycat/metadata/MetadataManager.java @@ -65,7 +65,7 @@ public enum MetadataManager { private final Logger LOGGER = LoggerFactory.getLogger(MetadataManager.class); final ConcurrentHashMap schemaMap = new ConcurrentHashMap<>(); - private final SchemaRepository TABLE_REPOSITORY = new SchemaRepository(DbType.mysql); + public final SchemaRepository TABLE_REPOSITORY = new SchemaRepository(DbType.mysql); public void removeSchema(String schemaName) { schemaMap.remove(schemaName); diff --git a/hbt/src/main/java/io/mycat/upondb/MycatDBClientBasedConfig.java b/hbt/src/main/java/io/mycat/upondb/MycatDBClientBasedConfig.java index e93223fb9..dc3c1450e 100644 --- a/hbt/src/main/java/io/mycat/upondb/MycatDBClientBasedConfig.java +++ b/hbt/src/main/java/io/mycat/upondb/MycatDBClientBasedConfig.java @@ -14,8 +14,12 @@ public class MycatDBClientBasedConfig { final Map schemaMap; final Map reflectiveSchemas; + private boolean cache; - public MycatDBClientBasedConfig(Map schemaMap, Map reflectiveSchemas) { + public MycatDBClientBasedConfig(Map schemaMap, + Map reflectiveSchemas, + boolean cache) { + this.cache = cache; if (schemaMap == null) { schemaMap = Collections.emptyMap(); } @@ -32,4 +36,8 @@ public TableHandler getTable(String schema, String table) { TableHandler tableHandler = stringTableHandlerMap.logicTables().get(table); return Objects.requireNonNull(tableHandler, "table is not existed"); } + + public boolean isCache() { + return cache; + } } \ No newline at end of file diff --git a/hbt/src/main/java/io/mycat/upondb/MycatDBs.java b/hbt/src/main/java/io/mycat/upondb/MycatDBs.java index 896625cce..d435beaa1 100644 --- a/hbt/src/main/java/io/mycat/upondb/MycatDBs.java +++ b/hbt/src/main/java/io/mycat/upondb/MycatDBs.java @@ -1,5 +1,6 @@ package io.mycat.upondb; +import com.google.common.collect.ImmutableSet; import io.mycat.MycatConnection; import io.mycat.MycatDataContext; import io.mycat.MycatDataContextEnum; @@ -7,22 +8,32 @@ import io.mycat.beans.mycat.TransactionType; import io.mycat.beans.mysql.InformationSchemaRuntime; import io.mycat.beans.mysql.MySQLVariablesEnum; -import io.mycat.datasource.jdbc.datasource.DefaultConnection; import io.mycat.metadata.MetadataManager; import io.mycat.util.SQLContext; import io.mycat.util.SQLContextImpl; +import org.jetbrains.annotations.NotNull; import java.util.Collections; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; public class MycatDBs { + public final static Set VARIABLES_COLUMNNAME_SET = ImmutableSet + .of("autocommit", "net_write_timeout", "SQL_SELECT_LIMIT", "character_set_results", "read_only", "current_user"); + public static MycatDBClientMediator createClient(MycatDataContext dataContext) { - return new MycatDBClientMediator() { + return createClient(dataContext, new MycatDBClientBasedConfig(MetadataManager.INSTANCE.getSchemaMap() + ,Collections.singletonMap("information_schema", InformationSchemaRuntime.INSTANCE.get() + ),true)); + } + @NotNull + public static MycatDBClientMediator createClient(MycatDataContext dataContext, MycatDBClientBasedConfig config) { + return new MycatDBClientMediator() { @Override public void setVariable(String target, Object text) { String value = Objects.toString(text); @@ -49,19 +60,20 @@ public void setVariable(String target, Object text) { @Override public Object getVariable(String target) { + target = target.toLowerCase(); if (target.contains("autocommit")) { return this.isAutoCommit() ? 1 : 0; } else if (target.equalsIgnoreCase("xa")) { return dataContext.getTransactionSession().name(); } else if (target.contains("net_write_timeout")) { return dataContext.getVariable(MycatDataContextEnum.NET_WRITE_TIMEOUT); - } else if ("SQL_SELECT_LIMIT".equalsIgnoreCase(target)) { + } else if ("sql_select_limit".equalsIgnoreCase(target)) { return dataContext.getVariable(MycatDataContextEnum.SELECT_LIMIT); } else if ("character_set_results".equalsIgnoreCase(target)) { return dataContext.getVariable(MycatDataContextEnum.CHARSET_SET_RESULT); } else if (target.contains("read_only")) { return dataContext.getVariable(MycatDataContextEnum.IS_READ_ONLY); - }else if (target.contains("current_user")) { + } else if (target.contains("current_user")) { return dataContext.getUser().getUserName(); } Map map = RootHelper.INSTANCE.getConfigProvider().globalVariables(); @@ -82,10 +94,7 @@ public MycatDBSharedServer getUponDBSharedServer() { @Override public MycatDBClientBasedConfig config() { - MycatDBClientBasedConfig mycatDBClientBasedConfig = new MycatDBClientBasedConfig(MetadataManager.INSTANCE.getSchemaMap(), - Collections.singletonMap("information_schema", InformationSchemaRuntime.INSTANCE.get() - )); - return mycatDBClientBasedConfig; + return config; } @Override diff --git a/hbt/src/main/java/io/mycat/util/Response.java b/hbt/src/main/java/io/mycat/util/Response.java index 581c75322..e956961aa 100644 --- a/hbt/src/main/java/io/mycat/util/Response.java +++ b/hbt/src/main/java/io/mycat/util/Response.java @@ -48,7 +48,7 @@ default void proxySelect(String defaultTargetName, SQLSelectStatement statement) */ void sendExplain(Class defErrorCommandClass, Object map); - void sendResultSet(RowBaseIterator rowBaseIterator, Supplier> explainSupplier); + void sendResultSet(Supplier rowBaseIterator, Supplier> explainSupplier); void sendResponse(MycatResponse[] mycatResponses, Supplier> explainSupplier); diff --git a/hbt2/pom.xml b/hbt2/pom.xml new file mode 100644 index 000000000..1710b04cc --- /dev/null +++ b/hbt2/pom.xml @@ -0,0 +1,20 @@ + + + + parent + io.mycat + 1.07-SNAPSHOT + + 4.0.0 + + hbt2 + + + + io.mycat + mycat + + + \ No newline at end of file diff --git a/mycat2/src/main/java/io/mycat/DDLManager.java b/mycat2/src/main/java/io/mycat/DDLManager.java new file mode 100644 index 000000000..1324e54cb --- /dev/null +++ b/mycat2/src/main/java/io/mycat/DDLManager.java @@ -0,0 +1,40 @@ +package io.mycat; + +import io.mycat.beans.mysql.InformationSchema; +import io.mycat.beans.mysql.InformationSchemaRuntime; +import io.mycat.metadata.MetadataManager; +import io.mycat.metadata.TableHandler; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public enum DDLManager { + INSTANCE; + public void updateTables() { + List collect = MetadataManager.INSTANCE.getSchemaMap().values().stream().distinct() + .flatMap(i -> i.logicTables().values().stream()).distinct().collect(Collectors.toList()); + ArrayList objects = new ArrayList<>(); + for (TableHandler value : collect) { + String TABLE_CATALOG = "def"; + String TABLE_SCHEMA = value.getSchemaName(); + String TABLE_NAME = value.getTableName(); + String TABLE_TYPE = "BASE TABLE"; + String ENGINE = "InnoDB"; + Long VERSION = 10L; + String ROW_FORMAT = "DYNAMIC"; + InformationSchema.TABLES_TABLE_OBJECT tableObject = InformationSchema.TABLES_TABLE_OBJECT.builder() + .TABLE_CATALOG(TABLE_CATALOG) + .TABLE_SCHEMA(TABLE_SCHEMA) + .TABLE_NAME(TABLE_NAME) + .TABLE_TYPE(TABLE_TYPE) + .ENGINE(ENGINE) + .VERSION(VERSION) + .ROW_FORMAT(ROW_FORMAT) + .build(); + objects.add(tableObject); + } + InformationSchema.TABLES_TABLE_OBJECT[] tables_table_objects = objects.toArray(new InformationSchema.TABLES_TABLE_OBJECT[0]); + InformationSchemaRuntime.INSTANCE.update(informationSchema -> informationSchema.TABLES = tables_table_objects); + } +} \ No newline at end of file diff --git a/mycat2/src/main/java/io/mycat/ReceiverImpl.java b/mycat2/src/main/java/io/mycat/ReceiverImpl.java index 09c3ea8ef..7f9d32b21 100644 --- a/mycat2/src/main/java/io/mycat/ReceiverImpl.java +++ b/mycat2/src/main/java/io/mycat/ReceiverImpl.java @@ -88,7 +88,7 @@ public void evalSimpleSql(SQLStatement sql) { block(session -> { try (DefaultConnection connection = JdbcRuntime.INSTANCE.getConnection(target)) { try (RowBaseIterator rowBaseIterator = connection.executeQuery(sql.toString())) { - sendResultSet(rowBaseIterator, () -> { + sendResultSet(()->rowBaseIterator, () -> { throw new UnsupportedOperationException(); }); } @@ -182,9 +182,9 @@ public void sendExplain(Class defErrorCommandClass, Object map) { } @Override - public void sendResultSet(RowBaseIterator rowBaseIterator, Supplier> explainSupplier) { + public void sendResultSet(Supplier rowBaseIterator, Supplier> explainSupplier) { if (!this.explainMode) { - sendResponse(new MycatResponse[]{new TextResultSetResponse(rowBaseIterator)}, explainSupplier); + sendResponse(new MycatResponse[]{new TextResultSetResponse(rowBaseIterator.get())}, explainSupplier); } else { sendExplain(null, explainSupplier.get()); } diff --git a/mycat2/src/main/java/io/mycat/client/UserSpace.java b/mycat2/src/main/java/io/mycat/client/UserSpace.java index 58008dbeb..1f0c84bd4 100644 --- a/mycat2/src/main/java/io/mycat/client/UserSpace.java +++ b/mycat2/src/main/java/io/mycat/client/UserSpace.java @@ -174,6 +174,9 @@ public synchronized void cache(CacheConfig cacheConfig) { } cache = CacheLib.cache(() -> new TextResultSetResponse(query), finalText.replaceAll(" ", "_")); } finally { + if (query !=null){ + query.close(); + } if (cache2 != null) { cache2.close(); } diff --git a/mycat2/src/main/java/io/mycat/commands/DistributedQueryCommand.java b/mycat2/src/main/java/io/mycat/commands/DistributedQueryCommand.java index b3270e3a4..9849702e1 100644 --- a/mycat2/src/main/java/io/mycat/commands/DistributedQueryCommand.java +++ b/mycat2/src/main/java/io/mycat/commands/DistributedQueryCommand.java @@ -23,7 +23,7 @@ public boolean run(MycatRequest request, MycatDataContext context, Response resp MycatDBClientMediator client = MycatDBs.createClient(context); MycatSQLPrepareObject mycatSQLPrepareObject = client.getUponDBSharedServer().innerQueryPrepareObject(client.sqlContext().simplySql(sql), client); PlanRunner plan = mycatSQLPrepareObject.plan(Collections.emptyList()); - response.sendResultSet(plan.run(), () -> plan.explain()); + response.sendResultSet(()->plan.run(), () -> plan.explain()); return true; } diff --git a/mycat2/src/main/java/io/mycat/commands/ExplainPlanCommand.java b/mycat2/src/main/java/io/mycat/commands/ExplainPlanCommand.java index ca8d5a1c9..0e687caa8 100644 --- a/mycat2/src/main/java/io/mycat/commands/ExplainPlanCommand.java +++ b/mycat2/src/main/java/io/mycat/commands/ExplainPlanCommand.java @@ -14,7 +14,7 @@ public enum ExplainPlanCommand implements MycatCommand{ public boolean run(MycatRequest request, MycatDataContext context, Response response) { String text = request.getText(); MycatDBClientMediator client = MycatDBs.createClient(context); - response.sendResultSet(client.executeRel(text), () -> client.explainRel(text)); + response.sendResultSet(()->client.executeRel(text), () -> client.explainRel(text)); return true; } diff --git a/mycat2/src/main/java/io/mycat/commands/MycatdbCommand.java b/mycat2/src/main/java/io/mycat/commands/MycatdbCommand.java index d1b46e48d..9740df0fe 100644 --- a/mycat2/src/main/java/io/mycat/commands/MycatdbCommand.java +++ b/mycat2/src/main/java/io/mycat/commands/MycatdbCommand.java @@ -89,7 +89,6 @@ public enum MycatdbCommand implements MycatCommand { sqlHandlers.add(new ShowCreateFunctionHanlder()); //Analyze - sqlHandlers.add(new ShowCreateFunctionHanlder()); sqlHandlers.add(new AnalyzeHanlder()); } @@ -117,7 +116,7 @@ public boolean explain(MycatRequest request, MycatDataContext context, Response try { final String finalSql = request.getText().trim(); if (finalSql.startsWith("execute ")) { - response.sendResultSet(client.executeRel(finalSql), () -> client.explainRel(finalSql)); + response.sendResultSet(()->client.executeRel(finalSql), () -> client.explainRel(finalSql)); isRun = true; } } catch (Throwable e1) { @@ -177,7 +176,7 @@ private void executeQuery(MycatRequest req, MycatDataContext dataContext, Respon String pre = "execute plan "; if (trim.toLowerCase().startsWith(pre)) { final String finalSql = trim.substring(pre.length()); - receiver.sendResultSet(db.executeRel(finalSql), () -> db.explainRel(finalSql)); + receiver.sendResultSet(()->db.executeRel(finalSql), () -> db.explainRel(finalSql)); isRun = true; } } catch (Throwable e1) { diff --git a/mycat2/src/main/java/io/mycat/commands/SelectAutocommitCommand.java b/mycat2/src/main/java/io/mycat/commands/SelectAutocommitCommand.java index 1ded9bf16..e239a6991 100644 --- a/mycat2/src/main/java/io/mycat/commands/SelectAutocommitCommand.java +++ b/mycat2/src/main/java/io/mycat/commands/SelectAutocommitCommand.java @@ -22,7 +22,7 @@ public boolean run(MycatRequest request, MycatDataContext context, Response resp resultSetBuilder.addColumnInfo(columnName, JDBCType.BIGINT); resultSetBuilder.addObjectRowPayload(isAutocommit); RowBaseIterator rowBaseIterator = resultSetBuilder.build(); - response.sendResultSet(rowBaseIterator, () -> Arrays.asList(columnName+":"+ (context.isAutocommit() ? 1 :0))); + response.sendResultSet(()->rowBaseIterator, () -> Arrays.asList(columnName+":"+ (context.isAutocommit() ? 1 :0))); return true; } diff --git a/mycat2/src/main/java/io/mycat/commands/SelectLastInsertIdCommand.java b/mycat2/src/main/java/io/mycat/commands/SelectLastInsertIdCommand.java index d968d58ac..a7a954a6c 100644 --- a/mycat2/src/main/java/io/mycat/commands/SelectLastInsertIdCommand.java +++ b/mycat2/src/main/java/io/mycat/commands/SelectLastInsertIdCommand.java @@ -22,7 +22,7 @@ public boolean run(MycatRequest request, MycatDataContext context, Response resp resultSetBuilder.addColumnInfo(columnName, JDBCType.BIGINT); resultSetBuilder.addObjectRowPayload(lastInsertId); RowBaseIterator rowBaseIterator = resultSetBuilder.build(); - response.sendResultSet(rowBaseIterator, ()->Arrays.asList(""+columnName+":"+context.getLastInsertId()+"")); + response.sendResultSet(()->rowBaseIterator, ()->Arrays.asList(""+columnName+":"+context.getLastInsertId()+"")); return true; } diff --git a/mycat2/src/main/java/io/mycat/commands/SelectTransactionReadOnlyCommand.java b/mycat2/src/main/java/io/mycat/commands/SelectTransactionReadOnlyCommand.java index 66115e44a..e52e323fc 100644 --- a/mycat2/src/main/java/io/mycat/commands/SelectTransactionReadOnlyCommand.java +++ b/mycat2/src/main/java/io/mycat/commands/SelectTransactionReadOnlyCommand.java @@ -23,7 +23,7 @@ public boolean run(MycatRequest request, MycatDataContext context, Response resp resultSetBuilder.addColumnInfo(columnName, JDBCType.BIGINT); resultSetBuilder.addObjectRowPayload(isReadOnly); RowBaseIterator rowBaseIterator = resultSetBuilder.build(); - response.sendResultSet(rowBaseIterator, new Supplier>() { + response.sendResultSet(()->rowBaseIterator, new Supplier>() { @Override public List get() { return Arrays.asList(""+columnName+":"+(context.isReadOnly()?1:0)); diff --git a/mycat2/src/main/java/io/mycat/route/GlobalRouter.java b/mycat2/src/main/java/io/mycat/route/GlobalRouter.java index e9e108f91..01f135bed 100644 --- a/mycat2/src/main/java/io/mycat/route/GlobalRouter.java +++ b/mycat2/src/main/java/io/mycat/route/GlobalRouter.java @@ -11,7 +11,7 @@ public class GlobalRouter implements SqlRouteChain { @Override public boolean handle(ParseContext parseContext) { - List leftTables = parseContext.getLeftTables(); + List leftTables = parseContext.startAndGetLeftTables(); List> set = new ArrayList<>(); HashMap> mapping = new HashMap<>(); for (SQLExprTableSource leftTable : leftTables) { diff --git a/mycat2/src/main/java/io/mycat/route/HBTBuilder.java b/mycat2/src/main/java/io/mycat/route/HBTBuilder.java index 3c6aa5ff6..1cd54ab17 100644 --- a/mycat2/src/main/java/io/mycat/route/HBTBuilder.java +++ b/mycat2/src/main/java/io/mycat/route/HBTBuilder.java @@ -1,20 +1,26 @@ package io.mycat.route; +import io.mycat.hbt.ast.HBTOp; import io.mycat.hbt.ast.base.OrderItem; import io.mycat.hbt.ast.base.Schema; import io.mycat.hbt.ast.query.FromSqlSchema; +import io.mycat.hbt.ast.query.SetOpSchema; +import org.checkerframework.checker.units.qual.A; +import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedList; import java.util.List; public class HBTBuilder { - Schema schema; + LinkedList stack; + public static HBTBuilder create() { return new HBTBuilder(); } - public HBTBuilder from(String targetName, String sql) { - schema = new FromSqlSchema(Collections.emptyList(),targetName,sql); + public HBTBuilder from(String targetName, String sql) { + stack.push(new FromSqlSchema(Collections.emptyList(), targetName, sql)); return this; } @@ -22,7 +28,12 @@ public HBTBuilder distinct() { return null; } - public HBTBuilder union(boolean b) { + public HBTBuilder unionMore(boolean all) { + ArrayList arrayList = new ArrayList<>(); + while (stack.isEmpty()){ + arrayList.add(stack.pop()); + } +// stack.push(new SetOpSchema(all?HBTOp.UNION_ALL,)); return null; } @@ -35,6 +46,6 @@ public HBTBuilder limit(List concertOrder) { } public Schema build() { - return schema; + return stack.pop(); } } \ No newline at end of file diff --git a/mycat2/src/main/java/io/mycat/route/NoTablesRouter.java b/mycat2/src/main/java/io/mycat/route/NoTablesRouter.java index 17d60e2cd..8b99a670e 100644 --- a/mycat2/src/main/java/io/mycat/route/NoTablesRouter.java +++ b/mycat2/src/main/java/io/mycat/route/NoTablesRouter.java @@ -3,7 +3,7 @@ public class NoTablesRouter implements SqlRouteChain { @Override public boolean handle(ParseContext t) { - if (t.getLeftTables().isEmpty()) { + if (t.startAndGetLeftTables().isEmpty()) { t.plan(HBTBuilder.create() .from(t.getDefaultTarget(), t.getSqlStatement().toString()).build()); diff --git a/mycat2/src/main/java/io/mycat/route/ParseContext.java b/mycat2/src/main/java/io/mycat/route/ParseContext.java index fcdb2632d..21168f449 100644 --- a/mycat2/src/main/java/io/mycat/route/ParseContext.java +++ b/mycat2/src/main/java/io/mycat/route/ParseContext.java @@ -3,27 +3,34 @@ import com.alibaba.fastsql.sql.ast.SQLExpr; import com.alibaba.fastsql.sql.ast.SQLName; import com.alibaba.fastsql.sql.ast.SQLStatement; -import com.alibaba.fastsql.sql.ast.statement.SQLExprTableSource; +import com.alibaba.fastsql.sql.ast.expr.SQLAggregateExpr; +import com.alibaba.fastsql.sql.ast.statement.*; +import com.alibaba.fastsql.sql.dialect.mysql.ast.statement.DrdsRecoverDDLJob; +import com.alibaba.fastsql.sql.dialect.mysql.ast.statement.DrdsRemoveDDLJob; +import com.alibaba.fastsql.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; import com.alibaba.fastsql.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter; import io.mycat.DataNode; import io.mycat.hbt.ast.base.Schema; import io.mycat.replica.ReplicaSelectorRuntime; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; -import java.util.Set; public class ParseContext implements ParseHelper { + private String defaultSchema; final SQLStatement sqlStatement; List leftTables; Schema plan; - - public ParseContext(SQLStatement sqlStatement) { + List aggregateExprs = new LinkedList<>(); + List complexTableSources = new LinkedList<>(); + public ParseContext(String defaultSchema,SQLStatement sqlStatement) { + this.defaultSchema = defaultSchema; this.sqlStatement = sqlStatement; } - public static ParseContext of(SQLStatement sqlStatement) { - return new ParseContext(sqlStatement); + public static ParseContext of(String defaultSchema,SQLStatement sqlStatement) { + return new ParseContext(defaultSchema,sqlStatement); } @@ -31,20 +38,55 @@ public SQLStatement getSqlStatement() { return sqlStatement; } - public List getLeftTables() { + public MySqlSelectQueryBlock tryGetQueryBlock() { + return unWapperToQueryBlock(getSqlStatement()); + } + + public List startAndGetLeftTables() { if (leftTables == null) { SQLStatement sqlStatement = getSqlStatement(); leftTables = new ArrayList<>(); + aggregateExprs = new ArrayList<>(); sqlStatement.accept(new MySqlASTVisitorAdapter() { + + + @Override + public boolean visit(SQLAggregateExpr x) { + aggregateExprs.add(x); + return super.visit(x); + } + + @Override + public boolean visit(SQLJoinTableSource x) { + complexTableSources.add(x); + return true; + } + + @Override + public boolean visit(SQLSubqueryTableSource x) { + complexTableSources.add(x); + return true; + } + @Override + public boolean visit(SQLUnionQueryTableSource x) { + complexTableSources.add(x); + return true; + } + + @Override + public boolean visit(SQLValuesTableSource x) { + complexTableSources.add(x); + return true; + } + + + @Override - public boolean visit(SQLExprTableSource x) { - if (x.getExpr() instanceof SQLName) {//必须是名字 - leftTables.add(x); - return true; - } else { - return super.visit(x); - } + public boolean visit(SQLUnnestTableSource x) { + complexTableSources.add(x); + return true; } + }); } return leftTables; @@ -55,33 +97,29 @@ public String getDefaultTarget() { } - - - - public SharingTableInfo getSharingTableInfo(String schemaName, String tableName){ + public SharingTableInfo getSharingTableInfo(String schemaName, String tableName) { return null; } - - public SharingTableInfo getSharingTableInfo(SQLExprTableSource sqlExprTableSource){ + public SharingTableInfo getSharingTableInfo(SQLExprTableSource sqlExprTableSource) { return null; } - public boolean isNoAgg(){ - return false; + public boolean isNoAgg() { + return aggregateExprs.isEmpty(); } - public boolean isNoWhere(){ + public boolean isNoWhere() { return false; } - public boolean isNoSubQuery(){ + public boolean isNoSubQuery() { return false; } - public List computeWhere(SQLExpr where){ + public List computeWhere(SQLExpr where) { return null; } @@ -97,4 +135,16 @@ public void plan(Schema build) { public Schema getPlan() { return plan; } + + public boolean isNoComplexDatasource() { + return complexTableSources.isEmpty(); + } + + public String getDefaultSchema() { + return defaultSchema; + } + + public boolean isNoOrder() { + return false; + } } \ No newline at end of file diff --git a/mycat2/src/main/java/io/mycat/route/SharingRouter.java b/mycat2/src/main/java/io/mycat/route/SharingRouter.java index 0ecaab487..ca5dbf373 100644 --- a/mycat2/src/main/java/io/mycat/route/SharingRouter.java +++ b/mycat2/src/main/java/io/mycat/route/SharingRouter.java @@ -17,7 +17,7 @@ public class SharingRouter implements SqlRouteChain { @Override public boolean handle(ParseContext parseContext) { - List leftTables = parseContext.getLeftTables(); + List leftTables = parseContext.startAndGetLeftTables(); if (leftTables.size() == 1) {//means no join SQLExprTableSource singleDataSource = leftTables.get(0); SharingTableInfo sharingTableInfo = parseContext.getSharingTableInfo(singleDataSource); @@ -52,7 +52,7 @@ public boolean handle(ParseContext parseContext) { source.from(targetName, sql); } - source = source.union(!queryBlock.isDistinct()); + source = source.unionMore(!queryBlock.isDistinct()); SQLOrderBy orderBy = queryBlock.getOrderBy(); diff --git a/mycat2/src/main/java/io/mycat/route/SimpleShardingRouter.java b/mycat2/src/main/java/io/mycat/route/SimpleShardingRouter.java new file mode 100644 index 000000000..2148798be --- /dev/null +++ b/mycat2/src/main/java/io/mycat/route/SimpleShardingRouter.java @@ -0,0 +1,48 @@ +package io.mycat.route; + +import com.alibaba.fastsql.sql.ast.SQLStatement; +import com.alibaba.fastsql.sql.ast.statement.SQLExprTableSource; +import com.alibaba.fastsql.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; +import io.mycat.hbt.ast.base.Schema; +import io.mycat.metadata.MetadataManager; +import io.mycat.metadata.ShardingTable; +import io.mycat.metadata.TableHandler; + +import java.util.List; +import java.util.Map; + +public class SimpleShardingRouter implements SqlRouteChain { + @Override + public boolean handle(ParseContext parseContext) { + List leftTables = parseContext.startAndGetLeftTables(); + if (leftTables == null || leftTables.isEmpty() || parseContext.isNoAgg() || parseContext.isNoComplexDatasource() || parseContext.isNoSubQuery() || parseContext.isNoOrder()) { + return false; + } + if (leftTables.size() == 1) { + SQLExprTableSource tableSource = leftTables.get(0); + MySqlSelectQueryBlock queryBlock = parseContext.tryGetQueryBlock(); + boolean distinct = queryBlock.isDistinct(); + TableHandler table = MetadataManager.INSTANCE.getTable(tableSource.getSchema(), tableSource.getTableName()); + if (table instanceof ShardingTable) { + SQLStatement sqlStatement = parseContext.getSqlStatement(); + Map> stringListMap = MetadataManager.INSTANCE.rewriteSQL(parseContext.getDefaultSchema(), sqlStatement.toString()); + int size = stringListMap.size(); + if (size == 0) { + return false; + } else { + HBTBuilder hbtBuilder = HBTBuilder.create(); + Map.Entry> next = stringListMap.entrySet().iterator().next(); + String key = next.getKey(); + List values = next.getValue(); + for (String value : values) { + hbtBuilder.from(key, value); + } + HBTBuilder union = hbtBuilder.unionMore(!distinct); + Schema build = hbtBuilder.build(); + } + } + } + + return false; + } +} \ No newline at end of file diff --git a/mycat2/src/main/java/io/mycat/route/SqlRouteChains.java b/mycat2/src/main/java/io/mycat/route/SqlRouteChains.java index 909e3e907..1c445ff7b 100644 --- a/mycat2/src/main/java/io/mycat/route/SqlRouteChains.java +++ b/mycat2/src/main/java/io/mycat/route/SqlRouteChains.java @@ -4,7 +4,11 @@ public enum SqlRouteChains { INSTANCE; - final SqlRouteChain[] sqlRouteChains = ImmutableList.builder().add(new NoTablesRouter(), new GlobalRouter()).build().toArray(new SqlRouteChain[0]); + final SqlRouteChain[] sqlRouteChains = ImmutableList.builder().add( + new NoTablesRouter(), + new SimpleShardingRouter(), + new GlobalRouter() + ).build().toArray(new SqlRouteChain[0]); public boolean execute(ParseContext context) { for (int i = 0; i < sqlRouteChains.length; i++) { diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/dcl/KillSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/dcl/KillSQLHandler.java index 1effabd77..7dba690c1 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/dcl/KillSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/dcl/KillSQLHandler.java @@ -14,6 +14,7 @@ public class KillSQLHandler extends AbstractSQLHandler { @Override protected ExecuteCode onExecute(SQLRequest request, MycatDataContext dataContext, Response response) { + response.sendOk(); return ExecuteCode.PERFORMED; } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/AlterDatabaseSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/AlterDatabaseSQLHandler.java index e0e975385..a4519e72a 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/AlterDatabaseSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/AlterDatabaseSQLHandler.java @@ -14,7 +14,7 @@ public class AlterDatabaseSQLHandler extends AbstractSQLHandler request, MycatDataContext dataContext, Response response) { - response.proxyDDL(request.getAst()); + response.sendOk(); return ExecuteCode.PERFORMED; } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/AlterTableSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/AlterTableSQLHandler.java index e1a520e5f..a667a26d0 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/AlterTableSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/AlterTableSQLHandler.java @@ -14,7 +14,7 @@ public class AlterTableSQLHandler extends AbstractSQLHandler request, MycatDataContext dataContext, Response response) { - response.proxyDDL(request.getAst()); + response.sendOk(); return ExecuteCode.PERFORMED; } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateDatabaseSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateDatabaseSQLHandler.java index f8a850ce4..a87db1ccc 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateDatabaseSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateDatabaseSQLHandler.java @@ -15,7 +15,7 @@ public class CreateDatabaseSQLHandler extends AbstractSQLHandler request, MycatDataContext dataContext, Response response) { - response.proxyDDL(request.getAst()); + response.sendOk(); return ExecuteCode.PERFORMED; } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateIndexSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateIndexSQLHandler.java index 9ee285f9a..3f045f828 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateIndexSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateIndexSQLHandler.java @@ -14,7 +14,7 @@ public class CreateIndexSQLHandler extends AbstractSQLHandler request, MycatDataContext dataContext, Response response) { - response.proxyDDL(request.getAst()); + response.sendOk(); return ExecuteCode.PERFORMED; } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateTableSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateTableSQLHandler.java index 195b11fc8..e18ef2ed0 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateTableSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateTableSQLHandler.java @@ -1,20 +1,176 @@ package io.mycat.sqlHandler.ddl; +import com.alibaba.fastsql.sql.SQLUtils; import com.alibaba.fastsql.sql.ast.statement.SQLCreateTableStatement; +import io.mycat.BackendTableInfo; import io.mycat.MycatDataContext; +import io.mycat.MycatException; +import io.mycat.SchemaInfo; +import io.mycat.datasource.jdbc.JdbcRuntime; +import io.mycat.datasource.jdbc.datasource.DefaultConnection; +import io.mycat.metadata.GlobalTableHandler; +import io.mycat.metadata.MetadataManager; +import io.mycat.metadata.ShardingTableHandler; +import io.mycat.metadata.TableHandler; +import io.mycat.replica.ReplicaDataSourceSelector; +import io.mycat.replica.ReplicaSelectorRuntime; import io.mycat.sqlHandler.AbstractSQLHandler; import io.mycat.sqlHandler.ExecuteCode; import io.mycat.sqlHandler.SQLRequest; import io.mycat.util.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.Resource; +import java.text.MessageFormat; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +/** + * chenjunwnen + * + * 实现创建表 + */ @Resource public class CreateTableSQLHandler extends AbstractSQLHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(CreateTableSQLHandler.class); @Override protected ExecuteCode onExecute(SQLRequest request, MycatDataContext dataContext, Response response) { - response.proxyDDL(request.getAst()); - return ExecuteCode.PERFORMED; + SQLCreateTableStatement ast = request.getAst(); + + List throwables = new ArrayList<>(); + try { + String schemaName = ast.getSchema() == null ? dataContext.getDefaultSchema() : SQLUtils.normalize(ast.getSchema()); + String tableName = ast.getTableName(); + if (tableName == null) { + response.sendError(new MycatException("CreateTableSQL need tableName")); + return ExecuteCode.PERFORMED; + } + tableName = SQLUtils.normalize(tableName); + TableHandler tableHandler = MetadataManager.INSTANCE.getTable(schemaName, tableName); + if (tableHandler == null) { + response.sendError(new MycatException(schemaName + "." + tableName + " is not existed")); + return ExecuteCode.PERFORMED; + } + Map> sqlAndDatasoureMap = new HashMap<>(); + List databaseCollections= new ArrayList<>(); + if (tableHandler instanceof ShardingTableHandler) { + ShardingTableHandler handler = (ShardingTableHandler) tableHandler; + for (BackendTableInfo shardingBackend : handler.getShardingBackends()) { + makeTask(ast, sqlAndDatasoureMap, shardingBackend); + } + databaseCollections.addAll(handler.getShardingBackends()); + } else if (tableHandler instanceof GlobalTableHandler) { + GlobalTableHandler handler = (GlobalTableHandler) tableHandler; + for (BackendTableInfo shardingBackend : handler.getDataNodeMap().values()) { + makeTask(ast, sqlAndDatasoureMap, shardingBackend); + } + databaseCollections.addAll(handler.getDataNodeMap().values()); + } else { + throw new UnsupportedOperationException("UnsupportedOperation :" + tableHandler); + } + List dataSources = sqlAndDatasoureMap.values().stream().flatMap(i->i.stream()).distinct().collect(Collectors.toList()); + + //建立物理数据中与逻辑库逻辑表同名物理库 + SchemaInfo schemaInfo = new SchemaInfo(tableHandler.getSchemaName(),tableHandler.getTableName()); + dataSources.forEach(i->{ + BackendTableInfo backendTableInfo = new BackendTableInfo(i, schemaInfo); + makeTask(ast, sqlAndDatasoureMap, backendTableInfo); + }); + + //创建库 + createDatabase(throwables, databaseCollections); + createTable(throwables, sqlAndDatasoureMap); + + if (throwables.isEmpty()) { + response.sendOk(); + return ExecuteCode.PERFORMED; + } else { + response.sendError(new MycatException(throwables.toString())); + return ExecuteCode.PERFORMED; + } + } catch (Throwable throwable) { + response.sendError(throwable); + return ExecuteCode.PERFORMED; + } + } + + private void createTable(List throwables, Map> sqlAndDatasoureMap) throws InterruptedException, java.util.concurrent.ExecutionException, java.util.concurrent.TimeoutException { + List resList = new ArrayList<>(); + + sqlAndDatasoureMap.forEach((sql, dataSources) -> { + for (String dataSource : dataSources) { + resList.add(CompletableFuture.runAsync(() -> { + try (DefaultConnection connection = JdbcRuntime.INSTANCE.getConnection(dataSource)) { + connection.executeUpdate(sql, false, 0); + } + }, JdbcRuntime.INSTANCE.getFetchDataExecutorService())); + } + }); + + CompletableFuture.allOf(resList.toArray(new CompletableFuture[0])) + .exceptionally(throwable -> { + LOGGER.error("执行SQL失败", throwable); + throwables.add(throwable); + return null; + }) + .get(5, TimeUnit.MINUTES); + } + + private void createDatabase(List throwables, List databaseCollections) throws InterruptedException, java.util.concurrent.ExecutionException, java.util.concurrent.TimeoutException { + List resList = new ArrayList<>(); + for (BackendTableInfo databaseCollection : databaseCollections) { + for (String dataSource : getDatasource(databaseCollection.getTargetName())) { + resList.add(CompletableFuture.runAsync(() -> { + try (DefaultConnection connection = JdbcRuntime.INSTANCE.getConnection(dataSource)) { + connection.executeUpdate(MessageFormat.format("create database if not exists {0} ", + dataSource), false, 0); + } + }, JdbcRuntime.INSTANCE.getFetchDataExecutorService())); + } + } + + CompletableFuture.allOf(resList.toArray(new CompletableFuture[0])) + .exceptionally(throwable -> { + LOGGER.error("执行SQL失败", throwable); + throwables.add(throwable); + return null; + }) + .get(5, TimeUnit.MINUTES); + } + + + private void makeTask(SQLCreateTableStatement ast, Map> sqlAndDatasoureMap, BackendTableInfo shardingBackend) { + String targetName = shardingBackend.getTargetName(); + SchemaInfo schemaInfo = shardingBackend.getSchemaInfo(); + SQLCreateTableStatement entry = ast.clone(); + entry.setIfNotExiists(true); + entry.setTableName(schemaInfo.getTargetTable());//设置库名 表名顺序不能乱 + entry.setSchema(schemaInfo.getTargetSchema()); + if (!schemaInfo.getTargetTable().equals(entry.getTableName())) { + throw new AssertionError(); + } + if (!schemaInfo.getTargetSchema().equals(entry.getSchema())) { + throw new AssertionError(); + } + + String sql = entry.toString(); + Set set = sqlAndDatasoureMap.computeIfAbsent(sql, s -> new HashSet<>()); + set.addAll(getDatasource(targetName)); + } + + private static Set getDatasource(String targetName) { + Set dataSources = new HashSet<>(); + if (ReplicaSelectorRuntime.INSTANCE.isReplicaName(targetName)) { + ReplicaDataSourceSelector dataSourceSelector = ReplicaSelectorRuntime.INSTANCE.getDataSourceSelector(targetName); + dataSources.addAll(dataSourceSelector.getRwaDataSourceMap().keySet()); + } + if (ReplicaSelectorRuntime.INSTANCE.isDatasource(targetName)) { + dataSources.add(targetName); + } + return dataSources; } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateViewSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateViewSQLHandler.java index 25c75af3d..6d2214212 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateViewSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/CreateViewSQLHandler.java @@ -14,7 +14,7 @@ public class CreateViewSQLHandler extends AbstractSQLHandler request, MycatDataContext dataContext, Response response) { - response.proxyDDL(request.getAst()); + response.sendOk(); return ExecuteCode.PERFORMED; } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/DropDatabaseSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/DropDatabaseSQLHandler.java index 42264c76f..94dcf5a01 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/DropDatabaseSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/DropDatabaseSQLHandler.java @@ -14,7 +14,7 @@ public class DropDatabaseSQLHandler extends AbstractSQLHandler request, MycatDataContext dataContext, Response response) { - response.proxyDDL(request.getAst()); + response.sendOk(); return ExecuteCode.PERFORMED; } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/DropTableSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/DropTableSQLHandler.java index f22980c71..bcf1bb42b 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/DropTableSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/DropTableSQLHandler.java @@ -14,7 +14,7 @@ public class DropTableSQLHandler extends AbstractSQLHandler request, MycatDataContext dataContext, Response response) { - response.proxyDDL(request.getAst()); + response.sendOk(); return ExecuteCode.PERFORMED; } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/DropViewSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/DropViewSQLHandler.java index 32b95b87c..765f49899 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/DropViewSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/DropViewSQLHandler.java @@ -14,7 +14,7 @@ public class DropViewSQLHandler extends AbstractSQLHandler @Override protected ExecuteCode onExecute(SQLRequest request, MycatDataContext dataContext, Response response) { - response.proxyDDL(request.getAst()); + response.sendOk(); return ExecuteCode.PERFORMED; } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/RenameTableSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/RenameTableSQLHandler.java index 4fe9e327f..329914af5 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/ddl/RenameTableSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/ddl/RenameTableSQLHandler.java @@ -14,7 +14,7 @@ public class RenameTableSQLHandler extends AbstractSQLHandler request, MycatDataContext dataContext, Response response) { - response.proxyDDL(request.getAst()); + response.sendOk(); return ExecuteCode.PERFORMED; } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/dml/SetSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/dml/SetSQLHandler.java index c2d1a0c05..7a5694fef 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/dml/SetSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/dml/SetSQLHandler.java @@ -6,6 +6,7 @@ import io.mycat.sqlHandler.AbstractSQLHandler; import io.mycat.sqlHandler.ExecuteCode; import io.mycat.sqlHandler.SQLRequest; +import io.mycat.upondb.MycatDBClientMediator; import io.mycat.upondb.MycatDBs; import io.mycat.util.Response; @@ -23,10 +24,11 @@ protected ExecuteCode onExecute(SQLRequest request, MycatDataCo if (items == null) { items = Collections.emptyList(); } + MycatDBClientMediator client = MycatDBs.createClient(dataContext); for (SQLAssignItem item : items) { String name = Objects.toString(item.getTarget()).toLowerCase(); String value = Objects.toString(item.getValue()); - MycatDBs.createClient(dataContext).setVariable(name, value); + client.setVariable(name, value); } response.sendOk(); return ExecuteCode.PERFORMED; diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/dql/AnalyzeHanlder.java b/mycat2/src/main/java/io/mycat/sqlHandler/dql/AnalyzeHanlder.java index 36c659148..1b13ad84e 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/dql/AnalyzeHanlder.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/dql/AnalyzeHanlder.java @@ -54,7 +54,7 @@ protected ExecuteCode onExecute(SQLRequest request, Mycat } StatisticCenter.INSTANCE.computeTableRowCount(tableHandler); } - response.sendResultSet(resultSetBuilder.build(),null); + response.sendResultSet(()->resultSetBuilder.build(),()->{throw new UnsupportedOperationException();}); return ExecuteCode.PERFORMED; } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/dql/SelectSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/dql/SelectSQLHandler.java index 974f5a264..5925e9673 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/dql/SelectSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/dql/SelectSQLHandler.java @@ -113,7 +113,7 @@ protected ExecuteCode onSelectDual(SQLSelectQueryBlock sqlSelectQueryBlock, payloadList.add(payload); } resultSetBuilder.addObjectRowPayload(payloadList); - receiver.sendResultSet(resultSetBuilder.build(), Collections::emptyList); + receiver.sendResultSet(()->resultSetBuilder.build(), Collections::emptyList); return ExecuteCode.PERFORMED; } @@ -201,7 +201,7 @@ protected ExecuteCode onSelectTable(MycatDataContext dataContext, SQLTableSource } HBTRunners hbtRunners = new HBTRunners(mycatDBContext); RowBaseIterator run = hbtRunners.run(plan); - receiver.sendResultSet(run, null); + receiver.sendResultSet(()->run, null); return ExecuteCode.PERFORMED; } dataContext.block(() -> { @@ -221,7 +221,7 @@ protected ExecuteCode onSelectTable(MycatDataContext dataContext, SQLTableSource return; } } - receiver.sendResultSet(plan.run(), plan::explain); + receiver.sendResultSet(()->plan.run(), plan::explain); }); return ExecuteCode.PERFORMED; diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowColumnsSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowColumnsSQLHandler.java index 77c2e90e6..199c77027 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowColumnsSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowColumnsSQLHandler.java @@ -1,20 +1,112 @@ package io.mycat.sqlHandler.dql; +import com.alibaba.fastsql.DbType; +import com.alibaba.fastsql.sql.SQLUtils; +import com.alibaba.fastsql.sql.ast.statement.SQLColumnDefinition; import com.alibaba.fastsql.sql.ast.statement.SQLShowColumnsStatement; +import com.alibaba.fastsql.sql.builder.impl.SQLSelectBuilderImpl; +import com.alibaba.fastsql.sql.repository.SchemaObject; import io.mycat.MycatDataContext; +import io.mycat.MycatException; +import io.mycat.beans.mysql.InformationSchema; +import io.mycat.beans.mysql.InformationSchemaRuntime; +import io.mycat.metadata.MetadataManager; +import io.mycat.metadata.TableHandler; +import io.mycat.queryCondition.SimpleColumnInfo; import io.mycat.sqlHandler.AbstractSQLHandler; import io.mycat.sqlHandler.ExecuteCode; import io.mycat.sqlHandler.SQLRequest; +import io.mycat.upondb.MycatDBClientBasedConfig; +import io.mycat.upondb.MycatDBClientMediator; +import io.mycat.upondb.MycatDBs; import io.mycat.util.Response; import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +/** + * @ chenjunwen + */ @Resource public class ShowColumnsSQLHandler extends AbstractSQLHandler { @Override protected ExecuteCode onExecute(SQLRequest request, MycatDataContext dataContext, Response response) { - response.proxyShow(request.getAst()); + SQLShowColumnsStatement ast = request.getAst(); +// response.proxyShow(ast); +// return ExecuteCode.PERFORMED; + String defaultSchema = dataContext.getDefaultSchema(); + String schema = ast.getDatabase() != null ? SQLUtils.normalize(ast.getDatabase().getSimpleName()) : defaultSchema; + boolean full = ast.isFull(); + String table = SQLUtils.normalize(ast.getTable().getSimpleName()); + + SQLSelectBuilderImpl sqlSelectBuilder = new SQLSelectBuilderImpl(DbType.mysql); + if (ast.getLike() != null) { + sqlSelectBuilder.whereAnd(" COLUMN_NAME " + ast.getLike()); + } + if (ast.getWhere() != null) { + sqlSelectBuilder.whereAnd(ast.getWhere().toString()); + } + if (full) { + sqlSelectBuilder.selectWithAlias("COLUMN_NAME", "Field"); + sqlSelectBuilder.selectWithAlias("DATA_TYPE", "Type"); + sqlSelectBuilder.selectWithAlias("COLLATION_NAME", "Collection"); + sqlSelectBuilder.selectWithAlias("IS_NULLABLE", "Null"); + sqlSelectBuilder.selectWithAlias("COLUMN_KEY", "Key"); + sqlSelectBuilder.selectWithAlias("COLUMN_DEFAULT", "Default"); + sqlSelectBuilder.selectWithAlias("EXTRA", "Extra"); + sqlSelectBuilder.selectWithAlias("PRIVILEGES", "Privileges"); + sqlSelectBuilder.selectWithAlias("COLUMN_COMMENT", "Comment"); + } else { + sqlSelectBuilder.selectWithAlias("COLUMN_NAME", "Field"); + sqlSelectBuilder.selectWithAlias("DATA_TYPE", "Type"); + sqlSelectBuilder.selectWithAlias("IS_NULLABLE", "Null"); + sqlSelectBuilder.selectWithAlias("COLUMN_KEY", "key"); + sqlSelectBuilder.selectWithAlias("COLUMN_DEFAULT", "Default"); + sqlSelectBuilder.selectWithAlias("EXTRA", "Extra"); + } + String sql = sqlSelectBuilder.from("information_schema.COLUMNS").toString(); + + SchemaObject table1 = MetadataManager.INSTANCE.TABLE_REPOSITORY.findTable(schema + "." + table); + if (table1 == null) { + response.sendError(new MycatException("table is not existed")); + return ExecuteCode.PERFORMED; + } + InformationSchema informationSchema = InformationSchemaRuntime.INSTANCE.get(); + TableHandler tableHandler = MetadataManager.INSTANCE.getTable(schema, table); + List array = new ArrayList<>(); + long index = 0; + for (SimpleColumnInfo column : tableHandler.getColumns()) { + SQLColumnDefinition table1Column = table1.findColumn(column.getColumnName()); + String columnName = SQLUtils.normalize(column.getColumnName()); + InformationSchema.COLUMNS_TABLE_OBJECT.COLUMNS_TABLE_OBJECTBuilder builder + = InformationSchema + .COLUMNS_TABLE_OBJECT + .builder() + .TABLE_CATALOG("def") + .TABLE_SCHEMA(schema) + .TABLE_NAME(table) + .COLUMN_NAME(columnName) + .ORDINAL_POSITION(index); + if (table1Column.getDefaultExpr() != null) { + builder.COLUMN_DEFAULT(table1Column.getDefaultExpr().toString()); + } + + builder.IS_NULLABLE(column.isNullable() ? "YES" : "NO"); + builder.DATA_TYPE(table1Column.getDataType().toString()); + + array.add(builder.build()); + index++; + } + informationSchema.COLUMNS = array.toArray(new InformationSchema.COLUMNS_TABLE_OBJECT[0]); + MycatDBClientMediator client = MycatDBs.createClient(dataContext, new MycatDBClientBasedConfig(MetadataManager.INSTANCE.getSchemaMap() + , Collections.singletonMap("information_schema", InformationSchemaRuntime.INSTANCE.get() + ), false)); + ; + + response.sendResultSet(()->client.query(sql),()->{throw new UnsupportedOperationException();}); return ExecuteCode.PERFORMED; } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowCreateTableSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowCreateTableSQLHandler.java index dddeb288a..5a7617342 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowCreateTableSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowCreateTableSQLHandler.java @@ -1,20 +1,60 @@ package io.mycat.sqlHandler.dql; +import com.alibaba.fastsql.sql.SQLUtils; +import com.alibaba.fastsql.sql.ast.SQLName; +import com.alibaba.fastsql.sql.ast.expr.SQLIdentifierExpr; +import com.alibaba.fastsql.sql.ast.expr.SQLPropertyExpr; import com.alibaba.fastsql.sql.ast.statement.SQLShowCreateTableStatement; import io.mycat.MycatDataContext; +import io.mycat.MycatException; +import io.mycat.beans.mycat.ResultSetBuilder; +import io.mycat.metadata.MetadataManager; +import io.mycat.metadata.TableHandler; import io.mycat.sqlHandler.AbstractSQLHandler; import io.mycat.sqlHandler.ExecuteCode; import io.mycat.sqlHandler.SQLRequest; import io.mycat.util.Response; import javax.annotation.Resource; +import java.sql.JDBCType; +import java.util.Arrays; @Resource public class ShowCreateTableSQLHandler extends AbstractSQLHandler { @Override protected ExecuteCode onExecute(SQLRequest request, MycatDataContext dataContext, Response response) { - response.proxyShow(request.getAst()); + SQLShowCreateTableStatement ast = request.getAst(); + + SQLName nameExpr = ast.getName(); + if (nameExpr == null) { + response.sendError(new MycatException("table name is null")); + return ExecuteCode.PERFORMED; + } + String schemaName = dataContext.getDefaultSchema(); + String tableName; + if (nameExpr instanceof SQLIdentifierExpr) { + tableName = ((SQLIdentifierExpr) nameExpr).normalizedName(); + }else if (nameExpr instanceof SQLPropertyExpr){ + schemaName = + ((SQLIdentifierExpr)((SQLPropertyExpr) nameExpr).getOwner()).normalizedName(); + tableName = SQLUtils.normalize(((SQLPropertyExpr) nameExpr).getName()); + }else { + response.sendError(new MycatException("unsupport name :"+nameExpr)); + return ExecuteCode.PERFORMED; + } + TableHandler table = MetadataManager.INSTANCE.getTable(schemaName, tableName); + if (table == null){ + response.sendError(new MycatException("table "+ schemaName+"."+tableName+" is not existed")); + return ExecuteCode.PERFORMED; + } + String createTableSQL = table.getCreateTableSQL(); + + ResultSetBuilder resultSetBuilder = ResultSetBuilder.create(); + resultSetBuilder.addColumnInfo("Table", JDBCType.VARCHAR); + resultSetBuilder.addColumnInfo("Create Table", JDBCType.VARCHAR); + resultSetBuilder.addObjectRowPayload(Arrays.asList(table.getTableName(),createTableSQL)); + response.sendResultSet(()->resultSetBuilder.build(),()->{throw new UnsupportedOperationException();}); return ExecuteCode.PERFORMED; } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowDatabasesHanlder.java b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowDatabasesHanlder.java index 8a81b8392..83bc7fe01 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowDatabasesHanlder.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowDatabasesHanlder.java @@ -24,7 +24,7 @@ protected ExecuteCode onExecute(SQLRequest { + response.sendResultSet(()->rowBaseIterator, () -> { throw new UnsupportedOperationException(); }); return ExecuteCode.PERFORMED; diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowEnginesSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowEnginesSQLHandler.java index b156c9cd6..2e7783372 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowEnginesSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowEnginesSQLHandler.java @@ -2,19 +2,42 @@ import com.alibaba.fastsql.sql.dialect.mysql.ast.statement.MySqlShowEnginesStatement; import io.mycat.MycatDataContext; +import io.mycat.beans.mycat.ResultSetBuilder; import io.mycat.sqlHandler.AbstractSQLHandler; import io.mycat.sqlHandler.ExecuteCode; import io.mycat.sqlHandler.SQLRequest; import io.mycat.util.Response; import javax.annotation.Resource; +import java.sql.JDBCType; +import java.util.Arrays; +/** + * chenjunwen + * mock ShowEngines + */ @Resource public class ShowEnginesSQLHandler extends AbstractSQLHandler { @Override protected ExecuteCode onExecute(SQLRequest request, MycatDataContext dataContext, Response response) { - response.proxyShow(request.getAst()); + + ResultSetBuilder resultSetBuilder = ResultSetBuilder.create(); + + resultSetBuilder.addColumnInfo("Engine", JDBCType.VARCHAR); + resultSetBuilder.addColumnInfo("Support", JDBCType.VARCHAR); + resultSetBuilder.addColumnInfo("Comment", JDBCType.VARCHAR); + + resultSetBuilder.addObjectRowPayload(Arrays.asList("InnoDB","DRFAULT","Supports transactions, row-level locking, foreign keys and encryption for tables")); + resultSetBuilder.addObjectRowPayload(Arrays.asList("CSV","YES","Stores tables as CSV files")); + resultSetBuilder.addObjectRowPayload(Arrays.asList("MRG_MyISAM","YES","Collection of identical MyISAM tables")); + resultSetBuilder.addObjectRowPayload(Arrays.asList("MEMORY","YES","Hash based, stored in memory, useful for temporary tables")); + resultSetBuilder.addObjectRowPayload(Arrays.asList("MyISAM","YES","Non-transactional engine with good performance and small data footprint")); + resultSetBuilder.addObjectRowPayload(Arrays.asList("SEQUENCE","YES","Generated tables filled with sequential values")); + resultSetBuilder.addObjectRowPayload(Arrays.asList("Aria","YES","Crash-safe tables with MyISAM heritage")); + resultSetBuilder.addObjectRowPayload(Arrays.asList("PERFORMANCE_SCHEMA","YES","Performance Schema")); + + response.sendResultSet(()->resultSetBuilder.build(),()->{throw new UnsupportedOperationException();}); return ExecuteCode.PERFORMED; } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowProcedureStatusSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowProcedureStatusSQLHandler.java index 5ae261749..cc6a7f846 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowProcedureStatusSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowProcedureStatusSQLHandler.java @@ -14,7 +14,7 @@ public class ShowProcedureStatusSQLHandler extends AbstractSQLHandler request, MycatDataContext dataContext, Response response) { - response.proxyShow(request.getAst()); + response.sendOk(); return ExecuteCode.PERFORMED; } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowTableStatusSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowTableStatusSQLHandler.java index 1a8e67775..5171e6189 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowTableStatusSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowTableStatusSQLHandler.java @@ -1,20 +1,392 @@ package io.mycat.sqlHandler.dql; +import com.alibaba.fastsql.sql.SQLUtils; import com.alibaba.fastsql.sql.dialect.mysql.ast.statement.MySqlShowTableStatusStatement; +import io.mycat.DDLManager; import io.mycat.MycatDataContext; +import io.mycat.api.collector.RowBaseIterator; +import io.mycat.beans.mycat.ColumnInfo; +import io.mycat.beans.mycat.ResultSetBuilder; +import io.mycat.router.ShowStatementRewriter; import io.mycat.sqlHandler.AbstractSQLHandler; import io.mycat.sqlHandler.ExecuteCode; import io.mycat.sqlHandler.SQLRequest; +import io.mycat.upondb.MycatDBs; import io.mycat.util.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.Resource; +import java.sql.JDBCType; +import java.util.ArrayList; +import java.util.List; +/** + * chenjunwen + */ @Resource public class ShowTableStatusSQLHandler extends AbstractSQLHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(ShowTableStatusSQLHandler.class); @Override protected ExecuteCode onExecute(SQLRequest request, MycatDataContext dataContext, Response response) { - response.proxyShow(request.getAst()); + MySqlShowTableStatusStatement ast = request.getAst(); + + try { + DDLManager.INSTANCE.updateTables(); + String databaseName = ast.getDatabase() == null ? dataContext.getDefaultSchema() : + SQLUtils.normalize(ast.getDatabase().getSimpleName()); + + String tableName = ast.getTableGroup() == null ? null + : SQLUtils.normalize(ast.getTableGroup().getSimpleName()); + + String sql = ShowStatementRewriter.showTableStatus(ast, databaseName, tableName); + + try (RowBaseIterator query = MycatDBs.createClient(dataContext).query(sql)) { + response.sendResultSet(() -> query, () -> { + throw new UnsupportedOperationException(); + }); + } + }catch (Exception e){ + LOGGER.error("",e); + response.sendError(e); + } return ExecuteCode.PERFORMED; } + + private void addColumns(ResultSetBuilder resultSetBuilder) { + /** + * MySQL Protocol + * Packet Length: 66 + * Packet Number: 2 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Name + * Original name: TABLE_NAME + * Charset number: utf8mb4 COLLATE utf8mb4_unicode_ci (224) + * Length: 256 + * Type: FIELD_TYPE_VAR_STRING (253) + * Flags: 0x0001 + * Decimals: 0 + */ + resultSetBuilder.addColumnInfo("Name", JDBCType.VARCHAR); + + /** + * MySQL Protocol + * Packet Length: 64 + * Packet Number: 3 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Engine + * Original name: ENGINE + * Charset number: utf8mb4 COLLATE utf8mb4_unicode_ci (224) + * Length: 256 + * Type: FIELD_TYPE_VAR_STRING (253) + * Flags: 0x0000 + * Decimals: 0 + */ + resultSetBuilder.addColumnInfo("Engine", JDBCType.VARCHAR); + + /** + * MySQL Protocol + * Packet Length: 66 + * Packet Number: 4 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Version + * Original name: VERSION + * Charset number: binary COLLATE binary (63) + * Length: 21 + * Type: FIELD_TYPE_LONGLONG (8) + * Flags: 0x0020 + * Decimals: 0 + */ + resultSetBuilder.addColumnInfo("Version", JDBCType.BIGINT); + + + /** + * MySQL Protocol + * Packet Length: 72 + * Packet Number: 5 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Row_format + * Original name: ROW_FORMAT + * Charset number: utf8mb4 COLLATE utf8mb4_unicode_ci (224) + * Length: 40 + * Type: FIELD_TYPE_VAR_STRING (253) + * Flags: 0x0000 + * Decimals: 0 + */ + resultSetBuilder.addColumnInfo("Row_format", JDBCType.VARCHAR); + + /** + * MySQL Protocol + * Packet Length: 66 + * Packet Number: 6 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Rows + * Original name: TABLE_ROWS + * Charset number: binary COLLATE binary (63) + * Length: 21 + * Type: FIELD_TYPE_LONGLONG (8) + * Flags: 0x0020 + * Decimals: 0 + */ + + resultSetBuilder.addColumnInfo("Rows", JDBCType.BIGINT); + + /** + * MySQL Protocol + * Packet Length: 80 + * Packet Number: 7 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Avg_row_length + * Original name: AVG_ROW_LENGTH + * Charset number: binary COLLATE binary (63) + * Length: 21 + * Type: FIELD_TYPE_LONGLONG (8) + * Flags: 0x0020 + * Decimals: 0 + * + * + */ + resultSetBuilder.addColumnInfo("Avg_row_length", JDBCType.BIGINT); + + /** + * MySQL Protocol + * Packet Length: 74 + * Packet Number: 8 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Data_length + * Original name: DATA_LENGTH + * Charset number: binary COLLATE binary (63) + * Length: 21 + * Type: FIELD_TYPE_LONGLONG (8) + * Flags: 0x0020 + * Decimals: 0 + */ + resultSetBuilder.addColumnInfo("Data_length", JDBCType.BIGINT); + + /** + * MySQL Protocol + * Packet Length: 82 + * Packet Number: 9 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Max_data_length + * Original name: MAX_DATA_LENGTH + * Charset number: binary COLLATE binary (63) + * Length: 21 + * Type: FIELD_TYPE_LONGLONG (8) + * Flags: 0x0020 + * Decimals: 0 + */ + resultSetBuilder.addColumnInfo("Max_data_length", JDBCType.BIGINT); + + /** + * MySQL Protocol + * Packet Length: 76 + * Packet Number: 10 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Index_length + * Original name: INDEX_LENGTH + * Charset number: binary COLLATE binary (63) + * Length: 21 + * Type: FIELD_TYPE_LONGLONG (8) + * Flags: 0x0020 + * Decimals: 0 + */ + resultSetBuilder.addColumnInfo("Index_length", JDBCType.BIGINT); + + /** + * MySQL Protocol + * Packet Length: 70 + * Packet Number: 11 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Data_free + * Original name: DATA_FREE + * Charset number: binary COLLATE binary (63) + * Length: 21 + * Type: FIELD_TYPE_LONGLONG (8) + * Flags: 0x0020 + * Decimals: 0 + */ + resultSetBuilder.addColumnInfo("Data_free", JDBCType.BIGINT); + + /** + * MySQL Protocol + * Packet Length: 80 + * Packet Number: 12 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Auto_increment + * Original name: AUTO_INCREMENT + * Charset number: binary COLLATE binary (63) + * Length: 21 + * Type: FIELD_TYPE_LONGLONG (8) + * Flags: 0x0020 + * Decimals: 0 + */ + resultSetBuilder.addColumnInfo("Auto_increment", JDBCType.BIGINT); + + /** + * MySQL Protocol + * Packet Length: 74 + * Packet Number: 13 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Create_time + * Original name: CREATE_TIME + * Charset number: binary COLLATE binary (63) + * Length: 19 + * Type: FIELD_TYPE_DATETIME (12) + * Flags: 0x0080 + * Decimals: 0 + */ + resultSetBuilder.addColumnInfo("Create_time", JDBCType.TIME); + + /** + * MySQL Protocol + * Packet Length: 74 + * Packet Number: 14 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Update_time + * Original name: UPDATE_TIME + * Charset number: binary COLLATE binary (63) + * Length: 19 + * Type: FIELD_TYPE_DATETIME (12) + * Flags: 0x0080 + * Decimals: 0 + */ + resultSetBuilder.addColumnInfo("Update_time", JDBCType.TIME); + + /** + * MySQL Protocol + * Packet Length: 72 + * Packet Number: 15 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Check_time + * Original name: CHECK_TIME + * Charset number: binary COLLATE binary (63) + * Length: 19 + * Type: FIELD_TYPE_DATETIME (12) + * Flags: 0x0080 + * Decimals: 0 + * + * + */ + resultSetBuilder.addColumnInfo("Check_time", JDBCType.TIME); + + /** + * MySQL Protocol + * Packet Length: 76 + * Packet Number: 16 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Collation + * Original name: TABLE_COLLATION + * Charset number: utf8mb4 COLLATE utf8mb4_unicode_ci (224) + * Length: 128 + * Type: FIELD_TYPE_VAR_STRING (253) + * Flags: 0x0000 + * Decimals: 0 + * + * + */ + resultSetBuilder.addColumnInfo("Collation", JDBCType.VARCHAR); + + /** + * MySQL Protocol + * Packet Length: 68 + * Packet Number: 17 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Checksum + * Original name: CHECKSUM + * Charset number: binary COLLATE binary (63) + * Length: 21 + * Type: FIELD_TYPE_LONGLONG (8) + * Flags: 0x0020 + * Decimals: 0 + * + */ + resultSetBuilder.addColumnInfo("Checksum", JDBCType.BIGINT); + + /** + * MySQL Protocol + * Packet Length: 80 + * Packet Number: 18 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Create_options + * Original name: CREATE_OPTIONS + * Charset number: utf8mb4 COLLATE utf8mb4_unicode_ci (224) + * Length: 8192 + * Type: FIELD_TYPE_VAR_STRING (253) + * Flags: 0x0000 + * Decimals: 0 + * + */ + resultSetBuilder.addColumnInfo("Create_options", JDBCType.VARCHAR); + + /** + * MySQL Protocol + * Packet Length: 72 + * Packet Number: 19 + * Catalog: def + * Database: information_schema + * Table: TABLES + * Original table: TABLES + * Name: Comment + * Original name: TABLE_COMMENT + * Charset number: utf8mb4 COLLATE utf8mb4_unicode_ci (224) + * Length: 8192 + * Type: FIELD_TYPE_VAR_STRING (253) + * Flags: 0x0001 + * Decimals: 0 + */ + resultSetBuilder.addColumnInfo("Comment", JDBCType.VARCHAR); + } } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowTablesSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowTablesSQLHandler.java index 954348cea..28b54b51f 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowTablesSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowTablesSQLHandler.java @@ -3,9 +3,11 @@ import com.alibaba.fastsql.sql.SQLUtils; import com.alibaba.fastsql.sql.ast.SQLName; import com.alibaba.fastsql.sql.ast.statement.SQLShowTablesStatement; +import io.mycat.DDLManager; import io.mycat.MycatDataContext; import io.mycat.api.collector.ComposeRowBaseIterator; import io.mycat.api.collector.RowBaseIterator; +import io.mycat.beans.mysql.InformationSchema; import io.mycat.beans.mysql.InformationSchema.TABLES_TABLE_OBJECT; import io.mycat.beans.mysql.InformationSchemaRuntime; import io.mycat.datasource.jdbc.JdbcRuntime; @@ -34,31 +36,7 @@ public class ShowTablesSQLHandler extends AbstractSQLHandler request, MycatDataContext dataContext, Response response) { - - List collect = MetadataManager.INSTANCE.getSchemaMap().values().stream().distinct() - .flatMap(i -> i.logicTables().values().stream()).distinct().collect(Collectors.toList()); - ArrayList objects = new ArrayList<>(); - for (TableHandler value : collect) { - String TABLE_CATALOG = "def"; - String TABLE_SCHEMA = value.getSchemaName(); - String TABLE_NAME = value.getTableName(); - String TABLE_TYPE = "BASE TABLE"; - String ENGINE = "InnoDB"; - Long VERSION = 10L; - String ROW_FORMAT = "DYNAMIC"; - TABLES_TABLE_OBJECT tableObject = TABLES_TABLE_OBJECT.builder() - .TABLE_CATALOG(TABLE_CATALOG) - .TABLE_SCHEMA(TABLE_SCHEMA) - .TABLE_NAME(TABLE_NAME) - .TABLE_TYPE(TABLE_TYPE) - .ENGINE(ENGINE) - .VERSION(VERSION) - .ROW_FORMAT(ROW_FORMAT) - .build(); - objects.add(tableObject); - } - TABLES_TABLE_OBJECT[] tables_table_objects = objects.toArray(new TABLES_TABLE_OBJECT[0]); - InformationSchemaRuntime.INSTANCE.update(informationSchema -> informationSchema.TABLES = tables_table_objects); + DDLManager.INSTANCE.updateTables(); String sql = ShowStatementRewriter.rewriteShowTables(dataContext.getDefaultSchema(), request.getAst()); LOGGER.info(sql); //show 语句变成select 语句 @@ -69,32 +47,39 @@ protected ExecuteCode onExecute(SQLRequest request, Myca SQLShowTablesStatement showTablesStatement = request.getAst(); SQLName from = showTablesStatement.getFrom(); String schema = SQLUtils.normalize(from == null ? dataContext.getDefaultSchema() : from.getSimpleName()); - if (schema != null) { - String defaultTargetName = Optional.ofNullable(MetadataManager.INSTANCE) - .map(i -> i.getSchemaMap()) - .map(i -> i.get(schema)) + if (WithDefaultTargetInfo(response, sql, query, schema)) return ExecuteCode.PERFORMED; + } catch (Exception e) { + LOGGER.error("", e); + } + response.sendResultSet(()->query, null); + return ExecuteCode.PERFORMED; + } + } + + private boolean WithDefaultTargetInfo(Response response, String sql, RowBaseIterator query, String schema) { + if (schema != null) { + String defaultTargetName = Optional.ofNullable(MetadataManager.INSTANCE) + .map(i -> i.getSchemaMap()) + .map(i -> i.get(schema)) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //暂时定为没有配置分片表才读取默认targetName的表作为tables - .filter(i -> i.logicTables() == null || i.logicTables().isEmpty()) + //暂时定为没有配置分片表才读取默认targetName的表作为tables + .filter(i -> i.logicTables() == null || i.logicTables().isEmpty()) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - .map(i -> i.defaultTargetName()) - .orElse(null); - if (defaultTargetName != null) { - defaultTargetName = ReplicaSelectorRuntime.INSTANCE.getDatasourceNameByReplicaName(defaultTargetName, true, null); - try (DefaultConnection connection = JdbcRuntime.INSTANCE.getConnection(defaultTargetName)) { - RowBaseIterator rowBaseIterator = connection.executeQuery(sql); + .map(i -> i.defaultTargetName()) + .orElse(null); + if (defaultTargetName != null) { + defaultTargetName = ReplicaSelectorRuntime.INSTANCE.getDatasourceNameByReplicaName(defaultTargetName, true, null); + try (DefaultConnection connection = JdbcRuntime.INSTANCE.getConnection(defaultTargetName)) { + RowBaseIterator rowBaseIterator = connection.executeQuery(sql); - //safe - response.sendResultSet(ComposeRowBaseIterator.of(rowBaseIterator, query), null); - return ExecuteCode.PERFORMED; - } - } + //safe + response.sendResultSet(()-> ComposeRowBaseIterator.of(rowBaseIterator, query), null); + return true; } - } catch (Exception e) { - LOGGER.error("", e); } - response.sendResultSet(query, null); - return ExecuteCode.PERFORMED; } + return false; } + + } diff --git a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowVariantsSQLHandler.java b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowVariantsSQLHandler.java index 3abf5fb80..20da59ef2 100644 --- a/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowVariantsSQLHandler.java +++ b/mycat2/src/main/java/io/mycat/sqlHandler/dql/ShowVariantsSQLHandler.java @@ -2,19 +2,118 @@ import com.alibaba.fastsql.sql.dialect.mysql.ast.statement.MySqlShowVariantsStatement; import io.mycat.MycatDataContext; +import io.mycat.RootHelper; +import io.mycat.api.collector.RowBaseIterator; +import io.mycat.beans.mysql.InformationSchema; +import io.mycat.beans.mysql.InformationSchemaRuntime; +import io.mycat.metadata.MetadataManager; +import io.mycat.router.ShowStatementRewriter; import io.mycat.sqlHandler.AbstractSQLHandler; import io.mycat.sqlHandler.ExecuteCode; import io.mycat.sqlHandler.SQLRequest; +import io.mycat.upondb.MycatDBClientBasedConfig; +import io.mycat.upondb.MycatDBClientMediator; +import io.mycat.upondb.MycatDBs; import io.mycat.util.Response; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.Resource; +import java.util.*; +/** + * chenjunwen + * 实现ShowVariants + */ @Resource public class ShowVariantsSQLHandler extends AbstractSQLHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(ShowVariantsSQLHandler.class); + /** + * 查询 + * GLOBAL_VARIABLES + * SESSION_VARIABLES + * + * @param request + * @param dataContext + * @param response + * @return + */ @Override protected ExecuteCode onExecute(SQLRequest request, MycatDataContext dataContext, Response response) { - response.proxyShow(request.getAst()); + try { + MySqlShowVariantsStatement ast = request.getAst(); + + boolean global = ast.isGlobal(); + boolean session = ast.isSession(); + + if (!global && !session) { + session = true;//如果没有设置则为session + } + String sql = ShowStatementRewriter.rewriteVariables(ast, "SESSION_VARIABLES"); + + InformationSchema informationSchema = (InformationSchema) InformationSchemaRuntime.INSTANCE.get().clone(); + MycatDBClientMediator client = MycatDBs.createClient(dataContext, new MycatDBClientBasedConfig(MetadataManager.INSTANCE.getSchemaMap(), + Collections.singletonMap("information_schema", informationSchema),false)); + + try { + //session值覆盖全局值 + Map globalMap = new HashMap<>(); + for (Map.Entry stringObjectEntry : RootHelper.INSTANCE.getConfigProvider().globalVariables().entrySet()) { + String key = fixKeyName(stringObjectEntry.getKey()); + globalMap.put(key, stringObjectEntry.getValue()); + } + + + Map sessionMap = new HashMap<>(); + for (String k : MycatDBs.VARIABLES_COLUMNNAME_SET) { + String keyName = fixKeyName(k); + Object variable = client.getVariable(k); + sessionMap.put(keyName,variable ); + sessionMap.put(keyName.toLowerCase(),variable ); + sessionMap.put(keyName.toUpperCase(),variable ); + } + globalMap.putAll(sessionMap); + + ArrayList list = new ArrayList<>(); + for (Map.Entry entry : globalMap.entrySet()) { + list.add(InformationSchema + .SESSION_VARIABLES_TABLE_OBJECT + .builder() + .VARIABLE_NAME(entry.getKey()) + .VARIABLE_VALUE(entry.getValue() == null ? null : Objects.toString(entry.getValue())) + .build()); + } + + informationSchema.SESSION_VARIABLES = list.toArray(new InformationSchema.SESSION_VARIABLES_TABLE_OBJECT[0]); + + RowBaseIterator query = client.query(sql); + + response.sendResultSet(() -> query, () -> { + throw new UnsupportedOperationException(); + }); + } finally { + client.close(); + } + } catch (Throwable e) { + LOGGER.error("", e); + response.sendError(e); + } return ExecuteCode.PERFORMED; } + + @NotNull + private String fixKeyName(String key) { + while (true) { + if (key.startsWith("@")) { + key = key.substring(1); + } else { + break; + } + } + return key; + } + + } diff --git a/mycat2/src/test/java/io/mycat/sql/SQLExprChecker.java b/mycat2/src/test/java/io/mycat/sql/SQLExprChecker.java index cfe187fc4..923daa0b9 100644 --- a/mycat2/src/test/java/io/mycat/sql/SQLExprChecker.java +++ b/mycat2/src/test/java/io/mycat/sql/SQLExprChecker.java @@ -61,8 +61,8 @@ public void run() { check("select user_id*id from db1.travelrecord",(999*max)+")("+(999*min)); check("select (user_id*1.0)/(id*1.0) from db1.travelrecord");//结果不确定 // check("select user_id DIV id from db1.travelrecord",(999/max)+")("+(999/min));不支持 - check("select user_id % id from db1.travelrecord",(999%max)+")("+(999%min)); - check("select user_id MOD id from db1.travelrecord",(999%max)+")("+(999%min)); + check("select user_id % id from db1.travelrecord");//结果不确定 + check("select user_id MOD id from db1.travelrecord");//结果不确定 // diff --git a/pom.xml b/pom.xml index d805807fd..f90198fca 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,7 @@ autohandler testsuite statistic + hbt2 pom parent diff --git a/replica/src/main/java/io/mycat/replica/DataSourceNearnessImpl.java b/replica/src/main/java/io/mycat/replica/DataSourceNearnessImpl.java index b3438646e..ffe224926 100644 --- a/replica/src/main/java/io/mycat/replica/DataSourceNearnessImpl.java +++ b/replica/src/main/java/io/mycat/replica/DataSourceNearnessImpl.java @@ -1,6 +1,7 @@ package io.mycat.replica; import io.mycat.DataSourceNearness; +import io.mycat.TransactionSession; import java.util.HashMap; import java.util.Objects; @@ -14,9 +15,10 @@ public class DataSourceNearnessImpl implements DataSourceNearness { HashMap map = new HashMap<>(); String loadBalanceStrategy; Boolean replicaMode; - boolean update; + private TransactionSession transactionSession; - public DataSourceNearnessImpl() { + public DataSourceNearnessImpl(TransactionSession transactionSession) { + this.transactionSession = transactionSession; } public String getDataSourceByTargetName(final String targetName) { @@ -28,7 +30,7 @@ public String getDataSourceByTargetName(final String targetName) { String res; if (replicaMode) { res = map.computeIfAbsent(targetName, (s) -> { - String datasourceNameByReplicaName = instance.getDatasourceNameByReplicaName(targetName, false, loadBalanceStrategy); + String datasourceNameByReplicaName = instance.getDatasourceNameByReplicaName(targetName, !transactionSession.isAutocommit()||transactionSession.isInTransaction(), loadBalanceStrategy); return Objects.requireNonNull(datasourceNameByReplicaName); }); }else { @@ -41,9 +43,6 @@ public void setLoadBalanceStrategy(String loadBalanceStrategy) { this.loadBalanceStrategy = loadBalanceStrategy; } - public void setUpdate(boolean update) { - this.update = update; - } public void clear(){ map.clear(); diff --git a/replica/src/main/java/io/mycat/replica/ReplicaDataSourceSelector.java b/replica/src/main/java/io/mycat/replica/ReplicaDataSourceSelector.java index 0723608ed..65399f53b 100644 --- a/replica/src/main/java/io/mycat/replica/ReplicaDataSourceSelector.java +++ b/replica/src/main/java/io/mycat/replica/ReplicaDataSourceSelector.java @@ -238,4 +238,7 @@ public void unregister(String datasourceName) { writeDataSourceList.removeIf((i) -> i.getName().equals(datasourceName)); readDataSource.removeIf((i) -> i.getName().equals(datasourceName)); } + public Map getRwaDataSourceMap(){ + return Collections.unmodifiableMap(this.datasourceMap); + } } diff --git a/router/src/main/java/io/mycat/router/ShowStatementRewriter.java b/router/src/main/java/io/mycat/router/ShowStatementRewriter.java index 235b8e749..e4ff98a3b 100644 --- a/router/src/main/java/io/mycat/router/ShowStatementRewriter.java +++ b/router/src/main/java/io/mycat/router/ShowStatementRewriter.java @@ -1,9 +1,14 @@ package io.mycat.router; +import com.alibaba.fastsql.DbType; import com.alibaba.fastsql.sql.SQLUtils; import com.alibaba.fastsql.sql.ast.SQLExpr; import com.alibaba.fastsql.sql.ast.SQLName; +import com.alibaba.fastsql.sql.ast.expr.SQLBooleanExpr; import com.alibaba.fastsql.sql.ast.statement.SQLShowTablesStatement; +import com.alibaba.fastsql.sql.builder.impl.SQLSelectBuilderImpl; +import com.alibaba.fastsql.sql.dialect.mysql.ast.statement.MySqlShowTableStatusStatement; +import com.alibaba.fastsql.sql.dialect.mysql.ast.statement.MySqlShowVariantsStatement; import io.mycat.MycatException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,4 +42,62 @@ public static String rewriteShowTables(String defaultSchema, SQLShowTablesStatem LOGGER.info(ast + "->" + sql); return sql; } + + + public static String showTableStatus(MySqlShowTableStatusStatement ast, String databaseName, String tableName) { + if (databaseName == null) { + throw new MycatException(1046, "No database selected"); + } + String like = ast.getLike() == null ? new SQLBooleanExpr(true).toString() : " TABLE_NAME like "+ast.getLike(); + SQLExpr where = ast.getWhere() == null ? new SQLBooleanExpr(true) : ast.getWhere(); + + String schemaCondition = " TABLE_SCHEMA = '" + databaseName + "' "; + String tableCondition = tableName != null ? " TABLE_NAME = '" + tableName + "' " : " true "; + + SQLSelectBuilderImpl sqlSelectBuilder = new SQLSelectBuilderImpl(DbType.mysql); + String sql = sqlSelectBuilder + .selectWithAlias("TABLE_NAME", "Name") + .selectWithAlias("ENGINE", "Engine") + .selectWithAlias("VERSION", "Version") + .selectWithAlias("ROW_FORMAT", "Row_format") + .selectWithAlias("AVG_ROW_LENGTH", "Avg_row_length") + .selectWithAlias("DATA_LENGTH", "Data_length") + .selectWithAlias("MAX_DATA_LENGTH", "Data_length") + .selectWithAlias("INDEX_LENGTH", "Max_data_length") + .selectWithAlias("DATA_FREE", "Data_free") + .selectWithAlias("AUTO_INCREMENT", "Auto_increment") + .selectWithAlias("CREATE_TIME", "UPDATE_TIME") + .selectWithAlias("UPDATE_TIME", "Update_time") + .selectWithAlias("CHECK_TIME", "Check_time") + .selectWithAlias("TABLE_COLLATION", "Collation") + .selectWithAlias("CHECKSUM", "Checksum") + .selectWithAlias("CREATE_OPTIONS", "Create_options") + .selectWithAlias("TABLE_COMMENT", "Comment") + .from("information_schema.`TABLES`") + .whereAnd(schemaCondition) + .whereAnd(tableCondition) + .whereAnd(like.toString()) + .whereAnd(where.toString()) + .toString(); + LOGGER.info(ast + "->" + sql); + return sql; + } + + public static String rewriteVariables(MySqlShowVariantsStatement ast, String tableName) { + if (tableName == null) { + tableName = !ast.isGlobal() ? "SESSION_VARIABLES" : "GLOBAL_VARIABLES"; + } + SQLSelectBuilderImpl sqlSelectBuilder = new SQLSelectBuilderImpl(DbType.mysql); + sqlSelectBuilder.selectWithAlias("VARIABLE_NAME", "Variable_name"); + sqlSelectBuilder.selectWithAlias("VARIABLE_VALUE", "Value"); + if (ast.getLike() != null) { + sqlSelectBuilder.whereAnd(" VARIABLE_NAME like "+ast.getLike().toString()); + } + if (ast.getWhere() != null) { + sqlSelectBuilder.whereAnd(ast.getWhere().toString()); + } + return sqlSelectBuilder.from("information_schema." + tableName) + .toString(); + } + } \ No newline at end of file