package com.palacesun.engine.wrapper;

import bean.Column;
import com.palacesun.engine.common.CallableStatementInformation;
import com.palacesun.engine.common.ConnectionInformation;
import com.palacesun.engine.common.PreparedStatementInformation;
import com.palacesun.engine.common.StatementInformation;
import com.palacesun.engine.event.JdbcEventListener;
import com.palacesun.engine.gateway.EncryptionGatewayManager;
import com.palacesun.engine.gateway.GatewayContext;
import com.palacesun.engine.test.DbCache;
import com.palacesun.engine.test.TestJdbcEventListener;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
import com.alibaba.druid.stat.TableStat;
import com.palacesun.masking.appuser.AppUser;
import com.palacesun.masking.log.access.AccessContext;
import com.palacesun.masking.tools.EngineUtil;
import com.palacesun.masking.tools.InsertSqlVaulesUtil;
import com.palacesun.masking.tools.JdbcUtil;
import com.palacesun.masking.tools.ruleload.RuleLoadUtil;
import com.palacesun.masking.vo.Columninfo;
import com.palacesun.masking.vo.ConnectionInfo;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import util.SqlUtil;
import util.StringJoin;
import util.sqlparse.visitor.common.scope.ReplaceInfo;

public class ConnectionWrapper extends AbstractWrapper implements Connection {
   private final Connection delegate;
   private final JdbcEventListener jdbcEventListener;
   private final ConnectionInformation connectionInformation;
   protected static Logger logger = Logger.getLogger(ConnectionWrapper.class.getName());
   private static final String ENCRYPT_LIKE_OPEN = EncryptionGatewayManager.getParameterValue("encryption.like.open");
   private static final String ENCRYPT_SEPARATOR = EncryptionGatewayManager.getParameterValue("encryption.separator");
   public static Map<String, List<Map<String, Object>>> sqlParseMap = new HashMap();
   public List<Column> columnList = new ArrayList();

   public static ConnectionWrapper wrap(Connection delegate, JdbcEventListener eventListener, ConnectionInformation connectionInformation) throws Exception {
      if (delegate == null) {
         return null;
      } else {
         ConnectionWrapper connectionWrapper = new ConnectionWrapper(delegate, eventListener, connectionInformation);
         eventListener.onConnectionWrapped(connectionInformation);
         return connectionWrapper;
      }
   }

   protected ConnectionWrapper(Connection delegate, JdbcEventListener jdbcEventListener, ConnectionInformation connectionInformation) {
      super(delegate);
      if (delegate == null) {
         throw new NullPointerException("Delegate must not be null");
      } else {
         this.delegate = delegate;
         this.connectionInformation = connectionInformation;
         this.jdbcEventListener = jdbcEventListener;
      }
   }

   public JdbcEventListener getJdbcEventListener() {
      return this.jdbcEventListener;
   }

   public JdbcEventListener getEventListener() {
      return this.jdbcEventListener;
   }

   public Connection getDelegate() {
      return this.delegate;
   }

   public ConnectionInformation getConnectionInformation() {
      return this.connectionInformation;
   }

   public Statement createStatement() throws SQLException {
      return StatementWrapper.wrap(this.delegate.createStatement(), new StatementInformation(this.connectionInformation), this.jdbcEventListener);
   }

