drill-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ve...@apache.org
Subject drill git commit: DRILL-4732: Update JDBC driver to use the new prepared statement APIs on DrillClient
Date Mon, 08 Aug 2016 21:50:55 GMT
Repository: drill
Updated Branches:
  refs/heads/master 14f6ec7dd -> e02aa596f


DRILL-4732: Update JDBC driver to use the new prepared statement APIs on DrillClient

this closes #532


Project: http://git-wip-us.apache.org/repos/asf/drill/repo
Commit: http://git-wip-us.apache.org/repos/asf/drill/commit/e02aa596
Tree: http://git-wip-us.apache.org/repos/asf/drill/tree/e02aa596
Diff: http://git-wip-us.apache.org/repos/asf/drill/diff/e02aa596

Branch: refs/heads/master
Commit: e02aa596fa64f38bce773fd108f15032f8086601
Parents: 14f6ec7
Author: vkorukanti <venki@dremio.com>
Authored: Mon Jun 20 14:40:05 2016 -0700
Committer: vkorukanti <venki@dremio.com>
Committed: Mon Aug 8 14:49:14 2016 -0700

----------------------------------------------------------------------
 .../org/apache/drill/common/types/Types.java    | 112 +++------
 .../jdbc/impl/DrillColumnMetaDataList.java      |  58 ++++-
 .../drill/jdbc/impl/DrillConnectionImpl.java    |  42 +++-
 .../drill/jdbc/impl/DrillPrepareResult.java     |  16 +-
 .../drill/jdbc/impl/DrillResultSetImpl.java     |  12 +-
 .../jdbc/impl/DrillResultSetMetaDataImpl.java   |   3 +-
 .../drill/jdbc/PreparedStatementTest.java       | 226 ++++++++++++++-----
 ...69UnsupportedReportsUseSqlExceptionTest.java |   2 +-
 8 files changed, 327 insertions(+), 144 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/drill/blob/e02aa596/common/src/main/java/org/apache/drill/common/types/Types.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/drill/common/types/Types.java b/common/src/main/java/org/apache/drill/common/types/Types.java
index 504b876..ed77ccd 100644
--- a/common/src/main/java/org/apache/drill/common/types/Types.java
+++ b/common/src/main/java/org/apache/drill/common/types/Types.java
@@ -163,84 +163,42 @@ public class Types {
   }
 
   /***
-   * Gets JDBC type code for given Drill RPC-/protobuf-level type.
+   * Gets JDBC type code for given SQL data type name.
    */
