Merge pull request #34 from RajashekharInmobi/master

[LENS-1545]: Fixed a Bug and made changes for PreparedQuery.
diff --git a/lens-cube/src/main/java/org/apache/lens/cube/metadata/CubeMetastoreClient.java b/lens-cube/src/main/java/org/apache/lens/cube/metadata/CubeMetastoreClient.java
index 34069d9..357d4de 100644
--- a/lens-cube/src/main/java/org/apache/lens/cube/metadata/CubeMetastoreClient.java
+++ b/lens-cube/src/main/java/org/apache/lens/cube/metadata/CubeMetastoreClient.java
@@ -1830,30 +1830,19 @@
         for (UpdatePeriod updatePeriod : updatePeriods) {
           tableNames.add(updatePeriodToTableMap.get(updatePeriod));
         }
-        if (tableNames.size() <= 1) {
-          XStorageTableElement tblElement = JAXBUtils.getXStorageTableFromHiveTable(
-            getHiveTable(MetastoreUtil.getFactOrDimtableStorageTableName(cft.getName(), storageName)));
-          tblElement.setStorageName(storageName);
-          for (UpdatePeriod p : updatePeriods) {
-            tblElement.getUpdatePeriods().getUpdatePeriod().add(XUpdatePeriod.valueOf(p.name()));
-          }
-          factTable.getStorageTables().getStorageTable().add(tblElement);
-        } else {
-          // Multiple storage tables.
-          XStorageTableElement tblElement = new XStorageTableElement();
-          tblElement.setStorageName(storageName);
-          XUpdatePeriods xUpdatePeriods = new XUpdatePeriods();
-          tblElement.setUpdatePeriods(xUpdatePeriods);
-          for (Map.Entry entry : updatePeriodToTableMap.entrySet()) {
-            XUpdatePeriodTableDescriptor updatePeriodTableDescriptor = new XUpdatePeriodTableDescriptor();
-            updatePeriodTableDescriptor.setTableDesc(getStorageTableDescFromHiveTable(
+        XStorageTableElement tblElement = new XStorageTableElement();
+        tblElement.setStorageName(storageName);
+        XUpdatePeriods xUpdatePeriods = new XUpdatePeriods();
+        tblElement.setUpdatePeriods(xUpdatePeriods);
+        for (Map.Entry entry : updatePeriodToTableMap.entrySet()) {
+          XUpdatePeriodTableDescriptor updatePeriodTableDescriptor = new XUpdatePeriodTableDescriptor();
+          updatePeriodTableDescriptor.setTableDesc(getStorageTableDescFromHiveTable(
               this.getHiveTable(MetastoreUtil.getFactOrDimtableStorageTableName(cft.getName(),
-                (String) entry.getValue()))));
-            updatePeriodTableDescriptor.setUpdatePeriod(XUpdatePeriod.valueOf(((UpdatePeriod) entry.getKey()).name()));
-            xUpdatePeriods.getUpdatePeriodTableDescriptor().add(updatePeriodTableDescriptor);
-          }
-          factTable.getStorageTables().getStorageTable().add(tblElement);
+                  (String) entry.getValue()))));
+          updatePeriodTableDescriptor.setUpdatePeriod(XUpdatePeriod.valueOf(((UpdatePeriod) entry.getKey()).name()));
+          xUpdatePeriods.getUpdatePeriodTableDescriptor().add(updatePeriodTableDescriptor);
         }
+        factTable.getStorageTables().getStorageTable().add(tblElement);
       }
       fact = factTable;
     }
diff --git a/lens-cube/src/test/java/org/apache/lens/cube/metadata/TestCubeMetastoreClient.java b/lens-cube/src/test/java/org/apache/lens/cube/metadata/TestCubeMetastoreClient.java
index 6e76eda..ef5f162 100644
--- a/lens-cube/src/test/java/org/apache/lens/cube/metadata/TestCubeMetastoreClient.java
+++ b/lens-cube/src/test/java/org/apache/lens/cube/metadata/TestCubeMetastoreClient.java
@@ -30,6 +30,7 @@
 import java.text.SimpleDateFormat;
 import java.util.*;
 
