footmanFF opened a new issue #9637:
URL: https://github.com/apache/shardingsphere/issues/9637


   ### the full test case I use
   
   
https://gitee.com/footmanff/sharding-jdbc-demos/blob/master/sharding-jdbc-3.1.0-bug-test/src/main/java/com/footmanff/sharding/jdbc/sample/Test1.java
   
   ### information
   
   version:3.1.0
   project:sharding-jdbc
   
   ### logic sql
   ```
   select * from order where user_id =?  // 1
   select * from t_record where user_id =?  // 1
   ```
   ### db and table
   
   I use two DB, sharding_jdbc_demo_db0 and sharding_jdbc_demo_db1:
   
   #### sharding_jdbc_demo_db0:
   ```
   CREATE TABLE `order_0` (
     `id` int(11) NOT NULL AUTO_INCREMENT,
     `order_id` bigint(20) NOT NULL,
     `user_id` bigint(20) NOT NULL,
     PRIMARY KEY (`id`),
     KEY `idx_order_id` (`order_id`),
     KEY `idx_user_id` (`user_id`)
   ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
   
   CREATE TABLE `order_1` (
     `id` int(11) NOT NULL AUTO_INCREMENT,
     `order_id` bigint(20) NOT NULL,
     `user_id` bigint(20) NOT NULL,
     PRIMARY KEY (`id`),
     KEY `idx_order_id` (`order_id`),
     KEY `idx_user_id` (`user_id`)
   ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
   
   CREATE TABLE `t_record_0` (
     `id` int(11) NOT NULL AUTO_INCREMENT,
     `order_id` bigint(20) NOT NULL,
     `user_id` bigint(20) NOT NULL,
     PRIMARY KEY (`id`),
     KEY `idx_order_id` (`order_id`),
     KEY `idx_user_id` (`user_id`)
   ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
   
   CREATE TABLE `t_record_1` (
     `id` int(11) NOT NULL AUTO_INCREMENT,
     `order_id` bigint(20) NOT NULL,
     `user_id` bigint(20) NOT NULL,
     PRIMARY KEY (`id`),
     KEY `idx_order_id` (`order_id`),
     KEY `idx_user_id` (`user_id`)
   ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
   ```
   #### sharding_jdbc_demo_db1:
   ```
   CREATE TABLE `order_0` (
     `id` int(11) NOT NULL AUTO_INCREMENT,
     `order_id` bigint(20) NOT NULL,
     `user_id` bigint(20) NOT NULL,
     PRIMARY KEY (`id`),
     KEY `idx_order_id` (`order_id`),
     KEY `idx_user_id` (`user_id`)
   ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
   
   CREATE TABLE `order_1` (
     `id` int(11) NOT NULL AUTO_INCREMENT,
     `order_id` bigint(20) NOT NULL,
     `user_id` bigint(20) NOT NULL,
     PRIMARY KEY (`id`),
     KEY `idx_order_id` (`order_id`),
     KEY `idx_user_id` (`user_id`)
   ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
   
   CREATE TABLE `t_record_0` (
     `id` int(11) NOT NULL AUTO_INCREMENT,
     `order_id` bigint(20) NOT NULL,
     `user_id` bigint(20) NOT NULL,
     PRIMARY KEY (`id`),
     KEY `idx_order_id` (`order_id`),
     KEY `idx_user_id` (`user_id`)
   ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
   
   CREATE TABLE `t_record_1` (
     `id` int(11) NOT NULL AUTO_INCREMENT,
     `order_id` bigint(20) NOT NULL,
     `user_id` bigint(20) NOT NULL,
     PRIMARY KEY (`id`),
     KEY `idx_order_id` (`order_id`),
     KEY `idx_user_id` (`user_id`)
   ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
   ```
   ### datasource sharding rule and table sharding rule
   ```java
       @Bean
       public DataSource dataSource() throws SQLException {
           ShardingRuleConfiguration shardingRuleConfig = new 
ShardingRuleConfiguration();
   
           // t_record
           
shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration1());
           
           // order
           
shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration2());
   
           Map<String, Object> configMap = new HashMap<>();
   
           Properties props = new Properties();
   
           props.put("sql.show", "true");
   
           return 
ShardingDataSourceFactory.createDataSource(createDataSourceMap(), 
shardingRuleConfig, configMap, props);
       }
   
       TableRuleConfiguration getOrderTableRuleConfiguration1() {
           TableRuleConfiguration result = new TableRuleConfiguration();
           result.setLogicTable("t_record");
           
result.setActualDataNodes("sharding_jdbc_demo_db${0..1}.t_record_${0..1}");
           result.setKeyGeneratorColumnName("order_id");
   
           result.setDatabaseShardingStrategyConfig(new 
InlineShardingStrategyConfiguration("user_id", "sharding_jdbc_demo_db${user_id 
% 2}"));
           result.setTableShardingStrategyConfig(new 
InlineShardingStrategyConfiguration("order_id", "t_record_${order_id % 2}"));
           
           return result;
       }
   
       TableRuleConfiguration getOrderTableRuleConfiguration2() {
           TableRuleConfiguration result = new TableRuleConfiguration();
           result.setLogicTable("order");
           
result.setActualDataNodes("sharding_jdbc_demo_db${0..1}.order_${0..1}");
           result.setKeyGeneratorColumnName("order_id");
           
           result.setDatabaseShardingStrategyConfig(new 
InlineShardingStrategyConfiguration("user_id", "sharding_jdbc_demo_db${user_id 
% 2}"));
           result.setTableShardingStrategyConfig(new 
InlineShardingStrategyConfiguration("user_id", "order_${user_id % 2}"));
           
           return result;
       }
       
       public Map<String, DataSource> createDataSourceMap() {
           // 配置第 1 个数据源
           DruidDataSource dataSource1 = new DruidDataSource();
           dataSource1.setDriverClassName("com.mysql.jdbc.Driver");
           
dataSource1.setUrl("jdbc:mysql://localhost:3306/sharding_jdbc_demo_db0");
           dataSource1.setUsername("root");
           dataSource1.setPassword("root");
           
           // 配置第 2 个数据源
           DruidDataSource dataSource2 = new DruidDataSource();
           dataSource2.setDriverClassName("com.mysql.jdbc.Driver");
           
dataSource2.setUrl("jdbc:mysql://localhost:3306/sharding_jdbc_demo_db1");
           dataSource2.setUsername("root");
           dataSource2.setPassword("root");
           
           Map<String, DataSource> result = new HashMap<>();
           result.put("sharding_jdbc_demo_db0", dataSource1);
           result.put("sharding_jdbc_demo_db1", dataSource2);
           return result;
       }
   ```
   ### my test case
   ```java
       @Test
       public void t1() throws Exception {
           ApplicationContext ctx = new 
ClassPathXmlApplicationContext("spring.xml");
           final DataSource dataSource = ctx.getBean(DataSource.class);
   
           ExecutorService executorService = Executors.newFixedThreadPool(100);
   
           int count = 1000;
   
           CountDownLatch countDownLatch = new CountDownLatch(count);
   
           for (int i = 0; i < count; i++) {
               final int a = i;
               executorService.submit(() -> {
                   if (a % 2 == 0) {
                       queryOrder(dataSource);
                   } else {
                       queryRecord(dataSource);
                   }
                   countDownLatch.countDown();
               });
   
           }
           countDownLatch.await();
       }
   
       private void queryOrder(DataSource dataSource) {
           try {
               Connection connection = dataSource.getConnection();
               PreparedStatement preparedStatement = 
connection.prepareStatement("select * from order where user_id =?");
               preparedStatement.setLong(1, 1L);
               ResultSet resultSet = preparedStatement.executeQuery();
   
               while (resultSet.next()) {
                   long id = resultSet.getLong(1);
                   long orderId = resultSet.getLong(2);
                   long userId = resultSet.getLong(3);
                   System.out.println("order( " + id + ", " + orderId + ", " + 
userId + ")");
               }
   
               preparedStatement.close();
               connection.close();
           } catch (SQLException throwables) {
               throwables.printStackTrace();
           }
       }
   
       private void queryRecord(DataSource dataSource) {
           try {
               Connection connection = dataSource.getConnection();
               PreparedStatement preparedStatement = 
connection.prepareStatement("select * from t_record where user_id =?");
               preparedStatement.setLong(1, 1L);
               ResultSet resultSet = preparedStatement.executeQuery();
   
               while (resultSet.next()) {
                   long id = resultSet.getLong(1);
                   long orderId = resultSet.getLong(2);
                   long userId = resultSet.getLong(3);
                   System.out.println("t_record(" + id + ", " + orderId + ", " 
+ userId + ")");
               }
   
               preparedStatement.close();
               connection.close();
           } catch (SQLException throwables) {
               throwables.printStackTrace();
           }
       }
   ```
   
   ### Expected behavior
   
   this sql only execute on db `sharding_jdbc_demo_db1` and table `order_1`
   ```
   select * from order where user_id =?  // 1 
   ```
   
   ### Actual behavior
   
   I saw actual sql execute log like this:
   ```
   [INFO] [pool-4-thread-67] ShardingSphere-SQL - Rule Type: sharding 
   [INFO] [pool-4-thread-43] ShardingSphere-SQL - Logic SQL: select * from 
order where user_id =? 
   [INFO] [pool-4-thread-43] ShardingSphere-SQL - SQLStatement: 
SelectStatement(super=DQLStatement(super=io.shardingsphere.core.parsing.parser.sql.dql.select.SelectStatement@d8f0ccc),
 containStar=true, firstSelectItemStartPosition=7, selectListLastPosition=9, 
groupByLastPosition=0, items=[StarSelectItem(owner=Optional.absent())], 
groupByItems=[], orderByItems=[], limit=null, subQueryStatement=null, 
subQueryStatements=[], subQueryConditions=[]) 
   [INFO] [pool-4-thread-43] ShardingSphere-SQL - Actual SQL: 
sharding_jdbc_demo_db0 ::: select * from order_0 where user_id =? ::: [[1]] 
   [INFO] [pool-4-thread-43] ShardingSphere-SQL - Actual SQL: 
sharding_jdbc_demo_db0 ::: select * from order_1 where user_id =? ::: [[1]] 
   [INFO] [pool-4-thread-43] ShardingSphere-SQL - Actual SQL: 
sharding_jdbc_demo_db1 ::: select * from order_0 where user_id =? ::: [[1]] 
   [INFO] [pool-4-thread-43] ShardingSphere-SQL - Actual SQL: 
sharding_jdbc_demo_db1 ::: select * from order_1 where user_id =? ::: [[1]] 
   ```
   
   the sql executed on all database and all table.
   
   ### my analyze
   
   i guess the 
