diff options
7 files changed, 194 insertions, 146 deletions
diff --git a/src/changes/changes.xml b/src/changes/changes.xml index f77b937..0832c4b 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -52,6 +52,9 @@ irrelevant failures when reading databases which have invalid column properties. </action> + <action dev="jahlborn" type="fix" system="SourceForge2" issue="151"> + Fix length in units calculation for Access 97 text fields. + </action> </release> <release version="2.2.0" date="2018-09-08" description="Add support for expression evaluation"> diff --git a/src/main/java/com/healthmarketscience/jackcess/ColumnBuilder.java b/src/main/java/com/healthmarketscience/jackcess/ColumnBuilder.java index 35aeca3..48fa1cf 100644 --- a/src/main/java/com/healthmarketscience/jackcess/ColumnBuilder.java +++ b/src/main/java/com/healthmarketscience/jackcess/ColumnBuilder.java @@ -68,7 +68,7 @@ public class ColumnBuilder { public ColumnBuilder(String name) { this(name, null); } - + public ColumnBuilder(String name, DataType type) { _name = name; _type = type; @@ -96,7 +96,7 @@ public class ColumnBuilder { public ColumnBuilder setSQLType(int type) throws SQLException { return setSQLType(type, 0, null); } - + /** * Sets the type for the new column based on the given SQL type and target * data length (in type specific units). @@ -182,9 +182,9 @@ public class ColumnBuilder { * Sets the length (in type specific units) for the new column. */ public ColumnBuilder setLengthInUnits(int unitLength) { - return setLength(_type.getUnitSize() * unitLength); + return setLength(_type.fromUnitSize(unitLength)); } - + /** * Sets the length for the new column to the max length for the type. Does * nothing for types which are not variable length. @@ -196,7 +196,7 @@ public class ColumnBuilder { } return this; } - + /** * Sets whether of not the new column is an auto-number column. */ @@ -295,12 +295,12 @@ public class ColumnBuilder { private PropertyMap.Property getProperty(String name) { return ((_props != null) ? _props.get(name) : null); } - + /** * Sets all attributes except name from the given Column template (including * all column properties except GUID). */ - public ColumnBuilder setFromColumn(Column template) + public ColumnBuilder setFromColumn(Column template) throws IOException { DataType type = template.getType(); @@ -325,7 +325,7 @@ public class ColumnBuilder { setProperty(colProp.getName(), colProp); } } - + return this; } @@ -349,7 +349,7 @@ public class ColumnBuilder { if(template._props != null) { _props = new HashMap<String,PropertyMap.Property>(template._props); } - + return this; } @@ -410,7 +410,7 @@ public class ColumnBuilder { throw new IllegalArgumentException(withErrorContext( "Database format " + format + " does not support type " + getType())); } - + if(!getType().isVariableLength()) { if(getLength() < getType().getFixedSize()) { throw new IllegalArgumentException(withErrorContext( @@ -433,7 +433,7 @@ public class ColumnBuilder { if(!getType().isValidPrecision(getPrecision())) { throw new IllegalArgumentException(withErrorContext( "Precision must be from " + getType().getMinPrecision() + " to " + - getType().getMaxPrecision() + " inclusive, found " + + getType().getMaxPrecision() + " inclusive, found " + getPrecision())); } } diff --git a/src/main/java/com/healthmarketscience/jackcess/DataType.java b/src/main/java/com/healthmarketscience/jackcess/DataType.java index 11483b1..6070dbd 100644 --- a/src/main/java/com/healthmarketscience/jackcess/DataType.java +++ b/src/main/java/com/healthmarketscience/jackcess/DataType.java @@ -391,14 +391,27 @@ public enum DataType { return _unitSize; } - public int toUnitSize(int size) - { - return(size / getUnitSize()); + public int getUnitSize(JetFormat format) { + if((format != null) && isTextual()) { + return format.SIZE_TEXT_FIELD_UNIT; + } + return _unitSize; } - public int fromUnitSize(int unitSize) - { - return(unitSize * getUnitSize()); + public int toUnitSize(int size) { + return toUnitSize(size, null); + } + + public int toUnitSize(int size, JetFormat format) { + return(size / getUnitSize(format)); + } + + public int fromUnitSize(int unitSize) { + return fromUnitSize(unitSize, null); + } + + public int fromUnitSize(int unitSize, JetFormat format) { + return(unitSize * getUnitSize(format)); } public boolean isValidSize(int size) { @@ -478,13 +491,15 @@ public enum DataType { if(rtnArr == null) { throw new SQLException("Unsupported SQL type: " + sqlType); } + JetFormat format = + ((fileFormat != null) ? + DatabaseImpl.getFileFormatDetails(fileFormat).getFormat() : + null); DataType rtn = rtnArr[0]; - if((rtnArr.length > 1) && (fileFormat != null)) { + if((rtnArr.length > 1) && (format != null)) { // there are multiple possibilities, ordered from lowest version to // highest version supported. go in opposite order to find the best // type for this format - JetFormat format = DatabaseImpl.getFileFormatDetails(fileFormat) - .getFormat(); for(int i = rtnArr.length - 1; i >= 0; --i) { DataType tmp = rtnArr[i]; if(format.isSupportedDataType(tmp)) { @@ -495,7 +510,7 @@ public enum DataType { } // make sure size is reasonable - int size = lengthInUnits * rtn.getUnitSize(); + int size = rtn.fromUnitSize(lengthInUnits, format); if(rtn.isVariableLength() && !rtn.isValidSize(size)) { // try alternate type. we always accept alternate "long value" types // regardless of the given lengthInUnits diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/CalculatedColumnUtil.java b/src/main/java/com/healthmarketscience/jackcess/impl/CalculatedColumnUtil.java index 8caab73..8e3802b 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/CalculatedColumnUtil.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/CalculatedColumnUtil.java @@ -242,10 +242,11 @@ class CalculatedColumnUtil } @Override - public short getLengthInUnits() { + protected int calcLengthInUnits() { // the byte "length" includes the calculated field overhead. remove // that to get the _actual_ data length (in units) - return (short)getType().toUnitSize(getLength() - CALC_EXTRA_DATA_LEN); + return getType().toUnitSize(getLength() - CALC_EXTRA_DATA_LEN, + getFormat()); } @Override @@ -285,10 +286,11 @@ class CalculatedColumnUtil } @Override - protected int getMaxLengthInUnits() { + protected int calcMaxLengthInUnits() { // the byte "length" includes the calculated field overhead. remove // that to get the _actual_ data length (in units) - return getType().toUnitSize(getType().getMaxSize() - CALC_EXTRA_DATA_LEN); + return getType().toUnitSize(getType().getMaxSize() - CALC_EXTRA_DATA_LEN, + getFormat()); } @Override diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java index 4172874..212b912 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java @@ -186,6 +186,8 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl>, DateTimeConte /** auto numbers must be > 0 */ static final int INVALID_AUTO_NUMBER = 0; + static final int INVALID_LENGTH = -1; + /** owning table */ private final TableImpl _table; @@ -219,6 +221,8 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl>, DateTimeConte private ColumnValidator _validator = SimpleColumnValidator.INSTANCE; /** default value generator */ private ColDefaultValueEvalContext _defValue; + /** length of the column in units, lazily computed */ + private int _lengthInUnits = INVALID_LENGTH; /** * @usage _advanced_method_ @@ -469,8 +473,15 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl>, DateTimeConte } @Override - public short getLengthInUnits() { - return (short)getType().toUnitSize(getLength()); + public final short getLengthInUnits() { + if(_lengthInUnits == INVALID_LENGTH) { + _lengthInUnits = calcLengthInUnits(); + } + return (short)_lengthInUnits; + } + + protected int calcLengthInUnits() { + return getType().toUnitSize(getLength(), getFormat()); } @Override diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/JetFormat.java b/src/main/java/com/healthmarketscience/jackcess/impl/JetFormat.java index a230edf..6ca0dd1 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/JetFormat.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/JetFormat.java @@ -34,7 +34,7 @@ import com.healthmarketscience.jackcess.Database; * @author Tim McCune */ public abstract class JetFormat { - + /** Maximum size of a record minus OLE objects and Memo fields */ public static final int MAX_RECORD_SIZE = 1900; //2kb minus some overhead @@ -46,7 +46,7 @@ public abstract class JetFormat { public enum CodecType { NONE, JET, MSISAM, OFFICE; } - + /** Offset in the file that holds the byte describing the Jet format version */ private static final int OFFSET_VERSION = 20; @@ -67,7 +67,7 @@ public abstract class JetFormat { static final int LENGTH_ENGINE_NAME = 0xF; /** amount of initial data to be read to determine database type */ private static final int HEADER_LENGTH = 21; - + private final static byte[] MSISAM_ENGINE = new byte[] { 'M', 'S', 'I', 'S', 'A', 'M', ' ', 'D', 'a', 't', 'a', 'b', 'a', 's', 'e' }; @@ -78,11 +78,11 @@ public abstract class JetFormat { (byte)0xC2, (byte)0x55, (byte)0xEB, (byte)0xA9, (byte)0x67, (byte)0x72, (byte)0x43, (byte)0x3F, (byte)0x00, (byte)0x9C, (byte)0x7A, (byte)0x9F, (byte)0x90, (byte)0xFF, (byte)0x80, (byte)0x9A, (byte)0x31, (byte)0xC5, - (byte)0x79, (byte)0xBA, (byte)0xED, (byte)0x30, (byte)0xBC, (byte)0xDF, + (byte)0x79, (byte)0xBA, (byte)0xED, (byte)0x30, (byte)0xBC, (byte)0xDF, (byte)0xCC, (byte)0x9D, (byte)0x63, (byte)0xD9, (byte)0xE4, (byte)0xC3, (byte)0x7B, (byte)0x42, (byte)0xFB, (byte)0x8A, (byte)0xBC, (byte)0x4E, (byte)0x86, (byte)0xFB, (byte)0xEC, (byte)0x37, (byte)0x5D, (byte)0x44, - (byte)0x9C, (byte)0xFA, (byte)0xC6, (byte)0x5E, (byte)0x28, (byte)0xE6, + (byte)0x9C, (byte)0xFA, (byte)0xC6, (byte)0x5E, (byte)0x28, (byte)0xE6, (byte)0x13, (byte)0xB6, (byte)0x8A, (byte)0x60, (byte)0x54, (byte)0x94, (byte)0x7B, (byte)0x36, (byte)0xF5, (byte)0x72, (byte)0xDF, (byte)0xB1, (byte)0x77, (byte)0xF4, (byte)0x13, (byte)0x43, (byte)0xCF, (byte)0xAF, @@ -95,7 +95,7 @@ public abstract class JetFormat { (byte)0x27, (byte)0x44, (byte)0xD2, (byte)0xEE, (byte)0xCF, (byte)0x65, (byte)0xED, (byte)0xFF, (byte)0x07, (byte)0xC7, (byte)0x46, (byte)0xA1, (byte)0x78, (byte)0x16, (byte)0x0C, (byte)0xED, (byte)0xE9, (byte)0x2D, - (byte)0x62, (byte)0xD4}; + (byte)0x62, (byte)0xD4}; /** value of the "AccessVersion" property for access 2000 dbs: {@code "08.50"} */ @@ -111,22 +111,22 @@ public abstract class JetFormat { // use nested inner class to avoid problematic static init loops private static final class PossibleFileFormats { - private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_3 = + private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_3 = Collections.singletonMap((String)null, Database.FileFormat.V1997); - private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_4 = + private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_4 = new HashMap<String,Database.FileFormat>(); - private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_12 = + private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_12 = Collections.singletonMap((String)null, Database.FileFormat.V2007); - private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_14 = + private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_14 = Collections.singletonMap((String)null, Database.FileFormat.V2010); - private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_16 = + private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_16 = Collections.singletonMap((String)null, Database.FileFormat.V2016); - private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_MSISAM = + private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_MSISAM = Collections.singletonMap((String)null, Database.FileFormat.MSISAM); static { @@ -137,10 +137,10 @@ public abstract class JetFormat { } /** calculated types supported in version 14 */ - private static final Set<DataType> V14_CALC_TYPES = + private static final Set<DataType> V14_CALC_TYPES = EnumSet.of(DataType.BOOLEAN, DataType.BYTE, DataType.INT, DataType.LONG, - DataType.FLOAT, DataType.DOUBLE, DataType.GUID, - DataType.SHORT_DATE_TIME, DataType.MONEY, DataType.NUMERIC, + DataType.FLOAT, DataType.DOUBLE, DataType.GUID, + DataType.SHORT_DATE_TIME, DataType.MONEY, DataType.NUMERIC, DataType.TEXT, DataType.MEMO); /** calculated types supported in version 16 */ @@ -168,20 +168,20 @@ public abstract class JetFormat { /** the name of this format */ private final String _name; - + /** the read/write mode of this format */ public final boolean READ_ONLY; - + /** whether or not we can use indexes in this format */ public final boolean INDEXES_SUPPORTED; /** type of page encoding supported */ public final CodecType CODEC_TYPE; - + /** Database page size in bytes */ public final int PAGE_SIZE; public final long MAX_DATABASE_SIZE; - + public final int MAX_ROW_SIZE; public final int DATA_PAGE_INITIAL_FREE_SPACE; @@ -207,10 +207,10 @@ public abstract class JetFormat { public final int OFFSET_OWNED_PAGES; public final int OFFSET_FREE_SPACE_PAGES; public final int OFFSET_INDEX_DEF_BLOCK; - + public final int SIZE_INDEX_COLUMN_BLOCK; public final int SIZE_INDEX_INFO_BLOCK; - + public final int OFFSET_COLUMN_TYPE; public final int OFFSET_COLUMN_NUMBER; public final int OFFSET_COLUMN_PRECISION; @@ -224,26 +224,26 @@ public abstract class JetFormat { public final int OFFSET_COLUMN_VARIABLE_TABLE_INDEX; public final int OFFSET_COLUMN_FIXED_DATA_OFFSET; public final int OFFSET_COLUMN_FIXED_DATA_ROW_OFFSET; - + public final int OFFSET_TABLE_DEF_LOCATION; - + public final int OFFSET_ROW_START; public final int OFFSET_USAGE_MAP_START; - + public final int OFFSET_USAGE_MAP_PAGE_DATA; - + public final int OFFSET_REFERENCE_MAP_PAGE_NUMBERS; - + public final int OFFSET_FREE_SPACE; public final int OFFSET_NUM_ROWS_ON_DATA_PAGE; public final int MAX_NUM_ROWS_ON_DATA_PAGE; - + public final int OFFSET_INDEX_COMPRESSED_BYTE_COUNT; public final int OFFSET_INDEX_ENTRY_MASK; public final int OFFSET_PREV_INDEX_PAGE; public final int OFFSET_NEXT_INDEX_PAGE; public final int OFFSET_CHILD_TAIL_INDEX_PAGE; - + public final int SIZE_INDEX_DEFINITION; public final int SIZE_COLUMN_HEADER; public final int SIZE_ROW_LOCATION; @@ -263,7 +263,7 @@ public abstract class JetFormat { public final int SIZE_NAME_LENGTH; public final int SIZE_ROW_COLUMN_COUNT; public final int SIZE_ROW_VAR_COL_OFFSET; - + public final int USAGE_MAP_TABLE_BYTE_LENGTH; public final int MAX_COLUMNS_PER_TABLE; @@ -273,11 +273,12 @@ public abstract class JetFormat { public final int MAX_INDEX_NAME_LENGTH; public final boolean LEGACY_NUMERIC_INDEXES; - + public final Charset CHARSET; public final ColumnImpl.SortOrder DEFAULT_SORT_ORDER; public final byte[] PROPERTY_MAP_TYPE; - + public final int SIZE_TEXT_FIELD_UNIT; + /** * @param channel the database file. * @return The Jet Format represented in the passed-in file @@ -309,20 +310,20 @@ public abstract class JetFormat { ((version < CODE_VERSION_3) ? "older" : "newer") + " version: " + version); } - + private JetFormat(String name) { _name = name; - + READ_ONLY = defineReadOnly(); INDEXES_SUPPORTED = defineIndexesSupported(); CODEC_TYPE = defineCodecType(); - + PAGE_SIZE = definePageSize(); MAX_DATABASE_SIZE = defineMaxDatabaseSize(); - + MAX_ROW_SIZE = defineMaxRowSize(); DATA_PAGE_INITIAL_FREE_SPACE = defineDataPageInitialFreeSpace(); - + OFFSET_MASKED_HEADER = defineOffsetMaskedHeader(); HEADER_MASK = defineHeaderMask(); OFFSET_HEADER_DATE = defineOffsetHeaderDate(); @@ -345,10 +346,10 @@ public abstract class JetFormat { OFFSET_OWNED_PAGES = defineOffsetOwnedPages(); OFFSET_FREE_SPACE_PAGES = defineOffsetFreeSpacePages(); OFFSET_INDEX_DEF_BLOCK = defineOffsetIndexDefBlock(); - + SIZE_INDEX_COLUMN_BLOCK = defineSizeIndexColumnBlock(); SIZE_INDEX_INFO_BLOCK = defineSizeIndexInfoBlock(); - + OFFSET_COLUMN_TYPE = defineOffsetColumnType(); OFFSET_COLUMN_NUMBER = defineOffsetColumnNumber(); OFFSET_COLUMN_PRECISION = defineOffsetColumnPrecision(); @@ -362,26 +363,26 @@ public abstract class JetFormat { OFFSET_COLUMN_VARIABLE_TABLE_INDEX = defineOffsetColumnVariableTableIndex(); OFFSET_COLUMN_FIXED_DATA_OFFSET = defineOffsetColumnFixedDataOffset(); OFFSET_COLUMN_FIXED_DATA_ROW_OFFSET = defineOffsetColumnFixedDataRowOffset(); - + OFFSET_TABLE_DEF_LOCATION = defineOffsetTableDefLocation(); - + OFFSET_ROW_START = defineOffsetRowStart(); OFFSET_USAGE_MAP_START = defineOffsetUsageMapStart(); - + OFFSET_USAGE_MAP_PAGE_DATA = defineOffsetUsageMapPageData(); - + OFFSET_REFERENCE_MAP_PAGE_NUMBERS = defineOffsetReferenceMapPageNumbers(); - + OFFSET_FREE_SPACE = defineOffsetFreeSpace(); OFFSET_NUM_ROWS_ON_DATA_PAGE = defineOffsetNumRowsOnDataPage(); MAX_NUM_ROWS_ON_DATA_PAGE = defineMaxNumRowsOnDataPage(); - + OFFSET_INDEX_COMPRESSED_BYTE_COUNT = defineOffsetIndexCompressedByteCount(); OFFSET_INDEX_ENTRY_MASK = defineOffsetIndexEntryMask(); OFFSET_PREV_INDEX_PAGE = defineOffsetPrevIndexPage(); OFFSET_NEXT_INDEX_PAGE = defineOffsetNextIndexPage(); OFFSET_CHILD_TAIL_INDEX_PAGE = defineOffsetChildTailIndexPage(); - + SIZE_INDEX_DEFINITION = defineSizeIndexDefinition(); SIZE_COLUMN_HEADER = defineSizeColumnHeader(); SIZE_ROW_LOCATION = defineSizeRowLocation(); @@ -409,24 +410,25 @@ public abstract class JetFormat { MAX_TABLE_NAME_LENGTH = defineMaxTableNameLength(); MAX_COLUMN_NAME_LENGTH = defineMaxColumnNameLength(); MAX_INDEX_NAME_LENGTH = defineMaxIndexNameLength(); - + LEGACY_NUMERIC_INDEXES = defineLegacyNumericIndexes(); - + CHARSET = defineCharset(); DEFAULT_SORT_ORDER = defineDefaultSortOrder(); PROPERTY_MAP_TYPE = definePropMapType(); + SIZE_TEXT_FIELD_UNIT = defineSizeTextFieldUnit(); } - + protected abstract boolean defineReadOnly(); protected abstract boolean defineIndexesSupported(); protected abstract CodecType defineCodecType(); - + protected abstract int definePageSize(); protected abstract long defineMaxDatabaseSize(); - + protected abstract int defineMaxRowSize(); protected abstract int defineDataPageInitialFreeSpace(); - + protected abstract int defineOffsetMaskedHeader(); protected abstract byte[] defineHeaderMask(); protected abstract int defineOffsetHeaderDate(); @@ -449,10 +451,10 @@ public abstract class JetFormat { protected abstract int defineOffsetOwnedPages(); protected abstract int defineOffsetFreeSpacePages(); protected abstract int defineOffsetIndexDefBlock(); - + protected abstract int defineSizeIndexColumnBlock(); protected abstract int defineSizeIndexInfoBlock(); - + protected abstract int defineOffsetColumnType(); protected abstract int defineOffsetColumnNumber(); protected abstract int defineOffsetColumnPrecision(); @@ -466,26 +468,26 @@ public abstract class JetFormat { protected abstract int defineOffsetColumnVariableTableIndex(); protected abstract int defineOffsetColumnFixedDataOffset(); protected abstract int defineOffsetColumnFixedDataRowOffset(); - + protected abstract int defineOffsetTableDefLocation(); - + protected abstract int defineOffsetRowStart(); protected abstract int defineOffsetUsageMapStart(); - + protected abstract int defineOffsetUsageMapPageData(); - + protected abstract int defineOffsetReferenceMapPageNumbers(); - + protected abstract int defineOffsetFreeSpace(); protected abstract int defineOffsetNumRowsOnDataPage(); protected abstract int defineMaxNumRowsOnDataPage(); - + protected abstract int defineOffsetIndexCompressedByteCount(); protected abstract int defineOffsetIndexEntryMask(); protected abstract int defineOffsetPrevIndexPage(); protected abstract int defineOffsetNextIndexPage(); protected abstract int defineOffsetChildTailIndexPage(); - + protected abstract int defineSizeIndexDefinition(); protected abstract int defineSizeColumnHeader(); protected abstract int defineSizeRowLocation(); @@ -513,10 +515,11 @@ public abstract class JetFormat { protected abstract int defineMaxTableNameLength(); protected abstract int defineMaxColumnNameLength(); protected abstract int defineMaxIndexNameLength(); - + protected abstract Charset defineCharset(); protected abstract ColumnImpl.SortOrder defineDefaultSortOrder(); protected abstract byte[] definePropMapType(); + protected abstract int defineSizeTextFieldUnit(); protected abstract boolean defineLegacyNumericIndexes(); @@ -530,7 +533,7 @@ public abstract class JetFormat { public String toString() { return _name; } - + private static class Jet3Format extends JetFormat { private Jet3Format() { @@ -539,33 +542,33 @@ public abstract class JetFormat { @Override protected boolean defineReadOnly() { return true; } - + @Override protected boolean defineIndexesSupported() { return false; } @Override - protected CodecType defineCodecType() { - return CodecType.JET; + protected CodecType defineCodecType() { + return CodecType.JET; } - + @Override protected int definePageSize() { return 2048; } - + @Override protected long defineMaxDatabaseSize() { return (1L * 1024L * 1024L * 1024L); } - + @Override protected int defineMaxRowSize() { return 2012; } @Override protected int defineDataPageInitialFreeSpace() { return PAGE_SIZE - 14; } - + @Override protected int defineOffsetMaskedHeader() { return 24; } @Override - protected byte[] defineHeaderMask() { - return ByteUtil.copyOf(BASE_HEADER_MASK, BASE_HEADER_MASK.length - 2); + protected byte[] defineHeaderMask() { + return ByteUtil.copyOf(BASE_HEADER_MASK, BASE_HEADER_MASK.length - 2); } @Override protected int defineOffsetHeaderDate() { return -1; } @@ -612,7 +615,7 @@ public abstract class JetFormat { protected int defineSizeIndexColumnBlock() { return 39; } @Override protected int defineSizeIndexInfoBlock() { return 20; } - + @Override protected int defineOffsetColumnType() { return 0; } @Override @@ -639,28 +642,28 @@ public abstract class JetFormat { protected int defineOffsetColumnFixedDataOffset() { return 14; } @Override protected int defineOffsetColumnFixedDataRowOffset() { return 1; } - + @Override protected int defineOffsetTableDefLocation() { return 4; } - + @Override protected int defineOffsetRowStart() { return 10; } @Override protected int defineOffsetUsageMapStart() { return 5; } - + @Override protected int defineOffsetUsageMapPageData() { return 4; } - + @Override protected int defineOffsetReferenceMapPageNumbers() { return 1; } - + @Override protected int defineOffsetFreeSpace() { return 2; } @Override protected int defineOffsetNumRowsOnDataPage() { return 8; } @Override protected int defineMaxNumRowsOnDataPage() { return 255; } - + @Override protected int defineOffsetIndexCompressedByteCount() { return 20; } @Override @@ -671,7 +674,7 @@ public abstract class JetFormat { protected int defineOffsetNextIndexPage() { return 12; } @Override protected int defineOffsetChildTailIndexPage() { return 16; } - + @Override protected int defineSizeIndexDefinition() { return 8; } @Override @@ -710,25 +713,25 @@ public abstract class JetFormat { protected int defineSizeRowColumnCount() { return 1; } @Override protected int defineSizeRowVarColOffset() { return 1; } - + @Override protected int defineUsageMapTableByteLength() { return 128; } - + @Override protected int defineMaxColumnsPerTable() { return 255; } - + @Override protected int defineMaxIndexesPerTable() { return 32; } - + @Override protected int defineMaxTableNameLength() { return 64; } - + @Override protected int defineMaxColumnNameLength() { return 64; } - + @Override protected int defineMaxIndexNameLength() { return 64; } - + @Override protected boolean defineLegacyNumericIndexes() { return true; } @@ -744,7 +747,10 @@ public abstract class JetFormat { protected byte[] definePropMapType() { return PROPERTY_MAP_TYPES[1]; } - + + @Override + protected int defineSizeTextFieldUnit() { return 1; } + @Override protected Map<String,Database.FileFormat> getPossibleFileFormats() { @@ -762,7 +768,7 @@ public abstract class JetFormat { return false; } } - + private static class Jet4Format extends JetFormat { private Jet4Format() { @@ -775,28 +781,28 @@ public abstract class JetFormat { @Override protected boolean defineReadOnly() { return false; } - + @Override protected boolean defineIndexesSupported() { return true; } - + @Override - protected CodecType defineCodecType() { - return CodecType.JET; + protected CodecType defineCodecType() { + return CodecType.JET; } @Override protected int definePageSize() { return 4096; } - + @Override protected long defineMaxDatabaseSize() { return (2L * 1024L * 1024L * 1024L); } - + @Override protected int defineMaxRowSize() { return 4060; } @Override protected int defineDataPageInitialFreeSpace() { return PAGE_SIZE - 14; } - + @Override protected int defineOffsetMaskedHeader() { return 24; } @Override @@ -846,7 +852,7 @@ public abstract class JetFormat { protected int defineSizeIndexColumnBlock() { return 52; } @Override protected int defineSizeIndexInfoBlock() { return 28; } - + @Override protected int defineOffsetColumnType() { return 0; } @Override @@ -873,28 +879,28 @@ public abstract class JetFormat { protected int defineOffsetColumnFixedDataOffset() { return 21; } @Override protected int defineOffsetColumnFixedDataRowOffset() { return 2; } - + @Override protected int defineOffsetTableDefLocation() { return 4; } - + @Override protected int defineOffsetRowStart() { return 14; } @Override protected int defineOffsetUsageMapStart() { return 5; } - + @Override protected int defineOffsetUsageMapPageData() { return 4; } - + @Override protected int defineOffsetReferenceMapPageNumbers() { return 1; } - + @Override protected int defineOffsetFreeSpace() { return 2; } @Override protected int defineOffsetNumRowsOnDataPage() { return 12; } @Override protected int defineMaxNumRowsOnDataPage() { return 255; } - + @Override protected int defineOffsetIndexCompressedByteCount() { return 24; } @Override @@ -905,7 +911,7 @@ public abstract class JetFormat { protected int defineOffsetNextIndexPage() { return 16; } @Override protected int defineOffsetChildTailIndexPage() { return 20; } - + @Override protected int defineSizeIndexDefinition() { return 12; } @Override @@ -944,25 +950,25 @@ public abstract class JetFormat { protected int defineSizeRowColumnCount() { return 2; } @Override protected int defineSizeRowVarColOffset() { return 2; } - + @Override protected int defineUsageMapTableByteLength() { return 64; } - + @Override protected int defineMaxColumnsPerTable() { return 255; } - + @Override protected int defineMaxIndexesPerTable() { return 32; } - + @Override protected int defineMaxTableNameLength() { return 64; } - + @Override protected int defineMaxColumnNameLength() { return 64; } - + @Override protected int defineMaxIndexNameLength() { return 64; } - + @Override protected boolean defineLegacyNumericIndexes() { return true; } @@ -980,6 +986,9 @@ public abstract class JetFormat { } @Override + protected int defineSizeTextFieldUnit() { return TEXT_FIELD_UNIT_SIZE; } + + @Override protected Map<String,Database.FileFormat> getPossibleFileFormats() { return PossibleFileFormats.POSSIBLE_VERSION_4; @@ -996,15 +1005,15 @@ public abstract class JetFormat { return false; } } - + private static final class MSISAMFormat extends Jet4Format { private MSISAMFormat() { super("MSISAM"); } @Override - protected CodecType defineCodecType() { - return CodecType.MSISAM; + protected CodecType defineCodecType() { + return CodecType.MSISAM; } @Override @@ -1024,8 +1033,8 @@ public abstract class JetFormat { } @Override - protected CodecType defineCodecType() { - return CodecType.OFFICE; + protected CodecType defineCodecType() { + return CodecType.OFFICE; } @Override @@ -1041,7 +1050,7 @@ public abstract class JetFormat { @Override protected int defineOffsetColumnComplexId() { return 11; } - + @Override public boolean isSupportedDataType(DataType type) { return (type != DataType.BIG_INT); @@ -1088,7 +1097,7 @@ public abstract class JetFormat { private Jet16Format() { super("VERSION_16"); } - + @Override public boolean isSupportedDataType(DataType type) { return true; diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/LongValueColumnImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/LongValueColumnImpl.java index f878562..d1b2a07 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/LongValueColumnImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/LongValueColumnImpl.java @@ -55,6 +55,7 @@ class LongValueColumnImpl extends ColumnImpl /** Holds additional info for writing long values */ private LongValueBufferHolder _lvalBufferH; + private int _maxLenInUnits = INVALID_LENGTH; LongValueColumnImpl(InitArgs args) throws IOException { @@ -84,8 +85,15 @@ class LongValueColumnImpl extends ColumnImpl super.postTableLoadInit(); } - protected int getMaxLengthInUnits() { - return getType().toUnitSize(getType().getMaxSize()); + protected final int getMaxLengthInUnits() { + if(_maxLenInUnits == INVALID_LENGTH) { + _maxLenInUnits = calcMaxLengthInUnits(); + } + return _maxLenInUnits; + } + + protected int calcMaxLengthInUnits() { + return getType().toUnitSize(getType().getMaxSize(), getFormat()); } @Override |