return putProperty(PropertyMap.RESULT_TYPE_PROP, getType().getValue());
}
+ public boolean isVariableLength() {
+ // calculated columns are written as var len
+ return(getType().isVariableLength() || isCalculated());
+ }
+
/**
* Sets whether of not the new column allows unicode compression.
*/
// offset to the actual data
private static final int CALC_DATA_OFFSET = CALC_DATA_LEN_OFFSET + 4;
// total amount of extra bytes added for calculated values
- private static final int CALC_EXTRA_DATA_LEN = 23;
+ static final int CALC_EXTRA_DATA_LEN = 23;
+ // ms access seems to define all fixed-len calc fields as this length
+ static final short CALC_FIXED_FIELD_LEN = 39;
// fully encode calculated BOOLEAN "true" value
private static final byte[] CALC_BOOL_TRUE = wrapCalculatedValue(
throws IOException
{
int totalDataLen = Math.min(CALC_EXTRA_DATA_LEN + 16 + 4, getLength());
- int dataLen = totalDataLen - CALC_EXTRA_DATA_LEN;
+ // data length must be multiple of 4
+ int dataLen = toMul4(totalDataLen - CALC_EXTRA_DATA_LEN);
ByteBuffer buffer = prepareWrappedCalcValue(dataLen, order);
writeCalcNumericValue(buffer, obj, dataLen);
// numeric bytes need to be a multiple of 4 and we currently handle at
// most 16 bytes
int numByteLen = ((totalLen > 0) ? totalLen : buffer.remaining()) - 2;
- numByteLen = Math.min((numByteLen / 4) * 4, 16);
+ numByteLen = Math.min(toMul4(numByteLen), 16);
byte scale = buffer.get();
boolean negate = (buffer.get() != 0);
ByteUtil.swap8Bytes(bytes, pos);
}
}
+
+ private static int toMul4(int val) {
+ return ((val / 4) * 4);
+ }
}
}
*/
private static byte getColumnBitFlags(ColumnBuilder col) {
byte flags = UNKNOWN_FLAG_MASK;
- if(!col.getType().isVariableLength()) {
+ if(!col.isVariableLength()) {
flags |= FIXED_LEN_FLAG_MASK;
}
if(col.isAutoNumber()) {
public static short countVariableLength(List<ColumnBuilder> columns) {
short rtn = 0;
for (ColumnBuilder col : columns) {
- if (col.getType().isVariableLength()) {
+ if (col.isVariableLength()) {
rtn++;
}
}
* found in the list
* @usage _advanced_method_
*/
- public static short countNonLongVariableLength(List<ColumnBuilder> columns) {
+ private static short countNonLongVariableLength(List<ColumnBuilder> columns) {
short rtn = 0;
for (ColumnBuilder col : columns) {
- if (col.getType().isVariableLength() && !col.getType().isLongValue()) {
+ if (col.isVariableLength() && !col.getType().isLongValue()) {
rtn++;
}
}
buffer.putInt(TableImpl.MAGIC_TABLE_NUMBER); //constant magic number
buffer.putShort(col.getColumnNumber()); //Column Number
- if (col.getType().isVariableLength()) {
+ if(col.isVariableLength()) {
if(!col.getType().isLongValue()) {
buffer.putShort(variableOffset++);
} else {
buffer.putInt(0); //Unknown, but always 0.
//Offset for fixed length columns
- if (col.getType().isVariableLength()) {
+ if(col.isVariableLength()) {
buffer.putShort((short) 0);
} else {
buffer.putShort(fixedOffset);
}
if(!col.getType().isLongValue()) {
- buffer.putShort(col.getLength()); //Column length
+ short length = col.getLength();
+ if(col.isCalculated()) {
+ // calced columns have additional value overhead
+ if(!col.getType().isVariableLength() ||
+ col.getType().getHasScalePrecision()) {
+ length = CalculatedColumnUtil.CALC_FIXED_FIELD_LEN;
+ } else {
+ length += CalculatedColumnUtil.CALC_EXTRA_DATA_LEN;
+ }
+ }
+ buffer.putShort(length); //Column length
} else {
buffer.putShort((short)0x0000); // unused
}
package com.healthmarketscience.jackcess.impl;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
.addColumn(new ColumnBuilder("id", DataType.LONG)
.setAutoNumber(true))
.addColumn(new ColumnBuilder("data", DataType.TEXT))
- .addColumn(new ColumnBuilder("calc_data", DataType.TEXT)
+ .addColumn(new ColumnBuilder("calc_text", DataType.TEXT)
.setCalculatedInfo("[id] & \"_\" & [data]"))
+ .addColumn(new ColumnBuilder("calc_memo", DataType.MEMO)
+ .setCalculatedInfo("[id] & \"_\" & [data]"))
+ .addColumn(new ColumnBuilder("calc_bool", DataType.BOOLEAN)
+ .setCalculatedInfo("[id] > 0"))
+ .addColumn(new ColumnBuilder("calc_long", DataType.LONG)
+ .setCalculatedInfo("[id] + 1"))
+ .addColumn(new ColumnBuilder("calc_numeric", DataType.NUMERIC)
+ .setCalculatedInfo("[id] / 0.03"))
.toTable(db);
- Column col = t.getColumn("calc_data");
+ Column col = t.getColumn("calc_text");
assertTrue(col.isCalculated());
assertEquals("[id] & \"_\" & [data]", col.getProperties().getValue(
PropertyMap.EXPRESSION_PROP));
col.getProperties().getValue(
PropertyMap.RESULT_TYPE_PROP));
- t.addRow(Column.AUTO_NUMBER, "foo", "1_foo");
+ String longStr = createString(1000);
+ BigDecimal bd1 = new BigDecimal("-1234.5678");
+ BigDecimal bd2 = new BigDecimal("0.0234");
+
+ t.addRow(Column.AUTO_NUMBER, "foo", "1_foo", longStr, true, 2, bd1);
+ t.addRow(Column.AUTO_NUMBER, "bar", "2_bar", longStr, false, -37, bd2);
List<? extends Map<String, Object>> expectedRows =
createExpectedTable(
createExpectedRow(
"id", 1,
"data", "foo",
- "calc_data", "1_foo"));
+ "calc_text", "1_foo",
+ "calc_memo", longStr,
+ "calc_bool", true,
+ "calc_long", 2,
+ "calc_numeric", bd1),
+ createExpectedRow(
+ "id", 2,
+ "data", "bar",
+ "calc_text", "2_bar",
+ "calc_memo", longStr,
+ "calc_bool", false,
+ "calc_long", -37,
+ "calc_numeric", bd2));
assertTable(expectedRows, t);