io.shardingsphere.core.parsing.antlr.extractor.impl.FromWhereExtractor cause 
the problem.
   
   FromWhereExtractor is used as single instance. but the field called 
predicateSegmentExtractor is created every time execute the method called 
extract of FromWhereExtractor:
   
   ```java
   /**
    * From clause extractor.
    *
    * @author duhongjun
    */
   public final class FromWhereExtractor implements OptionalSQLSegmentExtractor 
{
       private PredicateExtractor predicateSegmentExtractor;     
       /**
        * Extract SQL segment from SQL AST.
        *
        * @param ancestorNode ancestor node of AST
        * @param rootNode root node of AST
        * @return SQL segment
        */
       public Optional<FromWhereSegment> extract(final ParserRuleContext 
ancestorNode, final ParserRuleContext rootNode) {
           // ...
   
           FromWhereSegment result = new FromWhereSegment();
           predicateSegmentExtractor = new 
PredicateExtractor(result.getTableAliases());
   
           // ...
       }
   }
   ```
   tableAliases(Map<String, String>) is shared by the field 
predicateSegmentExtractor. i guess this is the caused.
   
   the returned FromWhereSegment of  method extract will wrong.
   
   the field tableName of class ColumnSegment my be wrong. this cause the wrong 
sql route.
   
   
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to