   public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
      return StatementWrapper.wrap(this.delegate.createStatement(resultSetType, resultSetConcurrency), new StatementInformation(this.connectionInformation), this.jdbcEventListener);
   }

   public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
      return StatementWrapper.wrap(this.delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability), new StatementInformation(this.connectionInformation), this.jdbcEventListener);
   }

   public PreparedStatement prepareStatement(String sql) throws SQLException {
      RuleLoadUtil.writeLog("@@插件@@---connectionWrapper--->prepareStatement:" + sql);
      String url = this.delegate.getMetaData().getURL();
      Map<String, Object> stringObjectMap = this.digestSql(sql, url);
      sql = (String)stringObjectMap.get("sql");
      sql = sql + " -- appUsername=" + AppUser.loginUser() + "\r\n";
      PreparedStatementInformation statementInformation = new PreparedStatementInformation(this.connectionInformation, sql);
      AccessContext context = new AccessContext();
      statementInformation.context = context;
      statementInformation.setDigestMap((Map)stringObjectMap.get("digestColumns"));
      statementInformation.setStatementQuery(sql);
      context.setStatementInfo(statementInformation);
      if ("1".equals(EncryptionGatewayManager.getParameterValue("replaceSql"))) {
         Map<String, Object> sql1 = LikeReplaceSql.sqlLikeReplace(statementInformation);
         sql = (String)sql1.get("sql");
         statementInformation.setReplaceInfo((ReplaceInfo)sql1.get("replaceInfo"));
         statementInformation.setStatementQuery(sql);
      }

      if (DbCache.isNeedIntercept(sql, statementInformation) && GatewayContext.isPluginEnabled()) {
         try {
            sql = this.encData(statementInformation);
         } catch (Exception exception) {
            exception.printStackTrace();
            throw new SQLException(exception);
         }
      }

      return PreparedStatementWrapper.wrap(this.delegate.prepareStatement(sql), statementInformation, this.jdbcEventListener);
   }

   public String removeFirstOccurrence(String str, String target) {
      int index = str.toLowerCase().indexOf(target);
      return index != -1 ? str.substring(0, index) + str.substring(index + target.length()) : str;
   }

   public Boolean find(String empNumber, Collection<TableStat.Column> list) {
      for(TableStat.Column column : list) {
         if (column.getName().equalsIgnoreCase(empNumber)) {
            return true;
         }
      }

      return false;
   }

   public String getFieldTableName(String sql, String field, String dbType) {
      String tableName = "";
      List<SQLStatement> stmtList = SQLUtils.parseStatements(sql, dbType);
      SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(DbType.of(dbType));
      SQLStatement sqlStatement = (SQLStatement)stmtList.get(0);
      sqlStatement.accept(visitor);

      for(TableStat.Column column : visitor.getColumns()) {
         if (column.getName().equalsIgnoreCase(field)) {
            tableName = column.getTable();
            break;
         }
      }

      return tableName;
   }

   public String encData(PreparedStatementInformation statementInformation) throws Exception {
      String returnSql = "";
      SqlUtil sqlUtil = new SqlUtil();
      String sqlUser = "";
      String urlDbType = statementInformation.getConnectionInformation().getUrl();
      String driverName = statementInformation.getConnectionInformation().getConnection().getMetaData().getDriverName();
      String dbType = "";
      dbType = getDbType(driverName, urlDbType, dbType);

      try {
         Connection connection = statementInformation.getConnectionInformation().getConnection();
         String urlTemp = connection.getMetaData().getURL();
         String ip = (String)TestJdbcEventListener.getIpAndPort(urlTemp).get("ip");
         String port = (String)TestJdbcEventListener.getIpAndPort(urlTemp).get("port");
         String schema = "";
         if ("oracle".equals(dbType)) {
            schema = connection.getMetaData().getUserName();
         } else if (!"postgresql".equals(dbType) && !"greenplum".equals(dbType) && !"gauss".equals(dbType)) {
            if ("sql server".equals(dbType)) {
               String url = connection.getMetaData().getURL();
               if (url.indexOf("applicationName") > 0) {
                  schema = url.substring(url.indexOf("applicationName") + "applicationName".length() + 1);
                  if (schema.indexOf(";") != -1) {
                     schema = schema.substring(0, schema.indexOf(";"));
                  }
               } else {
                  schema = "dbo";
               }
            } else if ("dm".equals(dbType)) {
               String url = connection.getMetaData().getURL();
               if (url.toLowerCase().contains("schema=")) {
                  schema = url.substring(url.toLowerCase().indexOf("schema=") + 7);
               } else {
                  int from = url.indexOf("://");
                  int end = url.indexOf("?");
                  String address = end == -1 ? url.substring(from + 3) : url.substring(from + 3, end);
                  int idx = address.lastIndexOf("/");
                  schema = address.substring(idx + 1);
               }
            } else if ("db2".equals(dbType)) {
               Statement stmt = connection.createStatement();
               ResultSet rs = stmt.executeQuery("SELECT CURRENT SCHEMA FROM SYSIBM.SYSDUMMY1");
               if (rs.next()) {
                  schema = rs.getString(1).trim();
               } else {
                  schema = connection.getMetaData().getUserName();
               }

               rs.close();
               stmt.close();
            } else if ("kingbase".equals(dbType)) {
               String url = connection.getMetaData().getURL();
               if (url.indexOf("searchpath") > 0) {
                  schema = url.substring(url.indexOf("searchpath") + 11);
               } else if (url.indexOf("currentSchema") > 0) {
                  schema = url.substring(url.indexOf("currentSchema") + 14);
               } else {
                  schema = "public";
               }
            } else if ("mysql".equals(dbType)) {
               String url = connection.getMetaData().getURL();
               int from = url.indexOf("://");
               int end = url.indexOf("?");
               String address = end == -1 ? url.substring(from + 3) : url.substring(from + 3, end);
               int idx = address.lastIndexOf("/");
               schema = address.substring(idx + 1);
            } else if ("mariadb".equals(dbType)) {
               String url = connection.getMetaData().getURL();
               int from = url.indexOf("://");
               int end = url.indexOf("?");
               String address = end == -1 ? url.substring(from + 3) : url.substring(from + 3, end);
               int idx = address.lastIndexOf("/");
               schema = address.substring(idx + 1);
            } else if ("hive".equals(dbType)) {
               String url = connection.getMetaData().getURL();
               int from = url.indexOf("://");
               int end = url.indexOf("?");
               String address = end == -1 ? url.substring(from + 3) : url.substring(from + 3, end);
               int idx = address.lastIndexOf("/");
               schema = address.substring(idx + 1);
               if (schema.indexOf(";") > 0) {
                  schema = schema.substring(0, schema.indexOf(";"));
               }
            } else {
               schema = connection.getCatalog();
            }
         } else {
            String url = connection.getMetaData().getURL();
            if (url.indexOf("searchpath") > 0) {
               schema = url.substring(url.indexOf("searchpath") + 11);
            } else if (url.indexOf("currentSchema") > 0) {
               schema = url.substring(url.indexOf("currentSchema") + 14);
            } else if (url.toLowerCase().indexOf("schema=") > 0) {
               schema = url.substring(url.indexOf("schema=") + 7);
            } else {
               schema = "public";
            }
         }

         String sqlTemp = statementInformation.getSql();
         int n = sqlTemp.indexOf("-- appUsername=");
         sqlUser = sqlTemp.substring(sqlTemp.indexOf("-- appUsername="));
         String sqlAll = sqlTemp.substring(0, n).trim();
         List<Map<String, Object>> stringObjectMapList = (List)sqlParseMap.get(sqlAll);
         if (stringObjectMapList == null || stringObjectMapList.isEmpty()) {
            stringObjectMapList = this.sortColumns(statementInformation, sqlAll, dbType, schema);
         }

         String[] split = sqlAll.split(";\r\n");

         for(int i = 0; i < split.length; ++i) {
            String sql = split[i];
            new ArrayList();
            new ArrayList();
            Map<String, String> whereStringList = new HashMap();
            Map<String, Object> stringObjectMap = (Map)stringObjectMapList.get(i);
            ArrayList<Column> columnList = (ArrayList)stringObjectMap.get("columnList");
            if (columnList == null || columnList.isEmpty()) {
               String sqlTmp = statementInformation.getSql().toLowerCase().trim();
               if (!sqlTmp.startsWith("delete")) {
                  return statementInformation.getSql();
               }
            }

            List<Map> whereList = (List)stringObjectMap.get("whereList");
            Boolean encFlag = false;
            Set encryFieldSet = new HashSet();
            if (whereList != null && !whereList.isEmpty()) {
               encFlag = this.encryption(ip, port, schema, encFlag, whereList, statementInformation.getReplaceInfo(), encryFieldSet);
               if (encFlag) {
                  sql = this.encryptionWhere(statementInformation, sqlUtil, sql, dbType, schema, whereList, whereStringList);
               }
            }

            returnSql = returnSql + sql + ";";
         }

         if (returnSql.endsWith(";")) {
            returnSql = returnSql.substring(0, returnSql.length() - 1);
         }
      } catch (Exception e1) {
         e1.printStackTrace();
         throw e1;
      }

      returnSql = returnSql.concat(" ").concat(sqlUser);
      return returnSql;
   }

   private String encryptionWhere(PreparedStatementInformation statementInformation, SqlUtil sqlUtil, String sql, String dbType, String schema, List<Map> whereList, Map<String, String> whereStringList) throws Exception {
      Map<String, String> params = new HashMap();
      params.put("encryption", "1");
      params.put("sql", sql);
      params.put("dbType", dbType);
      params.put("schema", schema);
      params.put("url", statementInformation.getConnectionInformation().getConnection().getMetaData().getURL());

      for(Map entry : whereList) {
         if (entry.get("columnValue") instanceof ArrayList) {
            ArrayList arrayList = (ArrayList)entry.get("columnValue");
            ArrayList valueList = new ArrayList();

            for(int v = 0; v < arrayList.size(); ++v) {
               if (arrayList.get(v) instanceof SQLCharExpr) {
                  valueList.add(((SQLCharExpr)arrayList.get(v)).getText());
               }
            }

            whereStringList.put((String)entry.get("column"), StringJoin.join(valueList, ","));
         } else {
            whereStringList.put((String)entry.get("column"), (String)entry.get("columnValue"));
         }
      }

      sql = sqlUtil.pareSqlReplaceValue2(params, whereList);
      return sql;
   }

   private void joinWhereStr(List<Map> whereList, StringBuffer sb, String lowerSql) {
      if (lowerSql.indexOf("where") > 0 && whereList.size() > 0) {
         sb.append(" where ");

         for(Map map : whereList) {
            sb.append(map.get("key")).append("=").append(map.get("value")).append(" and ");
         }

         sb.delete(sb.length() - 4, sb.length());
      }

   }

   private ArrayList<Column> sortColumns(ArrayList<Column> columnList, Collection<TableStat.Column> insertFields) {
      ArrayList<Column> sortColumnList = new ArrayList();
      if (!(insertFields instanceof ArrayList)) {
         return columnList;
      } else {
         List<TableStat.Column> insertList = (ArrayList)insertFields;

         for(int i = 0; i < insertList.size(); ++i) {
            for(Column column : columnList) {
               if (column.getColumnName().equalsIgnoreCase(((TableStat.Column)insertList.get(i)).getName())) {
                  sortColumnList.add(column);
                  break;
               }
            }
         }

         return sortColumnList;
      }
   }

   private Boolean encryption(String ip, String port, String schema, Boolean encFlag, List<Map> whereList, ReplaceInfo replaceInfo, Set encryFieldSet) throws Exception {
      for(Map<String, Object> whereMap : whereList) {
         String key = (String)whereMap.get("column");
         String columnName = key.contains(".") ? key.split("\\.")[2].replace("\"", "") : key.replace("\"", "");
         String tableName = key.contains(".") ? key.split("\\.")[1] : "";
         schema = key.contains(".") ? key.split("\\.")[0] : schema;
         if (!String.valueOf(whereMap.get("columnValue")).trim().equals("?")) {
            String mathKey = (ip + "_" + port + "_" + schema + "_" + tableName + "_" + columnName).toLowerCase().replace("`", "").replace("\"", "");
            if (EngineUtil.encryptionMap.isEmpty()) {
               EngineUtil.keyCacheFromFile();
            }

            boolean ismaksing = EngineUtil.encryptionMap.containsKey(mathKey);
            if ("1".equals(EncryptionGatewayManager.getParameterValue("replaceSql")) && replaceInfo != null) {
               String replaceColumn = ip + "_" + port + "_" + replaceInfo.getPrefix() + "_" + replaceInfo.getColumnName();
               if (mathKey.equals(replaceColumn)) {
                  continue;
               }
            }

            if (ismaksing) {
               Boolean flag = false;

               try {
                  Columninfo map = (Columninfo)EngineUtil.encryptionMap.get(mathKey);
                  Object value = whereMap.get("columnValue");
                  if (value != null) {
                     String type = (String)whereMap.get("type");
                     if (type.toUpperCase().equals("LIKE")) {
                        String likeValue = ((String)value).trim();
                        boolean beforeLike = false;
                        boolean afterLike = false;
                        if (!likeValue.equals("%%")) {
                           if (likeValue.startsWith("%")) {
                              likeValue = likeValue.substring(1);
                              beforeLike = true;
                           }

                           if (likeValue.endsWith("%")) {
                              likeValue = likeValue.substring(0, likeValue.length() - 1);
                              afterLike = true;
                           }

                           value = EngineUtil.exeEngine(map, (ConnectionInfo)null, flag, likeValue, true);
                           if (afterLike) {
                              value = value.toString().replace(ENCRYPT_SEPARATOR, "");
                           }
                        }

                        if (ENCRYPT_LIKE_OPEN.equals(map.getIsLike())) {
                           if (beforeLike) {
                              value = "%" + value;
                           }

                           if (afterLike) {
                              value = value + "%";
                           }
                        }
                     } else {
                        value = EngineUtil.exeEngine(map, (ConnectionInfo)null, flag, value, true);
                     }
                  }

                  whereMap.put("columnValue", value);
                  encFlag = true;
                  encryFieldSet.add(mathKey);
               } catch (Exception e1) {
                  e1.printStackTrace();
                  throw e1;
               } finally {
                  ;
               }
            }
         }
      }

      return encFlag;
   }

   private void getAllFields(PreparedStatementInformation statementInformation, String dbType, String schema, String tableName, ArrayList<Column> updateList) throws SQLException {
      List<Column> columnList = null;
      new ArrayList();
      if ("mysql".equals(dbType)) {
         JdbcUtil.getColumnOfMysql(statementInformation.getConnectionInformation().getConnection().createStatement(), schema, tableName);
      } else if ("oracle".equals(dbType)) {
         JdbcUtil.getColumnOfOracle(statementInformation.getConnectionInformation().getConnection().createStatement(), schema, tableName);
      } else if ("postgresql".equals(dbType)) {
         JdbcUtil.getColumnOfPostgresql(statementInformation.getConnectionInformation().getConnection().createStatement(), schema, tableName);
      } else if ("hive".equals(dbType)) {
         JdbcUtil.getColumnOfHive(statementInformation.getConnectionInformation().getConnection().createStatement(), schema, tableName);
      } else if ("dm".equals(dbType)) {
         JdbcUtil.getColumnOfDm(statementInformation.getConnectionInformation().getConnection().createStatement(), schema, tableName);
      } else if ("db2".equals(dbType)) {
         JdbcUtil.getColumnOfDb2(statementInformation.getConnectionInformation().getConnection().createStatement(), schema, tableName);
      } else if ("sql server".equals(dbType)) {
         JdbcUtil.getColumnOfSqlserver(statementInformation.getConnectionInformation().getConnection().createStatement(), schema, tableName);
      } else if ("kingbase".equals(dbType)) {
         JdbcUtil.getColumnOfKingbase(statementInformation.getConnectionInformation().getConnection().createStatement(), schema, tableName);
      } else if ("gbase".equals(dbType)) {
      }

      ArrayList<Column> finalUpdateList = updateList;

      for(Column col : updateList) {
         Column tm = new Column(col.getColumnName(), col.getSchema(), col.getTable(), col.getDataType());
         finalUpdateList.add(tm);
      }

   }

   private List<Object> getInsertSqlValueList(String sql, List<Object> valueList) {
      if (sql.indexOf("-- appUsername=") > 0) {
         sql = sql.substring(0, sql.indexOf("-- appUsername=")).trim();
      }

      String lowerSql = sql.toLowerCase();
      String[] split = lowerSql.split(";\r\n");

      for(String s : split) {
         if (s.contains("values")) {
            String tempsql = s.substring(s.indexOf("values") + 6);
            tempsql = tempsql.replaceFirst("\\(", "");
            tempsql = tempsql.replaceFirst("[\\\\)]+$", "");
            if (tempsql.trim().endsWith(";")) {
               tempsql = tempsql.trim().substring(0, tempsql.trim().length() - 1);
            }

            valueList.addAll(InsertSqlVaulesUtil.getTableColumnValueByMatchingSingleQuotes(tempsql.split(",")));
         }
      }

      return valueList;
   }

   private List<Map<String, Object>> sortColumns(PreparedStatementInformation statementInformation, String sql, String dbType, String schema) throws SQLException {
      Map<String, String> params = new HashMap();
      if (sql.indexOf("-- appUsername=") > 0) {
         sql = sql.substring(0, sql.indexOf("-- appUsername=")).trim();
      }

      params.put("sql", sql);
      params.put("dbType", dbType);
      params.put("schema", schema);
      params.put("encryption", "1");
      String url = statementInformation.getConnectionInformation().getConnection().getMetaData().getURL();
      params.put("url", url);
      SqlUtil sqlUtil = new SqlUtil();
      List<Map<String, Object>> maps = sqlUtil.parseSqlStructureEnc(params);
      if (maps != null && !maps.isEmpty()) {
         Map<String, Object> stringObjectMap = (Map)maps.get(0);
         if (!stringObjectMap.isEmpty()) {
            String trim = sql.toLowerCase().trim();
            if ((trim.startsWith("insert") || trim.startsWith("update")) && trim.contains("?")) {
               sqlParseMap.put(sql, maps);
            } else if (trim.startsWith("select")) {
               sqlParseMap.put(sql, maps);
            }

            statementInformation.sqlParse = maps;
         }
      }

      return maps;
   }

   public static String getDbType(String driverName, String url, String dbType) throws Exception {
      try {
         String dbTypeTmp = (String)StatementWrapper.dbTypeMap.get(driverName);
         if (dbTypeTmp != null && !dbTypeTmp.equals("")) {
            return dbTypeTmp;
         } else if (!url.toLowerCase().contains("jdbc:hive") && !url.toLowerCase().contains("jdbc:inceptor2") && !url.toLowerCase().contains("jdbc:transwarp2")) {
            String driverNameLower = driverName.toLowerCase();
            if (driverNameLower.contains("mysql")) {
               dbType = "mysql";
            } else if (driverNameLower.contains("oracle")) {
               dbType = "oracle";
            } else if (driverNameLower.contains("postgresql")) {
               dbType = "postgresql";
            } else if (driverNameLower.contains("vastbase")) {
               dbType = "postgresql";
            } else if (driverNameLower.contains("opengauss")) {
               dbType = "postgresql";
            } else if (driverNameLower.contains("hive")) {
               dbType = "hive";
            } else if (driverNameLower.contains("dm")) {
               dbType = "dm";
            } else if (driverNameLower.contains("ibm")) {
               dbType = "db2";
            } else if (driverNameLower.contains("sql server")) {
               dbType = "sql server";
            } else if (driverNameLower.contains("kingbase")) {
               dbType = "kingbase";
            } else if (driverNameLower.contains("vertica")) {
               dbType = "postgresql";
            }

            StatementWrapper.dbTypeMap.put(driverName, dbType);
            return dbType;
         } else {
            return "hive";
         }
      } catch (Exception e) {
         e.printStackTrace();
         throw e;
      }
   }

   public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
      RuleLoadUtil.writeLog("@@插件@@---connectionWrapper--->prepareStatement:" + sql);
      String url = this.delegate.getMetaData().getURL();
      Map<String, Object> stringObjectMap = this.digestSql(sql, url);
      sql = (String)stringObjectMap.get("sql");
      sql = sql + " -- appUsername=" + AppUser.loginUser() + "\r\n";
      PreparedStatementInformation statementInformation = new PreparedStatementInformation(this.connectionInformation, sql);
      AccessContext context = new AccessContext();
      statementInformation.context = context;
      statementInformation.setDigestMap((Map)stringObjectMap.get("digestColumns"));
      statementInformation.setStatementQuery(sql);
      context.setStatementInfo(statementInformation);
      if ("1".equals(EncryptionGatewayManager.getParameterValue("replaceSql"))) {
         Map<String, Object> sql1 = LikeReplaceSql.sqlLikeReplace(statementInformation);
         sql = (String)sql1.get("sql");
         statementInformation.setReplaceInfo((ReplaceInfo)sql1.get("replaceInfo"));
         statementInformation.setStatementQuery(sql);
      }

      if (DbCache.isNeedIntercept(sql, statementInformation) && GatewayContext.isPluginEnabled()) {
         try {
            sql = this.encData(statementInformation);
         } catch (Exception exception) {
            exception.printStackTrace();
            throw new SQLException(exception);
         }
      }

      return PreparedStatementWrapper.wrap(this.delegate.prepareStatement(sql, resultSetType, resultSetConcurrency), statementInformation, this.jdbcEventListener);
   }

   public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
      RuleLoadUtil.writeLog("@@插件@@---connectionWrapper--->prepareStatement:" + sql);
      String url = this.delegate.getMetaData().getURL();
      Map<String, Object> stringObjectMap = this.digestSql(sql, url);
      sql = (String)stringObjectMap.get("sql");
      sql = sql + " -- appUsername=" + AppUser.loginUser() + "\r\n";
      PreparedStatementInformation statementInformation = new PreparedStatementInformation(this.connectionInformation, sql);
      AccessContext context = new AccessContext();
      statementInformation.context = context;
      statementInformation.setDigestMap((Map)stringObjectMap.get("digestColumns"));
      statementInformation.setStatementQuery(sql);
      context.setStatementInfo(statementInformation);
      if ("1".equals(EncryptionGatewayManager.getParameterValue("replaceSql"))) {
         Map<String, Object> sql1 = LikeReplaceSql.sqlLikeReplace(statementInformation);
         sql = (String)sql1.get("sql");
         statementInformation.setReplaceInfo((ReplaceInfo)sql1.get("replaceInfo"));
         statementInformation.setStatementQuery(sql);
      }

      if (DbCache.isNeedIntercept(sql, statementInformation) && GatewayContext.isPluginEnabled()) {
         try {
            sql = this.encData(statementInformation);
         } catch (Exception exception) {
            exception.printStackTrace();
            throw new SQLException(exception);
         }
      }

      return PreparedStatementWrapper.wrap(this.delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability), statementInformation, this.jdbcEventListener);
   }

   public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
      RuleLoadUtil.writeLog("@@插件@@---connectionWrapper--->prepareStatement:" + sql);
      String url = this.delegate.getMetaData().getURL();
      Map<String, Object> stringObjectMap = this.digestSql(sql, url);
      sql = (String)stringObjectMap.get("sql");
      sql = sql + " -- appUsername=" + AppUser.loginUser() + "\r\n";
      PreparedStatementInformation statementInformation = new PreparedStatementInformation(this.connectionInformation, sql);
      AccessContext context = new AccessContext();
      statementInformation.context = context;
      statementInformation.setDigestMap((Map)stringObjectMap.get("digestColumns"));
      statementInformation.setStatementQuery(sql);
      context.setStatementInfo(statementInformation);
      if ("1".equals(EncryptionGatewayManager.getParameterValue("replaceSql"))) {
         Map<String, Object> sql1 = LikeReplaceSql.sqlLikeReplace(statementInformation);
         sql = (String)sql1.get("sql");
         statementInformation.setReplaceInfo((ReplaceInfo)sql1.get("replaceInfo"));
         statementInformation.setStatementQuery(sql);
      }

      if (DbCache.isNeedIntercept(sql, statementInformation) && GatewayContext.isPluginEnabled()) {
         try {
            sql = this.encData(statementInformation);
         } catch (Exception exception) {
            exception.printStackTrace();
            throw new SQLException(exception);
         }
      }

      return PreparedStatementWrapper.wrap(this.delegate.prepareStatement(sql, autoGeneratedKeys), statementInformation, this.jdbcEventListener);
   }

   public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
      RuleLoadUtil.writeLog("@@插件@@---connectionWrapper--->prepareStatement:" + sql);
      String url = this.delegate.getMetaData().getURL();
      Map<String, Object> stringObjectMap = this.digestSql(sql, url);
      sql = (String)stringObjectMap.get("sql");
      sql = sql + " -- appUsername=" + AppUser.loginUser() + "\r\n";
      PreparedStatementInformation statementInformation = new PreparedStatementInformation(this.connectionInformation, sql);
      AccessContext context = new AccessContext();
      statementInformation.context = context;
      statementInformation.setDigestMap((Map)stringObjectMap.get("digestColumns"));
      statementInformation.setStatementQuery(sql);
      context.setStatementInfo(statementInformation);
      if ("1".equals(EncryptionGatewayManager.getParameterValue("replaceSql"))) {
         Map<String, Object> sql1 = LikeReplaceSql.sqlLikeReplace(statementInformation);
         sql = (String)sql1.get("sql");
         statementInformation.setReplaceInfo((ReplaceInfo)sql1.get("replaceInfo"));
         statementInformation.setStatementQuery(sql);
      }

      if (DbCache.isNeedIntercept(sql, statementInformation) && GatewayContext.isPluginEnabled()) {
         try {
            sql = this.encData(statementInformation);
         } catch (Exception exception) {
            exception.printStackTrace();
            throw new SQLException(exception);
         }
      }

      return PreparedStatementWrapper.wrap(this.delegate.prepareStatement(sql, columnIndexes), statementInformation, this.jdbcEventListener);
   }

   public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
      RuleLoadUtil.writeLog("@@插件@@---connectionWrapper--->prepareStatement:" + sql);
      String url = this.delegate.getMetaData().getURL();
      Map<String, Object> stringObjectMap = this.digestSql(sql, url);
      sql = (String)stringObjectMap.get("sql");
      sql = sql + " -- appUsername=" + AppUser.loginUser() + "\r\n";
      PreparedStatementInformation statementInformation = new PreparedStatementInformation(this.connectionInformation, sql);
      AccessContext context = new AccessContext();
      statementInformation.context = context;
      statementInformation.setDigestMap((Map)stringObjectMap.get("digestColumns"));
      statementInformation.setStatementQuery(sql);
      context.setStatementInfo(statementInformation);
      if (DbCache.isNeedIntercept(sql, statementInformation) && GatewayContext.isPluginEnabled()) {
         try {
            sql = this.encData(statementInformation);
         } catch (Exception exception) {
            exception.printStackTrace();
            throw new SQLException(exception);
         }
      }

      return PreparedStatementWrapper.wrap(this.delegate.prepareStatement(sql, columnNames), statementInformation, this.jdbcEventListener);
   }

   public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
      return CallableStatementWrapper.wrap(this.delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability), new CallableStatementInformation(this.connectionInformation, sql), this.jdbcEventListener);
   }

   public CallableStatement prepareCall(String sql) throws SQLException {
      return CallableStatementWrapper.wrap(this.delegate.prepareCall(sql), new CallableStatementInformation(this.connectionInformation, sql), this.jdbcEventListener);
   }

   public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
      return CallableStatementWrapper.wrap(this.delegate.prepareCall(sql, resultSetType, resultSetConcurrency), new CallableStatementInformation(this.connectionInformation, sql), this.jdbcEventListener);
   }

   public void commit() throws SQLException {
      SQLException e = null;
      long start = System.nanoTime();

      try {
         this.jdbcEventListener.onBeforeCommit(this.connectionInformation);
         this.delegate.commit();
      } catch (SQLException sqle) {
         e = sqle;
         throw sqle;
      } finally {
         this.jdbcEventListener.onAfterCommit(this.connectionInformation, System.nanoTime() - start, e);
      }

   }

   public void rollback() throws SQLException {
      SQLException e = null;
      long start = System.nanoTime();

      try {
         this.jdbcEventListener.onBeforeRollback(this.connectionInformation);
         this.delegate.rollback();
      } catch (SQLException sqle) {
         e = sqle;
         throw sqle;
      } finally {
         this.jdbcEventListener.onAfterRollback(this.connectionInformation, System.nanoTime() - start, e);
      }

   }

   public void rollback(Savepoint savepoint) throws SQLException {
      SQLException e = null;
      long start = System.nanoTime();

      try {
         this.jdbcEventListener.onBeforeRollback(this.connectionInformation);
         this.delegate.rollback(savepoint);
      } catch (SQLException sqle) {
         e = sqle;
         throw sqle;
      } finally {
         this.jdbcEventListener.onAfterRollback(this.connectionInformation, System.nanoTime() - start, e);
      }

   }

   public String nativeSQL(String sql) throws SQLException {
      return this.delegate.nativeSQL(sql);
   }

   public void setAutoCommit(boolean autoCommit) throws SQLException {
      SQLException e = null;
      boolean oldAutoCommit = this.delegate.getAutoCommit();

      try {
         this.jdbcEventListener.onBeforeSetAutoCommit(this.connectionInformation, autoCommit, oldAutoCommit);
         this.delegate.setAutoCommit(autoCommit);
      } catch (SQLException sqle) {
         e = sqle;
         throw sqle;
      } finally {
         this.jdbcEventListener.onAfterSetAutoCommit(this.connectionInformation, autoCommit, oldAutoCommit, e);
      }

   }

   public boolean getAutoCommit() throws SQLException {
      return this.delegate.getAutoCommit();
   }

   public void close() throws SQLException {
      SQLException e = null;
      long start = System.nanoTime();

      try {
         this.delegate.close();
      } catch (SQLException sqle) {
         e = sqle;
         throw sqle;
      } finally {
         this.connectionInformation.setTimeToCloseConnectionNs(System.nanoTime() - start);
         this.jdbcEventListener.onAfterConnectionClose(this.connectionInformation, e);
      }

   }

   public boolean isClosed() throws SQLException {
      return this.delegate.isClosed();
   }

   public DatabaseMetaData getMetaData() throws SQLException {
      return this.delegate.getMetaData();
   }

   public void setReadOnly(boolean readOnly) throws SQLException {
      this.delegate.setReadOnly(readOnly);
   }

   public boolean isReadOnly() throws SQLException {
      return this.delegate.isReadOnly();
   }

   public void setCatalog(String catalog) throws SQLException {
      this.delegate.setCatalog(catalog);
   }

   public String getCatalog() throws SQLException {
      return this.delegate.getCatalog();
   }

   public void setTransactionIsolation(int level) throws SQLException {
      this.delegate.setTransactionIsolation(level);
   }

   public int getTransactionIsolation() throws SQLException {
      return this.delegate.getTransactionIsolation();
   }

   public SQLWarning getWarnings() throws SQLException {
      return this.delegate.getWarnings();
   }

   public void clearWarnings() throws SQLException {
      this.delegate.clearWarnings();
   }

   public Map<String, Class<?>> getTypeMap() throws SQLException {
      return this.delegate.getTypeMap();
   }

   public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
      this.delegate.setTypeMap(map);
   }

   public void setHoldability(int holdability) throws SQLException {
      this.delegate.setHoldability(holdability);
   }

   public int getHoldability() throws SQLException {
      return this.delegate.getHoldability();
   }

   public Savepoint setSavepoint() throws SQLException {
      return this.delegate.setSavepoint();
   }

   public Savepoint setSavepoint(String name) throws SQLException {
      return this.delegate.setSavepoint(name);
   }

   public void releaseSavepoint(Savepoint savepoint) throws SQLException {
      this.delegate.releaseSavepoint(savepoint);
   }

   public Clob createClob() throws SQLException {
      return this.delegate.createClob();
   }

   public Blob createBlob() throws SQLException {
      return this.delegate.createBlob();
   }

   public NClob createNClob() throws SQLException {
      return this.delegate.createNClob();
   }

   public SQLXML createSQLXML() throws SQLException {
      return this.delegate.createSQLXML();
   }

   public boolean isValid(int timeout) throws SQLException {
      return this.delegate.isValid(timeout);
   }

   public void setClientInfo(String name, String value) throws SQLClientInfoException {
      this.delegate.setClientInfo(name, value);
   }

   public void setClientInfo(Properties properties) throws SQLClientInfoException {
      this.delegate.setClientInfo(properties);
   }

   public String getClientInfo(String name) throws SQLException {
      return this.delegate.getClientInfo(name);
   }

   public Properties getClientInfo() throws SQLException {
      return this.delegate.getClientInfo();
   }

   public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
      return this.delegate.createArrayOf(typeName, elements);
   }

   public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
      return this.delegate.createStruct(typeName, attributes);
   }

   public void setSchema(String schema) throws SQLException {
   }

   public String getSchema() throws SQLException {
      return this.delegate.getCatalog();
   }

   public void abort(Executor executor) throws SQLException {
   }

   public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
   }

   public int getNetworkTimeout() throws SQLException {
      return 0;
   }

   public Map<String, Object> digestSql(String sql, String url) {
      Map<String, Object> returnMap = new HashMap();
      Map<String, Integer> map = new HashMap();
      returnMap.put("sql", sql);
      returnMap.put("digestColumns", map);
      if (!EngineUtil.digestMap.isEmpty()) {
         if (sql.toLowerCase().trim().startsWith("insert") || sql.toLowerCase().trim().startsWith("update")) {
            int count = 0;
            if (sql.toLowerCase().trim().startsWith("insert") && !sql.toLowerCase().contains("select")) {
               for(int i = 0; i < sql.length(); ++i) {
                  if (sql.charAt(i) == '?') {
                     ++count;
                  }
               }
            } else if (sql.toLowerCase().trim().startsWith("update")) {
               String sqlTemp = sql.toLowerCase();
               if (sql.toLowerCase().contains("where")) {
                  sqlTemp = sqlTemp.substring(0, sqlTemp.toLowerCase().indexOf("where"));
               }

               for(int i = 0; i < sqlTemp.length(); ++i) {
                  if (sql.charAt(i) == '?') {
                     ++count;
                  }
               }
            }

            String addColumns = "";
            String addColumnsValue = "";
            int s = sql.indexOf("where");
            String sqlTemp = s == -1 ? sql.toLowerCase() : sql.substring(0, s).toLowerCase();
            String sqlTable = "";
            String[] sqlColumns = new String[0];
            if (sql.toLowerCase().trim().startsWith("insert")) {
               sqlTemp = this.removeFirstOccurrence(this.removeFirstOccurrence(sqlTemp, "insert"), "into");
               sqlTemp = sqlTemp.replace(" ", "").replace("\n", "").replace("\t", "");
               sqlTemp = sqlTemp.substring(0, sqlTemp.indexOf(")values("));
               sqlTable = sqlTemp.split("\\(")[0];
               sqlTemp = sqlTemp.substring(sqlTemp.indexOf("(") + 1);
               sqlColumns = sqlTemp.split(",");
            } else if (sql.toLowerCase().trim().startsWith("update")) {
               sqlTemp = this.removeFirstOccurrence(sqlTemp, "update").replace("\n", "").replace("\t", "");
               sqlTable = sqlTemp.substring(0, sqlTemp.indexOf(" set ")).replace(" ", "");
               sqlTemp = this.removeFirstOccurrence(sqlTemp, sqlTable);
               sqlTemp = sqlTemp.substring(sqlTemp.indexOf("set") + 3).replace(" ", "").replace("=?", "");
               sqlColumns = sqlTemp.split(",");
            }

            Map<String, String> ipAndPort = TestJdbcEventListener.getIpAndPort(url);
            if (count > 0) {
               for(String key : EngineUtil.digestMap.keySet()) {
                  String[] split = key.split("@@");
                  if (((String)ipAndPort.get("ip")).equals(split[0]) && ((String)ipAndPort.get("port")).equals(split[1])) {
                     String tableName = split[3];
                     String columnName = split[4];
                     if (sqlTable.contains(tableName) && Arrays.asList(sqlColumns).contains(columnName)) {
                        ++count;
                        map.put(tableName + "@@" + columnName, count);
                        if (sql.toLowerCase().trim().startsWith("insert")) {
                           addColumns = addColumns + "," + columnName + "_enc ";
                           addColumnsValue = addColumnsValue + ", ? ";
                        } else if (sql.toLowerCase().trim().startsWith("update")) {
                           addColumnsValue = addColumnsValue + "," + columnName + "_enc = ? ";
                        }
                     }
                  }
               }

               if (sql.toLowerCase().trim().startsWith("insert") && !"".equals(addColumns)) {
                  int i = sql.indexOf(")");
                  int n = sql.lastIndexOf(")");
                  String insert = sql.substring(0, i);
                  String middle = sql.substring(i, n);
                  String last = sql.substring(n);
                  sql = insert + addColumns + middle + addColumnsValue + last;
               } else if (sql.toLowerCase().trim().startsWith("update") && !"".equals(addColumnsValue)) {
                  int i = sql.toLowerCase().indexOf("where");
                  if (i == -1) {
                     sql = sql + addColumnsValue;
                  } else {
                     String update = sql.substring(0, i);
                     String where = sql.substring(i);
                     sql = update + addColumnsValue + where;
                  }
               }
            }
         }

         returnMap.put("digestColumns", map);
         returnMap.put("sql", sql);
      }

      return returnMap;
   }
}
