Add the ability to set properties in DatabaseBuilder, TableBuilder,
and ColumnBuilder.
</action>
+ <action dev="jahlborn" type="add">
+ Add the ability to create tables with calculated fields.
+ </action>
</release>
<release version="2.0.4" date="2014-04-05">
<action dev="jahlborn" type="add">
private boolean _autoNumber;
/** whether or not the column allows compressed unicode */
private boolean _compressedUnicode;
+ /** whether or not the column is calculated */
+ private boolean _calculated;
/** whether or not the column is a hyperlink (memo only) */
private boolean _hyperlink;
/** 0-based column number */
return _compressedUnicode;
}
+ /**
+ * Sets whether of not the new column is a calculated column.
+ */
+ public ColumnBuilder setCalculated(boolean calculated) {
+ _calculated = calculated;
+ return this;
+ }
+
+ public boolean isCalculated() {
+ return _calculated;
+ }
+
+ /**
+ * Convenience method to set the various info for a calculated type (flag,
+ * result type property and expression)
+ */
+ public ColumnBuilder setCalculatedInfo(String expression) {
+ setCalculated(true);
+ putProperty(PropertyMap.EXPRESSION_PROP, expression);
+ return putProperty(PropertyMap.RESULT_TYPE_PROP, getType().getValue());
+ }
+
/**
* Sets whether of not the new column allows unicode compression.
*/
public Map<String,PropertyMap.Property> getProperties() {
return _props;
}
+
+ private PropertyMap.Property getProperty(String name) {
+ return ((_props != null) ? _props.get(name) : null);
+ }
/**
* Sets all attributes except name from the given Column template.
"Only memo columns can be hyperlinks");
}
}
+
+ if(isCalculated()) {
+ if(!format.isSupportedCalculatedDataType(getType())) {
+ throw new IllegalArgumentException(
+ "Database format " + format + " does not support calculated type " +
+ getType());
+ }
+
+ // must have an expression
+ if(getProperty(PropertyMap.EXPRESSION_PROP) == null) {
+ throw new IllegalArgumentException(
+ "No expression provided for calculated type " + getType());
+ }
+
+ // must have result type (just fill in if missing)
+ if(getProperty(PropertyMap.RESULT_TYPE_PROP) == null) {
+ putProperty(PropertyMap.RESULT_TYPE_PROP, getType().getValue());
+ }
+ }
}
/**
_props.put(name, PropertyMapImpl.createProperty(name, type, value));
return this;
}
-
+
/**
* Creates a new Table in the given Database with the currently configured
* attributes.
buffer.put(col.getType().getValue());
buffer.putInt(TableImpl.MAGIC_TABLE_NUMBER); //constant magic number
buffer.putShort(col.getColumnNumber()); //Column Number
+
if (col.getType().isVariableLength()) {
if(!col.getType().isLongValue()) {
buffer.putShort(variableOffset++);
} else {
buffer.putShort((short) 0);
}
+
buffer.putShort(col.getColumnNumber()); //Column Number again
+
if(col.getType().isTextual()) {
// this will write 4 bytes (note we don't support writing dbs which
// use the text code page)
writeSortOrder(buffer, col.getTextSortOrder(), creator.getFormat());
} else {
- if(col.getType().getHasScalePrecision()) {
+ // note scale/precision not stored for calculated numeric fields
+ if(col.getType().getHasScalePrecision() && !col.isCalculated()) {
buffer.put(col.getPrecision()); // numeric precision
buffer.put(col.getScale()); // numeric scale
} else {
}
buffer.putShort((short) 0); //Unknown
}
+
buffer.put(getColumnBitFlags(col)); // misc col flags
- if (col.isCompressedUnicode()) { //Compressed
- buffer.put((byte) 1);
+
+ // note access doesn't seem to allow unicode compression for calced fields
+ if(col.isCalculated()) {
+ buffer.put(CALCULATED_EXT_FLAG_MASK);
+ } else if (col.isCompressedUnicode()) { //Compressed
+ buffer.put(COMPRESSED_UNICODE_EXT_FLAG_MASK);
} else {
- buffer.put((byte) 0);
+ buffer.put((byte)0);
}
+
buffer.putInt(0); //Unknown, but always 0.
+
//Offset for fixed length columns
if (col.getType().isVariableLength()) {
buffer.putShort((short) 0);
buffer.putShort(fixedOffset);
fixedOffset += col.getType().getFixedSize(col.getLength());
}
+
if(!col.getType().isLongValue()) {
buffer.putShort(col.getLength()); //Column length
} else {
buffer.putShort((short)0x0000); // unused
}
+
}
for (ColumnBuilder col : columns) {
TableImpl.writeName(buffer, col.getName(), creator.getCharset());
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.Collections;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
-import com.healthmarketscience.jackcess.Database;
import com.healthmarketscience.jackcess.DataType;
+import com.healthmarketscience.jackcess.Database;
/**
* Encapsulates constants describing a specific version of the Access Jet format
}
}
+ /** calculated types supported in version 14 */
+ 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.TEXT, DataType.MEMO);
+
/** the JetFormat constants for the Jet database version "3" */
public static final JetFormat VERSION_3 = new Jet3Format();
/** the JetFormat constants for the Jet database version "4" */
public abstract boolean isSupportedDataType(DataType type);
+ public abstract boolean isSupportedCalculatedDataType(DataType type);
+
@Override
public String toString() {
return _name;
public boolean isSupportedDataType(DataType type) {
return (type != DataType.COMPLEX_TYPE);
}
+
+ @Override
+ public boolean isSupportedCalculatedDataType(DataType type) {
+ return false;
+ }
}
private static class Jet4Format extends JetFormat {
public boolean isSupportedDataType(DataType type) {
return (type != DataType.COMPLEX_TYPE);
}
+
+ @Override
+ public boolean isSupportedCalculatedDataType(DataType type) {
+ return false;
+ }
}
private static final class MSISAMFormat extends Jet4Format {
public boolean isSupportedDataType(DataType type) {
return true;
}
+
+ @Override
+ public boolean isSupportedCalculatedDataType(DataType type) {
+ return false;
+ }
}
private static final class Jet14Format extends Jet12Format {
protected Map<String,Database.FileFormat> getPossibleFileFormats() {
return PossibleFileFormats.POSSIBLE_VERSION_14;
}
+
+ @Override
+ public boolean isSupportedCalculatedDataType(DataType type) {
+ return V14_CALC_TYPES.contains(type);
+ }
}
}