You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@drill.apache.org by me...@apache.org on 2015/07/31 05:16:45 UTC
[3/3] drill git commit: DRILL-3151: Fix many ResultSetMetaData method
return values.
DRILL-3151: Fix many ResultSetMetaData method return values.
Added ~unit test for ResultSetMetaData implementation.
Made getObject return classes available to implementation of getColumnClassName:
- Added SqlAccessor.getObjectClass() (to put that metadata right next to code
to which it corresponds rather than in far-away parallel code).
- Added similar AvaticaDrillSqlAccessor.getObjectClass().
- Changed DrillAccessorList.accessors from Accessor[] to
AvaticaDrillSqlAccessor[] for better access to JDBC getObject return class.
- Extracted return classes from accessors to pass to updateColumnMetaData.
Reworked some data type mapping and utilities:
- Added Added Types.getSqlTypeName(...).
- Renamed Types.getJdbcType(...) to getJdbcTypeCode(...)
- Replaced Types.isUnSigned with isJdbcSignedType.
- Fixed various bogus RPC-type XXX -> java.sql.Types.SMALLINT mappings.
- Removed DrillColumnMetaDataList.getJdbcTypeName.
- Moved getAvaticaType up (for bottom-up order).
- Revised DrillColumnMetaDataList.getAvaticaType(...).
MAIN:
- Updated updateColumnMetaData(...) to change many calculations of metadata
input to ColumnMetaData construction. [DrillColumnMetaDataList]
Updated other metadata tests per changes.
Project: http://git-wip-us.apache.org/repos/asf/drill/repo
Commit: http://git-wip-us.apache.org/repos/asf/drill/commit/80835082
Tree: http://git-wip-us.apache.org/repos/asf/drill/tree/80835082
Diff: http://git-wip-us.apache.org/repos/asf/drill/diff/80835082
Branch: refs/heads/master
Commit: 80835082414d274fda8bf0c66fd01386180fdde5
Parents: 9932246
Author: dbarclay <db...@maprtech.com>
Authored: Fri Jun 19 19:05:39 2015 -0700
Committer: Mehant Baid <me...@gmail.com>
Committed: Thu Jul 30 18:46:02 2015 -0700
----------------------------------------------------------------------
.../org/apache/drill/common/types/Types.java | 163 ++-
.../main/codegen/templates/SqlAccessors.java | 29 +
.../vector/accessor/BoundCheckingAccessor.java | 5 +
.../exec/vector/accessor/GenericAccessor.java | 6 +
.../drill/exec/vector/accessor/SqlAccessor.java | 8 +
.../jdbc/impl/AvaticaDrillSqlAccessor.java | 7 +
.../drill/jdbc/impl/DrillAccessorList.java | 8 +-
.../jdbc/impl/DrillColumnMetaDataList.java | 185 ++-
.../org/apache/drill/jdbc/impl/DrillCursor.java | 38 +-
.../jdbc/impl/TypeConvertingSqlAccessor.java | 5 +
.../jdbc/DatabaseMetaDataGetColumnsTest.java | 323 +++--
.../drill/jdbc/DrillColumnMetaDataListTest.java | 20 +-
.../jdbc/ResultSetGetMethodConversionsTest.java | 71 +-
.../drill/jdbc/ResultSetMetaDataTest.java | 1107 ++++++++++++++++++
.../impl/TypeConvertingSqlAccessorTest.java | 5 +
.../jdbc/test/TestInformationSchemaColumns.java | 203 ++--
16 files changed, 1745 insertions(+), 438 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/drill/blob/80835082/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 df484b7..69b1b4c 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
@@ -82,9 +82,85 @@ public class Types {
}
/***
+ * Gets SQL data type name for given Drill RPC-/protobuf-level data type.
+ * @return
+ * canonical keyword sequence for SQL data type (leading keywords in
+ * corresponding {@code <data type>}; what
+ * {@code INFORMATION_SCHEMA.COLUMNS.TYPE_NAME} would list)
+ */
+ public static String getSqlTypeName(final MajorType type) {
+ if (type.getMode() == DataMode.REPEATED) {
+ return "ARRAY";
+ }
+
+ switch (type.getMinorType()) {
+
+ // Standard SQL atomic data types:
+
+ case BIT: return "BOOLEAN";
+
+ case SMALLINT: return "SMALLINT";
+ case INT: return "INTEGER";
+ case BIGINT: return "BIGINT";
+
+ case FLOAT4: return "FLOAT";
+ case FLOAT8: return "DOUBLE";
+
+ case DECIMAL9:
+ case DECIMAL18:
+ case DECIMAL28DENSE:
+ case DECIMAL28SPARSE:
+ case DECIMAL38DENSE:
+ case DECIMAL38SPARSE: return "DECIMAL";
+
+ case VARCHAR: return "CHARACTER VARYING";
+ case FIXEDCHAR: return "CHARACTER";
+
+ case VAR16CHAR: return "NATIONAL CHARACTER VARYING";
+ case FIXED16CHAR: return "NATIONAL CHARACTER";
+
+ case VARBINARY: return "BINARY VARYING";
+ case FIXEDBINARY: return "BINARY";
+
+ case DATE: return "DATE";
+ case TIME: return "TIME";
+ case TIMETZ: return "TIME WITH TIME ZONE";
+ case TIMESTAMP: return "TIMESTAMP";
+ case TIMESTAMPTZ: return "TIMESTAMP WITH TIME ZONE";
+
+ case INTERVALYEAR:
+ case INTERVALDAY: return "INTERVAL";
+
+ // Non-standard SQL atomic data types:
+
+ case INTERVAL: return "INTERVAL";
+ case MONEY: return "DECIMAL";
+ case TINYINT: return "TINYINT";
+
+ // Composite types and other types that are not atomic types (SQL standard
+ // or not) except ARRAY types (handled above):
+
+ case MAP: return "MAP";
+ case LATE: return "ANY";
+ case NULL: return "NULL";
+
+ // Internal types not actually used at level of SQL types(?):
+
+ case UINT1: return "TINYINT";
+ case UINT2: return "SMALLINT";
+ case UINT4: return "INTEGER";
+ case UINT8: return "BIGINT";
+
+ default:
+ throw new AssertionError(
+ "Unexpected/unhandled MinorType value " + type.getMinorType() );
+ }
+ }
+
+ /***
* Gets JDBC type code for given Drill RPC-/protobuf-level type.
*/
- public static int getJdbcType(final MajorType type) {
+ public static int getJdbcTypeCode(final MajorType type) {
if (type.getMode() == DataMode.REPEATED) {
return java.sql.Types.ARRAY;
}
@@ -120,10 +196,13 @@ public class Types {
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:
@@ -132,7 +211,7 @@ public class Types {
case TIMESTAMP:
return java.sql.Types.TIMESTAMP;
case TIMETZ:
- return java.sql.Types.DATE;
+ return java.sql.Types.TIME;
case TINYINT:
return java.sql.Types.TINYINT;
case UINT1:
@@ -154,22 +233,80 @@ public class Types {
// is an unexpected, code-out-of-sync-with-itself case, so use an
// exception intended for that.
throw new UnsupportedOperationException(
- "Unexpected/unhandled " + type.getMinorType() + " value " + type.getMinorType() );
+ "Unexpected/unhandled MinorType value " + type.getMinorType() );
}
}
- public static boolean isUnSigned(final MajorType type) {
- switch(type.getMinorType()) {
- case UINT1:
- case UINT2:
- case UINT4:
- case UINT8:
- return true;
- default:
- return false;
+ /**
+ * Reports whether given RPC-level type is a signed type (per semantics of
+ * {@link ResultSetMetaData#isSigned(int)}).
+ */
+ public static boolean isJdbcSignedType( final MajorType type ) {
+ final boolean isSigned;
+ switch ( type.getMode() ) {
+ case REPEATED:
+ isSigned = false; // SQL ARRAY
+ break;
+ case REQUIRED:
+ case OPTIONAL:
+ switch ( type.getMinorType() ) {
+ // Verified signed types:
+ case SMALLINT:
+ case INT: // SQL INTEGER
+ case BIGINT:
+ case FLOAT4: // SQL REAL / FLOAT(N)
+ case FLOAT8: // SQL DOUBLE PRECISION / FLOAT(N)
+ case INTERVALYEAR: // SQL INTERVAL w/YEAR and/or MONTH
+ case INTERVALDAY: // SQL INTERVAL w/DAY, HOUR, MINUTE and/or SECOND
+ // Not-yet seen/verified signed types:
+ case DECIMAL9: // SQL DECIMAL (if used)
+ case DECIMAL18: // SQL DECIMAL (if used)
+ case DECIMAL28SPARSE: // SQL DECIMAL (if used)
+ case DECIMAL38SPARSE: // SQL DECIMAL (if used)
+ case DECIMAL28DENSE: // SQL DECIMAL (if used)
+ case DECIMAL38DENSE: // SQL DECIMAL (if used)
+ case TINYINT: // (not standard SQL)
+ case MONEY: // (not standard SQL)
+ case INTERVAL: // unknown (given INTERVALYEAR and INTERVALDAY)
+ isSigned = true;
+ break;
+ // Verified unsigned types:
+ case BIT: // SQL BOOLEAN
+ case VARCHAR:
+ case FIXEDCHAR: // SQL CHARACTER
+ case VARBINARY:
+ case FIXEDBINARY: // SQL BINARY
+ case DATE:
+ case TIME: // SQL TIME WITHOUT TIME ZONE
+ case TIMESTAMP: // SQL TIMESTAMP WITHOUT TIME ZONE
+ // Not-yet seen/verified unsigned types:
+ case UINT1:
+ case UINT2:
+ case UINT4:
+ case UINT8:
+ case FIXED16CHAR:
+ case VAR16CHAR:
+ case GENERIC_OBJECT:
+ case LATE:
+ case LIST:
+ case MAP:
+ case NULL:
+ case TIMETZ: // SQL TIME WITH TIME ZONE
+ case TIMESTAMPTZ: // SQL TIMESTAMP WITH TIME ZONE
+ isSigned = false;
+ break;
+ default:
+ throw new UnsupportedOperationException(
+ "Unexpected/unhandled MinorType value " + type.getMinorType() );
+ }
+ break;
+ default:
+ throw new UnsupportedOperationException(
+ "Unexpected/unhandled DataMode value " + type.getMode() );
}
-
+ return isSigned;
}
+
public static boolean usesHolderForGet(final MajorType type) {
if (type.getMode() == REPEATED) {
return true;
http://git-wip-us.apache.org/repos/asf/drill/blob/80835082/exec/java-exec/src/main/codegen/templates/SqlAccessors.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/codegen/templates/SqlAccessors.java b/exec/java-exec/src/main/codegen/templates/SqlAccessors.java
index c50a3e2..3257499 100644
--- a/exec/java-exec/src/main/codegen/templates/SqlAccessors.java
+++ b/exec/java-exec/src/main/codegen/templates/SqlAccessors.java
@@ -24,6 +24,10 @@ import java.lang.Override;
<#list ["", "Nullable"] as mode>
<#assign name = mode + minor.class?cap_first />
<#assign javaType = (minor.javaType!type.javaType) />
+<#assign friendlyType = (minor.friendlyType!minor.boxedType!type.boxedType) />
+<#-- Class returned by ResultSet.getObject(...): -->
+<#assign jdbcObjectClass = minor.jdbcObjectClass ! friendlyType />
+
<@pp.changeOutputFile name="/org/apache/drill/exec/vector/accessor/${name}Accessor.java" />
<#include "/@includes/license.ftl" />
@@ -60,6 +64,11 @@ public class ${name}Accessor extends AbstractSqlAccessor {
}
<#if minor.class != "TimeStamp" && minor.class != "Time" && minor.class != "Date">
+ @Override
+ public Class<?> getObjectClass() {
+ return ${jdbcObjectClass}.class;
+ }
+
public Object getObject(int index) {
<#if mode == "Nullable">
if (ac.isNull(index)) {
@@ -161,6 +170,11 @@ public class ${name}Accessor extends AbstractSqlAccessor {
<#if minor.class == "TimeStampTZ">
+ @Override
+ public Class<?> getObjectClass() {
+ return Timestamp.class;
+ }
+
public Object getObject(int index) {
return getTimestamp(index);
}
@@ -200,6 +214,11 @@ public class ${name}Accessor extends AbstractSqlAccessor {
}
<#elseif minor.class == "Date">
+ @Override
+ public Class<?> getObjectClass() {
+ return Date.class;
+ }
+
public Object getObject(int index) {
<#if mode == "Nullable">
if (ac.isNull(index)) {
@@ -223,6 +242,11 @@ public class ${name}Accessor extends AbstractSqlAccessor {
<#elseif minor.class == "TimeStamp">
+ @Override
+ public Class<?> getObjectClass() {
+ return Timestamp.class;
+ }
+
public Object getObject(int index) {
<#if mode == "Nullable">
if (ac.isNull(index)) {
@@ -246,6 +270,11 @@ public class ${name}Accessor extends AbstractSqlAccessor {
<#elseif minor.class == "Time">
+ @Override
+ public Class<?> getObjectClass() {
+ return Time.class;
+ }
+
public Object getObject(int index) {
return getTime(index);
}
http://git-wip-us.apache.org/repos/asf/drill/blob/80835082/exec/java-exec/src/main/java/org/apache/drill/exec/vector/accessor/BoundCheckingAccessor.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/accessor/BoundCheckingAccessor.java b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/accessor/BoundCheckingAccessor.java
index 3d3683e..bfef947 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/accessor/BoundCheckingAccessor.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/accessor/BoundCheckingAccessor.java
@@ -45,6 +45,11 @@ public class BoundCheckingAccessor implements SqlAccessor {
}
@Override
+ public Class<?> getObjectClass() {
+ return delegate.getObjectClass();
+ }
+
+ @Override
public boolean isNull(int rowOffset) {
return delegate.isNull(rowOffset);
}
http://git-wip-us.apache.org/repos/asf/drill/blob/80835082/exec/java-exec/src/main/java/org/apache/drill/exec/vector/accessor/GenericAccessor.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/accessor/GenericAccessor.java b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/accessor/GenericAccessor.java
index 65c34ad..d8f2995 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/accessor/GenericAccessor.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/accessor/GenericAccessor.java
@@ -20,6 +20,7 @@ package org.apache.drill.exec.vector.accessor;
import org.apache.drill.common.types.TypeProtos;
import org.apache.drill.exec.vector.ValueVector;
+
public class GenericAccessor extends AbstractSqlAccessor {
private ValueVector v;
@@ -29,6 +30,11 @@ public class GenericAccessor extends AbstractSqlAccessor {
}
@Override
+ public Class<?> getObjectClass() {
+ return Object.class;
+ }
+
+ @Override
public boolean isNull(int index) {
return v.getAccessor().isNull(index);
}
http://git-wip-us.apache.org/repos/asf/drill/blob/80835082/exec/java-exec/src/main/java/org/apache/drill/exec/vector/accessor/SqlAccessor.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/accessor/SqlAccessor.java b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/accessor/SqlAccessor.java
index 19e6fcf..636456d 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/accessor/SqlAccessor.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/accessor/SqlAccessor.java
@@ -63,6 +63,14 @@ public interface SqlAccessor {
MajorType getType();
/**
+ * Reports the class returned by getObject() of this accessor.
+ * <p>
+ * (Is for {@link ResultSetMetaData#getColumnClassName(...)}.)
+ * </p>
+ */
+ Class<?> getObjectClass();
+
+ /**
* Reports whether the logical value is a SQL NULL.
*/
boolean isNull(int rowOffset);
http://git-wip-us.apache.org/repos/asf/drill/blob/80835082/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/AvaticaDrillSqlAccessor.java
----------------------------------------------------------------------
diff --git a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/AvaticaDrillSqlAccessor.java b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/AvaticaDrillSqlAccessor.java
index 64f5b87..7e53a07 100644
--- a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/AvaticaDrillSqlAccessor.java
+++ b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/AvaticaDrillSqlAccessor.java
@@ -78,6 +78,13 @@ class AvaticaDrillSqlAccessor implements Accessor {
}
}
+ /**
+ * @see SQLAccesstor#getObjectClass()
+ */
+ public Class<?> getObjectClass() {
+ return underlyingAccessor.getObjectClass();
+ }
+
@Override
public boolean wasNull() throws SQLException {
return underlyingAccessor.isNull(getCurrentRecordNumber());
http://git-wip-us.apache.org/repos/asf/drill/blob/80835082/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillAccessorList.java
----------------------------------------------------------------------
diff --git a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillAccessorList.java b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillAccessorList.java
index 25ca1ba..9284875 100644
--- a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillAccessorList.java
+++ b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillAccessorList.java
@@ -31,14 +31,14 @@ import org.apache.drill.exec.vector.accessor.SqlAccessor;
class DrillAccessorList extends BasicList<Accessor>{
static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DrillAccessorList.class);
- private Accessor[] accessors = new Accessor[0];
+ private AvaticaDrillSqlAccessor[] accessors = new AvaticaDrillSqlAccessor[0];
// TODO Rename to lastColumnAccessed and/or document.
// TODO Why 1, rather than, say, -1?
private int lastColumn = 1;
- void generateAccessors(DrillCursor cursor, RecordBatchLoader currentBatch){
+ void generateAccessors(DrillCursor cursor, RecordBatchLoader currentBatch) {
int cnt = currentBatch.getSchema().getFieldCount();
- accessors = new Accessor[cnt];
+ accessors = new AvaticaDrillSqlAccessor[cnt];
for(int i =0; i < cnt; i++){
final ValueVector vector = currentBatch.getValueAccessorById(null, i).getValueVector();
final SqlAccessor acc =
@@ -50,7 +50,7 @@ class DrillAccessorList extends BasicList<Accessor>{
}
@Override
- public Accessor get(int index) {
+ public AvaticaDrillSqlAccessor get(int index) {
lastColumn = index;
return accessors[index];
}
http://git-wip-us.apache.org/repos/asf/drill/blob/80835082/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 d43755e..1813cc7 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
@@ -41,7 +41,7 @@ public class DrillColumnMetaDataList extends BasicList<ColumnMetaData>{
@Override
public int size() {
- return (columns.size());
+ return columns.size();
}
@Override
@@ -49,121 +49,80 @@ public class DrillColumnMetaDataList extends BasicList<ColumnMetaData>{
return columns.get(index);
}
- public void updateColumnMetaData(String catalogName, String schemaName, String tableName, BatchSchema schema){
-
- columns = new ArrayList<ColumnMetaData>(schema.getFieldCount());
- for(int i = 0; i < schema.getFieldCount(); i++){
- MaterializedField f = schema.getColumn(i);
- MajorType t = f.getType();
- ColumnMetaData col = new ColumnMetaData( //
- i, // ordinal
- false, // autoIncrement
- true, // caseSensitive
- false, // searchable
- false, // currency
- f.getDataMode() == DataMode.OPTIONAL ? ResultSetMetaData.columnNullable : ResultSetMetaData.columnNoNulls, //nullability
- !Types.isUnSigned(t), // signed
- 10, // display size.
- f.getAsSchemaPath().getRootSegment().getPath(), // label
- f.getAsSchemaPath().getRootSegment().getPath(), // columnname
- schemaName, // schemaname
- t.hasPrecision() ? t.getPrecision() : 0, // precision
- t.hasScale() ? t.getScale() : 0, // scale
- null, // tablename is null so sqlline doesn't try to retrieve primary keys.
- catalogName, // catalogname
- getAvaticaType(t), // sql type
- true, // readonly
- false, // writable
- false, // definitely writable
- "none" // column class name
- );
- columns.add(col);
- }
+ /**
+ * 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 );
+ return ColumnMetaData.scalar( jdbcTypeId, sqlTypeName,
+ Rep.BOOLEAN /* dummy value, unused */ );
}
- private static AvaticaType getAvaticaType(MajorType t){
- final int jdbcTypeId = Types.getJdbcType(t);
- return ColumnMetaData.scalar(jdbcTypeId, getJdbcTypeName(jdbcTypeId), Rep.BOOLEAN /* dummy value, unused */);
- }
-
- private static String getJdbcTypeName(int type) {
- switch (type) {
- case java.sql.Types.BIT:
- return "BIT";
- case java.sql.Types.TINYINT:
- return "TINYINT";
- case java.sql.Types.SMALLINT:
- return "SMALLINT";
- case java.sql.Types.INTEGER:
- return "INTEGER";
- case java.sql.Types.BIGINT:
- return "BIGINT";
- case java.sql.Types.FLOAT:
- return "FLOAT";
- case java.sql.Types.REAL:
- return "REAL";
- case java.sql.Types.DOUBLE:
- return "DOUBLE";
- case java.sql.Types.NUMERIC:
- return "NUMERIC";
- case java.sql.Types.DECIMAL:
- return "DECIMAL";
- case java.sql.Types.CHAR:
- return "CHAR";
- case java.sql.Types.VARCHAR:
- return "VARCHAR";
- case java.sql.Types.LONGVARCHAR:
- return "LONGVARCHAR";
- case java.sql.Types.DATE:
- return "DATE";
- case java.sql.Types.TIME:
- return "TIME";
- case java.sql.Types.TIMESTAMP:
- return "TIMESTAMP";
- case java.sql.Types.BINARY:
- return "BINARY";
- case java.sql.Types.VARBINARY:
- return "VARBINARY";
- case java.sql.Types.LONGVARBINARY:
- return "LONGVARBINARY";
- case java.sql.Types.NULL:
- return "NULL";
- case java.sql.Types.OTHER:
- return "OTHER";
- case java.sql.Types.JAVA_OBJECT:
- return "JAVA_OBJECT";
- case java.sql.Types.DISTINCT:
- return "DISTINCT";
- case java.sql.Types.STRUCT:
- return "STRUCT";
- case java.sql.Types.ARRAY:
- return "ARRAY";
- case java.sql.Types.BLOB:
- return "BLOB";
- case java.sql.Types.CLOB:
- return "CLOB";
- case java.sql.Types.REF:
- return "REF";
- case java.sql.Types.DATALINK:
- return "DATALINK";
- case java.sql.Types.BOOLEAN:
- return "BOOLEAN";
- case java.sql.Types.ROWID:
- return "ROWID";
- case java.sql.Types.NCHAR:
- return "NCHAR";
- case java.sql.Types.NVARCHAR:
- return "NVARCHAR";
- case java.sql.Types.LONGNVARCHAR:
- return "LONGNVARCHAR";
- case java.sql.Types.NCLOB:
- return "NCLOB";
- case java.sql.Types.SQLXML:
- return "SQLXML";
- default:
- logger.error( "Unexpected java.sql.Types value {}", type );
- return "unknown java.sql.Types value " + type;
+ public void updateColumnMetaData(String catalogName, String schemaName,
+ String tableName, BatchSchema schema,
+ List<Class<?>> getObjectClasses ) {
+ final List<ColumnMetaData> newColumns =
+ new ArrayList<ColumnMetaData>(schema.getFieldCount());
+ for (int colOffset = 0; colOffset < schema.getFieldCount(); colOffset++) {
+ final MaterializedField field = schema.getColumn(colOffset);
+ Class<?> objectClass = getObjectClasses.get( colOffset );
+
+ final String columnName = field.getPath().getRootSegment().getPath();
+
+ final MajorType rpcDataType = field.getType();
+ final AvaticaType bundledSqlDataType = getAvaticaType(rpcDataType);
+ final String columnClassName = objectClass.getName();
+
+ final int nullability;
+ switch ( field.getDataMode() ) {
+ case OPTIONAL: nullability = ResultSetMetaData.columnNullable; break;
+ case REQUIRED: nullability = ResultSetMetaData.columnNoNulls; break;
+ // Should REPEATED still map to columnNoNulls? or to columnNullable?
+ case REPEATED: nullability = ResultSetMetaData.columnNoNulls; break;
+ default:
+ throw new AssertionError( "Unexpected new DataMode value '"
+ + field.getDataMode().name() + "'" );
+ }
+ final boolean isSigned = Types.isJdbcSignedType( rpcDataType );
+
+ // TODO(DRILL-3355): TODO(DRILL-3356): When string lengths, precisions,
+ // interval kinds, etc., are available from RPC-level data, implement:
+ // - precision for ResultSetMetadata.getPrecision(...) (like
+ // getColumns()'s COLUMN_SIZE)
+ // - scale for getScale(...), and
+ // - and displaySize for getColumnDisplaySize(...).
+ final int precision =
+ rpcDataType.hasPrecision() ? rpcDataType.getPrecision() : 0;
+ final int scale = rpcDataType.hasScale() ? rpcDataType.getScale() : 0;
+ final int displaySize = 10;
+
+ ColumnMetaData col = new ColumnMetaData(
+ colOffset, // (zero-based ordinal (for Java arrays/lists).)
+ false, /* autoIncrement */
+ false, /* caseSensitive */
+ true, /* searchable */
+ false, /* currency */
+ nullability,
+ isSigned,
+ displaySize,
+ columnName, /* label */
+ columnName, /* columnName */
+ schemaName,
+ precision,
+ scale,
+ tableName,
+ catalogName,
+ bundledSqlDataType,
+ true, /* readOnly */
+ false, /* writable */
+ false, /* definitelyWritable */
+ columnClassName
+ );
+ newColumns.add(col);
}
+ columns = newColumns;
}
@Override
http://git-wip-us.apache.org/repos/asf/drill/blob/80835082/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillCursor.java
----------------------------------------------------------------------
diff --git a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillCursor.java b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillCursor.java
index 5ae7509..07d7066 100644
--- a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillCursor.java
+++ b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillCursor.java
@@ -18,6 +18,7 @@
package org.apache.drill.jdbc.impl;
import java.sql.SQLException;
+import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
@@ -31,6 +32,7 @@ import org.apache.drill.exec.exception.SchemaChangeException;
import org.apache.drill.exec.record.BatchSchema;
import org.apache.drill.exec.record.RecordBatchLoader;
import org.apache.drill.exec.rpc.user.QueryDataBatch;
+import org.apache.drill.exec.store.ischema.InfoSchemaConstants;
import org.slf4j.Logger;
import static org.slf4j.LoggerFactory.getLogger;
@@ -38,7 +40,8 @@ import static org.slf4j.LoggerFactory.getLogger;
class DrillCursor implements Cursor {
private static final Logger logger = getLogger( DrillCursor.class );
- private static final String UNKNOWN = "--UNKNOWN--";
+ /** JDBC-specified string for unknown catalog, schema, and table names. */
+ private static final String UNKNOWN_NAME_STRING = "";
/** The associated {@link java.sql.ResultSet} implementation. */
private final DrillResultSetImpl resultSet;
@@ -104,6 +107,10 @@ class DrillCursor implements Cursor {
return currentRecordNumber;
}
+ // (Overly restrictive Avatica uses List<Accessor> instead of List<? extends
+ // Accessor>, so accessors/DrillAccessorList can't be of type
+ // List<AvaticaDrillSqlAccessor>, and we have to cast from Accessor to
+ // AvaticaDrillSqlAccessor in updateColumns().)
@Override
public List<Accessor> createAccessors(List<ColumnMetaData> types,
Calendar localCalendar, Factory factory) {
@@ -111,9 +118,31 @@ class DrillCursor implements Cursor {
return accessors;
}
+ /**
+ * Updates column accessors and metadata from current record batch.
+ */
private void updateColumns() {
+ // First update accessors and schema from batch:
accessors.generateAccessors(this, currentBatchHolder);
- columnMetaDataList.updateColumnMetaData(UNKNOWN, UNKNOWN, UNKNOWN, schema);
+
+ // Extract Java types from accessors for metadata's getColumnClassName:
+ final List<Class<?>> getObjectClasses = new ArrayList<>();
+ // (Can't use modern for loop because, for some incompletely clear reason,
+ // DrillAccessorList blocks iterator() (throwing exception).)
+ for ( int ax = 0; ax < accessors.size(); ax++ ) {
+ final AvaticaDrillSqlAccessor accessor =
+ (AvaticaDrillSqlAccessor) accessors.get( ax );
+ getObjectClasses.add( accessor.getObjectClass() );
+ }
+
+ // Update metadata for result set.
+ columnMetaDataList.updateColumnMetaData(
+ InfoSchemaConstants.IS_CATALOG_NAME,
+ UNKNOWN_NAME_STRING, // schema name
+ UNKNOWN_NAME_STRING, // table name
+ schema,
+ getObjectClasses );
+
if (getResultSet().changeListener != null) {
getResultSet().changeListener.schemaChanged(schema);
}
@@ -180,8 +209,9 @@ class DrillCursor implements Cursor {
afterLastRow = true;
return false;
} else {
- // Got next (or first) batch--reset record offset to beginning,
- // assimilate schema if changed, ... ???
+ // Got next (or first) batch--reset record offset to beginning;
+ // assimilate schema if changed; set up return value for first call
+ // to next().
currentRecordNumber = 0;
http://git-wip-us.apache.org/repos/asf/drill/blob/80835082/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/TypeConvertingSqlAccessor.java
----------------------------------------------------------------------
diff --git a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/TypeConvertingSqlAccessor.java b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/TypeConvertingSqlAccessor.java
index b542f94..2e17e33 100644
--- a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/TypeConvertingSqlAccessor.java
+++ b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/TypeConvertingSqlAccessor.java
@@ -46,6 +46,11 @@ class TypeConvertingSqlAccessor implements SqlAccessor {
}
@Override
+ public Class<?> getObjectClass() {
+ return innerAccessor.getObjectClass();
+ }
+
+ @Override
public boolean isNull( int rowOffset ) {
return innerAccessor.isNull( rowOffset );
}