content: /*
   * Copyright (c) 2013. wyouflf (wyouflf@gmail.com)
   *
   * 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.lidroid.xutils;
  
  import android.content.Context;
  import android.database.Cursor;
  import android.database.sqlite.SQLiteDatabase;
  import android.text.TextUtils;
  import com.lidroid.xutils.db.sqlite.*;
  import com.lidroid.xutils.db.table.DbModel;
  import com.lidroid.xutils.db.table.Id;
  import com.lidroid.xutils.db.table.Table;
  import com.lidroid.xutils.db.table.TableUtils;
  import com.lidroid.xutils.exception.DbException;
  import com.lidroid.xutils.util.IOUtils;
  import com.lidroid.xutils.util.LogUtils;
  
  import java.io.File;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.concurrent.ConcurrentHashMap;
  import java.util.concurrent.locks.Lock;
  import java.util.concurrent.locks.ReentrantLock;
  
  public class DbUtils {
  
      //*************************************** create instance ****************************************************
  
      /**
       * key: dbName
       */
      private static HashMap<String, DbUtils> daoMap = new HashMap<String, DbUtils>();
  
      private SQLiteDatabase database;
      private DaoConfig daoConfig;
      private boolean debug = false;
      private boolean allowTransaction = false;
  
      private DbUtils(DaoConfig config) {
          if (config == null) {
              throw new IllegalArgumentException("daoConfig may not be null");
          }
          this.database = createDatabase(config);
          this.daoConfig = config;
      }
  
  
      private synchronized static DbUtils getInstance(DaoConfig daoConfig) {
          DbUtils dao = daoMap.get(daoConfig.getDbName());
          if (dao == null) {
              dao = new DbUtils(daoConfig);
              daoMap.put(daoConfig.getDbName(), dao);
          } else {
              dao.daoConfig = daoConfig;
          }
  
          // update the database if needed
          SQLiteDatabase database = dao.database;
          int oldVersion = database.getVersion();
          int newVersion = daoConfig.getDbVersion();
          if (oldVersion != newVersion) { //数据库升级
              if (oldVersion != 0) {
                  DbUpgradeListener upgradeListener = daoConfig.getDbUpgradeListener();
                  if (upgradeListener != null) {
                      upgradeListener.onUpgrade(dao, oldVersion, newVersion);
                  } else {
                      try {
                          dao.dropDb();
                      } catch (DbException e) {
                          LogUtils.e(e.getMessage(), e);
                      }
                  }
              }
              database.setVersion(newVersion);
          }
  
          return dao;
      }
  
      public static DbUtils create(Context context) {
          DaoConfig config = new DaoConfig(context);
          return getInstance(config);
      }
  
      public static DbUtils create(Context context, String dbName) {
          DaoConfig config = new DaoConfig(context);
          config.setDbName(dbName);
          return getInstance(config);
      }
  
      public static DbUtils create(Context context, String dbDir, String dbName) {
          DaoConfig config = new DaoConfig(context);
          config.setDbDir(dbDir);
          config.setDbName(dbName);
          return getInstance(config);
      }
  
      public static DbUtils create(Context context, String dbName, int dbVersion, DbUpgradeListener dbUpgradeListener) {
          DaoConfig config = new DaoConfig(context);
          config.setDbName(dbName);
          config.setDbVersion(dbVersion);
          config.setDbUpgradeListener(dbUpgradeListener);
          return getInstance(config);
      }
  
      public static DbUtils create(Context context, String dbDir, String dbName, int dbVersion, DbUpgradeListener dbUpgradeListener) {
          DaoConfig config = new DaoConfig(context);
          config.setDbDir(dbDir);
          config.setDbName(dbName);
          config.setDbVersion(dbVersion);
          config.setDbUpgradeListener(dbUpgradeListener);
          return getInstance(config);
      }
  
      public static DbUtils create(DaoConfig daoConfig) {
          return getInstance(daoConfig);
      }
  
      public DbUtils configDebug(boolean debug) {
          this.debug = debug;
          return this;
      }
  
      public DbUtils configAllowTransaction(boolean allowTransaction) {
          this.allowTransaction = allowTransaction;
          return this;
      }
  
      public SQLiteDatabase getDatabase() {
          return database;
      }
  
      public DaoConfig getDaoConfig() {
          return daoConfig;
      }
  
      //*********************************************** operations ********************************************************
  
      public void saveOrUpdate(Object entity) throws DbException {
          try {
              beginTransaction();
  
              createTableIfNotExist(entity.getClass());
              saveOrUpdateWithoutTransaction(entity);
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
      }
  
      public void saveOrUpdateAll(List<?> entities) throws DbException {
          if (entities == null || entities.size() == 0) return;
          try {
              beginTransaction();
  
              createTableIfNotExist(entities.get(0).getClass());
              for (Object entity : entities) {
                  saveOrUpdateWithoutTransaction(entity);
              }
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
      }
  
      public void replace(Object entity) throws DbException {
          try {
              beginTransaction();
  
              createTableIfNotExist(entity.getClass());
              execNonQuery(SqlInfoBuilder.buildReplaceSqlInfo(this, entity));
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
      }
  
      public void replaceAll(List<?> entities) throws DbException {
          if (entities == null || entities.size() == 0) return;
          try {
              beginTransaction();
  
              createTableIfNotExist(entities.get(0).getClass());
              for (Object entity : entities) {
                  execNonQuery(SqlInfoBuilder.buildReplaceSqlInfo(this, entity));
              }
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
      }
  
      public void save(Object entity) throws DbException {
          try {
              beginTransaction();
  
              createTableIfNotExist(entity.getClass());
              execNonQuery(SqlInfoBuilder.buildInsertSqlInfo(this, entity));
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
      }
  
      public void saveAll(List<?> entities) throws DbException {
          if (entities == null || entities.size() == 0) return;
          try {
              beginTransaction();
  
              createTableIfNotExist(entities.get(0).getClass());
              for (Object entity : entities) {
                  execNonQuery(SqlInfoBuilder.buildInsertSqlInfo(this, entity));
              }
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
      }
  
      public boolean saveBindingId(Object entity) throws DbException {
          boolean result = false;
          try {
              beginTransaction();
  
              createTableIfNotExist(entity.getClass());
              result = saveBindingIdWithoutTransaction(entity);
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
          return result;
      }
  
      public void saveBindingIdAll(List<?> entities) throws DbException {
          if (entities == null || entities.size() == 0) return;
          try {
              beginTransaction();
  
              createTableIfNotExist(entities.get(0).getClass());
              for (Object entity : entities) {
                  if (!saveBindingIdWithoutTransaction(entity)) {
                      throw new DbException("saveBindingId error, transaction will not commit!");
                  }
              }
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
      }
  
      public void deleteById(Class<?> entityType, Object idValue) throws DbException {
          if (!tableIsExist(entityType)) return;
          try {
              beginTransaction();
  
              execNonQuery(SqlInfoBuilder.buildDeleteSqlInfo(this, entityType, idValue));
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
      }
  
      public void delete(Object entity) throws DbException {
          if (!tableIsExist(entity.getClass())) return;
          try {
              beginTransaction();
  
              execNonQuery(SqlInfoBuilder.buildDeleteSqlInfo(this, entity));
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
      }
  
      public void delete(Class<?> entityType, WhereBuilder whereBuilder) throws DbException {
          if (!tableIsExist(entityType)) return;
          try {
              beginTransaction();
  
              execNonQuery(SqlInfoBuilder.buildDeleteSqlInfo(this, entityType, whereBuilder));
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
      }
  
      public void deleteAll(List<?> entities) throws DbException {
          if (entities == null || entities.size() == 0 || !tableIsExist(entities.get(0).getClass())) return;
          try {
              beginTransaction();
  
              for (Object entity : entities) {
                  execNonQuery(SqlInfoBuilder.buildDeleteSqlInfo(this, entity));
              }
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
      }
  
      public void deleteAll(Class<?> entityType) throws DbException {
          delete(entityType, null);
      }
  
      public void update(Object entity, String... updateColumnNames) throws DbException {
          if (!tableIsExist(entity.getClass())) return;
          try {
              beginTransaction();
  
              execNonQuery(SqlInfoBuilder.buildUpdateSqlInfo(this, entity, updateColumnNames));
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
      }
  
      public void update(Object entity, WhereBuilder whereBuilder, String... updateColumnNames) throws DbException {
          if (!tableIsExist(entity.getClass())) return;
          try {
              beginTransaction();
  
              execNonQuery(SqlInfoBuilder.buildUpdateSqlInfo(this, entity, whereBuilder, updateColumnNames));
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
      }
  
      public void updateAll(List<?> entities, String... updateColumnNames) throws DbException {
          if (entities == null || entities.size() == 0 || !tableIsExist(entities.get(0).getClass())) return;
          try {
              beginTransaction();
  
              for (Object entity : entities) {
                  execNonQuery(SqlInfoBuilder.buildUpdateSqlInfo(this, entity, updateColumnNames));
              }
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
      }
  
      public void updateAll(List<?> entities, WhereBuilder whereBuilder, String... updateColumnNames) throws DbException {
          if (entities == null || entities.size() == 0 || !tableIsExist(entities.get(0).getClass())) return;
          try {
              beginTransaction();
  
              for (Object entity : entities) {
                  execNonQuery(SqlInfoBuilder.buildUpdateSqlInfo(this, entity, whereBuilder, updateColumnNames));
              }
  
              setTransactionSuccessful();
          } finally {
              endTransaction();
          }
      }
  
      @SuppressWarnings("unchecked")
      public <T> T findById(Class<T> entityType, Object idValue) throws DbException {
          if (!tableIsExist(entityType)) return null;
  
          Table table = Table.get(this, entityType);
          Selector selector = Selector.from(entityType).where(table.id.getColumnName(), "=", idValue);
  
          String sql = selector.limit(1).toString();
          long seq = CursorUtils.FindCacheSequence.getSeq();
          findTempCache.setSeq(seq);
          Object obj = findTempCache.get(sql);
          if (obj != null) {
              return (T) obj;
          }
  
          Cursor cursor = execQuery(sql);
          if (cursor != null) {
              try {
                  if (cursor.moveToNext()) {
                      T entity = (T) CursorUtils.getEntity(this, cursor, entityType, seq);
                      findTempCache.put(sql, entity);
                      return entity;
                  }
              } catch (Throwable e) {
                  throw new DbException(e);
              } finally {
                  IOUtils.closeQuietly(cursor);
              }
          }
          return null;
      }
  
      @SuppressWarnings("unchecked")
      public <T> T findFirst(Selector selector) throws DbException {
          if (!tableIsExist(selector.getEntityType())) return null;
  
          String sql = selector.limit(1).toString();
          long seq = CursorUtils.FindCacheSequence.getSeq();
          findTempCache.setSeq(seq);
          Object obj = findTempCache.get(sql);
          if (obj != null) {
              return (T) obj;
          }
  
          Cursor cursor = execQuery(sql);
          if (cursor != null) {
              try {
                  if (cursor.moveToNext()) {
                      T entity = (T) CursorUtils.getEntity(this, cursor, selector.getEntityType(), seq);
                      findTempCache.put(sql, entity);
                      return entity;
                  }
              } catch (Throwable e) {
                  throw new DbException(e);
              } finally {
                  IOUtils.closeQuietly(cursor);
              }
          }
          return null;
      }
  
      public <T> T findFirst(Class<T> entityType) throws DbException {
          return findFirst(Selector.from(entityType));
      }
  
      @SuppressWarnings("unchecked")
      public <T> List<T> findAll(Selector selector) throws DbException {
          if (!tableIsExist(selector.getEntityType())) return null;
  
          String sql = selector.toString();
          long seq = CursorUtils.FindCacheSequence.getSeq();
          findTempCache.setSeq(seq);
          Object obj = findTempCache.get(sql);
          if (obj != null) {
              return (List<T>) obj;
          }
  
          List<T> result = new ArrayList<T>();
  
          Cursor cursor = execQuery(sql);
          if (cursor != null) {
              try {
                  while (cursor.moveToNext()) {
                      T entity = (T) CursorUtils.getEntity(this, cursor, selector.getEntityType(), seq);
                      result.add(entity);
                  }
                  findTempCache.put(sql, result);
              } catch (Throwable e) {
                  throw new DbException(e);
              } finally {
                  IOUtils.closeQuietly(cursor);
              }
          }
          return result;
      }
  
      public <T> List<T> findAll(Class<T> entityType) throws DbException {
          return findAll(Selector.from(entityType));
      }
  
      public DbModel findDbModelFirst(SqlInfo sqlInfo) throws DbException {
          Cursor cursor = execQuery(sqlInfo);
          if (cursor != null) {
              try {
                  if (cursor.moveToNext()) {
                      return CursorUtils.getDbModel(cursor);
                  }
              } catch (Throwable e) {
                  throw new DbException(e);
              } finally {
                  IOUtils.closeQuietly(cursor);
              }
          }
          return null;
      }
  
      public DbModel findDbModelFirst(DbModelSelector selector) throws DbException {
          if (!tableIsExist(selector.getEntityType())) return null;
  
          Cursor cursor = execQuery(selector.limit(1).toString());
          if (cursor != null) {
              try {
                  if (cursor.moveToNext()) {
                      return CursorUtils.getDbModel(cursor);
                  }
              } catch (Throwable e) {
                  throw new DbException(e);
              } finally {
                  IOUtils.closeQuietly(cursor);
              }
          }
          return null;
      }
  
      public List<DbModel> findDbModelAll(SqlInfo sqlInfo) throws DbException {
          List<DbModel> dbModelList = new ArrayList<DbModel>();
  
          Cursor cursor = execQuery(sqlInfo);
          if (cursor != null) {
              try {
                  while (cursor.moveToNext()) {
                      dbModelList.add(CursorUtils.getDbModel(cursor));
                  }
              } catch (Throwable e) {
                  throw new DbException(e);
              } finally {
                  IOUtils.closeQuietly(cursor);
              }
          }
          return dbModelList;
      }
  
      public List<DbModel> findDbModelAll(DbModelSelector selector) throws DbException {
          if (!tableIsExist(selector.getEntityType())) return null;
  
          List<DbModel> dbModelList = new ArrayList<DbModel>();
  
          Cursor cursor = execQuery(selector.toString());
          if (cursor != null) {
              try {
                  while (cursor.moveToNext()) {
                      dbModelList.add(CursorUtils.getDbModel(cursor));
                  }
              } catch (Throwable e) {
                  throw new DbException(e);
              } finally {
                  IOUtils.closeQuietly(cursor);
              }
          }
          return dbModelList;
      }
  
      public long count(Selector selector) throws DbException {
          Class<?> entityType = selector.getEntityType();
          if (!tableIsExist(entityType)) return 0;
  
          Table table = Table.get(this, entityType);
          DbModelSelector dmSelector = selector.select("count(" + table.id.getColumnName() + ") as count");
          return findDbModelFirst(dmSelector).getLong("count");
      }
  
      public long count(Class<?> entityType) throws DbException {
          return count(Selector.from(entityType));
      }
  
      //******************************************** config ******************************************************
  
      public static class DaoConfig {
          private Context context;
          private String dbName = "xUtils.db"; // default db name
          private int dbVersion = 1;
          private DbUpgradeListener dbUpgradeListener;
  
          private String dbDir;
  
          public DaoConfig(Context context) {
              this.context = context.getApplicationContext();
          }
  
          public Context getContext() {
              return context;
          }
  
          public String getDbName() {
              return dbName;
          }
  
          public void setDbName(String dbName) {
              if (!TextUtils.isEmpty(dbName)) {
                  this.dbName = dbName;
              }
          }
  
          public int getDbVersion() {
              return dbVersion;
          }
  
          public void setDbVersion(int dbVersion) {
              this.dbVersion = dbVersion;
          }
  
          public DbUpgradeListener getDbUpgradeListener() {
              return dbUpgradeListener;
          }
  
          public void setDbUpgradeListener(DbUpgradeListener dbUpgradeListener) {
              this.dbUpgradeListener = dbUpgradeListener;
          }
  
          public String getDbDir() {
              return dbDir;
          }
  
          /**
           * set database dir
           *
           * @param dbDir If dbDir is null or empty, use the app default db dir.
           */
          public void setDbDir(String dbDir) {
              this.dbDir = dbDir;
          }
      }
  
      public interface DbUpgradeListener {
          public void onUpgrade(DbUtils db, int oldVersion, int newVersion);
      }
  
      private SQLiteDatabase createDatabase(DaoConfig config) {
          SQLiteDatabase result = null;
  
          String dbDir = config.getDbDir();
          if (!TextUtils.isEmpty(dbDir)) {
              File dir = new File(dbDir);
              if (dir.exists() || dir.mkdirs()) {
                  File dbFile = new File(dbDir, config.getDbName());
                  result = SQLiteDatabase.openOrCreateDatabase(dbFile, null);
              }
          } else {
              result = config.getContext().openOrCreateDatabase(config.getDbName(), 0, null);
          }
          return result;
      }
  
      //***************************** private operations with out transaction *****************************
      private void saveOrUpdateWithoutTransaction(Object entity) throws DbException {
          Table table = Table.get(this, entity.getClass());
          Id id = table.id;
          if (id.isAutoIncrement()) {
              if (id.getColumnValue(entity) != null) {
                  execNonQuery(SqlInfoBuilder.buildUpdateSqlInfo(this, entity));
              } else {
                  saveBindingIdWithoutTransaction(entity);
              }
          } else {
              execNonQuery(SqlInfoBuilder.buildReplaceSqlInfo(this, entity));
          }
      }
  
      private boolean saveBindingIdWithoutTransaction(Object entity) throws DbException {
          Class<?> entityType = entity.getClass();
          Table table = Table.get(this, entityType);
          Id idColumn = table.id;
          if (idColumn.isAutoIncrement()) {
              execNonQuery(SqlInfoBuilder.buildInsertSqlInfo(this, entity));
              long id = getLastAutoIncrementId(table.tableName);
              if (id == -1) {
                  return false;
              }
              idColumn.setAutoIncrementId(entity, id);
              return true;
          } else {
              execNonQuery(SqlInfoBuilder.buildInsertSqlInfo(this, entity));
              return true;
          }
      }
  
      //************************************************ tools ***********************************
  
      private long getLastAutoIncrementId(String tableName) throws DbException {
          long id = -1;
          Cursor cursor = execQuery("SELECT seq FROM sqlite_sequence WHERE name='" + tableName + "'");
          if (cursor != null) {
              try {
                  if (cursor.moveToNext()) {
                      id = cursor.getLong(0);
                  }
              } catch (Throwable e) {
                  throw new DbException(e);
              } finally {
                  IOUtils.closeQuietly(cursor);
              }
          }
          return id;
      }
  
      public void createTableIfNotExist(Class<?> entityType) throws DbException {
          if (!tableIsExist(entityType)) {
              SqlInfo sqlInfo = SqlInfoBuilder.buildCreateTableSqlInfo(this, entityType);
              execNonQuery(sqlInfo);
              String execAfterTableCreated = TableUtils.getExecAfterTableCreated(entityType);
              if (!TextUtils.isEmpty(execAfterTableCreated)) {
                  execNonQuery(execAfterTableCreated);
              }
          }
      }
  
      public boolean tableIsExist(Class<?> entityType) throws DbException {
          Table table = Table.get(this, entityType);
          if (table.isCheckedDatabase()) {
              return true;
          }
  
          Cursor cursor = execQuery("SELECT COUNT(*) AS c FROM sqlite_master WHERE type='table' AND name='" + table.tableName + "'");
          if (cursor != null) {
              try {
                  if (cursor.moveToNext()) {
                      int count = cursor.getInt(0);
                      if (count > 0) {
                          table.setCheckedDatabase(true);
                          return true;
                      }
                  }
              } catch (Throwable e) {
                  throw new DbException(e);
              } finally {
                  IOUtils.closeQuietly(cursor);
              }
          }
  
          return false;
      }
  
      public void dropDb() throws DbException {
          Cursor cursor = execQuery("SELECT name FROM sqlite_master WHERE type='table' AND name<>'sqlite_sequence'");
          if (cursor != null) {
              try {
                  while (cursor.moveToNext()) {
                      try {
                          String tableName = cursor.getString(0);
                          execNonQuery("DROP TABLE " + tableName);
                          Table.remove(this, tableName);
                      } catch (Throwable e) {
                          LogUtils.e(e.getMessage(), e);
                      }
                  }
  
              } catch (Throwable e) {
                  throw new DbException(e);
              } finally {
                  IOUtils.closeQuietly(cursor);
              }
          }
      }
  
      public void dropTable(Class<?> entityType) throws DbException {
          if (!tableIsExist(entityType)) return;
          String tableName = TableUtils.getTableName(entityType);
          execNonQuery("DROP TABLE " + tableName);
          Table.remove(this, entityType);
      }
  
      public void close() {
          String dbName = this.daoConfig.getDbName();
          if (daoMap.containsKey(dbName)) {
              daoMap.remove(dbName);
              this.database.close();
          }
      }
  
      ///////////////////////////////////// exec sql /////////////////////////////////////////////////////
      private void debugSql(String sql) {
          if (debug) {
              LogUtils.d(sql);
          }
      }
  
      private Lock writeLock = new ReentrantLock();
      private volatile boolean writeLocked = false;
  
      private void beginTransaction() {
          if (allowTransaction) {
              database.beginTransaction();
          } else {
              writeLock.lock();
              writeLocked = true;
          }
      }
  
      private void setTransactionSuccessful() {
          if (allowTransaction) {
              database.setTransactionSuccessful();
          }
      }
  
      private void endTransaction() {
          if (allowTransaction) {
              database.endTransaction();
          }
          if (writeLocked) {
              writeLock.unlock();
              writeLocked = false;
          }
      }
  
  
      public void execNonQuery(SqlInfo sqlInfo) throws DbException {
          debugSql(sqlInfo.getSql());
          try {
              if (sqlInfo.getBindArgs() != null) {
                  database.execSQL(sqlInfo.getSql(), sqlInfo.getBindArgsAsArray());
              } else {
                  database.execSQL(sqlInfo.getSql());
              }
          } catch (Throwable e) {
              throw new DbException(e);
          }
      }
  
      public void execNonQuery(String sql) throws DbException {
          debugSql(sql);
          try {
              database.execSQL(sql);
          } catch (Throwable e) {
              throw new DbException(e);
          }
      }
  
      public Cursor execQuery(SqlInfo sqlInfo) throws DbException {
          debugSql(sqlInfo.getSql());
          try {
              return database.rawQuery(sqlInfo.getSql(), sqlInfo.getBindArgsAsStrArray());
          } catch (Throwable e) {
              throw new DbException(e);
          }
      }
  
      public Cursor execQuery(String sql) throws DbException {
          debugSql(sql);
          try {
              return database.rawQuery(sql, null);
          } catch (Throwable e) {
              throw new DbException(e);
          }
      }
  
      /////////////////////// temp cache ////////////////////////////////////////////////////////////////
      private final FindTempCache findTempCache = new FindTempCache();
  
      private class FindTempCache {
          private FindTempCache() {
          }
  
          /**
           * key: sql;
           * value: find result
           */
          private final ConcurrentHashMap<String, Object> cache = new ConcurrentHashMap<String, Object>();
  
          private long seq = 0;
  
          public void put(String sql, Object result) {
              if (sql != null && result != null) {
                  cache.put(sql, result);
              }
          }
  
          public Object get(String sql) {
              return cache.get(sql);
          }
  
          public void setSeq(long seq) {
              if (this.seq != seq) {
                  cache.clear();
                  this.seq = seq;
              }
          }
      }
  
  }
  