content: /*
   * Copyright 1999-2018 Alibaba Group Holding Ltd.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package com.alibaba.druid.mock.handler;
  
  import com.alibaba.druid.mock.MockPreparedStatement;
  import com.alibaba.druid.mock.MockResultSet;
  import com.alibaba.druid.mock.MockResultSetMetaData;
  import com.alibaba.druid.mock.MockStatementBase;
  import com.alibaba.druid.sql.ast.SQLExpr;
  import com.alibaba.druid.sql.ast.SQLStatement;
  import com.alibaba.druid.sql.ast.expr.*;
  import com.alibaba.druid.sql.ast.statement.*;
  import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus;
  import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
  import com.alibaba.druid.sql.parser.SQLStatementParser;
  import com.alibaba.druid.util.jdbc.ResultSetMetaDataBase.ColumnMetaData;
  
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.sql.Timestamp;
  import java.sql.Types;
  import java.util.List;
  
  public class MySqlMockExecuteHandlerImpl implements MockExecuteHandler {
      @Override
      public ResultSet executeQuery(MockStatementBase statement, String sql) throws SQLException {
          SQLStatementParser parser = new MySqlStatementParser(sql);
          List<SQLStatement> stmtList = parser.parseStatementList();
  
          if (stmtList.size() > 1) {
              throw new SQLException("not support multi-statment. " + sql);
          }
  
          if (stmtList.isEmpty()) {
              throw new SQLException("executeQueryError : " + sql);
          }
  
          SQLStatement stmt = stmtList.get(0);
  
          if (stmt instanceof CobarShowStatus) {
              return showStatus(statement);
          }
  
          if (!(stmt instanceof SQLSelectStatement)) {
              throw new SQLException("executeQueryError : " + sql);
          }
  
          SQLSelect select = ((SQLSelectStatement) stmt).getSelect();
          SQLSelectQuery query = select.getQuery();
  
          if (query instanceof SQLSelectQueryBlock) {
              return executeQuery(statement, (SQLSelectQueryBlock) query);
          }
  
          throw new SQLException("TODO");
      }
  
      public ResultSet executeQuery(MockStatementBase statement, SQLSelectQueryBlock query) throws SQLException {
          SQLTableSource from = query.getFrom();
  
          if (from instanceof SQLExprTableSource) {
              SQLExpr expr = ((SQLExprTableSource) from).getExpr();
  
              if (expr instanceof SQLIdentifierExpr) {
                  String ident = ((SQLIdentifierExpr) expr).getName();
                  if ("dual".equalsIgnoreCase(ident)) {
                      return executeQueryFromDual(statement, query);
                  }
              }
              throw new SQLException("TODO : " + query);
          } else if (from == null) {
              return executeQueryFromDual(statement, query);
          } else {
              throw new SQLException("TODO");
          }
      }
  
      public ResultSet showStatus(MockStatementBase statement) throws SQLException {
          MockResultSet rs = new MockResultSet(statement);
          MockResultSetMetaData metaData = rs.getMockMetaData();
  
          Object[] row = new Object[]{"on"};
  
          ColumnMetaData column = new ColumnMetaData();
          column.setColumnType(Types.NVARCHAR);
          metaData.getColumns().add(column);
  
          rs.getRows().add(row);
  
          return rs;
      }
  
      public ResultSet executeQueryFromDual(MockStatementBase statement, SQLSelectQueryBlock query) throws SQLException {
          MockResultSet rs = statement.getConnection().getDriver().createMockResultSet(statement);
          MockResultSetMetaData metaData = rs.getMockMetaData();
  
          Object[] row = new Object[query.getSelectList().size()];
  
          for (int i = 0, size = query.getSelectList().size(); i < size; ++i) {
              ColumnMetaData column = new ColumnMetaData();
              SQLSelectItem item = query.getSelectList().get(i);
              SQLExpr expr = item.getExpr();
  
              if (expr instanceof SQLIntegerExpr) {
                  row[i] = ((SQLNumericLiteralExpr) expr).getNumber();
                  column.setColumnType(Types.INTEGER);
              } else if (expr instanceof SQLNumberExpr) {
                  row[i] = ((SQLNumericLiteralExpr) expr).getNumber();
                  column.setColumnType(Types.DECIMAL);
              } else if (expr instanceof SQLCharExpr) {
                  row[i] = ((SQLCharExpr) expr).getText();
                  column.setColumnType(Types.VARCHAR);
              } else if (expr instanceof SQLNCharExpr) {
                  row[i] = ((SQLNCharExpr) expr).getText();
                  column.setColumnType(Types.NVARCHAR);
              } else if (expr instanceof SQLBooleanExpr) {
                  row[i] = ((SQLBooleanExpr) expr).getBooleanValue();
                  column.setColumnType(Types.NVARCHAR);
              } else if (expr instanceof SQLNullExpr) {
                  row[i] = null;
              } else if (expr instanceof SQLMethodInvokeExpr) {
                  SQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr) expr;
  
                  if ("NOW".equalsIgnoreCase(methodInvokeExpr.getMethodName())) {
                      row[i] = new Timestamp(System.currentTimeMillis());
                  } else {
                      throw new SQLException("TODO");
                  }
              } else if (expr instanceof SQLVariantRefExpr) {
                  SQLVariantRefExpr varExpr = (SQLVariantRefExpr) expr;
                  int varIndex = varExpr.getIndex();
                  if (statement instanceof MockPreparedStatement) {
                      MockPreparedStatement mockPstmt = (MockPreparedStatement) statement;
                      row[i] = mockPstmt.getParameters().get(varIndex);
                  } else {
                      row[i] = null;
                  }
              } else {
                  row[i] = null;
              }
  
              metaData.getColumns().add(column);
          }
  
          rs.getRows().add(row);
  
          return rs;
      }
  }
  