+import org.apache.lens.api.metastore.XFact;
 import org.apache.lens.cube.error.LensCubeErrorCode;
 import org.apache.lens.cube.metadata.ExprColumn.ExprSpec;
 import org.apache.lens.cube.metadata.ReferencedDimAttribute.ChainRefCol;
@@ -47,6 +48,7 @@
 import org.apache.hadoop.hive.metastore.api.AlreadyExistsException;
 import org.apache.hadoop.hive.metastore.api.Database;
 import org.apache.hadoop.hive.metastore.api.FieldSchema;
+import org.apache.hadoop.hive.metastore.api.NoSuchObjectException;
 import org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat;
 import org.apache.hadoop.hive.ql.metadata.Hive;
 import org.apache.hadoop.hive.ql.metadata.HiveException;
@@ -89,6 +91,7 @@
   private static final String CUBE_NAME_WITH_PROPS = "testMetastoreCubeWithProps";
   private static final String DERIVED_CUBE_NAME = "derivedTestMetastoreCube";
   private static final String DERIVED_CUBE_NAME_WITH_PROPS = "derivedTestMetastoreCubeWithProps";
+  private static final String X_FACT_NAME = "testMetastoreXFact";
   private static final Map<String, String> CUBE_PROPERTIES = new HashMap<>();
   private static HiveConf conf = new HiveConf(TestCubeMetastoreClient.class);
   private static FieldSchema dtPart = new FieldSchema(getDatePartitionKey(), serdeConstants.STRING_TYPE_NAME,
@@ -144,6 +147,11 @@
     conf.set(LensConfConstants.AUTHORIZER_CLASS, "org.apache.lens.cube.parse.MockAuthorizer");
     LensAuthorizer.get().init(conf);
 
+    try {
+      Hive.get().dropDatabase(TestCubeMetastoreClient.class.getSimpleName(), true, true, true);
+    } catch (NoSuchObjectException e) {
+      fail();
+    }
     Database database = new Database();
     database.setName(TestCubeMetastoreClient.class.getSimpleName());
     Hive.get(conf).createDatabase(database);
@@ -1592,6 +1600,48 @@
   }
 
   @Test(priority = 2)
+  public void testGetXFactTable() throws Exception {
+    List<FieldSchema> factColumns = new ArrayList<>(cubeMeasures.size());
+    for (CubeMeasure measure : cubeMeasures) {
+      factColumns.add(measure.getColumn());
+    }
+
+    // add one dimension of the cube
+    factColumns.add(new FieldSchema("zipcode", "int", "zip"));
+    FieldSchema itPart = new FieldSchema("it", "string", "date part");
+    FieldSchema etPart = new FieldSchema("et", "string", "date part");
+    StorageTableDesc s1 = new StorageTableDesc(TextInputFormat.class, HiveIgnoreKeyTextOutputFormat.class,
+        Lists.newArrayList(getDatePartition(), itPart, etPart), Lists.newArrayList(getDatePartitionKey(),
+        itPart.getName(), etPart.getName()));
+
+    Set<UpdatePeriod> c1Storage = new HashSet<UpdatePeriod>();
+    c1Storage.add(HOURLY);
+    Map<String, Set<UpdatePeriod>> updatePeriods = new HashMap<String, Set<UpdatePeriod>>();
+    updatePeriods.put(c1, c1Storage);
+
+    Map<String, StorageTableDesc> storageTableDescs = getHashMap("HOURLY_c1", s1);
+
+    Map<UpdatePeriod, String> updatePeriodMap = new HashMap<>();
+    updatePeriodMap.put(HOURLY, HOURLY.toString() + "_" + c1);
+
+    Map<String, Set<String>> storageTablePartitionColumns = new HashMap<String, Set<String>>();
+    storageTablePartitionColumns.put(c1, new HashSet<>());
+
+    Map<String, Map<UpdatePeriod, String>> storageUpdatePeriodMap = new HashMap<String, Map<UpdatePeriod, String>>();
+
+    storageUpdatePeriodMap.put(c1, updatePeriodMap);
+
+    client.createCubeFactTable(CUBE_NAME_WITH_PROPS, X_FACT_NAME, factColumns, updatePeriods, 0.0d, new HashMap<String,
+        String>(), storageTableDescs, storageUpdatePeriodMap, storageTablePartitionColumns);
+
+    CubeFactTable cubeFact = new CubeFactTable(CUBE_NAME_WITH_PROPS, X_FACT_NAME, factColumns, updatePeriods, 0.0d,
+        new HashMap<String, String>(), storageUpdatePeriodMap, new HashMap<String, Set<String>>());
+    XFact xfact = client.getXFactTable(cubeFact);
+    assertEquals(xfact.getCubeName(), CUBE_NAME_WITH_PROPS);
+    assertEquals(xfact.getName(), X_FACT_NAME.toLowerCase());
+  }
+
+  @Test(priority = 2)
   public void testCubeFactWithThreeTimedParts() throws Exception {
     String factName = "testMetastoreFact3TimedParts";
     List<FieldSchema> factColumns = new ArrayList<>(cubeMeasures.size());
diff --git a/lens-driver-jdbc/src/main/java/org/apache/lens/driver/jdbc/JDBCDriver.java b/lens-driver-jdbc/src/main/java/org/apache/lens/driver/jdbc/JDBCDriver.java
index 8dd299a..62f615b 100644
--- a/lens-driver-jdbc/src/main/java/org/apache/lens/driver/jdbc/JDBCDriver.java
+++ b/lens-driver-jdbc/src/main/java/org/apache/lens/driver/jdbc/JDBCDriver.java
@@ -593,19 +593,25 @@
         + explainKeyword + " ");
     }
     log.info("{} Explain Query : {}", getFullyQualifiedName(), explainQuery);
