return column.write(value, 0, ENTRY_BYTE_ORDER).array();
}
+ /**
+ * Writes a binary value using the general binary entry encoding rules.
+ */
+ private static void writeGeneralBinaryEntry(byte[] valueBytes, boolean isAsc,
+ ByteStream bout)
+ {
+ int dataLen = valueBytes.length;
+ int extraLen = (dataLen + 7) / 8;
+ int entryLen = ((dataLen + extraLen + 8) / 9) * 9;
+
+ // reserve space for the full entry
+ bout.ensureNewCapacity(entryLen);
+
+ // binary data is written in 8 byte segments with a trailing length byte.
+ // The length byte is the amount of valid bytes in the segment (where 9
+ // indicates that there is more data _after_ this segment).
+ byte[] partialEntryBytes = new byte[9];
+
+ // bit twiddling rules:
+ // - isAsc => nothing
+ // - !isAsc => flipBytes, _but keep intermediate 09 unflipped_!
+
+ // first, write any intermediate segements
+ int segmentLen = dataLen;
+ int pos = 0;
+ while(segmentLen > 8) {
+
+ System.arraycopy(valueBytes, pos, partialEntryBytes, 0, 8);
+ if(!isAsc) {
+ // note, we do _not_ flip the length byte for intermediate segments
+ flipBytes(partialEntryBytes, 0, 8);
+ }
+
+ // we are writing intermediate segments (there is more data after this
+ // segment), so the length is always 9.
+ partialEntryBytes[8] = (byte)9;
+
+ pos += 8;
+ segmentLen -= 8;
+
+ bout.write(partialEntryBytes);
+ }
+
+ // write the last segment (with slightly different rules)
+ if(segmentLen > 0) {
+
+ System.arraycopy(valueBytes, pos, partialEntryBytes, 0, segmentLen);
+
+ // clear out an intermediate bytes between the real data and the final
+ // length byte
+ for(int i = segmentLen; i < 8; ++i) {
+ partialEntryBytes[i] = 0;
+ }
+
+ partialEntryBytes[8] = (byte)segmentLen;
+
+ if(!isAsc) {
+ // note, we _do_ flip the last length byte
+ flipBytes(partialEntryBytes, 0, 9);
+ }
+
+ bout.write(partialEntryBytes);
+ }
+ }
+
/**
* Creates one of the special index entries.
*/
return new BooleanColumnDescriptor(col, flags);
case GUID:
return new GuidColumnDescriptor(col, flags);
+ case BINARY:
+ return new BinaryColumnDescriptor(col, flags);
default:
// we can't modify this index at this point in time
writeNonNullValue(value, bout);
}
- protected abstract void writeNonNullValue(
- Object value, ByteStream bout)
+ protected abstract void writeNonNullValue(Object value, ByteStream bout)
throws IOException;
@Override
public String toString() {
return CustomToStringStyle.builder(this)
.append("column", getColumn())
- .append("flags", getFlags())
+ .append("flags", getFlags() + " " + (isAscending() ? "(ASC)" : "(DSC)"))
.toString();
}
}
}
@Override
- protected void writeNonNullValue(
- Object value, ByteStream bout)
+ protected void writeNonNullValue(Object value, ByteStream bout)
throws IOException
{
byte[] valueBytes = encodeNumberColumnValue(value, getColumn());
}
@Override
- protected void writeNonNullValue(
- Object value, ByteStream bout)
+ protected void writeNonNullValue(Object value, ByteStream bout)
throws IOException
{
byte[] valueBytes = encodeNumberColumnValue(value, getColumn());
}
@Override
- protected void writeNonNullValue(
- Object value, ByteStream bout)
+ protected void writeNonNullValue(Object value, ByteStream bout)
throws IOException
{
byte[] valueBytes = encodeNumberColumnValue(value, getColumn());
}
@Override
- protected void writeNonNullValue(
- Object value, ByteStream bout)
+ protected void writeNonNullValue(Object value, ByteStream bout)
throws IOException
{
byte[] valueBytes = encodeNumberColumnValue(value, getColumn());
}
@Override
- protected void writeNonNullValue(
- Object value, ByteStream bout)
+ protected void writeNonNullValue(Object value, ByteStream bout)
throws IOException
{
GeneralLegacyIndexCodes.GEN_LEG_INSTANCE.writeNonNullIndexTextValue(
}
@Override
- protected void writeNonNullValue(
- Object value, ByteStream bout)
+ protected void writeNonNullValue(Object value, ByteStream bout)
throws IOException
{
GeneralIndexCodes.GEN_INSTANCE.writeNonNullIndexTextValue(
}
@Override
- protected void writeNonNullValue(
- Object value, ByteStream bout)
+ protected void writeNonNullValue(Object value, ByteStream bout)
throws IOException
{
- byte[] valueBytes = encodeNumberColumnValue(value, getColumn());
-
- // index format <8-bytes> 0x09 <8-bytes> 0x08
-
- // bit twiddling rules:
- // - isAsc => nothing
- // - !isAsc => flipBytes, _but keep 09 unflipped_!
- if(!isAscending()) {
- flipBytes(valueBytes);
- }
-
- bout.write(valueBytes, 0, 8);
- bout.write(MID_GUID);
- bout.write(valueBytes, 8, 8);
- bout.write(isAscending() ? ASC_END_GUID : DESC_END_GUID);
+ writeGeneralBinaryEntry(
+ encodeNumberColumnValue(value, getColumn()), isAscending(),
+ bout);
}
}
+ /**
+ * ColumnDescriptor for BINARY columns.
+ */
+ private static final class BinaryColumnDescriptor extends ColumnDescriptor
+ {
+ private BinaryColumnDescriptor(ColumnImpl column, byte flags)
+ throws IOException
+ {
+ super(column, flags);
+ }
+
+ @Override
+ protected void writeNonNullValue(Object value, ByteStream bout)
+ throws IOException
+ {
+ writeGeneralBinaryEntry(
+ ColumnImpl.toByteArray(value), isAscending(), bout);
+ }
+ }
+
+
/**
* ColumnDescriptor for columns which we cannot currently write.
*/
package com.healthmarketscience.jackcess.util;
import java.io.IOException;
+import java.util.Arrays;
import com.healthmarketscience.jackcess.DataType;
import com.healthmarketscience.jackcess.Table;
public boolean matches(Table table, String columnName, Object value1,
Object value2)
{
- if(ObjectUtils.equals(value1, value2)) {
+ if(equals(value1, value2)) {
return true;
}
Object internalV1 = ColumnImpl.toInternalValue(dataType, value1);
Object internalV2 = ColumnImpl.toInternalValue(dataType, value2);
- return ObjectUtils.equals(internalV1, internalV2);
+ return equals(internalV1, internalV2);
} catch(IOException e) {
// ignored, just go with the original result
}
return false;
}
+ /**
+ * Returns {@code true} if the two objects are equal, handling {@code null}
+ * and objects of type {@code byte[]}.
+ */
+ private static boolean equals(Object o1, Object o2)
+ {
+ return (ObjectUtils.equals(o1, o2) ||
+ ((o1 instanceof byte[]) && (o2 instanceof byte[]) &&
+ Arrays.equals((byte[])o1, (byte[])o2)));
+ }
+
}