-  public static int getJdbcTypeCode(final MajorType type) {
-    if (type.getMode() == DataMode.REPEATED || type.getMinorType() == MinorType.LIST) {
-      return java.sql.Types.ARRAY;
-    }
-
-    switch (type.getMinorType()) {
-    case BIGINT:
-      return java.sql.Types.BIGINT;
-    case BIT:
-      return java.sql.Types.BOOLEAN;
-    case DATE:
-      return java.sql.Types.DATE;
-    case DECIMAL9:
-    case DECIMAL18:
-    case DECIMAL28DENSE:
-    case DECIMAL28SPARSE:
-    case DECIMAL38DENSE:
-    case DECIMAL38SPARSE:
-      return java.sql.Types.DECIMAL;
-    case FIXED16CHAR:
-      return java.sql.Types.NCHAR;
-    case FIXEDBINARY:
-      return java.sql.Types.BINARY;
-    case FIXEDCHAR:
-      return java.sql.Types.NCHAR;
-    case FLOAT4:
-      return java.sql.Types.FLOAT;
-    case FLOAT8:
-      return java.sql.Types.DOUBLE;
-    case INT:
-      return java.sql.Types.INTEGER;
-    case MAP:
-      return java.sql.Types.STRUCT;
-    case MONEY:
-      return java.sql.Types.DECIMAL;
-    case NULL:
-      return java.sql.Types.NULL;
-    case INTERVAL:
-    case INTERVALYEAR:
-    case INTERVALDAY:
-      return java.sql.Types.OTHER;  // JDBC (4.1) has nothing for INTERVAL
-    case LATE:
-      return java.sql.Types.OTHER;
-    case SMALLINT:
-      return java.sql.Types.SMALLINT;
-    case TIME:
-      return java.sql.Types.TIME;
-    case TIMESTAMPTZ:
-    case TIMESTAMP:
-      return java.sql.Types.TIMESTAMP;
-    case TIMETZ:
-      return java.sql.Types.TIME;
-    case TINYINT:
-      return java.sql.Types.TINYINT;
-    case UINT1:
-      return java.sql.Types.TINYINT;
-    case UINT2:
-      return java.sql.Types.SMALLINT;
-    case UINT4:
-      return java.sql.Types.INTEGER;
-    case UINT8:
-      return java.sql.Types.BIGINT;
-    case VAR16CHAR:
-      return java.sql.Types.NVARCHAR;
-    case VARBINARY:
-      return java.sql.Types.VARBINARY;
-    case VARCHAR:
-      return java.sql.Types.VARCHAR;
-    case UNION:
-      return java.sql.Types.OTHER;
-    default:
-      // TODO:  This isn't really an unsupported-operation/-type case; this
-      //   is an unexpected, code-out-of-sync-with-itself case, so use an
-      //   exception intended for that.
-      throw new UnsupportedOperationException(
-          "Unexpected/unhandled MinorType value " + type.getMinorType() );
+  public static int getJdbcTypeCode(final String sqlTypeName) {
+
+    switch (sqlTypeName) {
+      case "ANY":                           return java.sql.Types.OTHER;
+      case "ARRAY":                         return java.sql.Types.ARRAY;
+      case "BIGINT":                        return java.sql.Types.BIGINT;
+      case "BINARY VARYING":                return java.sql.Types.VARBINARY;
+      case "BINARY":                        return java.sql.Types.BINARY;
+      case "BOOLEAN":                       return java.sql.Types.BOOLEAN;
+      case "CHARACTER VARYING":             return java.sql.Types.VARCHAR;
+      case "CHARACTER":                     return java.sql.Types.NCHAR;
+      case "DATE":                          return java.sql.Types.DATE;
+      case "DECIMAL":                       return java.sql.Types.DECIMAL;
+      case "DOUBLE":                        return java.sql.Types.DOUBLE;
+      case "FLOAT":                         return java.sql.Types.FLOAT;
+      case "INTEGER":                       return java.sql.Types.INTEGER;
+      case "INTERVAL":                      return java.sql.Types.OTHER;  // JDBC (4.1) has
nothing for INTERVAL
+      case "MAP":                           return java.sql.Types.STRUCT;
+      case "NATIONAL CHARACTER VARYING":    return java.sql.Types.NVARCHAR;
+      case "NATIONAL CHARACTER":            return java.sql.Types.NCHAR;
+      case "NULL":                          return java.sql.Types.NULL;
+      case "SMALLINT":                      return java.sql.Types.SMALLINT;
+      case "TIME WITH TIME ZONE":           // fall through
+      case "TIME":                          return java.sql.Types.TIME;
+      case "TIMESTAMP WITH TIME ZONE":      // fall through
+      case "TIMESTAMP":                     return java.sql.Types.TIMESTAMP;
+      case "TINYINT":                       return java.sql.Types.TINYINT;
+      case "UNION":                         return java.sql.Types.OTHER;
+      default:
+        // TODO:  This isn't really an unsupported-operation/-type case; this
+        //   is an unexpected, code-out-of-sync-with-itself case, so use an
+        //   exception intended for that.
+        throw new UnsupportedOperationException(
+            "Unexpected/unhandled SqlType value " + sqlTypeName );
     }
   }
 

http://git-wip-us.apache.org/repos/asf/drill/blob/e02aa596/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillColumnMetaDataList.java
----------------------------------------------------------------------
diff --git a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillColumnMetaDataList.java
b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillColumnMetaDataList.java
index d23e56f..a3e37ae 100644
--- a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillColumnMetaDataList.java
+++ b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillColumnMetaDataList.java
@@ -28,12 +28,16 @@ import net.hydromatic.avatica.ColumnMetaData;
 import net.hydromatic.avatica.ColumnMetaData.AvaticaType;
 import net.hydromatic.avatica.ColumnMetaData.Rep;
 
-import org.apache.drill.common.types.TypeProtos.DataMode;
 import org.apache.drill.common.types.TypeProtos.MajorType;
 import org.apache.drill.common.types.Types;
+import org.apache.drill.exec.proto.UserProtos.ColumnSearchability;
+import org.apache.drill.exec.proto.UserProtos.ColumnUpdatability;
+import org.apache.drill.exec.proto.UserProtos.ResultColumnMetadata;
 import org.apache.drill.exec.record.BatchSchema;
 import org.apache.drill.exec.record.MaterializedField;
 
+import com.google.common.collect.ImmutableList;
+
 public class DrillColumnMetaDataList extends BasicList<ColumnMetaData>{
   static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DrillColumnMetaDataList.class);
 
@@ -51,13 +55,61 @@ public class DrillColumnMetaDataList extends BasicList<ColumnMetaData>{
 
   /**
    * Gets AvaticaType carrying both JDBC {@code java.sql.Type.*} type code
+   * and SQL type name for given SQL type name.
+   */
+  private static AvaticaType getAvaticaType(String sqlTypeName) {
+    final int jdbcTypeId = Types.getJdbcTypeCode(sqlTypeName);
+    return ColumnMetaData.scalar( jdbcTypeId, sqlTypeName,
+        Rep.BOOLEAN /* dummy value, unused */ );
+  }
+
+  /**
+   * Update the metadata with given metadata received from server.
+   * @param metadata
+   */
+  public void updateColumnMetaData(List<ResultColumnMetadata> metadata) {
+    final List<ColumnMetaData> newColumns = new ArrayList<>(metadata.size());
+    int offset = 0;
+    for(ResultColumnMetadata m : metadata) {
+
+      final AvaticaType bundledSqlDataType = getAvaticaType(m.getDataType());
+
+      newColumns.add(new ColumnMetaData(
+          offset,
+          m.getAutoIncrement(),
+          m.getCaseSensitivity(),
+          m.getSearchability() != ColumnSearchability.NONE,
+          m.getIsCurrency(),
+          m.getIsNullable() ? ResultSetMetaData.columnNullable : ResultSetMetaData.columnNoNulls,
+          m.getSigned(),
+          m.getDisplaySize(),
+          m.getLabel(),
+          m.getColumnName(),
+          m.getSchemaName(),
+          m.getPrecision(),
+          m.getScale(),
+          m.getTableName(),
+          m.getCatalogName(),
+          bundledSqlDataType,
+          m.getUpdatability() == ColumnUpdatability.READ_ONLY,
+          m.getUpdatability() == ColumnUpdatability.WRITABLE,
+          m.getUpdatability() == ColumnUpdatability.WRITABLE,
+          m.getClassName()
+      ));
+      offset++;
+    }
+    columns = ImmutableList.copyOf(newColumns);
+  }
+
+  /**
+   * Gets AvaticaType carrying both JDBC {@code java.sql.Type.*} type code
    * and SQL type name for given RPC-level type (from batch schema).
    */
   private static AvaticaType getAvaticaType( MajorType rpcDateType ) {
     final String sqlTypeName = Types.getSqlTypeName( rpcDateType );
-    final int jdbcTypeId = Types.getJdbcTypeCode( rpcDateType );
+    final int jdbcTypeId = Types.getJdbcTypeCode( sqlTypeName );
     return ColumnMetaData.scalar( jdbcTypeId, sqlTypeName,
-                                  Rep.BOOLEAN /* dummy value, unused */ );
+        Rep.BOOLEAN /* dummy value, unused */ );
   }
 
   public void updateColumnMetaData(String catalogName, String schemaName,

http://git-wip-us.apache.org/repos/asf/drill/blob/e02aa596/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillConnectionImpl.java
----------------------------------------------------------------------
diff --git a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillConnectionImpl.java b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillConnectionImpl.java
index ab73a14..855a27e 100644
--- a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillConnectionImpl.java
+++ b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillConnectionImpl.java
@@ -17,7 +17,6 @@
  */
 package org.apache.drill.jdbc.impl;
 
-import java.io.IOException;
 import java.sql.Array;
 import java.sql.Blob;
 import java.sql.CallableStatement;
@@ -30,6 +29,7 @@ import java.sql.SQLClientInfoException;
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
 import java.sql.SQLNonTransientConnectionException;
+import java.sql.SQLTimeoutException;
 import java.sql.SQLWarning;
 import java.sql.SQLXML;
 import java.sql.Savepoint;
@@ -54,6 +54,9 @@ import org.apache.drill.exec.client.DrillClient;
 import org.apache.drill.exec.exception.OutOfMemoryException;
 import org.apache.drill.exec.memory.BufferAllocator;
 import org.apache.drill.exec.memory.RootAllocatorFactory;
+import org.apache.drill.exec.proto.UserProtos.CreatePreparedStatementResp;
+import org.apache.drill.exec.proto.UserProtos.RequestStatus;
+import org.apache.drill.exec.rpc.DrillRpcFuture;
 import org.apache.drill.exec.rpc.RpcException;
 import org.apache.drill.exec.server.Drillbit;
 import org.apache.drill.exec.server.RemoteServiceSet;
@@ -362,12 +365,47 @@ class DrillConnectionImpl extends AvaticaConnection
                                             int resultSetHoldability) throws SQLException
{
     throwIfClosed();
     try {
-      DrillPrepareResult prepareResult = new DrillPrepareResult(sql);
+      DrillRpcFuture<CreatePreparedStatementResp> respFuture = client.createPreparedStatement(sql);
+
+      CreatePreparedStatementResp resp;
+      try {
+        resp = respFuture.get();
+      } catch (InterruptedException e) {
+        // Preserve evidence that the interruption occurred so that code higher up
+        // on the call stack can learn of the interruption and respond to it if it
+        // wants to.
+        Thread.currentThread().interrupt();
+
+        throw new SQLException( "Interrupted", e );
+      }
+
+      final RequestStatus status = resp.getStatus();
+      if (status != RequestStatus.OK) {
+        final String errMsgFromServer = resp.getError() != null ? resp.getError().getMessage()
: "";
+
+        if (status == RequestStatus.TIMEOUT) {
+          logger.error("Request timed out to create prepare statement: {}", errMsgFromServer);
+          throw new SQLTimeoutException("Failed to create prepared statement: " + errMsgFromServer);
+        }
+
+        if (status == RequestStatus.FAILED) {
+          logger.error("Failed to create prepared statement: {}", errMsgFromServer);
+          throw new SQLException("Failed to create prepared statement: " + errMsgFromServer);
+        }
+
+        logger.error("Failed to create prepared statement. Unknown status: {}, Error: {}",
status, errMsgFromServer);
+        throw new SQLException(String.format(
+            "Failed to create prepared statement. Unknown status: %s, Error: %s", status,
errMsgFromServer));
+      }
+
+      DrillPrepareResult prepareResult = new DrillPrepareResult(sql, resp.getPreparedStatement());
       DrillPreparedStatementImpl statement =
           (DrillPreparedStatementImpl) factory.newPreparedStatement(
               this, prepareResult, resultSetType, resultSetConcurrency,
               resultSetHoldability);
       return statement;
+    } catch (SQLException e) {
+      throw e;
     } catch (RuntimeException e) {
       throw Helper.INSTANCE.createException("Error while preparing statement [" + sql + "]",
e);
     } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/drill/blob/e02aa596/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillPrepareResult.java
----------------------------------------------------------------------
diff --git a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillPrepareResult.java b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillPrepareResult.java
index 6870673..4042ead 100644
--- a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillPrepareResult.java
+++ b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillPrepareResult.java
@@ -17,6 +17,8 @@
  */
 package org.apache.drill.jdbc.impl;
 
+import org.apache.drill.exec.proto.UserProtos.PreparedStatement;
+
 import java.util.Collections;
 import java.util.List;
 
@@ -29,10 +31,17 @@ class DrillPrepareResult implements AvaticaPrepareResult{
 
   final String sql;
   final DrillColumnMetaDataList columns = new DrillColumnMetaDataList();
+  final PreparedStatement preparedStatement;
 
   DrillPrepareResult(String sql) {
-    super();
     this.sql = sql;
+    this.preparedStatement = null;
+  }
+
+  DrillPrepareResult(String sql, PreparedStatement preparedStatement) {
+    this.sql = sql;
+    this.preparedStatement = preparedStatement;
+    columns.updateColumnMetaData(preparedStatement.getColumnsList());
   }
 
   @Override
@@ -45,6 +54,11 @@ class DrillPrepareResult implements AvaticaPrepareResult{
     return sql;
   }
 
+
+  public PreparedStatement getPreparedStatement() {
+    return preparedStatement;
+  }
+
   @Override
   public List<AvaticaParameter> getParameterList() {
     return Collections.emptyList();

http://git-wip-us.apache.org/repos/asf/drill/blob/e02aa596/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillResultSetImpl.java
----------------------------------------------------------------------
diff --git a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillResultSetImpl.java b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillResultSetImpl.java
index a2083d3..778504e 100644
--- a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillResultSetImpl.java
+++ b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillResultSetImpl.java
@@ -1897,7 +1897,17 @@ class DrillResultSetImpl extends AvaticaResultSet implements DrillResultSet
{
 
   @Override
   protected DrillResultSetImpl execute() throws SQLException{
-    client.runQuery(QueryType.SQL, this.prepareResult.getSql(), resultsListener);
+    final DrillPrepareResult drillPrepareResult = ((DrillPrepareResult)prepareResult);
+    /**
+     * {@link DrillPrepareResult} is created both for normal queries and prepared queries.
+     * If the prepared statement exists submit the query as prepared statement, otherwise
+     * regular submission.
+     */
+    if (drillPrepareResult.getPreparedStatement() != null) {
+      client.executePreparedStatement(drillPrepareResult.getPreparedStatement().getServerHandle(),
resultsListener);
+    } else {
+      client.runQuery(QueryType.SQL, this.prepareResult.getSql(), resultsListener);
+    }
     connection.getDriver().handler.onStatementExecute(statement, null);
 
     super.execute();

http://git-wip-us.apache.org/repos/asf/drill/blob/e02aa596/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillResultSetMetaDataImpl.java
----------------------------------------------------------------------
diff --git a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillResultSetMetaDataImpl.java
b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillResultSetMetaDataImpl.java
index 79a3455..9847555 100644
--- a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillResultSetMetaDataImpl.java
+++ b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillResultSetMetaDataImpl.java
@@ -51,7 +51,8 @@ public class DrillResultSetMetaDataImpl extends AvaticaResultSetMetaData
{
                                       SQLException {
     // Statement.isClosed() call is to avoid exception from getResultSet().
     if (statement.isClosed()
-        || statement.getResultSet().isClosed()) {
+        || (statement.getResultSet() != null // result set doesn't exist for prepared statement
cases
+            && statement.getResultSet().isClosed())) {
         throw new AlreadyClosedSqlException(
             "ResultSetMetaData's ResultSet is already closed." );
     }

http://git-wip-us.apache.org/repos/asf/drill/blob/e02aa596/exec/jdbc/src/test/java/org/apache/drill/jdbc/PreparedStatementTest.java
----------------------------------------------------------------------
diff --git a/exec/jdbc/src/test/java/org/apache/drill/jdbc/PreparedStatementTest.java b/exec/jdbc/src/test/java/org/apache/drill/jdbc/PreparedStatementTest.java
index bea309f..225c690 100644
--- a/exec/jdbc/src/test/java/org/apache/drill/jdbc/PreparedStatementTest.java
+++ b/exec/jdbc/src/test/java/org/apache/drill/jdbc/PreparedStatementTest.java
@@ -17,24 +17,41 @@
  */
 package org.apache.drill.jdbc;
 
+import static java.sql.ResultSetMetaData.columnNoNulls;
+import static java.sql.Types.BIGINT;
+import static java.sql.Types.DATE;
+import static java.sql.Types.DECIMAL;
+import static java.sql.Types.INTEGER;
+import static java.sql.Types.TIMESTAMP;
+import static java.sql.Types.VARCHAR;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.hamcrest.CoreMatchers.*;
 
+import org.apache.drill.exec.planner.physical.PlannerSettings;
+import org.apache.drill.exec.store.ischema.InfoSchemaConstants;
 import org.hamcrest.Matcher;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
-import org.apache.drill.jdbc.Driver;
 
+import com.google.common.collect.ImmutableList;
+
+import java.math.BigDecimal;
 import java.sql.Clob;
 import java.sql.Connection;
+import java.sql.Date;
 import java.sql.DriverManager;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
+import java.sql.Statement;
+import java.sql.Timestamp;
+import java.util.List;
 
 
 /**
@@ -56,74 +73,165 @@ public class PreparedStatementTest extends JdbcTestBase {
   public static void setUpConnection() throws SQLException {
     Driver.load();
     connection = DriverManager.getConnection( "jdbc:drill:zk=local" );
+    try(Statement stmt = connection.createStatement()) {
+      stmt.execute(String.format("alter session set `%s` = true", PlannerSettings.ENABLE_DECIMAL_DATA_TYPE_KEY));
+    }
   }
 
   @AfterClass
   public static void tearDownConnection() throws SQLException {
+    if (connection != null) {
+      try (Statement stmt = connection.createStatement()) {
+        stmt.execute(String.format("alter session set `%s` = false", PlannerSettings.ENABLE_DECIMAL_DATA_TYPE_KEY));
+      }
+    }
     connection.close();
   }
 
-
   //////////
   // Basic querying-works test:
 
   /** Tests that basic executeQuery() (with query statement) works. */
   @Test
   public void testExecuteQueryBasicCaseWorks() throws SQLException {
-    PreparedStatement stmt = connection.prepareStatement( "VALUES 11" );
-    ResultSet rs = stmt.executeQuery();
-    assertThat( "Unexpected column count",
-                rs.getMetaData().getColumnCount(), equalTo( 1 ) );
-    assertTrue( "No expected first row", rs.next() );
-    assertThat( rs.getInt( 1 ), equalTo( 11 ) );
-    assertFalse( "Unexpected second row", rs.next() );
+    try (PreparedStatement stmt = connection.prepareStatement( "VALUES 11" )) {
+      try(ResultSet rs = stmt.executeQuery()) {
+        assertThat("Unexpected column count",
+            rs.getMetaData().getColumnCount(), equalTo(1)
+        );
+        assertTrue("No expected first row", rs.next());
+        assertThat(rs.getInt(1), equalTo(11));
+        assertFalse("Unexpected second row", rs.next());
+      }
+    }
   }
 
+  @Test
+  public void testQueryMetadataInPreparedStatement() throws SQLException {
+    try(PreparedStatement stmt = connection.prepareStatement(
+        "SELECT " +
+            "cast(1 as INTEGER ) as int_field, " +
+            "cast(12384729 as BIGINT ) as bigint_field, " +
+            "'varchar_value' as varchar_field, " +
+            "timestamp '2008-2-23 10:00:20.123' as ts_field, " +
+            "date '2008-2-23' as date_field, " +
+            "cast('99999912399.4567' as decimal(18, 5)) as decimal_field" +
+            " FROM sys.version")) {
 
-  //////////
-  // Parameters-not-implemented tests:
+      List<ExpectedColumnResult> exp = ImmutableList.of(
+          new ExpectedColumnResult("int_field", INTEGER, columnNoNulls, 0, 0, true, Integer.class.getName()),
+          new ExpectedColumnResult("bigint_field", BIGINT, columnNoNulls, 0, 0, true, Long.class.getName()),
+          new ExpectedColumnResult("varchar_field", VARCHAR, columnNoNulls, 65536, 0, false,
String.class.getName()),
+          new ExpectedColumnResult("ts_field", TIMESTAMP, columnNoNulls, 0, 0, false, Timestamp.class.getName()),
+          new ExpectedColumnResult("date_field", DATE, columnNoNulls, 0, 0, false, Date.class.getName()),
+          new ExpectedColumnResult("decimal_field", DECIMAL, columnNoNulls, 18, 5, true,
BigDecimal.class.getName())
+      );
 
-  /** Tests that basic case of trying to set parameter says not supported. */
-  @Test( expected = SQLFeatureNotSupportedException.class )
-  public void testParamSettingSaysUnsupported() throws SQLException {
-    PreparedStatement prepStmt = connection.prepareStatement( "VALUES ?, ?" );
-    try {
-      prepStmt.setInt( 0, 123456789 );
+      ResultSetMetaData prepareMetadata = stmt.getMetaData();
+      verifyMetadata(prepareMetadata, exp);
+
+      try (ResultSet rs = stmt.executeQuery()) {
+        ResultSetMetaData executeMetadata = rs.getMetaData();
+        verifyMetadata(executeMetadata, exp);
+
+        assertTrue("No expected first row", rs.next());
+        assertThat(rs.getInt(1), equalTo(1));
+        assertThat(rs.getLong(2), equalTo(12384729L));
+        assertThat(rs.getString(3), equalTo("varchar_value"));
+        assertThat(rs.getTimestamp(4), equalTo(Timestamp.valueOf("2008-2-23 10:00:20.123")));
+        assertThat(rs.getDate(5), equalTo(Date.valueOf("2008-2-23")));
+        assertThat(rs.getBigDecimal(6), equalTo(new BigDecimal("99999912399.45670")));
+        assertFalse("Unexpected second row", rs.next());
+      }
     }
-    catch ( final SQLFeatureNotSupportedException e ) {
-      assertThat(
-          "Check whether params.-unsupported wording changed or checks changed.",
-          e.toString(), PARAMETERS_NOT_SUPPORTED_MSG_MATCHER );
-      throw e;
+  }
+
+  private static void verifyMetadata(ResultSetMetaData act, List<ExpectedColumnResult>
exp) throws SQLException {
+    assertEquals(exp.size(), act.getColumnCount());
+    for(ExpectedColumnResult e : exp) {
+      boolean found = false;
+      for(int i=1; i<=act.getColumnCount(); i++) {
+        found = e.isEqualsTo(act, i);
+        if (found) {
+          break;
+        }
+      }
+      assertTrue("Failed to find the expected column metadata: " + e, found);
     }
   }
 
-  /** Tests that "not supported" has priority over "bad index" check. */
-  @Test( expected = SQLFeatureNotSupportedException.class )
-  public void testParamSettingWithImpossibleIndexSaysUnsupported() throws SQLException {
-    PreparedStatement prepStmt = connection.prepareStatement( "VALUES ?, ?" );
-    try {
-      prepStmt.setString( -1, "some value" );
+  private static class ExpectedColumnResult {
+    final String columnName;
+    final int type;
+    final int nullable;
+    final int precision;
+    final int scale;
+    final boolean signed;
+    final String className;
+
+    ExpectedColumnResult(String columnName, int type, int nullable, int precision, int scale,
boolean signed,
+        String className) {
+      this.columnName = columnName;
+      this.type = type;
+      this.nullable = nullable;
+      this.precision = precision;
+      this.scale = scale;
+      this.signed = signed;
+      this.className = className;
     }
-    catch ( final SQLFeatureNotSupportedException e ) {
-      assertThat(
-          "Check whether params.-unsupported wording changed or checks changed.",
-          e.toString(), PARAMETERS_NOT_SUPPORTED_MSG_MATCHER );
-      throw e;
+
+    boolean isEqualsTo(ResultSetMetaData metadata, int colNum) throws SQLException {
+      return
+          metadata.getCatalogName(colNum).equals(InfoSchemaConstants.IS_CATALOG_NAME) &&
+          metadata.getSchemaName(colNum).isEmpty() &&
+          metadata.getTableName(colNum).isEmpty() &&
+          metadata.getColumnName(colNum).equals(columnName) &&
+          metadata.getColumnLabel(colNum).equals(columnName) &&
+          metadata.getColumnType(colNum) == type &&
+          metadata.isNullable(colNum) == nullable &&
+          // There is an existing bug where query results doesn't contain the precision for
VARCHAR field.
+          //metadata.getPrecision(colNum) == precision &&
+          metadata.getScale(colNum) == scale &&
+          metadata.isSigned(colNum) == signed &&
+          metadata.getColumnDisplaySize(colNum) == 10 &&
+          metadata.getColumnClassName(colNum).equals(className) &&
+          metadata.isSearchable(colNum) &&
+          metadata.isAutoIncrement(colNum) == false &&
+          metadata.isCaseSensitive(colNum) == false &&
+          metadata.isReadOnly(colNum) &&
+          metadata.isWritable(colNum) == false &&
+          metadata.isDefinitelyWritable(colNum) == false &&
+          metadata.isCurrency(colNum) == false;
+    }
+
+    @Override
+    public String toString() {
+      return "ExpectedColumnResult[" +
+          "columnName='" + columnName + '\'' +
+          ", type='" + type + '\'' +
+          ", nullable=" + nullable +
+          ", precision=" + precision +
+          ", scale=" + scale +
+          ", signed=" + signed +
+          ", className='" + className + '\'' +
+          ']';
     }
   }
 
-  /** Tests that "not supported" has priority over "bad index" check. */
-  @Test( expected = SQLFeatureNotSupportedException.class )
-  public void testParamSettingWithInconsistentIndexSaysUnsupported() throws SQLException
{
-    PreparedStatement prepStmt = connection.prepareStatement( "VALUES ?, ?" );
+  //////////
+  // Parameters-not-implemented tests:
+
+  /** Tests that basic case of trying to create a prepare statement with parameters. */
+  @Test( expected = SQLException.class )
+  public void testSqlQueryWithParamNotSupported() throws SQLException {
+
     try {
-      prepStmt.setBytes( 4, null );
+      connection.prepareStatement( "VALUES ?, ?" );
     }
-    catch ( final SQLFeatureNotSupportedException e ) {
+    catch ( final SQLException e ) {
       assertThat(
           "Check whether params.-unsupported wording changed or checks changed.",
-          e.toString(), PARAMETERS_NOT_SUPPORTED_MSG_MATCHER );
+          e.toString(), containsString("Illegal use of dynamic parameter") );
       throw e;
     }
   }
@@ -132,15 +240,16 @@ public class PreparedStatementTest extends JdbcTestBase {
    *  check. */
   @Test( expected = SQLFeatureNotSupportedException.class )
   public void testParamSettingWhenNoParametersIndexSaysUnsupported() throws SQLException
{
-    PreparedStatement prepStmt = connection.prepareStatement( "VALUES 1" );
-    try {
-      prepStmt.setBytes( 4, null );
-    }
-    catch ( final SQLFeatureNotSupportedException e ) {
-      assertThat(
-          "Check whether params.-unsupported wording changed or checks changed.",
-          e.toString(), PARAMETERS_NOT_SUPPORTED_MSG_MATCHER );
-      throw e;
+    try(PreparedStatement prepStmt = connection.prepareStatement( "VALUES 1" )) {
+      try {
+        prepStmt.setBytes(4, null);
+      } catch (final SQLFeatureNotSupportedException e) {
+        assertThat(
+            "Check whether params.-unsupported wording changed or checks changed.",
+            e.toString(), PARAMETERS_NOT_SUPPORTED_MSG_MATCHER
+        );
+        throw e;
+      }
     }
   }
 
@@ -148,15 +257,16 @@ public class PreparedStatementTest extends JdbcTestBase {
    *  check. */
   @Test( expected = SQLFeatureNotSupportedException.class )
   public void testParamSettingWhenUnsupportedTypeSaysUnsupported() throws SQLException {
-    PreparedStatement prepStmt = connection.prepareStatement( "VALUES 1" );
-    try {
-      prepStmt.setClob( 2, (Clob) null );
-    }
-    catch ( final SQLFeatureNotSupportedException e ) {
-      assertThat(
-          "Check whether params.-unsupported wording changed or checks changed.",
-          e.toString(), PARAMETERS_NOT_SUPPORTED_MSG_MATCHER );
-      throw e;
+    try(PreparedStatement prepStmt = connection.prepareStatement( "VALUES 1" )) {
+      try {
+        prepStmt.setClob(2, (Clob) null);
+      } catch (final SQLFeatureNotSupportedException e) {
+        assertThat(
+            "Check whether params.-unsupported wording changed or checks changed.",
+            e.toString(), PARAMETERS_NOT_SUPPORTED_MSG_MATCHER
+        );
+        throw e;
+      }
     }
   }
 

http://git-wip-us.apache.org/repos/asf/drill/blob/e02aa596/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/Drill2769UnsupportedReportsUseSqlExceptionTest.java
----------------------------------------------------------------------
diff --git a/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/Drill2769UnsupportedReportsUseSqlExceptionTest.java
b/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/Drill2769UnsupportedReportsUseSqlExceptionTest.java
index a673d87..8bc03aa 100644
--- a/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/Drill2769UnsupportedReportsUseSqlExceptionTest.java
+++ b/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/Drill2769UnsupportedReportsUseSqlExceptionTest.java
@@ -398,7 +398,7 @@ public class Drill2769UnsupportedReportsUseSqlExceptionTest extends JdbcTestBase
     }
 
     protected PreparedStatement getJdbcObject() throws SQLException {
-      return factoryConnection.prepareStatement(null);
+      return factoryConnection.prepareStatement("VALUES 1");
     }
 
   } // class PlainStatementChecker


Mime
View raw message