-    QueryContext explainQueryCtx = QueryContext.createContextWithSingleDriver(explainQuery, null,
-      new LensConf(), explainConf, this, explainCtx.getLensSessionIdentifier(), false);
-    QueryResult result = null;
-    try {
-      result = executeInternal(explainQueryCtx, explainQuery);
-      if (result.error != null) {
-        throw new LensException("Query explain failed!", result.error);
-      }
-    } finally {
-      if (result != null) {
-        result.close();
+
+    boolean validateThroughPrepare = explainCtx.getDriverConf(this).getBoolean(JDBC_VALIDATE_THROUGH_PREPARE_OR_EXPLAIN,
+        DEFAULT_JDBC_VALIDATE_THROUGH_PREPARE_OR_EXPLAIN);
+    if (validateThroughPrepare) {
+      QueryContext explainQueryCtx = QueryContext.createContextWithSingleDriver(explainQuery, null, new LensConf(),
+          explainConf, this, explainCtx.getLensSessionIdentifier(), false);
+      QueryResult result = null;
+      try {
+        result = executeInternal(explainQueryCtx, explainQuery);
+        if (result.error != null) {
+          throw new LensException("Query explain failed!", result.error);
+        }
+      } finally {
+        if (result != null) {
+          result.close();
+        }
       }
     }
+
     JDBCQueryPlan jqp = new JDBCQueryPlan(calculateQueryCost(explainCtx));
     explainCtx.getDriverContext().setDriverQueryPlan(this, jqp);
     return jqp;
@@ -621,8 +627,8 @@
     if (pContext.getDriverQuery(this) == null) {
       throw new NullPointerException("Null driver query for " + pContext.getUserQuery());
     }
-    boolean validateThroughPrepare = pContext.getDriverConf(this).getBoolean(JDBC_VALIDATE_THROUGH_PREPARE,
-      DEFAULT_JDBC_VALIDATE_THROUGH_PREPARE);
+    boolean validateThroughPrepare = pContext.getDriverConf(this).getBoolean(JDBC_VALIDATE_THROUGH_PREPARE_OR_EXPLAIN,
+      DEFAULT_JDBC_VALIDATE_THROUGH_PREPARE_OR_EXPLAIN);
     if (validateThroughPrepare) {
       PreparedStatement stmt;
       // Estimate queries need to get connection from estimate pool to make sure
diff --git a/lens-driver-jdbc/src/main/java/org/apache/lens/driver/jdbc/JDBCDriverConfConstants.java b/lens-driver-jdbc/src/main/java/org/apache/lens/driver/jdbc/JDBCDriverConfConstants.java
index f2bfb69..95eb55b 100644
--- a/lens-driver-jdbc/src/main/java/org/apache/lens/driver/jdbc/JDBCDriverConfConstants.java
+++ b/lens-driver-jdbc/src/main/java/org/apache/lens/driver/jdbc/JDBCDriverConfConstants.java
@@ -94,11 +94,12 @@
   /** The Constant DEFAULT_JDBC_EXPLAIN_KEYWORD_BEFORE_SELECT. */
   public static final boolean DEFAULT_JDBC_EXPLAIN_KEYWORD_BEFORE_SELECT = true;
 
-  /** The Constant JDBC_VALIDATE_THROUGH_PREPARE. */
-  public static final String JDBC_VALIDATE_THROUGH_PREPARE = JDBC_DRIVER_PFX + "validate.through.prepare";
+  /** The Constant JDBC_VALIDATE_THROUGH_PREPARE_OR_EXPLAIN. */
+  public static final String JDBC_VALIDATE_THROUGH_PREPARE_OR_EXPLAIN =
+    JDBC_DRIVER_PFX + "validate.through.prepare.or.explain";
 
   /** The Constant DEFAULT_JDBC_VALIDATE_THROUGH_PREPARE. */
-  public static final boolean DEFAULT_JDBC_VALIDATE_THROUGH_PREPARE = true;
+  public static final boolean DEFAULT_JDBC_VALIDATE_THROUGH_PREPARE_OR_EXPLAIN = true;
 
   /** The Constant JDBC_VALIDATE_SKIP_WARNINGS */
   public static final String JDBC_VALIDATE_SKIP_WARNINGS = JDBC_DRIVER_PFX + "validate.skip.warnings";
diff --git a/lens-server-api/src/main/java/org/apache/lens/server/api/query/PreparedQueryContext.java b/lens-server-api/src/main/java/org/apache/lens/server/api/query/PreparedQueryContext.java
index 0b08459..69ee7c4 100644
--- a/lens-server-api/src/main/java/org/apache/lens/server/api/query/PreparedQueryContext.java
+++ b/lens-server-api/src/main/java/org/apache/lens/server/api/query/PreparedQueryContext.java
@@ -49,10 +49,17 @@
   private final QueryPrepareHandle prepareHandle;
 
   /**
-   * The prepared time.
+   * The prepare start time.
    */
   @Getter
-  private final Date preparedTime;
+  private final Date prepareStartTime;
+
+  /**
+   * The prepare end time.
+   */
+  @Getter
+  @Setter
+  private Date prepareEndTime = null;
 
   /**
    * The prepared user.
@@ -94,7 +101,7 @@
   public PreparedQueryContext(String query, String user, Configuration conf, LensConf qconf, Collection<LensDriver>
     drivers) {
     super(query, user, qconf, conf, drivers, true);
-    this.preparedTime = new Date();
+    this.prepareStartTime = new Date();
     this.preparedUser = user;
     this.prepareHandle = new QueryPrepareHandle(UUID.randomUUID());
     this.conf = conf;
@@ -119,9 +126,9 @@
   @Override
   public long getDelay(TimeUnit units) {
     long delayMillis;
-    if (this.preparedTime != null) {
+    if (this.prepareStartTime != null) {
       Date now = new Date();
-      long elapsedMills = now.getTime() - this.preparedTime.getTime();
+      long elapsedMills = now.getTime() - this.prepareStartTime.getTime();
       delayMillis = millisInWeek - elapsedMills;
       return units.convert(delayMillis, TimeUnit.MILLISECONDS);
     } else {
@@ -147,7 +154,7 @@
    * @return the lens prepared query
    */
   public LensPreparedQuery toPreparedQuery() {
-    return new LensPreparedQuery(prepareHandle, userQuery, preparedTime, preparedUser, getDriverContext()
+    return new LensPreparedQuery(prepareHandle, userQuery, prepareStartTime, preparedUser, getDriverContext()
         .getSelectedDriver() != null ? getDriverContext().getSelectedDriver().getFullyQualifiedName() : null,
         getDriverContext().getSelectedDriverQuery(), lensConf);
   }
diff --git a/lens-server/src/main/java/org/apache/lens/server/query/LensServerDAO.java b/lens-server/src/main/java/org/apache/lens/server/query/LensServerDAO.java
index 983365d..28b678b 100644
--- a/lens-server/src/main/java/org/apache/lens/server/query/LensServerDAO.java
+++ b/lens-server/src/main/java/org/apache/lens/server/query/LensServerDAO.java
@@ -35,6 +35,7 @@
 import org.apache.lens.api.query.QueryStatus;
 import org.apache.lens.server.api.error.LensException;
 import org.apache.lens.server.api.query.FinishedLensQuery;
+import org.apache.lens.server.api.query.PreparedQueryContext;
 import org.apache.lens.server.api.query.QueryContext;
 import org.apache.lens.server.session.LensSessionImpl;
 import org.apache.lens.server.util.UtilityMethods;
@@ -47,6 +48,7 @@
 import org.apache.hadoop.conf.Configuration;
 
 import com.google.common.collect.Lists;
+
 import lombok.extern.slf4j.Slf4j;
 
 /**
@@ -105,6 +107,20 @@
       log.warn("Unable to create finished queries table", e);
     }
   }
+
+  public void createPreparedQueriesTable() throws Exception {
+    String sql = "CREATE TABLE if not exists prepared_queries (handle varchar(255) NOT NULL unique,  userquery "
+      + "varchar(20000),  submitter varchar(255) NOT NULL,  timetaken bigint,  queryname varchar(255) DEFAULT NULL, "
+      + "drivername varchar(10000) DEFAULT NULL,  driverquery varchar(1000000),  starttime bigint)";
+    try {
+      QueryRunner runner = new QueryRunner(ds);
+      runner.update(sql);
+      log.info("Created prepared_queries queries table");
+    } catch (SQLException e) {
+      log.warn("Unable to create prepared_queries queries table", e);
+    }
+  }
+  
   public void createFailedAttemptsTable() throws Exception {
     String sql = "CREATE TABLE if not exists failed_attempts (handle varchar(255) not null,"
       + "attempt_number int, drivername varchar(10000), progress float, progressmessage varchar(10000), "
@@ -821,4 +837,35 @@
 
     return result;
   }
+
+  /**
+   * DAO method to insert a new Prepared query into Table.
+   *
+   * @param preparedQueryContext to be inserted
+   * @throws SQLException the exception
+   */
+  public void insertPreparedQuery(PreparedQueryContext preparedQueryContext) throws LensException {
+    String sql = "insert into prepared_queries (handle, userquery, submitter, timetaken, queryname, drivername, "
+        + "driverquery, starttime)" + " values (?,?,?,?,?,?,?,?)";
+    Connection conn = null;
+    try {
+      conn = getConnection();
+      conn.setAutoCommit(false);
+      QueryRunner runner = new QueryRunner();
+
+      long timeTaken =
+          preparedQueryContext.getPrepareEndTime().getTime() - preparedQueryContext.getPrepareStartTime().getTime();
+
+      runner.update(conn, sql, preparedQueryContext.getPrepareHandle().getQueryHandleString(),
+          preparedQueryContext.getUserQuery(), preparedQueryContext.getSubmittedUser(), timeTaken,
+          preparedQueryContext.getQueryName(), preparedQueryContext.getDriverContext().getSelectedDriver().toString(),
+          preparedQueryContext.getSelectedDriverQuery(), preparedQueryContext.getPrepareStartTime().getTime());
+      conn.commit();
+    } catch (SQLException e) {
+      log.error("Failed to insert prepared query into database with error, " + e);
+      throw new LensException(e);
+  } finally {
+      DbUtils.closeQuietly(conn);
+    }
+  }
 }
diff --git a/lens-server/src/main/java/org/apache/lens/server/query/QueryExecutionServiceImpl.java b/lens-server/src/main/java/org/apache/lens/server/query/QueryExecutionServiceImpl.java
index 9e5f2e6..18bd2d0 100644
--- a/lens-server/src/main/java/org/apache/lens/server/query/QueryExecutionServiceImpl.java
+++ b/lens-server/src/main/java/org/apache/lens/server/query/QueryExecutionServiceImpl.java
@@ -147,7 +147,9 @@
   /**
    * The Constant PREPARED_QUERY_PURGER_COUNTER.
    */
-  public static final String PREPARED_QUERY_PURGER_COUNTER = "prepared-query-purger-errors";
+  public static final String PREPARED_QUERY_PURGER_ERROR_COUNTER = "prepared-query-purger-errors";
+
+  public static final String PREPARED_QUERY_INSERT_ERROR_COUNTER = "prepared-query-insert-errors";
 
   /**
    * The millis in week.
@@ -1302,13 +1304,13 @@
           destroyPreparedQuery(prepared);
           log.info("Purged prepared query: {}", prepared.getPrepareHandle());
         } catch (LensException e) {
-          incrCounter(PREPARED_QUERY_PURGER_COUNTER);
+          incrCounter(PREPARED_QUERY_PURGER_ERROR_COUNTER);
           log.error("Error closing prepared query ", e);
         } catch (InterruptedException e) {
           log.info("PreparedQueryPurger has been interrupted, exiting");
           return;
         } catch (Exception e) {
-          incrCounter(PREPARED_QUERY_PURGER_COUNTER);
+          incrCounter(PREPARED_QUERY_PURGER_ERROR_COUNTER);
           log.error("Error in prepared query purger", e);
         }
       }
@@ -1415,6 +1417,7 @@
       this.lensServerDao.createFailedAttemptsTable();
       this.lensServerDao.createActiveSessionsTable();
       this.lensServerDao.createActiveQueriesTable();
+      this.lensServerDao.createPreparedQueriesTable();
     } catch (Exception e) {
       log.warn("Unable to create finished query tables, query purger will not purge queries", e);
     }
@@ -2054,9 +2057,10 @@
       acquire(sessionHandle);
       prepared = prepareQuery(sessionHandle, query, lensConf, SubmitOp.PREPARE);
       prepared.setQueryName(queryName);
-      prepared.getSelectedDriver().prepare(prepared);
+      lensServerDao.insertPreparedQuery(prepared);
       return prepared.getPrepareHandle();
     } catch (LensException e) {
+      incrCounter(PREPARED_QUERY_INSERT_ERROR_COUNTER);
       if (prepared != null) {
         destroyPreparedQuery(prepared);
       }
@@ -2087,6 +2091,7 @@
     preparedQueries.put(prepared.getPrepareHandle(), prepared);
     preparedQueryQueue.add(prepared);
     incrCounter(PREPARED_QUERIES_COUNTER);
+    prepared.setPrepareEndTime(new Date());
     return prepared;
   }
 
@@ -3031,7 +3036,7 @@
             continue;
           }
         }
-        long queryPrepTime = preparedQueryContext.getPreparedTime().getTime();
+        long queryPrepTime = preparedQueryContext.getPrepareStartTime().getTime();
         if (fromTime <= queryPrepTime && queryPrepTime < toTime) {
           continue;
         }
diff --git a/lens-server/src/test/java/org/apache/lens/server/query/TestLensDAO.java b/lens-server/src/test/java/org/apache/lens/server/query/TestLensDAO.java
index c741745..23b9813 100644
--- a/lens-server/src/test/java/org/apache/lens/server/query/TestLensDAO.java
+++ b/lens-server/src/test/java/org/apache/lens/server/query/TestLensDAO.java
@@ -22,6 +22,8 @@
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.util.Collection;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 
@@ -34,13 +36,20 @@
 import org.apache.lens.api.query.LensQuery;
 import org.apache.lens.api.query.QueryHandle;
 import org.apache.lens.api.query.QueryStatus;
+import org.apache.lens.driver.hive.EmbeddedThriftConnection;
+import org.apache.lens.driver.hive.HiveDriver;
+import org.apache.lens.driver.hive.ThriftConnection;
+import org.apache.lens.driver.jdbc.JDBCDriver;
 import org.apache.lens.driver.jdbc.JDBCResultSet;
 import org.apache.lens.server.LensJerseyTest;
 import org.apache.lens.server.LensServices;
+import org.apache.lens.server.api.LensConfConstants;
 import org.apache.lens.server.api.driver.LensDriver;
 import org.apache.lens.server.api.driver.MockDriver;
+import org.apache.lens.server.api.driver.hooks.DriverQueryHook;
 import org.apache.lens.server.api.error.LensException;
 import org.apache.lens.server.api.query.*;
+import org.apache.lens.server.api.user.MockDriverQueryHook;
 
 import org.apache.hadoop.conf.Configuration;
 
@@ -49,6 +58,7 @@
 import org.testng.annotations.Test;
 
 import com.google.common.collect.Lists;
+
 import lombok.extern.slf4j.Slf4j;
 
 /**
@@ -213,4 +223,64 @@
 
     service.closeSession(session);
   }
+
+  public void testPreparedQueryDAO() throws Exception {
+    QueryExecutionServiceImpl service = LensServices.get().getService(QueryExecutionService.NAME);
+    Connection conn = null;
+    Statement stmt = null;
+    final ObjectMapper MAPPER = new ObjectMapper();
+
+    try {
+      conn = service.lensServerDao.getConnection();
+      stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
+      ResultSet rs = stmt.executeQuery("SELECT handle FROM finished_queries");
+
+      JDBCResultSet jdbcResultSet = new JDBCResultSet(null, rs, false);
+      JDBCResultSet.JDBCResultSetMetadata jdbcRsMeta =
+          (JDBCResultSet.JDBCResultSetMetadata) jdbcResultSet.getMetadata();
+
+      String jsonMetadata = MAPPER.writeValueAsString(jdbcRsMeta);
+
+      log.info("@@@JSON {}" + jsonMetadata);
+
+    } catch (SQLException ex) {
+      log.error("Error creating result set ", ex);
+    } finally {
+      if (stmt != null) {
+        stmt.close();
+      }
+      if (conn != null) {
+        conn.close();
+      }
+    }
+
+    service.lensServerDao.createPreparedQueriesTable();
+    Configuration driverConf = new Configuration();
+    try {
+      PreparedQueryContext preparedQueryContext = new PreparedQueryContext("query", "user1", driverConf,
+          createDriver(driverConf));
+      preparedQueryContext.setPrepareEndTime(new Date());
+      service.lensServerDao.insertPreparedQuery(preparedQueryContext);
+    } catch (Exception e) {
+      Assert.fail("it shouldn't be coming in this catch block");
+    }
+
+
+  }
+
+  protected Collection<LensDriver> createDriver(Configuration driverConf) throws LensException {
+
+    driverConf.addResource("drivers/jdbc/jdbc1/jdbcdriver-site.xml");
+    driverConf.setClass(HiveDriver.HIVE_CONNECTION_CLASS, EmbeddedThriftConnection.class, ThriftConnection.class);
+    driverConf.setClass(LensConfConstants.DRIVER_HOOK_CLASSES_SFX, MockDriverQueryHook.class, DriverQueryHook.class);
+    driverConf.set("hive.lock.manager", "org.apache.hadoop.hive.ql.lockmgr.EmbeddedLockManager");
+    driverConf.setBoolean(HiveDriver.HS2_CALCULATE_PRIORITY, true);
+    JDBCDriver driver = new JDBCDriver();
+    driver.configure(driverConf, "jdbc", "jdbc1");
+    Collection<LensDriver> drivers = Lists.<LensDriver>newArrayList(driver);
+
+    System.out.println("TestJDBCDriver created");
+    return drivers;
+  }
 }
+
diff --git a/pom.xml b/pom.xml
index 9525332..3deff5d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -103,7 +103,7 @@
     <war.plugin.version>2.1.1</war.plugin.version>
     <license.plugin.version>2.6</license.plugin.version>
     <buildnumber.plugin.version>1.0</buildnumber.plugin.version>
-    <findbugs.plugin.version>3.0.1</findbugs.plugin.version>
+    <findbugs.plugin.version>3.0.4</findbugs.plugin.version>
     <antrun.plugin.version>1.8</antrun.plugin.version>
     <cobertura.plugin.version>2.7</cobertura.plugin.version>