content: package com.alibaba.druid.sql.visitor;
  
  import com.alibaba.druid.DbType;
  import com.alibaba.druid.FastsqlException;
  import com.alibaba.druid.sql.ast.*;
  import com.alibaba.druid.sql.ast.statement.SQLCharacterDataType;
  import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
  import com.alibaba.druid.util.FnvHash;
  import com.alibaba.druid.util.HiveUtils;
  import com.alibaba.druid.util.MySqlUtils;
  import com.alibaba.druid.util.OdpsUtils;
  
  import java.util.Arrays;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Set;
  
  public class SQLDataTypeValidator extends SQLASTVisitorAdapter {
      private long[] supportTypeHashCodes;
  
      public SQLDataTypeValidator(String[] supportTypes) {
          this.supportTypeHashCodes = FnvHash.fnv1a_64_lower(supportTypes, true);
      }
  
      public SQLDataTypeValidator(Set<String> typeSet) {
          this.supportTypeHashCodes = new long[typeSet.size()];
  
          int i = 0;
          for (String type : typeSet) {
              this.supportTypeHashCodes[i++] = FnvHash.fnv1a_64_lower(type);
          }
          Arrays.sort(supportTypeHashCodes);
      }
  
      public boolean visit(SQLDataType x) {
          validate(x);
          return true;
      }
  
      public boolean visit(SQLCharacterDataType x) {
          validate(x);
          return true;
      }
  
      public boolean visit(SQLArrayDataType x) {
          validate(x);
          return true;
      }
  
      public boolean visit(SQLMapDataType x) {
          validate(x);
          return true;
      }
  
      public boolean visit(SQLStructDataType x) {
          validate(x);
          return true;
      }
  
      public void validate(SQLDataType x) {
          long hash = x.nameHashCode64();
          if (Arrays.binarySearch(supportTypeHashCodes, hash) < 0) {
              String msg = "illegal dataType : " + x.getName();
  
              final SQLObject parent = x.getParent();
              if (parent instanceof SQLColumnDefinition) {
                  SQLColumnDefinition column = (SQLColumnDefinition) parent;
                  if (column.getName() != null) {
                      msg += ", column " + column.getName();
                  }
              }
              throw new FastsqlException(msg);
          }
      }
  
      private static String[] odpsTypes;
      private static String[] hiveTypes;
      private static String[] mysqlTypes;
  
      public static SQLDataTypeValidator of(DbType dbType) {
          Set<String> typeSet = null;
          String[] types = null;
          switch (dbType) {
              case odps: {
                  types = odpsTypes;
                  if (types == null) {
                      typeSet = new HashSet<>();
                      OdpsUtils.DIALECT.dumpBuiltInDataTypes(typeSet);
                  }
                  break;
              }
              case hive: {
                  types = hiveTypes;
                  if (types == null) {
                      typeSet = new HashSet<>();
                      HiveUtils.loadDataTypes(typeSet);
                  }
                  break;
              }
              case mysql: {
                  types = mysqlTypes;
                  if (types == null) {
                      typeSet = new HashSet<>();
                      MySqlUtils.loadDataTypes(typeSet);
                  }
                  break;
              }
              default:
                  break;
          }
  
          if (types == null && typeSet != null) {
              types = typeSet.toArray(new String[typeSet.size()]);
          }
  
          if (types == null) {
              throw new FastsqlException("dataType " + dbType + " not support.");
          }
  
          return new SQLDataTypeValidator(types);
      }
  
      public static void check(SQLStatement stmt) {
          SQLDataTypeValidator v = of(stmt.getDbType());
          stmt.accept(v);
      }
  
      public static void check(List<SQLStatement> stmtList) {
          if (stmtList.isEmpty()) {
              return;
          }
  
          DbType dbType = stmtList.get(0).getDbType();
          SQLDataTypeValidator v = of(dbType);
  
          check(stmtList, dbType);
      }
  
      public static void check(List<SQLStatement> stmtList, DbType dbType) {
          if (stmtList.isEmpty()) {
              return;
          }
  
          SQLDataTypeValidator v = of(dbType);
  
          for (SQLStatement stmt : stmtList) {
              stmt.accept(v);
          }
      }
  }
  