Repository: phoenix Updated Branches: refs/heads/4.x-HBase-0.98 3c205ac49 -> 3f620f54f
PHOENIX-2489 Support sequence metadata access through DatabaseMetaData interface Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/3f620f54 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/3f620f54 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/3f620f54 Branch: refs/heads/4.x-HBase-0.98 Commit: 3f620f54f842505c3a2f3cc1e9e0bdacd9f19dec Parents: 3c205ac Author: James Taylor <jamestay...@apache.org> Authored: Fri Jun 10 09:45:28 2016 -0700 Committer: James Taylor <jamestay...@apache.org> Committed: Fri Jun 10 09:59:35 2016 -0700 ---------------------------------------------------------------------- .../end2end/QueryDatabaseMetaDataIT.java | 99 ++++++++++- .../apache/phoenix/compile/UnionCompiler.java | 2 +- .../phoenix/filter/BooleanExpressionFilter.java | 1 + .../filter/MultiKeyValueComparisonFilter.java | 1 - .../phoenix/jdbc/PhoenixDatabaseMetaData.java | 167 +++++++++++++------ .../org/apache/phoenix/schema/ValueSchema.java | 30 ++-- 6 files changed, 235 insertions(+), 65 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f620f54/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryDatabaseMetaDataIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryDatabaseMetaDataIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryDatabaseMetaDataIT.java index aa7a6b2..65ba0ad 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryDatabaseMetaDataIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryDatabaseMetaDataIT.java @@ -175,6 +175,103 @@ public class QueryDatabaseMetaDataIT extends BaseClientManagedTimeIT { } @Test + public void testTableTypes() throws SQLException { + long ts = nextTimestamp(); + Properties props = new Properties(); + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 10)); + Connection conn = DriverManager.getConnection(getUrl(), props); + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getTableTypes(); + assertTrue(rs.next()); + assertEquals("INDEX",rs.getString(1)); + assertTrue(rs.next()); + assertEquals("SEQUENCE",rs.getString(1)); + assertTrue(rs.next()); + assertEquals("SYSTEM TABLE",rs.getString(1)); + assertTrue(rs.next()); + assertEquals("TABLE",rs.getString(1)); + assertTrue(rs.next()); + assertEquals("VIEW",rs.getString(1)); + assertFalse(rs.next()); + } + + @Test + public void testSequenceMetadataScan() throws SQLException { + long ts = nextTimestamp(); + Properties props = new Properties(); + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 10)); + Connection conn = DriverManager.getConnection(getUrl(), props); + conn.createStatement().execute("CREATE SEQUENCE b.s1"); + conn.createStatement().execute("CREATE SEQUENCE a.s2"); + conn.createStatement().execute("CREATE SEQUENCE b.s3"); + conn.createStatement().execute("CREATE SEQUENCE c.s1"); + + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 20)); + conn = DriverManager.getConnection(getUrl(), props); + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getTables(null, null, null, new String[] {"FOO"}); + assertFalse(rs.next()); + + rs = dbmd.getTables(null, null, null, new String[] {"FOO",PhoenixDatabaseMetaData.SEQUENCE_TABLE_TYPE}); + assertTrue(rs.next()); + assertNull(rs.getString("TABLE_CAT")); + assertEquals("A", rs.getString("TABLE_SCHEM")); + assertEquals("S2", rs.getString("TABLE_NAME")); + assertTrue(rs.next()); + assertNull(rs.getString("TABLE_CAT")); + assertEquals("B", rs.getString("TABLE_SCHEM")); + assertEquals("S1", rs.getString("TABLE_NAME")); + assertTrue(rs.next()); + assertNull(rs.getString("TABLE_CAT")); + assertEquals("B", rs.getString("TABLE_SCHEM")); + assertEquals("S3", rs.getString("TABLE_NAME")); + assertTrue(rs.next()); + assertNull(rs.getString("TABLE_CAT")); + assertEquals("C", rs.getString("TABLE_SCHEM")); + assertEquals("S1", rs.getString("TABLE_NAME")); + assertFalse(rs.next()); + + conn.createStatement().execute("CREATE TABLE foo (k bigint primary key)"); + conn.createStatement().execute("CREATE TABLE z.bas (k bigint primary key)"); + + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 30)); + conn = DriverManager.getConnection(getUrl(), props); + dbmd = conn.getMetaData(); + rs = dbmd.getTables(null, null, null, new String[] {PTableType.TABLE.toString(),PhoenixDatabaseMetaData.SEQUENCE_TABLE_TYPE}); + assertTrue(rs.next()); + assertNull(rs.getString("TABLE_CAT")); + assertEquals("A", rs.getString("TABLE_SCHEM")); + assertEquals("S2", rs.getString("TABLE_NAME")); + assertEquals(PhoenixDatabaseMetaData.SEQUENCE_TABLE_TYPE, rs.getString("TABLE_TYPE")); + assertTrue(rs.next()); + assertNull(rs.getString("TABLE_CAT")); + assertEquals("B", rs.getString("TABLE_SCHEM")); + assertEquals("S1", rs.getString("TABLE_NAME")); + assertEquals(PhoenixDatabaseMetaData.SEQUENCE_TABLE_TYPE, rs.getString("TABLE_TYPE")); + assertTrue(rs.next()); + assertNull(rs.getString("TABLE_CAT")); + assertEquals("B", rs.getString("TABLE_SCHEM")); + assertEquals("S3", rs.getString("TABLE_NAME")); + assertEquals(PhoenixDatabaseMetaData.SEQUENCE_TABLE_TYPE, rs.getString("TABLE_TYPE")); + assertTrue(rs.next()); + assertNull(rs.getString("TABLE_CAT")); + assertEquals("C", rs.getString("TABLE_SCHEM")); + assertEquals("S1", rs.getString("TABLE_NAME")); + assertEquals(PhoenixDatabaseMetaData.SEQUENCE_TABLE_TYPE, rs.getString("TABLE_TYPE")); + assertTrue(rs.next()); + assertNull(rs.getString("TABLE_CAT")); + assertNull(rs.getString("TABLE_SCHEM")); + assertEquals("FOO", rs.getString("TABLE_NAME")); + assertEquals(PTableType.TABLE.toString(), rs.getString("TABLE_TYPE")); + assertTrue(rs.next()); + assertNull(rs.getString("TABLE_CAT")); + assertEquals("Z", rs.getString("TABLE_SCHEM")); + assertEquals("BAS", rs.getString("TABLE_NAME")); + assertEquals(PTableType.TABLE.toString(), rs.getString("TABLE_TYPE")); + assertFalse(rs.next()); + } + + @Test public void testSchemaMetadataScan() throws SQLException { Properties props = new Properties(); props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(1)); @@ -191,7 +288,7 @@ public class QueryDatabaseMetaDataIT extends BaseClientManagedTimeIT { assertEquals(rs.getString(2),null); assertFalse(rs.next()); - rs = dbmd.getSchemas(null, null); + rs = dbmd.getSchemas(); assertTrue(rs.next()); assertEquals(rs.getString("TABLE_SCHEM"),CUSTOM_ENTITY_DATA_SCHEMA_NAME); assertEquals(rs.getString("TABLE_CATALOG"),null); http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f620f54/phoenix-core/src/main/java/org/apache/phoenix/compile/UnionCompiler.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/UnionCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/UnionCompiler.java index 8dd350c..df04a85 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/UnionCompiler.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/UnionCompiler.java @@ -60,7 +60,7 @@ public class UnionCompiler { List<? extends ColumnProjector> pros = plan.getProjector().getColumnProjectors(); for (int j = 0; j < columnCount; j++) { PDataType type = pros.get(j).getExpression().getDataType(); - if (!type.isCoercibleTo(selectTypes.get(j))) { + if (type != null && !type.isCoercibleTo(selectTypes.get(j))) { throw new SQLExceptionInfo.Builder(SQLExceptionCode.SELECT_COLUMN_TYPE_IN_UNIONALL_DIFFS).setMessage(".").build().buildException(); } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f620f54/phoenix-core/src/main/java/org/apache/phoenix/filter/BooleanExpressionFilter.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/filter/BooleanExpressionFilter.java b/phoenix-core/src/main/java/org/apache/phoenix/filter/BooleanExpressionFilter.java index c5b36b2..678ccca 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/filter/BooleanExpressionFilter.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/filter/BooleanExpressionFilter.java @@ -104,6 +104,7 @@ abstract public class BooleanExpressionFilter extends FilterBase implements Writ try { expression = ExpressionType.values()[WritableUtils.readVInt(input)].newInstance(); expression.readFields(input); + expression.reset(); // Initializes expression tree for partial evaluation } catch (Throwable t) { // Catches incompatibilities during reading/writing and doesn't retry ServerUtil.throwIOException("BooleanExpressionFilter failed during reading", t); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f620f54/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiKeyValueComparisonFilter.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiKeyValueComparisonFilter.java b/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiKeyValueComparisonFilter.java index 569faa5..dba700b 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiKeyValueComparisonFilter.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiKeyValueComparisonFilter.java @@ -189,7 +189,6 @@ public abstract class MultiKeyValueComparisonFilter extends BooleanExpressionFil } }; expression.accept(visitor); - expression.reset(); } @Override http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f620f54/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java index d80bd39..a067fb4 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java @@ -299,6 +299,7 @@ public class PhoenixDatabaseMetaData implements DatabaseMetaData { public static final byte[] APPEND_ONLY_SCHEMA_BYTES = Bytes.toBytes(APPEND_ONLY_SCHEMA); public static final String ASYNC_CREATED_DATE = "ASYNC_CREATED_DATE"; + public static final String SEQUENCE_TABLE_TYPE = SYSTEM_SEQUENCE_TABLE; private final PhoenixConnection connection; private final ResultSet emptyResultSet; @@ -915,7 +916,7 @@ public class PhoenixDatabaseMetaData implements DatabaseMetaData { @Override public ResultSet getSchemas() throws SQLException { - return getSchemas(null, null); + return getSchemas("", null); } @Override @@ -925,10 +926,14 @@ public class PhoenixDatabaseMetaData implements DatabaseMetaData { TENANT_ID + " " + TABLE_CATALOG + " from " + SYSTEM_CATALOG + " " + SYSTEM_CATALOG_ALIAS + " where " + COLUMN_NAME + " is null"); + addTenantIdFilter(buf, catalog); if (schemaPattern != null) { buf.append(" and " + TABLE_SCHEM + " like '" + StringUtil.escapeStringConstant(schemaPattern) + "'"); } buf.append(" and " + TABLE_NAME + " = '" + MetaDataClient.EMPTY_TABLE + "'"); + + // TODO: we should union this with SYSTEM.SEQUENCE too, but we only have support for + // UNION ALL and we really need UNION so that it dedups. Statement stmt = connection.createStatement(); return stmt.executeQuery(buf.toString()); } @@ -1010,67 +1015,133 @@ public class PhoenixDatabaseMetaData implements DatabaseMetaData { ), 0, true); private static final Collection<Tuple> TABLE_TYPE_TUPLES = Lists.newArrayListWithExpectedSize(PTableType.values().length); static { - for (PTableType tableType : PTableType.values()) { - TABLE_TYPE_TUPLES.add(new SingleKeyValueTuple(KeyValueUtil.newKeyValue(tableType.getValue().getBytes(), TABLE_FAMILY_BYTES, TABLE_TYPE_BYTES, MetaDataProtocol.MIN_TABLE_TIMESTAMP, ByteUtil.EMPTY_BYTE_ARRAY))); + List<byte[]> tableTypes = Lists.<byte[]>newArrayList( + PTableType.INDEX.getValue().getBytes(), + Bytes.toBytes(SEQUENCE_TABLE_TYPE), + PTableType.SYSTEM.getValue().getBytes(), + PTableType.TABLE.getValue().getBytes(), + PTableType.VIEW.getValue().getBytes()); + for (byte[] tableType : tableTypes) { + TABLE_TYPE_TUPLES.add(new SingleKeyValueTuple(KeyValueUtil.newKeyValue(tableType, TABLE_FAMILY_BYTES, TABLE_TYPE_BYTES, MetaDataProtocol.MIN_TABLE_TIMESTAMP, ByteUtil.EMPTY_BYTE_ARRAY))); } } + + /** + * Supported table types include: INDEX, SEQUENCE, SYSTEM TABLE, TABLE, VIEW + */ @Override public ResultSet getTableTypes() throws SQLException { return new PhoenixResultSet(new MaterializedResultIterator(TABLE_TYPE_TUPLES), TABLE_TYPE_ROW_PROJECTOR, new StatementContext(new PhoenixStatement(connection), false)); } - /** - * We support either: - * 1) A non null tableNamePattern to find an exactly match with a table name, in which case either a single - * row would be returned in the ResultSet (if found) or no rows would be returned (if not - * found). - * 2) A null tableNamePattern, in which case the ResultSet returned would have one row per - * table. - * Note that catalog and schemaPattern must be null or an empty string and types must be null - * or "TABLE". Otherwise, no rows will be returned. - */ @Override public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException { - StringBuilder buf = new StringBuilder("select \n" + - TENANT_ID + " " + TABLE_CAT + "," + // tenant_id is the catalog - TABLE_SCHEM + "," + - TABLE_NAME + " ," + - SQLTableTypeFunction.NAME + "(" + TABLE_TYPE + ") AS " + TABLE_TYPE + "," + - REMARKS + " ," + - TYPE_NAME + "," + - SELF_REFERENCING_COL_NAME + "," + - REF_GENERATION + "," + - IndexStateNameFunction.NAME + "(" + INDEX_STATE + ") AS " + INDEX_STATE + "," + - IMMUTABLE_ROWS + "," + - SALT_BUCKETS + "," + - MULTI_TENANT + "," + - VIEW_STATEMENT + "," + - SQLViewTypeFunction.NAME + "(" + VIEW_TYPE + ") AS " + VIEW_TYPE + "," + - SQLIndexTypeFunction.NAME + "(" + INDEX_TYPE + ") AS " + INDEX_TYPE + "," + - TRANSACTIONAL + - " from " + SYSTEM_CATALOG + " " + SYSTEM_CATALOG_ALIAS + - " where " + COLUMN_NAME + " is null" + - " and " + COLUMN_FAMILY + " is null" + - " and " + TABLE_NAME + " != '" + MetaDataClient.EMPTY_TABLE + "'"); - addTenantIdFilter(buf, catalog); - if (schemaPattern != null) { - buf.append(" and " + TABLE_SCHEM + (schemaPattern.length() == 0 ? " is null" : " like '" + StringUtil.escapeStringConstant(schemaPattern) + "'" )); + + boolean isSequence = false; + boolean hasTableTypes = types != null && types.length > 0; + StringBuilder typeClauseBuf = new StringBuilder(); + if (hasTableTypes) { + List<String> tableTypes = Lists.newArrayList(types); + isSequence = tableTypes.remove(SEQUENCE_TABLE_TYPE); + StringBuilder typeBuf = new StringBuilder(); + for (String type : tableTypes) { + try { + PTableType tableType = PTableType.fromValue(type); + typeBuf.append('\''); + typeBuf.append(tableType.getSerializedValue()); + typeBuf.append('\''); + typeBuf.append(','); + } catch (IllegalArgumentException e) { + // Ignore and continue + } + } + if (typeBuf.length() > 0) { + typeClauseBuf.append(" and " + TABLE_TYPE + " IN ("); + typeClauseBuf.append(typeBuf); + typeClauseBuf.setCharAt(typeClauseBuf.length()-1, ')'); + } } - if (tableNamePattern != null) { - buf.append(" and " + TABLE_NAME + " like '" + StringUtil.escapeStringConstant(tableNamePattern) + "'" ); + StringBuilder buf = new StringBuilder("select \n"); + // If there were table types specified and they were all filtered out + // and we're not querying for sequences, return an empty result set. + if (hasTableTypes && typeClauseBuf.length() == 0 && !isSequence) { + return this.emptyResultSet; } - if (types != null && types.length > 0) { - buf.append(" and " + TABLE_TYPE + " IN ("); - for (String type : types) { - buf.append('\''); - buf.append(PTableType.fromValue(type).getSerializedValue()); - buf.append('\''); - buf.append(','); + if (typeClauseBuf.length() > 0 || !isSequence) { + buf.append( + TENANT_ID + " " + TABLE_CAT + "," + // tenant_id is the catalog + TABLE_SCHEM + "," + + TABLE_NAME + " ," + + SQLTableTypeFunction.NAME + "(" + TABLE_TYPE + ") AS " + TABLE_TYPE + "," + + REMARKS + " ," + + TYPE_NAME + "," + + SELF_REFERENCING_COL_NAME + "," + + REF_GENERATION + "," + + IndexStateNameFunction.NAME + "(" + INDEX_STATE + ") AS " + INDEX_STATE + "," + + IMMUTABLE_ROWS + "," + + SALT_BUCKETS + "," + + MULTI_TENANT + "," + + VIEW_STATEMENT + "," + + SQLViewTypeFunction.NAME + "(" + VIEW_TYPE + ") AS " + VIEW_TYPE + "," + + SQLIndexTypeFunction.NAME + "(" + INDEX_TYPE + ") AS " + INDEX_TYPE + "," + + TRANSACTIONAL + "," + + IS_NAMESPACE_MAPPED + + " from " + SYSTEM_CATALOG + " " + SYSTEM_CATALOG_ALIAS + + " where " + COLUMN_NAME + " is null" + + " and " + COLUMN_FAMILY + " is null" + + " and " + TABLE_NAME + " != '" + MetaDataClient.EMPTY_TABLE + "'"); + addTenantIdFilter(buf, catalog); + if (schemaPattern != null) { + buf.append(" and " + TABLE_SCHEM + (schemaPattern.length() == 0 ? " is null" : " like '" + StringUtil.escapeStringConstant(schemaPattern) + "'" )); + } + if (tableNamePattern != null) { + buf.append(" and " + TABLE_NAME + " like '" + StringUtil.escapeStringConstant(tableNamePattern) + "'" ); + } + if (typeClauseBuf.length() > 0) { + buf.append(typeClauseBuf); + } + } + if (isSequence) { + // Union the SYSTEM.CATALOG entries with the SYSTEM.SEQUENCE entries + if (typeClauseBuf.length() > 0) { + buf.append(" UNION ALL\n"); + buf.append(" select\n"); + } + buf.append( + TENANT_ID + " " + TABLE_CAT + "," + // tenant_id is the catalog + SEQUENCE_SCHEMA + " " + TABLE_SCHEM + "," + + SEQUENCE_NAME + " " + TABLE_NAME + " ," + + "'" + SEQUENCE_TABLE_TYPE + "' " + TABLE_TYPE + "," + + "'' " + REMARKS + " ," + + "'' " + TYPE_NAME + "," + + "'' " + SELF_REFERENCING_COL_NAME + "," + + "'' " + REF_GENERATION + "," + + "CAST(null AS CHAR(1)) " + INDEX_STATE + "," + + "CAST(null AS BOOLEAN) " + IMMUTABLE_ROWS + "," + + "CAST(null AS INTEGER) " + SALT_BUCKETS + "," + + "CAST(null AS BOOLEAN) " + MULTI_TENANT + "," + + "'' " + VIEW_STATEMENT + "," + + "'' " + VIEW_TYPE + "," + + "'' " + INDEX_TYPE + "," + + "CAST(null AS BOOLEAN) " + TRANSACTIONAL + "," + + "CAST(null AS BOOLEAN) " + IS_NAMESPACE_MAPPED + "\n"); + buf.append( + " from " + SYSTEM_SEQUENCE + "\n"); + StringBuilder whereClause = new StringBuilder(); + addTenantIdFilter(whereClause, catalog); + if (schemaPattern != null) { + whereClause.append(" and " + SEQUENCE_SCHEMA + (schemaPattern.length() == 0 ? " is null" : " like '" + StringUtil.escapeStringConstant(schemaPattern) + "'\n" )); + } + if (tableNamePattern != null) { + whereClause.append(" and " + SEQUENCE_NAME + " like '" + StringUtil.escapeStringConstant(tableNamePattern) + "'\n" ); + } + if (whereClause.length() > 0) { + buf.append(" where\n"); + buf.append(whereClause); } - buf.setCharAt(buf.length()-1, ')'); } - buf.append(" order by " + SYSTEM_CATALOG_ALIAS + "." + TABLE_TYPE + "," +TENANT_ID + "," + TABLE_SCHEM + "," + TABLE_NAME); + buf.append(" order by 4, 1, 2, 3\n"); Statement stmt = connection.createStatement(); return stmt.executeQuery(buf.toString()); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f620f54/phoenix-core/src/main/java/org/apache/phoenix/schema/ValueSchema.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/ValueSchema.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/ValueSchema.java index 5c8c4f9..b2fa2b1 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/ValueSchema.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/ValueSchema.java @@ -86,18 +86,20 @@ public abstract class ValueSchema implements Writable { for (Field field : fields) { int fieldEstLength = 0; PDataType type = field.getDataType(); - Integer byteSize = type.getByteSize(); - if (type.isFixedWidth()) { - fieldEstLength += field.getByteSize(); - } else { - isFixedLength = false; - // Account for vint for length if not fixed - if (byteSize == null) { - isMaxLength = false; - fieldEstLength += ESTIMATED_VARIABLE_LENGTH_SIZE; + if (type != null) { + Integer byteSize = type.getByteSize(); + if (type.isFixedWidth()) { + fieldEstLength += field.getByteSize(); } else { - fieldEstLength += WritableUtils.getVIntSize(byteSize); - fieldEstLength = byteSize; + isFixedLength = false; + // Account for vint for length if not fixed + if (byteSize == null) { + isMaxLength = false; + fieldEstLength += ESTIMATED_VARIABLE_LENGTH_SIZE; + } else { + fieldEstLength += WritableUtils.getVIntSize(byteSize); + fieldEstLength = byteSize; + } } } positions += field.getCount(); @@ -159,7 +161,7 @@ public abstract class ValueSchema implements Writable { final int prime = 31; int result = 1; result = prime * result + byteSize; - result = prime * result + type.hashCode(); + result = prime * result + (type == null ? 0 : type.hashCode()); result = prime * result + sortOrder.hashCode(); result = prime * result + (isNullable ? 1231 : 1237); return result; @@ -195,7 +197,7 @@ public abstract class ValueSchema implements Writable { this.sortOrder = sortOrder; this.count = count; this.isNullable = isNullable; - if (this.type.isFixedWidth() && this.type.getByteSize() == null) { + if (this.type != null && this.type.isFixedWidth() && this.type.getByteSize() == null) { if (datum.getMaxLength() != null) { this.byteSize = datum.getMaxLength(); } @@ -205,7 +207,7 @@ public abstract class ValueSchema implements Writable { @Override public String toString() { return (count == 1 ? "" : count + " * ") - + type.toString() + + type + (byteSize == 0 ? "" : "(" + byteSize + ")") + (isNullable ? "" : " NOT NULL") + (sortOrder == SortOrder.ASC ? "" : " " + sortOrder);