Browse Source

merge branch newformats changes through r453

git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@454 f203690c-595d-4dc9-a70b-905162fa7fd2
tags/jackcess-1.2.0
James Ahlborn 14 years ago
parent
commit
4868f83aa6
69 changed files with 2500 additions and 1835 deletions
  1. 1
    0
      CREDITS.txt
  2. 1
    0
      pom.xml
  3. 7
    0
      project.xml
  4. 17
    0
      src/java/com/healthmarketscience/jackcess/ByteUtil.java
  5. 158
    13
      src/java/com/healthmarketscience/jackcess/Database.java
  6. 20
    6
      src/java/com/healthmarketscience/jackcess/Index.java
  7. 92
    5
      src/java/com/healthmarketscience/jackcess/JetFormat.java
  8. 2
    2
      src/java/com/healthmarketscience/jackcess/PageChannel.java
  9. 6
    3
      src/java/com/healthmarketscience/jackcess/UsageMap.java
  10. BIN
      src/resources/com/healthmarketscience/jackcess/empty2003.mdb
  11. BIN
      src/resources/com/healthmarketscience/jackcess/empty2007.accdb
  12. BIN
      test/data/V1997/testV1997.mdb
  13. 0
    0
      test/data/V2000/bigIndexTestV2000.mdb
  14. 0
    0
      test/data/V2000/compIndexTestV2000.mdb
  15. 0
    0
      test/data/V2000/delColTestV2000.mdb
  16. 0
    0
      test/data/V2000/delTestV2000.mdb
  17. 0
    0
      test/data/V2000/fixedNumericTestV2000.mdb
  18. 0
    0
      test/data/V2000/fixedTextTestV2000.mdb
  19. 0
    0
      test/data/V2000/indexCursorTestV2000.mdb
  20. 0
    0
      test/data/V2000/indexTestV2000.mdb
  21. 0
    0
      test/data/V2000/overflowTestV2000.mdb
  22. 0
    0
      test/data/V2000/queryTestV2000.mdb
  23. 0
    0
      test/data/V2000/test2V2000.mdb
  24. 0
    0
      test/data/V2000/testIndexCodesV2000.mdb
  25. 0
    0
      test/data/V2000/testIndexPropertiesV2000.mdb
  26. 0
    0
      test/data/V2000/testPromotionV2000.mdb
  27. 0
    0
      test/data/V2000/testV2000.mdb
  28. BIN
      test/data/V2003/bigIndexTestV2003.mdb
  29. BIN
      test/data/V2003/compIndexTestV2003.mdb
  30. BIN
      test/data/V2003/delColTestV2003.mdb
  31. BIN
      test/data/V2003/delTestV2003.mdb
  32. BIN
      test/data/V2003/fixedNumericTestV2003.mdb
  33. BIN
      test/data/V2003/fixedTextTestV2003.mdb
  34. BIN
      test/data/V2003/indexCursorTestV2003.mdb
  35. BIN
      test/data/V2003/indexTestV2003.mdb
  36. BIN
      test/data/V2003/overflowTestV2003.mdb
  37. BIN
      test/data/V2003/queryTestV2003.mdb
  38. BIN
      test/data/V2003/test2V2003.mdb
  39. BIN
      test/data/V2003/testIndexCodesV2003.mdb
  40. BIN
      test/data/V2003/testIndexPropertiesV2003.mdb
  41. BIN
      test/data/V2003/testPromotionV2003.mdb
  42. BIN
      test/data/V2003/testV2003.mdb
  43. BIN
      test/data/V2007/bigIndexTestV2007.accdb
  44. BIN
      test/data/V2007/compIndexTestV2007.accdb
  45. BIN
      test/data/V2007/delColTestV2007.accdb
  46. BIN
      test/data/V2007/delTestV2007.accdb
  47. BIN
      test/data/V2007/fixedNumericTestV2007.accdb
  48. BIN
      test/data/V2007/fixedTextTestV2007.accdb
  49. BIN
      test/data/V2007/indexCursorTestV2007.accdb
  50. BIN
      test/data/V2007/indexTestV2007.accdb
  51. BIN
      test/data/V2007/overflowTestV2007.accdb
  52. BIN
      test/data/V2007/queryTestV2007.accdb
  53. BIN
      test/data/V2007/test2V2007.accdb
  54. BIN
      test/data/V2007/testIndexCodesV2007.accdb
  55. BIN
      test/data/V2007/testIndexPropertiesV2007.accdb
  56. BIN
      test/data/V2007/testPromotionV2007.accdb
  57. BIN
      test/data/V2007/testV2007.accdb
  58. 129
    126
      test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java
  59. 114
    110
      test/src/java/com/healthmarketscience/jackcess/CursorBuilderTest.java
  60. 226
    185
      test/src/java/com/healthmarketscience/jackcess/CursorTest.java
  61. 764
    671
      test/src/java/com/healthmarketscience/jackcess/DatabaseTest.java
  62. 87
    84
      test/src/java/com/healthmarketscience/jackcess/ErrorHandlerTest.java
  63. 67
    60
      test/src/java/com/healthmarketscience/jackcess/ImportTest.java
  64. 303
    279
      test/src/java/com/healthmarketscience/jackcess/IndexCodesTest.java
  65. 206
    186
      test/src/java/com/healthmarketscience/jackcess/IndexTest.java
  66. 134
    0
      test/src/java/com/healthmarketscience/jackcess/JetFormatTest.java
  67. 45
    44
      test/src/java/com/healthmarketscience/jackcess/RelationshipTest.java
  68. 57
    0
      test/src/java/com/healthmarketscience/jackcess/UsageMapTest.java
  69. 64
    61
      test/src/java/com/healthmarketscience/jackcess/query/QueryTest.java

+ 1
- 0
CREDITS.txt View File

@@ -5,3 +5,4 @@ James Ahlborn - Added support for NUMERIC data type
Jon Iles - Added support for reading table definitions that span multiple pages
James Schopp - added support for reading currency columns
Patricia Donaldson - contributed RowFilter class
Dan Rollo - added support for new DB file formats

+ 1
- 0
pom.xml View File

@@ -37,6 +37,7 @@
<name>Dan Rollo</name>
<id>bhamail</id>
<email>bhamail@users.sf.net</email>
<organization>Composite Software, Inc.</organization>
<timezone>-5</timezone>
</developer>
</developers>

+ 7
- 0
project.xml View File

@@ -49,6 +49,13 @@
<organization>Health Market Science, Inc.</organization>
<timezone>-5</timezone>
</developer>
<developer>
<name>Dan Rollo</name>
<id>bhamail</id>
<email>bhamail@users.sf.net</email>
<organization>Composite Software, Inc.</organization>
<timezone>-5</timezone>
</developer>
</developers>
<licenses>
<license>

+ 17
- 0
src/java/com/healthmarketscience/jackcess/ByteUtil.java View File

@@ -308,6 +308,23 @@ public final class ByteUtil {
}
return true;
}

/**
* Searches for a pattern of bytes in the given buffer starting at the
* given offset.
* @return the offset of the pattern if a match is found, -1 otherwise
*/
public static int findRange(ByteBuffer buffer, int start, byte[] pattern)
{
byte firstByte = pattern[0];
int limit = buffer.limit() - pattern.length;
for(int i = start; i < limit; ++i) {
if((firstByte == buffer.get(i)) && matchesRange(buffer, i, pattern)) {
return i;
}
}
return -1;
}
/**
* Convert a byte buffer to a hexadecimal string for display

+ 158
- 13
src/java/com/healthmarketscience/jackcess/Database.java View File

@@ -168,9 +168,38 @@ public class Database
private static final String CAT_COL_DATE_UPDATE = "DateUpdate";
/** System catalog column name of the flags column */
private static final String CAT_COL_FLAGS = "Flags";
/** System catalog column name of the properties column */
private static final String CAT_COL_PROPS = "LvProp";
/** Empty database template for creating new databases */
private static final String EMPTY_MDB = "com/healthmarketscience/jackcess/empty.mdb";
public static enum FileFormat {

V1997(null, JetFormat.VERSION_3), // v97 is not supported, so no empty template is provided
V2000("com/healthmarketscience/jackcess/empty.mdb", JetFormat.VERSION_4),
V2003("com/healthmarketscience/jackcess/empty2003.mdb", JetFormat.VERSION_4),
V2007("com/healthmarketscience/jackcess/empty2007.accdb", JetFormat.VERSION_5, ".accdb");

private final String _emptyFile;
private final JetFormat _format;
private final String _ext;

private FileFormat(String emptyDBFile, JetFormat jetFormat) {
this(emptyDBFile, jetFormat, ".mdb");
}

private FileFormat(String emptyDBFile, JetFormat jetFormat, String ext) {
_emptyFile = emptyDBFile;
_format = jetFormat;
_ext = ext;
}

public JetFormat getJetFormat() { return _format; }

public String getFileExtension() { return _ext; }

@Override
public String toString() { return name() + ", jetFormat: " + getJetFormat(); }
}

/** Prefix for column or table names that are reserved words */
private static final String ESCAPE_PREFIX = "x";
/** Prefix that flags system tables */
@@ -183,6 +212,8 @@ public class Database
private static final String TABLE_SYSTEM_RELATIONSHIPS = "MSysRelationships";
/** Name of the table that contains queries */
private static final String TABLE_SYSTEM_QUERIES = "MSysQueries";
/** Name of the table that contains queries */
private static final String OBJECT_NAME_DBPROPS = "MSysDb";
/** System object type for table definitions */
private static final Short TYPE_TABLE = (short) 1;
/** System object type for query definitions */
@@ -269,6 +300,8 @@ public class Database
private boolean _useBigIndex;
/** optional error handler to use when row errors are encountered */
private ErrorHandler _dbErrorHandler;
/** the file format of the database */
private FileFormat _fileFormat;
/**
* Open an existing Database. If the existing file is not writeable, the
@@ -329,14 +362,14 @@ public class Database
}
return new Database(openChannel(mdbFile,
(!mdbFile.canWrite() || readOnly)),
autoSync);
autoSync, null);
}
/**
* Create a new Database
* Create a new Access 2000 Database
* <p>
* Equivalent to:
* {@code create(mdbFile, DEFAULT_AUTO_SYNC);}
* {@code create(FileFormat.V2000, mdbFile, DEFAULT_AUTO_SYNC);}
*
* @param mdbFile Location to write the new database to. <b>If this file
* already exists, it will be overwritten.</b>
@@ -348,7 +381,29 @@ public class Database
}
/**
* Create a new Database
* Create a new Database for the given fileFormat
* <p>
* Equivalent to:
* {@code create(fileFormat, mdbFile, DEFAULT_AUTO_SYNC);}
*
* @param fileFormat version of new database.
* @param mdbFile Location to write the new database to. <b>If this file
* already exists, it will be overwritten.</b>
*
* @see #create(File,boolean)
*/
public static Database create(FileFormat fileFormat, File mdbFile)
throws IOException
{
return create(fileFormat, mdbFile, DEFAULT_AUTO_SYNC);
}
/**
* Create a new Access 2000 Database
* <p>
* Equivalent to:
* {@code create(FileFormat.V2000, mdbFile, DEFAULT_AUTO_SYNC);}
*
* @param mdbFile Location to write the new database to. <b>If this file
* already exists, it will be overwritten.</b>
* @param autoSync whether or not to enable auto-syncing on write. if
@@ -362,19 +417,53 @@ public class Database
*/
public static Database create(File mdbFile, boolean autoSync)
throws IOException
{
{
return create(FileFormat.V2000, mdbFile, autoSync);
}

/**
* Create a new Database for the given fileFormat
* @param fileFormat version of new database.
* @param mdbFile Location to write the new database to. <b>If this file
* already exists, it will be overwritten.</b>
* @param autoSync whether or not to enable auto-syncing on write. if
* {@code true}, writes will be immediately flushed to disk.
* This leaves the database in a (fairly) consistent state
* on each write, but can be very inefficient for many
* updates. if {@code false}, flushing to disk happens at
* the jvm's leisure, which can be much faster, but may
* leave the database in an inconsistent state if failures
* are encountered during writing.
*/
public static Database create(FileFormat fileFormat, File mdbFile,
boolean autoSync)
throws IOException
{
FileChannel channel = openChannel(mdbFile, false);
channel.truncate(0);
channel.transferFrom(Channels.newChannel(
Thread.currentThread().getContextClassLoader().getResourceAsStream(
EMPTY_MDB)), 0, Integer.MAX_VALUE);
return new Database(channel, autoSync);
fileFormat._emptyFile)), 0, Integer.MAX_VALUE);
return new Database(channel, autoSync, fileFormat);
}
private static FileChannel openChannel(File mdbFile, boolean readOnly)

/**
* Package visible only to support unit tests via DatabaseTest.openChannel().
* @param mdbFile file to open
* @param readOnly true if read-only
* @return a FileChannel on the given file.
* @exception FileNotFoundException
* if the mode is <tt>"r"</tt> but the given file object does
* not denote an existing regular file, or if the mode begins
* with <tt>"rw"</tt> but the given file object does not denote
* an existing, writable regular file and a new regular file of
* that name cannot be created, or if some other error occurs
* while opening or creating the file
*/
static FileChannel openChannel(final File mdbFile, final boolean readOnly)
throws FileNotFoundException
{
String mode = (readOnly ? "r" : "rw");
final String mode = (readOnly ? "r" : "rw");
return new RandomAccessFile(mdbFile, mode).getChannel();
}
@@ -384,9 +473,12 @@ public class Database
* FileChannel instead of a ReadableByteChannel because we need to
* randomly jump around to various points in the file.
*/
protected Database(FileChannel channel, boolean autoSync) throws IOException
protected Database(FileChannel channel, boolean autoSync,
FileFormat fileFormat)
throws IOException
{
_format = JetFormat.getFormat(channel);
_fileFormat = fileFormat;
_pageChannel = new PageChannel(channel, _format, autoSync);
// note, it's slighly sketchy to pass ourselves along partially
// constructed, but only our _format and _pageChannel refs should be
@@ -449,6 +541,59 @@ public class Database
public void setErrorHandler(ErrorHandler newErrorHandler) {
_dbErrorHandler = newErrorHandler;
}

/**
* Returns the FileFormat of this database (which may involve inspecting the
* database itself).
* @throws IllegalStateException if the file format cannot be determined
*/
public FileFormat getFileFormat()
{
if(_fileFormat == null) {

Map<Database.FileFormat,byte[]> possibleFileFormats =
getFormat().getPossibleFileFormats();

if(possibleFileFormats.size() == 1) {

// single possible format, easy enough
_fileFormat = possibleFileFormats.keySet().iterator().next();

} else {

// need to check the "AccessVersion" property
byte[] dbProps = null;
for(Map<String,Object> row :
Cursor.createCursor(_systemCatalog).iterable(
Arrays.asList(CAT_COL_NAME, CAT_COL_PROPS))) {
if(OBJECT_NAME_DBPROPS.equals(row.get(CAT_COL_NAME))) {
dbProps = (byte[])row.get(CAT_COL_PROPS);
break;
}
}
if(dbProps != null) {

// search for certain "version strings" in the properties (we
// can't fully parse the properties objects, but we can still
// find the byte pattern)
ByteBuffer dbPropBuf = ByteBuffer.wrap(dbProps);
for(Map.Entry<Database.FileFormat,byte[]> possible :
possibleFileFormats.entrySet()) {
if(ByteUtil.findRange(dbPropBuf, 0, possible.getValue()) >= 0) {
_fileFormat = possible.getKey();
break;
}
}
}
if(_fileFormat == null) {
throw new IllegalStateException("Could not determine FileFormat");
}
}
}
return _fileFormat;
}
/**
* Read the system catalog

+ 20
- 6
src/java/com/healthmarketscience/jackcess/Index.java View File

@@ -1540,17 +1540,31 @@ public abstract class Index implements Comparable<Index> {
boolean isNegative = ((valueBytes[0] & 0x80) != 0);

// bit twiddling rules:
// isAsc && !isNeg => setReverseSignByte
// isAsc && isNeg => flipBytes, setReverseSignByte
// !isAsc && !isNeg => flipBytes, setReverseSignByte
// !isAsc && isNeg => setReverseSignByte
// isAsc && !isNeg => setReverseSignByte => FF 00 00 ...
// isAsc && isNeg => flipBytes, setReverseSignByte => 00 FF FF ...
// !isAsc && !isNeg => flipBytes, setReverseSignByte => FF FF FF ...
// !isAsc && isNeg => setReverseSignByte => 00 00 00 ...
// v2007 bit twiddling rules (old ordering was a bug, MS kb 837148):
// isAsc && !isNeg => setSignByte 0xFF => FF 00 00 ...
// isAsc && isNeg => setSignByte 0xFF, flipBytes => 00 FF FF ...
// !isAsc && !isNeg => setSignByte 0xFF => FF 00 00 ...
// !isAsc && isNeg => setSignByte 0xFF, flipBytes => 00 FF FF ...

boolean alwaysRevFirstByte = getColumn().getFormat().REVERSE_FIRST_BYTE_IN_DESC_NUMERIC_INDEXES;
if(alwaysRevFirstByte) {
// reverse the sign byte (before any byte flipping)
valueBytes[0] = (byte)0xFF;
}

if(isNegative == isAscending()) {
flipBytes(valueBytes);
}

// reverse the sign byte (after any previous byte flipping)
valueBytes[0] = (isNegative ? (byte)0x00 : (byte)0xFF);
if(!alwaysRevFirstByte) {
// reverse the sign byte (after any previous byte flipping)
valueBytes[0] = (isNegative ? (byte)0x00 : (byte)0xFF);
}
bout.write(valueBytes);
}

+ 92
- 5
src/java/com/healthmarketscience/jackcess/JetFormat.java View File

@@ -31,6 +31,9 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.EnumMap;
import java.util.Map;

/**
* Encapsulates constants describing a specific version of the Access Jet format
@@ -46,12 +49,41 @@ public abstract class JetFormat {
/** Maximum size of a text field */
public static final short TEXT_FIELD_MAX_LENGTH = 255 * TEXT_FIELD_UNIT_SIZE;
/** Offset in the file that holds the byte describing the Jet format version */
/** Offset in the file that holds the byte describing the Jet format
version */
private static final long OFFSET_VERSION = 20L;
/** Version code for Jet version 3 */
private static final byte CODE_VERSION_3 = 0x0;
/** Version code for Jet version 4 */
private static final byte CODE_VERSION_4 = 0x1;
/** Version code for Jet version 5 */
private static final byte CODE_VERSION_5 = 0x2;

/** value of the "AccessVersion" property for access 2000 dbs:
{@code "08.50"} */
private static final byte[] ACCESS_VERSION_2000 = new byte[] {
'0', 0, '8', 0, '.', 0, '5', 0, '0', 0};
/** value of the "AccessVersion" property for access 2002/2003 dbs
{@code "09.50"} */
private static final byte[] ACCESS_VERSION_2003 = new byte[] {
'0', 0, '9', 0, '.', 0, '5', 0, '0', 0};

// use nested inner class to avoid problematic static init loops
private static final class PossibleFileFormats {
private static final Map<Database.FileFormat,byte[]> POSSIBLE_VERSION_3 =
Collections.singletonMap(Database.FileFormat.V1997, (byte[])null);

private static final Map<Database.FileFormat,byte[]> POSSIBLE_VERSION_4 =
new EnumMap<Database.FileFormat,byte[]>(Database.FileFormat.class);

private static final Map<Database.FileFormat,byte[]> POSSIBLE_VERSION_5 =
Collections.singletonMap(Database.FileFormat.V2007, (byte[])null);

static {
POSSIBLE_VERSION_4.put(Database.FileFormat.V2000, ACCESS_VERSION_2000);
POSSIBLE_VERSION_4.put(Database.FileFormat.V2003, ACCESS_VERSION_2003);
}
}

//These constants are populated by this class's constructor. They can't be
//populated by the subclass's constructor because they are final, and Java
@@ -128,13 +160,19 @@ public abstract class JetFormat {
public final int MAX_TABLE_NAME_LENGTH;
public final int MAX_COLUMN_NAME_LENGTH;
public final int MAX_INDEX_NAME_LENGTH;

public final boolean REVERSE_FIRST_BYTE_IN_DESC_NUMERIC_INDEXES;
public final Charset CHARSET;
public static final JetFormat VERSION_3 = new Jet3Format();
public static final JetFormat VERSION_4 = new Jet4Format();
public static final JetFormat VERSION_5 = new Jet5Format();

/**
* @param channel the database file.
* @return The Jet Format represented in the passed-in file
* @throws IOException if the database file format is unsupported.
*/
public static JetFormat getFormat(FileChannel channel) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(1);
@@ -144,8 +182,12 @@ public abstract class JetFormat {
}
buffer.flip();
byte version = buffer.get();
if (version == CODE_VERSION_4) {
if (version == CODE_VERSION_3) {
return VERSION_3;
} else if (version == CODE_VERSION_4) {
return VERSION_4;
} else if (version == CODE_VERSION_5) {
return VERSION_5;
}
throw new IOException("Unsupported version: " + version);
}
@@ -220,7 +262,8 @@ public abstract class JetFormat {
MAX_TABLE_NAME_LENGTH = defineMaxTableNameLength();
MAX_COLUMN_NAME_LENGTH = defineMaxColumnNameLength();
MAX_INDEX_NAME_LENGTH = defineMaxIndexNameLength();

REVERSE_FIRST_BYTE_IN_DESC_NUMERIC_INDEXES = defineReverseFirstByteInDescNumericIndexes();
CHARSET = defineCharset();
}
@@ -295,15 +338,23 @@ public abstract class JetFormat {
protected abstract Charset defineCharset();

protected abstract boolean defineReverseFirstByteInDescNumericIndexes();

protected abstract Map<Database.FileFormat,byte[]> getPossibleFileFormats();

@Override
public String toString() {
return _name;
}
private static final class Jet4Format extends JetFormat {
private static class Jet4Format extends JetFormat {

private Jet4Format() {
super("VERSION_4");
this("VERSION_4");
}

private Jet4Format(final String name) {
super(name);
}

@Override
@@ -434,8 +485,44 @@ public abstract class JetFormat {
@Override
protected int defineMaxIndexNameLength() { return 64; }
@Override
protected boolean defineReverseFirstByteInDescNumericIndexes() { return false; }

@Override
protected Charset defineCharset() { return Charset.forName("UTF-16LE"); }

@Override
protected Map<Database.FileFormat,byte[]> getPossibleFileFormats()
{
return PossibleFileFormats.POSSIBLE_VERSION_4;
}

}
private static final class Jet3Format extends Jet4Format {
private Jet3Format() {
super("VERSION_3");
}

@Override
protected Map<Database.FileFormat,byte[]> getPossibleFileFormats() {
return PossibleFileFormats.POSSIBLE_VERSION_3;
}

}

private static final class Jet5Format extends Jet4Format {
private Jet5Format() {
super("VERSION_5");
}

@Override
protected boolean defineReverseFirstByteInDescNumericIndexes() { return true; }

@Override
protected Map<Database.FileFormat,byte[]> getPossibleFileFormats() {
return PossibleFileFormats.POSSIBLE_VERSION_5;
}
}

}

+ 2
- 2
src/java/com/healthmarketscience/jackcess/PageChannel.java View File

@@ -56,9 +56,9 @@ public class PageChannel implements Channel, Flushable {
new byte[]{PageTypes.INVALID, (byte)0, (byte)0, (byte)0};
/** Global usage map always lives on page 1 */
private static final int PAGE_GLOBAL_USAGE_MAP = 1;
static final int PAGE_GLOBAL_USAGE_MAP = 1;
/** Global usage map always lives at row 0 */
private static final int ROW_GLOBAL_USAGE_MAP = 0;
static final int ROW_GLOBAL_USAGE_MAP = 0;
/** Channel containing the database */
private final FileChannel _channel;

+ 6
- 3
src/java/com/healthmarketscience/jackcess/UsageMap.java View File

@@ -72,8 +72,11 @@ public class UsageMap
/** the current handler implementation for reading/writing the specific
usage map type. note, this may change over time. */
private Handler _handler;
/**

/** Error message prefix used when map type is unrecognized. */
static final String MSG_PREFIX_UNRECOGNIZED_MAP = "Unrecognized map type: ";

/**
* @param database database that contains this usage map
* @param tableBuffer Buffer that contains this map's declaration
* @param pageNum Page number that this usage map is contained in
@@ -139,7 +142,7 @@ public class UsageMap
} else if (mapType == MAP_TYPE_REFERENCE) {
_handler = new ReferenceHandler();
} else {
throw new IOException("Unrecognized map type: " + mapType);
throw new IOException(MSG_PREFIX_UNRECOGNIZED_MAP + mapType);
}
}

BIN
src/resources/com/healthmarketscience/jackcess/empty2003.mdb View File


BIN
src/resources/com/healthmarketscience/jackcess/empty2007.accdb View File


BIN
test/data/V1997/testV1997.mdb View File


test/data/bigIndexTest.mdb → test/data/V2000/bigIndexTestV2000.mdb View File


test/data/compIndexTest.mdb → test/data/V2000/compIndexTestV2000.mdb View File


test/data/delColTest.mdb → test/data/V2000/delColTestV2000.mdb View File


test/data/delTest.mdb → test/data/V2000/delTestV2000.mdb View File


test/data/fixedNumericTest.mdb → test/data/V2000/fixedNumericTestV2000.mdb View File


test/data/fixedTextTest.mdb → test/data/V2000/fixedTextTestV2000.mdb View File


test/data/indexCursorTest.mdb → test/data/V2000/indexCursorTestV2000.mdb View File


test/data/indexTest.mdb → test/data/V2000/indexTestV2000.mdb View File


test/data/overflowTest.mdb → test/data/V2000/overflowTestV2000.mdb View File


test/data/queryTest.mdb → test/data/V2000/queryTestV2000.mdb View File


test/data/test2.mdb → test/data/V2000/test2V2000.mdb View File


test/data/testIndexCodes.mdb → test/data/V2000/testIndexCodesV2000.mdb View File


test/data/testIndexProperties.mdb → test/data/V2000/testIndexPropertiesV2000.mdb View File


test/data/testPromotion.mdb → test/data/V2000/testPromotionV2000.mdb View File


test/data/test.mdb → test/data/V2000/testV2000.mdb View File


BIN
test/data/V2003/bigIndexTestV2003.mdb View File


BIN
test/data/V2003/compIndexTestV2003.mdb View File


BIN
test/data/V2003/delColTestV2003.mdb View File


BIN
test/data/V2003/delTestV2003.mdb View File


BIN
test/data/V2003/fixedNumericTestV2003.mdb View File


BIN
test/data/V2003/fixedTextTestV2003.mdb View File


BIN
test/data/V2003/indexCursorTestV2003.mdb View File


BIN
test/data/V2003/indexTestV2003.mdb View File


BIN
test/data/V2003/overflowTestV2003.mdb View File


BIN
test/data/V2003/queryTestV2003.mdb View File


BIN
test/data/V2003/test2V2003.mdb View File


BIN
test/data/V2003/testIndexCodesV2003.mdb View File


BIN
test/data/V2003/testIndexPropertiesV2003.mdb View File


BIN
test/data/V2003/testPromotionV2003.mdb View File


BIN
test/data/V2003/testV2003.mdb View File


BIN
test/data/V2007/bigIndexTestV2007.accdb View File


BIN
test/data/V2007/compIndexTestV2007.accdb View File


BIN
test/data/V2007/delColTestV2007.accdb View File


BIN
test/data/V2007/delTestV2007.accdb View File


BIN
test/data/V2007/fixedNumericTestV2007.accdb View File


BIN
test/data/V2007/fixedTextTestV2007.accdb View File


BIN
test/data/V2007/indexCursorTestV2007.accdb View File


BIN
test/data/V2007/indexTestV2007.accdb View File


BIN
test/data/V2007/overflowTestV2007.accdb View File


BIN
test/data/V2007/queryTestV2007.accdb View File


BIN
test/data/V2007/test2V2007.accdb View File


BIN
test/data/V2007/testIndexCodesV2007.accdb View File


BIN
test/data/V2007/testIndexPropertiesV2007.accdb View File


BIN
test/data/V2007/testPromotionV2007.accdb View File


BIN
test/data/V2007/testV2007.accdb View File


+ 129
- 126
test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java View File

@@ -27,7 +27,6 @@ King of Prussia, PA 19406

package com.healthmarketscience.jackcess;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -36,6 +35,7 @@ import java.util.Random;
import junit.framework.TestCase;

import static com.healthmarketscience.jackcess.DatabaseTest.*;
import static com.healthmarketscience.jackcess.JetFormatTest.*;


/**
@@ -67,157 +67,160 @@ public class BigIndexTest extends TestCase {
public void testComplexIndex() throws Exception
{
// this file has an index with "compressed" entries and node pages
Database db = open(new File("test/data/compIndexTest.mdb"));
Table t = db.getTable("Table1");
Index index = t.getIndex("CD_AGENTE");
assertFalse(index.isInitialized());
assertEquals(512, countRows(t));
assertEquals(512, index.getEntryCount());
db.close();
for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.COMP_INDEX)) {
// this file has an index with "compressed" entries and node pages
Database db = open(testDB);
Table t = db.getTable("Table1");
Index index = t.getIndex("CD_AGENTE");
assertFalse(index.isInitialized());
assertEquals(512, countRows(t));
assertEquals(512, index.getEntryCount());
db.close();
}
}

public void testBigIndex() throws Exception
{
for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.BIG_INDEX)) {
// this file has an index with "compressed" entries and node pages
File origFile = new File("test/data/bigIndexTest.mdb");
Database db = open(origFile);
Table t = db.getTable("Table1");
Index index = t.getIndex("col1");
assertFalse(index.isInitialized());
assertEquals(0, countRows(t));
assertEquals(0, index.getEntryCount());
db.close();

DatabaseTest._autoSync = false;
try {

String extraText = " some random text to fill out the index and make it fill up pages with lots of extra bytes so i will keep typing until i think that i probably have enough text in the index entry so that i do not need to add as many entries in order";
// copy to temp file and attempt to edit
db = openCopy(origFile);
t = db.getTable("Table1");
index = t.getIndex("col1");

System.out.println("BigIndexTest: Index type: " + index.getClass());

// add 2,000 (pseudo) random entries to the table
Random rand = new Random(13L);
for(int i = 0; i < 2000; ++i) {
if((i == 850) || (i == 1850)) {
int end = i + 50;
List<Object[]> rows = new ArrayList<Object[]>(50);
for(; i < end; ++i) {
Database db = open(testDB);
Table t = db.getTable("Table1");
Index index = t.getIndex("col1");
assertFalse(index.isInitialized());
assertEquals(0, countRows(t));
assertEquals(0, index.getEntryCount());
db.close();

DatabaseTest._autoSync = false;
try {

String extraText = " some random text to fill out the index and make it fill up pages with lots of extra bytes so i will keep typing until i think that i probably have enough text in the index entry so that i do not need to add as many entries in order";

// copy to temp file and attempt to edit
db = openCopy(testDB);
t = db.getTable("Table1");
index = t.getIndex("col1");

System.out.println("BigIndexTest: Index type: " + index.getClass());

// add 2,000 (pseudo) random entries to the table
Random rand = new Random(13L);
for(int i = 0; i < 2000; ++i) {
if((i == 850) || (i == 1850)) {
int end = i + 50;
List<Object[]> rows = new ArrayList<Object[]>(50);
for(; i < end; ++i) {
int nextInt = rand.nextInt(Integer.MAX_VALUE);
String nextVal = "" + nextInt + extraText;
if(((i + 1) % 333) == 0) {
nextVal = null;
}
rows.add(new Object[]{nextVal,
"this is some row data " + nextInt});
}
t.addRows(rows);
--i;
} else {
int nextInt = rand.nextInt(Integer.MAX_VALUE);
String nextVal = "" + nextInt + extraText;
if(((i + 1) % 333) == 0) {
nextVal = null;
}
rows.add(new Object[]{nextVal,
"this is some row data " + nextInt});
t.addRow(nextVal, "this is some row data " + nextInt);
}
t.addRows(rows);
--i;
} else {
int nextInt = rand.nextInt(Integer.MAX_VALUE);
String nextVal = "" + nextInt + extraText;
if(((i + 1) % 333) == 0) {
nextVal = null;
}

((BigIndex)index).validate();

db.flush();
t = db.getTable("Table1");
index = t.getIndex("col1");

// make sure all entries are there and correctly ordered
String firstValue = " ";
String prevValue = firstValue;
int rowCount = 0;
List<String> firstTwo = new ArrayList<String>();
for(Map<String,Object> row : Cursor.createIndexCursor(t, index)) {
String origVal = (String)row.get("col1");
String val = origVal;
if(val == null) {
val = firstValue;
}
t.addRow(nextVal, "this is some row data " + nextInt);
assertTrue("" + prevValue + " <= " + val + " " + rowCount,
prevValue.compareTo(val) <= 0);
if(firstTwo.size() < 2) {
firstTwo.add(origVal);
}
prevValue = val;
++rowCount;
}
}

((BigIndex)index).validate();
db.flush();
t = db.getTable("Table1");
index = t.getIndex("col1");

// make sure all entries are there and correctly ordered
String firstValue = " ";
String prevValue = firstValue;
int rowCount = 0;
List<String> firstTwo = new ArrayList<String>();
for(Map<String,Object> row : Cursor.createIndexCursor(t, index)) {
String origVal = (String)row.get("col1");
String val = origVal;
if(val == null) {
val = firstValue;
assertEquals(2000, rowCount);

((BigIndex)index).validate();

// delete an entry in the middle
Cursor cursor = Cursor.createIndexCursor(t, index);
for(int i = 0; i < (rowCount / 2); ++i) {
assertTrue(cursor.moveToNextRow());
}
assertTrue("" + prevValue + " <= " + val + " " + rowCount,
prevValue.compareTo(val) <= 0);
if(firstTwo.size() < 2) {
firstTwo.add(origVal);
cursor.deleteCurrentRow();
--rowCount;

// remove all but the first two entries (from the end)
cursor.afterLast();
for(int i = 0; i < (rowCount - 2); ++i) {
assertTrue(cursor.moveToPreviousRow());
cursor.deleteCurrentRow();
}
prevValue = val;
++rowCount;
}

assertEquals(2000, rowCount);
((BigIndex)index).validate();

((BigIndex)index).validate();
// delete an entry in the middle
Cursor cursor = Cursor.createIndexCursor(t, index);
for(int i = 0; i < (rowCount / 2); ++i) {
assertTrue(cursor.moveToNextRow());
}
cursor.deleteCurrentRow();
--rowCount;
// remove all but the first two entries (from the end)
cursor.afterLast();
for(int i = 0; i < (rowCount - 2); ++i) {
assertTrue(cursor.moveToPreviousRow());
cursor.deleteCurrentRow();
}
List<String> found = new ArrayList<String>();
for(Map<String,Object> row : Cursor.createIndexCursor(t, index)) {
found.add((String)row.get("col1"));
}

((BigIndex)index).validate();
List<String> found = new ArrayList<String>();
for(Map<String,Object> row : Cursor.createIndexCursor(t, index)) {
found.add((String)row.get("col1"));
}
assertEquals(firstTwo, found);

assertEquals(firstTwo, found);
// remove remaining entries
cursor = Cursor.createCursor(t);
for(int i = 0; i < 2; ++i) {
assertTrue(cursor.moveToNextRow());
cursor.deleteCurrentRow();
}

// remove remaining entries
cursor = Cursor.createCursor(t);
for(int i = 0; i < 2; ++i) {
assertTrue(cursor.moveToNextRow());
cursor.deleteCurrentRow();
}
assertFalse(cursor.moveToNextRow());
assertFalse(cursor.moveToPreviousRow());

((BigIndex)index).validate();

// add 50 (pseudo) random entries to the table
rand = new Random(42L);
for(int i = 0; i < 50; ++i) {
int nextInt = rand.nextInt(Integer.MAX_VALUE);
String nextVal = "some prefix " + nextInt + extraText;
if(((i + 1) % 3333) == 0) {
nextVal = null;
}
t.addRow(nextVal, "this is some row data " + nextInt);
}

((BigIndex)index).validate();

assertFalse(cursor.moveToNextRow());
assertFalse(cursor.moveToPreviousRow());
((BigIndex)index).validate();

// add 50 (pseudo) random entries to the table
rand = new Random(42L);
for(int i = 0; i < 50; ++i) {
int nextInt = rand.nextInt(Integer.MAX_VALUE);
String nextVal = "some prefix " + nextInt + extraText;
if(((i + 1) % 3333) == 0) {
nextVal = null;
cursor = Cursor.createIndexCursor(t, index);
while(cursor.moveToNextRow()) {
cursor.deleteCurrentRow();
}
t.addRow(nextVal, "this is some row data " + nextInt);
}

((BigIndex)index).validate();
((BigIndex)index).validate();

cursor = Cursor.createIndexCursor(t, index);
while(cursor.moveToNextRow()) {
cursor.deleteCurrentRow();
db.close();

} finally {
DatabaseTest._autoSync = Database.DEFAULT_AUTO_SYNC;
}
((BigIndex)index).validate();
db.close();
} finally {
DatabaseTest._autoSync = Database.DEFAULT_AUTO_SYNC;
}
}


+ 114
- 110
test/src/java/com/healthmarketscience/jackcess/CursorBuilderTest.java View File

@@ -29,6 +29,8 @@ package com.healthmarketscience.jackcess;

import junit.framework.TestCase;

import static com.healthmarketscience.jackcess.JetFormatTest.*;

/**
* @author James Ahlborn
*/
@@ -50,117 +52,119 @@ public class CursorBuilderTest extends TestCase {
public void test() throws Exception
{
Database db = CursorTest.createTestIndexTable();

Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);

Cursor expected = Cursor.createCursor(table);
Cursor found = new CursorBuilder(table).toCursor();
assertCursor(expected, found);

expected = Cursor.createIndexCursor(table, idx);
found = new CursorBuilder(table)
.setIndex(idx)
.toCursor();
assertCursor(expected, found);

expected = Cursor.createIndexCursor(table, idx);
found = new CursorBuilder(table)
.setIndexByName("id")
.toCursor();
assertCursor(expected, found);

try {
new CursorBuilder(table)
.setIndexByName("foo");
fail("IllegalArgumentException should have been thrown");
} catch(IllegalArgumentException ignored) {
// success
}
expected = Cursor.createIndexCursor(table, idx);
found = new CursorBuilder(table)
.setIndexByColumns(table.getColumn("id"))
.toCursor();
assertCursor(expected, found);

try {
new CursorBuilder(table)
.setIndexByColumns(table.getColumn("value"));
fail("IllegalArgumentException should have been thrown");
} catch(IllegalArgumentException ignored) {
// success
}
try {
new CursorBuilder(table)
.setIndexByColumns(table.getColumn("id"), table.getColumn("value"));
fail("IllegalArgumentException should have been thrown");
} catch(IllegalArgumentException ignored) {
// success
for (final TestDB indexCursorDB : CursorTest.INDEX_CURSOR_DBS) {
Database db = CursorTest.createTestIndexTable(indexCursorDB);

Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);

Cursor expected = Cursor.createCursor(table);

Cursor found = new CursorBuilder(table).toCursor();
assertCursor(expected, found);

expected = Cursor.createIndexCursor(table, idx);
found = new CursorBuilder(table)
.setIndex(idx)
.toCursor();
assertCursor(expected, found);

expected = Cursor.createIndexCursor(table, idx);
found = new CursorBuilder(table)
.setIndexByName("id")
.toCursor();
assertCursor(expected, found);

try {
new CursorBuilder(table)
.setIndexByName("foo");
fail("IllegalArgumentException should have been thrown");
} catch(IllegalArgumentException ignored) {
// success
}

expected = Cursor.createIndexCursor(table, idx);
found = new CursorBuilder(table)
.setIndexByColumns(table.getColumn("id"))
.toCursor();
assertCursor(expected, found);

try {
new CursorBuilder(table)
.setIndexByColumns(table.getColumn("value"));
fail("IllegalArgumentException should have been thrown");
} catch(IllegalArgumentException ignored) {
// success
}

try {
new CursorBuilder(table)
.setIndexByColumns(table.getColumn("id"), table.getColumn("value"));
fail("IllegalArgumentException should have been thrown");
} catch(IllegalArgumentException ignored) {
// success
}

expected = Cursor.createCursor(table);
expected.beforeFirst();
found = new CursorBuilder(table)
.beforeFirst()
.toCursor();
assertCursor(expected, found);

expected = Cursor.createCursor(table);
expected.afterLast();
found = new CursorBuilder(table)
.afterLast()
.toCursor();
assertCursor(expected, found);

expected = Cursor.createCursor(table);
expected.moveNextRows(2);
Cursor.Savepoint sp = expected.getSavepoint();
found = new CursorBuilder(table)
.afterLast()
.restoreSavepoint(sp)
.toCursor();
assertCursor(expected, found);

expected = Cursor.createIndexCursor(table, idx);
expected.moveNextRows(2);
sp = expected.getSavepoint();
found = new CursorBuilder(table)
.setIndex(idx)
.beforeFirst()
.restoreSavepoint(sp)
.toCursor();
assertCursor(expected, found);

expected = Cursor.createIndexCursor(table, idx,
idx.constructIndexRowFromEntry(3),
null);
found = new CursorBuilder(table)
.setIndex(idx)
.setStartEntry(3)
.toCursor();
assertCursor(expected, found);

expected = Cursor.createIndexCursor(table, idx,
idx.constructIndexRowFromEntry(3),
false,
idx.constructIndexRowFromEntry(7),
false);
found = new CursorBuilder(table)
.setIndex(idx)
.setStartEntry(3)
.setStartRowInclusive(false)
.setEndEntry(7)
.setEndRowInclusive(false)
.toCursor();
assertCursor(expected, found);



db.close();
}
expected = Cursor.createCursor(table);
expected.beforeFirst();
found = new CursorBuilder(table)
.beforeFirst()
.toCursor();
assertCursor(expected, found);

expected = Cursor.createCursor(table);
expected.afterLast();
found = new CursorBuilder(table)
.afterLast()
.toCursor();
assertCursor(expected, found);

expected = Cursor.createCursor(table);
expected.moveNextRows(2);
Cursor.Savepoint sp = expected.getSavepoint();
found = new CursorBuilder(table)
.afterLast()
.restoreSavepoint(sp)
.toCursor();
assertCursor(expected, found);

expected = Cursor.createIndexCursor(table, idx);
expected.moveNextRows(2);
sp = expected.getSavepoint();
found = new CursorBuilder(table)
.setIndex(idx)
.beforeFirst()
.restoreSavepoint(sp)
.toCursor();
assertCursor(expected, found);

expected = Cursor.createIndexCursor(table, idx,
idx.constructIndexRowFromEntry(3),
null);
found = new CursorBuilder(table)
.setIndex(idx)
.setStartEntry(3)
.toCursor();
assertCursor(expected, found);

expected = Cursor.createIndexCursor(table, idx,
idx.constructIndexRowFromEntry(3),
false,
idx.constructIndexRowFromEntry(7),
false);
found = new CursorBuilder(table)
.setIndex(idx)
.setStartEntry(3)
.setStartRowInclusive(false)
.setEndEntry(7)
.setEndRowInclusive(false)
.toCursor();
assertCursor(expected, found);


db.close();
}
}

+ 226
- 185
test/src/java/com/healthmarketscience/jackcess/CursorTest.java View File

@@ -27,7 +27,6 @@ King of Prussia, PA 19406

package com.healthmarketscience.jackcess;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -37,7 +36,9 @@ import java.util.TreeSet;

import junit.framework.TestCase;

import static com.healthmarketscience.jackcess.Database.*;
import static com.healthmarketscience.jackcess.DatabaseTest.*;
import static com.healthmarketscience.jackcess.JetFormatTest.*;

/**
* @author James Ahlborn
@@ -70,8 +71,8 @@ public class CursorTest extends TestCase {
return expectedRows;
}
private static Database createTestTable() throws Exception {
Database db = create();
private static Database createTestTable(final FileFormat fileFormat) throws Exception {
Database db = create(fileFormat);

Table table = new TableBuilder("test")
.addColumn(new ColumnBuilder("id", DataType.LONG).toColumn())
@@ -96,16 +97,18 @@ public class CursorTest extends TestCase {
}
return expectedRows;
}
static Database createTestIndexTable() throws Exception {
Database db = openCopy(new File("test/data/indexCursorTest.mdb"));

static final TestDB[] INDEX_CURSOR_DBS = TestDB.getSupportedForBasename(Basename.INDEX_CURSOR);

static Database createTestIndexTable(final TestDB indexCursorDB) throws Exception {
Database db = openCopy(indexCursorDB);

Table table = db.getTable("test");

for(Map<String,Object> row : createUnorderedTestTableData()) {
table.addRow(row.get("id"), row.get("value"));
}
return db;
}

@@ -139,16 +142,18 @@ public class CursorTest extends TestCase {
}
public void testSimple() throws Exception {
Database db = createTestTable();
for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
Database db = createTestTable(fileFormat);

Table table = db.getTable("test");
Cursor cursor = Cursor.createCursor(table);
doTestSimple(table, cursor, null);
db.close();
Table table = db.getTable("test");
Cursor cursor = Cursor.createCursor(table);
doTestSimple(cursor, null);
db.close();
}
}

private void doTestSimple(Table table, Cursor cursor,
List<Map<String,Object>> expectedRows)
private void doTestSimple(Cursor cursor,
List<Map<String, Object>> expectedRows)
throws Exception
{
if(expectedRows == null) {
@@ -164,17 +169,19 @@ public class CursorTest extends TestCase {
}

public void testMove() throws Exception {
Database db = createTestTable();
for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
Database db = createTestTable(fileFormat);

Table table = db.getTable("test");
Cursor cursor = Cursor.createCursor(table);
doTestMove(table, cursor, null);
db.close();
Table table = db.getTable("test");
Cursor cursor = Cursor.createCursor(table);
doTestMove(cursor, null);

db.close();
}
}

private void doTestMove(Table table, Cursor cursor,
List<Map<String,Object>> expectedRows)
private void doTestMove(Cursor cursor,
List<Map<String, Object>> expectedRows)
throws Exception
{
if(expectedRows == null) {
@@ -221,13 +228,15 @@ public class CursorTest extends TestCase {
}

public void testSearch() throws Exception {
Database db = createTestTable();
for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
Database db = createTestTable(fileFormat);

Table table = db.getTable("test");
Cursor cursor = Cursor.createCursor(table);
doTestSearch(table, cursor, null, 42, -13);
db.close();
Table table = db.getTable("test");
Cursor cursor = Cursor.createCursor(table);
doTestSearch(table, cursor, null, 42, -13);

db.close();
}
}

private void doTestSearch(Table table, Cursor cursor, Index index,
@@ -303,17 +312,19 @@ public class CursorTest extends TestCase {
}

public void testReverse() throws Exception {
Database db = createTestTable();
for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
Database db = createTestTable(fileFormat);

Table table = db.getTable("test");
Cursor cursor = Cursor.createCursor(table);
doTestReverse(table, cursor, null);
Table table = db.getTable("test");
Cursor cursor = Cursor.createCursor(table);
doTestReverse(cursor, null);

db.close();
db.close();
}
}

private void doTestReverse(Table table, Cursor cursor,
List<Map<String,Object>> expectedRows)
private void doTestReverse(Cursor cursor,
List<Map<String, Object>> expectedRows)
throws Exception
{
if(expectedRows == null) {
@@ -330,15 +341,17 @@ public class CursorTest extends TestCase {
}
public void testLiveAddition() throws Exception {
Database db = createTestTable();
for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
Database db = createTestTable(fileFormat);

Table table = db.getTable("test");
Table table = db.getTable("test");

Cursor cursor1 = Cursor.createCursor(table);
Cursor cursor2 = Cursor.createCursor(table);
doTestLiveAddition(table, cursor1, cursor2, 11);
db.close();
Cursor cursor1 = Cursor.createCursor(table);
Cursor cursor2 = Cursor.createCursor(table);
doTestLiveAddition(table, cursor1, cursor2, 11);

db.close();
}
}

private void doTestLiveAddition(Table table,
@@ -369,25 +382,27 @@ public class CursorTest extends TestCase {

public void testLiveDeletion() throws Exception {
Database db = createTestTable();
for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
Database db = createTestTable(fileFormat);

Table table = db.getTable("test");
Table table = db.getTable("test");

Cursor cursor1 = Cursor.createCursor(table);
Cursor cursor2 = Cursor.createCursor(table);
Cursor cursor3 = Cursor.createCursor(table);
Cursor cursor4 = Cursor.createCursor(table);
doTestLiveDeletion(table, cursor1, cursor2, cursor3, cursor4, 1);
db.close();
Cursor cursor1 = Cursor.createCursor(table);
Cursor cursor2 = Cursor.createCursor(table);
Cursor cursor3 = Cursor.createCursor(table);
Cursor cursor4 = Cursor.createCursor(table);
doTestLiveDeletion(cursor1, cursor2, cursor3, cursor4, 1);

db.close();
}
}

private void doTestLiveDeletion(Table table,
Cursor cursor1,
Cursor cursor2,
Cursor cursor3,
Cursor cursor4,
int firstValue) throws Exception
private void doTestLiveDeletion(
Cursor cursor1,
Cursor cursor2,
Cursor cursor3,
Cursor cursor4,
int firstValue) throws Exception
{
assertEquals(2, cursor1.moveNextRows(2));
assertEquals(3, cursor2.moveNextRows(3));
@@ -460,220 +475,246 @@ public class CursorTest extends TestCase {
}

public void testSimpleIndex() throws Exception {
Database db = createTestIndexTable();
for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
Database db = createTestIndexTable(indexCursorDB);

Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);

assertTable(createUnorderedTestTableData(), table);
assertTable(createUnorderedTestTableData(), table);

Cursor cursor = Cursor.createIndexCursor(table, idx);
doTestSimple(table, cursor, null);
Cursor cursor = Cursor.createIndexCursor(table, idx);
doTestSimple(cursor, null);

db.close();
db.close();
}
}

public void testMoveIndex() throws Exception {
Database db = createTestIndexTable();
for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
Database db = createTestIndexTable(indexCursorDB);

Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Cursor cursor = Cursor.createIndexCursor(table, idx);
doTestMove(table, cursor, null);
db.close();
Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Cursor cursor = Cursor.createIndexCursor(table, idx);
doTestMove(cursor, null);

db.close();
}
}
public void testReverseIndex() throws Exception {
Database db = createTestIndexTable();
for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
Database db = createTestIndexTable(indexCursorDB);

Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Cursor cursor = Cursor.createIndexCursor(table, idx);
doTestReverse(table, cursor, null);
Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Cursor cursor = Cursor.createIndexCursor(table, idx);
doTestReverse(cursor, null);

db.close();
db.close();
}
}

public void testSearchIndex() throws Exception {
Database db = createTestIndexTable();
for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
Database db = createTestIndexTable(indexCursorDB);

Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Cursor cursor = Cursor.createIndexCursor(table, idx);
doTestSearch(table, cursor, idx, 42, -13);
db.close();
Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Cursor cursor = Cursor.createIndexCursor(table, idx);
doTestSearch(table, cursor, idx, 42, -13);

db.close();
}
}

public void testLiveAdditionIndex() throws Exception {
Database db = createTestIndexTable();
for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
Database db = createTestIndexTable(indexCursorDB);

Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);

Cursor cursor1 = Cursor.createIndexCursor(table, idx);
Cursor cursor2 = Cursor.createIndexCursor(table, idx);
doTestLiveAddition(table, cursor1, cursor2, 11);
db.close();
Cursor cursor1 = Cursor.createIndexCursor(table, idx);
Cursor cursor2 = Cursor.createIndexCursor(table, idx);
doTestLiveAddition(table, cursor1, cursor2, 11);

db.close();
}
}

public void testLiveDeletionIndex() throws Exception {
Database db = createTestIndexTable();
for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
Database db = createTestIndexTable(indexCursorDB);

Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);

Cursor cursor1 = Cursor.createIndexCursor(table, idx);
Cursor cursor2 = Cursor.createIndexCursor(table, idx);
Cursor cursor3 = Cursor.createIndexCursor(table, idx);
Cursor cursor4 = Cursor.createIndexCursor(table, idx);
doTestLiveDeletion(table, cursor1, cursor2, cursor3, cursor4, 1);
db.close();
Cursor cursor1 = Cursor.createIndexCursor(table, idx);
Cursor cursor2 = Cursor.createIndexCursor(table, idx);
Cursor cursor3 = Cursor.createIndexCursor(table, idx);
Cursor cursor4 = Cursor.createIndexCursor(table, idx);
doTestLiveDeletion(cursor1, cursor2, cursor3, cursor4, 1);

db.close();
}
}

public void testSimpleIndexSubRange() throws Exception {
for(int i = 0; i < 2; ++i) {
Database db = createTestIndexTable();
for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
for(int i = 0; i < 2; ++i) {
Database db = createTestIndexTable(indexCursorDB);

Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);

Cursor cursor = createIndexSubRangeCursor(table, idx, i);
Cursor cursor = createIndexSubRangeCursor(table, idx, i);

List<Map<String,Object>> expectedRows =
createTestTableData(3, 9);
List<Map<String,Object>> expectedRows =
createTestTableData(3, 9);

doTestSimple(table, cursor, expectedRows);
db.close();
doTestSimple(cursor, expectedRows);

db.close();
}
}
}
public void testMoveIndexSubRange() throws Exception {
for(int i = 0; i < 2; ++i) {
Database db = createTestIndexTable();
for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
for(int i = 0; i < 2; ++i) {
Database db = createTestIndexTable(indexCursorDB);

Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);

Cursor cursor = createIndexSubRangeCursor(table, idx, i);
Cursor cursor = createIndexSubRangeCursor(table, idx, i);

List<Map<String,Object>> expectedRows =
createTestTableData(3, 9);
List<Map<String,Object>> expectedRows =
createTestTableData(3, 9);

doTestMove(table, cursor, expectedRows);
db.close();
doTestMove(cursor, expectedRows);

db.close();
}
}
}
public void testSearchIndexSubRange() throws Exception {
for(int i = 0; i < 2; ++i) {
Database db = createTestIndexTable();
for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
for(int i = 0; i < 2; ++i) {
Database db = createTestIndexTable(indexCursorDB);

Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);

Cursor cursor = createIndexSubRangeCursor(table, idx, i);
Cursor cursor = createIndexSubRangeCursor(table, idx, i);

doTestSearch(table, cursor, idx, 2, 9);
db.close();
doTestSearch(table, cursor, idx, 2, 9);

db.close();
}
}
}

public void testReverseIndexSubRange() throws Exception {
for(int i = 0; i < 2; ++i) {
Database db = createTestIndexTable();
for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
for(int i = 0; i < 2; ++i) {
Database db = createTestIndexTable(indexCursorDB);

Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);

Cursor cursor = createIndexSubRangeCursor(table, idx, i);
Cursor cursor = createIndexSubRangeCursor(table, idx, i);

List<Map<String,Object>> expectedRows =
createTestTableData(3, 9);
List<Map<String,Object>> expectedRows =
createTestTableData(3, 9);

doTestReverse(table, cursor, expectedRows);
doTestReverse(cursor, expectedRows);

db.close();
db.close();
}
}
}

public void testLiveAdditionIndexSubRange() throws Exception {
for(int i = 0; i < 2; ++i) {
Database db = createTestIndexTable();
for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
for(int i = 0; i < 2; ++i) {
Database db = createTestIndexTable(indexCursorDB);

Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);

Cursor cursor1 = createIndexSubRangeCursor(table, idx, i);
Cursor cursor2 = createIndexSubRangeCursor(table, idx, i);
Cursor cursor1 = createIndexSubRangeCursor(table, idx, i);
Cursor cursor2 = createIndexSubRangeCursor(table, idx, i);

doTestLiveAddition(table, cursor1, cursor2, 8);
db.close();
doTestLiveAddition(table, cursor1, cursor2, 8);

db.close();
}
}
}
public void testLiveDeletionIndexSubRange() throws Exception {
for(int i = 0; i < 2; ++i) {
Database db = createTestIndexTable();
for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
for(int i = 0; i < 2; ++i) {
Database db = createTestIndexTable(indexCursorDB);

Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);

Cursor cursor1 = createIndexSubRangeCursor(table, idx, i);
Cursor cursor2 = createIndexSubRangeCursor(table, idx, i);
Cursor cursor3 = createIndexSubRangeCursor(table, idx, i);
Cursor cursor4 = createIndexSubRangeCursor(table, idx, i);
Cursor cursor1 = createIndexSubRangeCursor(table, idx, i);
Cursor cursor2 = createIndexSubRangeCursor(table, idx, i);
Cursor cursor3 = createIndexSubRangeCursor(table, idx, i);
Cursor cursor4 = createIndexSubRangeCursor(table, idx, i);

doTestLiveDeletion(table, cursor1, cursor2, cursor3, cursor4, 4);
doTestLiveDeletion(cursor1, cursor2, cursor3, cursor4, 4);

db.close();
}
db.close();
}
}
}

public void testId() throws Exception
{
Database db = createTestIndexTable();
for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
Database db = createTestIndexTable(indexCursorDB);

Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);
Table table = db.getTable("test");
Index idx = table.getIndexes().get(0);

Cursor tCursor = Cursor.createCursor(table);
Cursor iCursor = Cursor.createIndexCursor(table, idx);
Cursor tCursor = Cursor.createCursor(table);
Cursor iCursor = Cursor.createIndexCursor(table, idx);

Cursor.Savepoint tSave = tCursor.getSavepoint();
Cursor.Savepoint iSave = iCursor.getSavepoint();
Cursor.Savepoint tSave = tCursor.getSavepoint();
Cursor.Savepoint iSave = iCursor.getSavepoint();

tCursor.restoreSavepoint(tSave);
iCursor.restoreSavepoint(iSave);
tCursor.restoreSavepoint(tSave);
iCursor.restoreSavepoint(iSave);

try {
tCursor.restoreSavepoint(iSave);
fail("IllegalArgumentException should have been thrown");
} catch(IllegalArgumentException e) {
// success
}
try {
tCursor.restoreSavepoint(iSave);
fail("IllegalArgumentException should have been thrown");
} catch(IllegalArgumentException e) {
// success
}

try {
iCursor.restoreSavepoint(tSave);
fail("IllegalArgumentException should have been thrown");
} catch(IllegalArgumentException e) {
// success
}
try {
iCursor.restoreSavepoint(tSave);
fail("IllegalArgumentException should have been thrown");
} catch(IllegalArgumentException e) {
// success
}

Cursor tCursor2 = Cursor.createCursor(table);
Cursor iCursor2 = Cursor.createIndexCursor(table, idx);
Cursor tCursor2 = Cursor.createCursor(table);
Cursor iCursor2 = Cursor.createIndexCursor(table, idx);

tCursor2.restoreSavepoint(tSave);
iCursor2.restoreSavepoint(iSave);
tCursor2.restoreSavepoint(tSave);
iCursor2.restoreSavepoint(iSave);

db.close();
db.close();
}
}
}

+ 764
- 671
test/src/java/com/healthmarketscience/jackcess/DatabaseTest.java
File diff suppressed because it is too large
View File


+ 87
- 84
test/src/java/com/healthmarketscience/jackcess/ErrorHandlerTest.java View File

@@ -35,6 +35,7 @@ import java.util.List;

import junit.framework.TestCase;

import static com.healthmarketscience.jackcess.Database.*;
import static com.healthmarketscience.jackcess.DatabaseTest.*;

/**
@@ -49,94 +50,96 @@ public class ErrorHandlerTest extends TestCase

public void testErrorHandler() throws Exception
{
Database db = create();

Table table =
new TableBuilder("test")
.addColumn(new ColumnBuilder("col", DataType.TEXT).toColumn())
.addColumn(new ColumnBuilder("val", DataType.LONG).toColumn())
.toTable(db);

table.addRow("row1", 1);
table.addRow("row2", 2);
table.addRow("row3", 3);

assertTable(createExpectedTable(
createExpectedRow("col", "row1",
"val", 1),
createExpectedRow("col", "row2",
"val", 2),
createExpectedRow("col", "row3",
"val", 3)),
table);


replaceColumn(table, "val");

table.reset();
try {
table.getNextRow();
fail("IOException should have been thrown");
} catch(IOException e) {
// success
}
for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
Database db = create(fileFormat);

Table table =
new TableBuilder("test")
.addColumn(new ColumnBuilder("col", DataType.TEXT).toColumn())
.addColumn(new ColumnBuilder("val", DataType.LONG).toColumn())
.toTable(db);

table.addRow("row1", 1);
table.addRow("row2", 2);
table.addRow("row3", 3);

assertTable(createExpectedTable(
createExpectedRow("col", "row1",
"val", 1),
createExpectedRow("col", "row2",
"val", 2),
createExpectedRow("col", "row3",
"val", 3)),
table);


replaceColumn(table, "val");

table.reset();
try {
table.getNextRow();
fail("IOException should have been thrown");
} catch(IOException e) {
// success
}

table.reset();
table.setErrorHandler(new ReplacementErrorHandler());
assertTable(createExpectedTable(
createExpectedRow("col", "row1",
"val", null),
createExpectedRow("col", "row2",
"val", null),
createExpectedRow("col", "row3",
"val", null)),
table);
Cursor c1 = Cursor.createCursor(table);
Cursor c2 = Cursor.createCursor(table);
Cursor c3 = Cursor.createCursor(table);
c2.setErrorHandler(new DebugErrorHandler("#error"));
c3.setErrorHandler(Database.DEFAULT_ERROR_HANDLER);
assertCursor(createExpectedTable(
createExpectedRow("col", "row1",
"val", null),
createExpectedRow("col", "row2",
"val", null),
createExpectedRow("col", "row3",
"val", null)),
c1);
assertCursor(createExpectedTable(
createExpectedRow("col", "row1",
"val", "#error"),
createExpectedRow("col", "row2",
"val", "#error"),
createExpectedRow("col", "row3",
"val", "#error")),
c2);
try {
c3.getNextRow();
fail("IOException should have been thrown");
} catch(IOException e) {
// success
}
table.reset();
table.setErrorHandler(new ReplacementErrorHandler());
assertTable(createExpectedTable(
createExpectedRow("col", "row1",
"val", null),
createExpectedRow("col", "row2",
"val", null),
createExpectedRow("col", "row3",
"val", null)),
table);
Cursor c1 = Cursor.createCursor(table);
Cursor c2 = Cursor.createCursor(table);
Cursor c3 = Cursor.createCursor(table);
c2.setErrorHandler(new DebugErrorHandler("#error"));
c3.setErrorHandler(Database.DEFAULT_ERROR_HANDLER);
assertCursor(createExpectedTable(
createExpectedRow("col", "row1",
"val", null),
createExpectedRow("col", "row2",
"val", null),
createExpectedRow("col", "row3",
"val", null)),
c1);
assertCursor(createExpectedTable(
createExpectedRow("col", "row1",
"val", "#error"),
createExpectedRow("col", "row2",
"val", "#error"),
createExpectedRow("col", "row3",
"val", "#error")),
c2);
try {
c3.getNextRow();
fail("IOException should have been thrown");
} catch(IOException e) {
// success
}

table.setErrorHandler(null);
c1.setErrorHandler(null);
c1.reset();
try {
c1.getNextRow();
fail("IOException should have been thrown");
} catch(IOException e) {
// success
}
table.setErrorHandler(null);
c1.setErrorHandler(null);
c1.reset();
try {
c1.getNextRow();
fail("IOException should have been thrown");
} catch(IOException e) {
// success
}


db.close();
db.close();
}
}

@SuppressWarnings("unchecked")

+ 67
- 60
test/src/java/com/healthmarketscience/jackcess/ImportTest.java View File

@@ -39,6 +39,7 @@ import java.util.List;

import junit.framework.TestCase;

import static com.healthmarketscience.jackcess.Database.*;
import static com.healthmarketscience.jackcess.DatabaseTest.*;

/**
@@ -53,75 +54,81 @@ public class ImportTest extends TestCase

public void testImportFromFile() throws Exception
{
Database db = create();
db.importFile("test", new File("test/data/sample-input.tab"), "\\t");
for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
Database db = create(fileFormat);
db.importFile("test", new File("test/data/sample-input.tab"), "\\t");
}
}

public void testImportFromFileWithOnlyHeaders() throws Exception
{
Database db = create();
db.importFile("test", new File("test/data/sample-input-only-headers.tab"),
for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
Database db = create(fileFormat);
db.importFile("test", new File("test/data/sample-input-only-headers.tab"),
"\\t");
}
}

public void testCopySqlHeaders() throws Exception
{
TestResultSet rs = new TestResultSet();

rs.addColumn(Types.INTEGER, "col1");
rs.addColumn(Types.VARCHAR, "col2", 60, 0, 0);
rs.addColumn(Types.VARCHAR, "col3", 500, 0, 0);
rs.addColumn(Types.BINARY, "col4", 128, 0, 0);
rs.addColumn(Types.BINARY, "col5", 512, 0, 0);
rs.addColumn(Types.NUMERIC, "col6", 0, 7, 15);
rs.addColumn(Types.VARCHAR, "col7", Integer.MAX_VALUE, 0, 0);

Database db = create();
db.copyTable("Test1", (ResultSet)Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[]{ResultSet.class},
rs));

Table t = db.getTable("Test1");
List<Column> columns = t.getColumns();
assertEquals(7, columns.size());

Column c = columns.get(0);
assertEquals("col1", c.getName());
assertEquals(DataType.LONG, c.getType());

c = columns.get(1);
assertEquals("col2", c.getName());
assertEquals(DataType.TEXT, c.getType());
assertEquals(120, c.getLength());

c = columns.get(2);
assertEquals("col3", c.getName());
assertEquals(DataType.MEMO, c.getType());
assertEquals(0, c.getLength());

c = columns.get(3);
assertEquals("col4", c.getName());
assertEquals(DataType.BINARY, c.getType());
assertEquals(128, c.getLength());
c = columns.get(4);
assertEquals("col5", c.getName());
assertEquals(DataType.OLE, c.getType());
assertEquals(0, c.getLength());
c = columns.get(5);
assertEquals("col6", c.getName());
assertEquals(DataType.NUMERIC, c.getType());
assertEquals(17, c.getLength());
assertEquals(7, c.getScale());
assertEquals(15, c.getPrecision());
c = columns.get(6);
assertEquals("col7", c.getName());
assertEquals(DataType.MEMO, c.getType());
assertEquals(0, c.getLength());

for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {

TestResultSet rs = new TestResultSet();

rs.addColumn(Types.INTEGER, "col1");
rs.addColumn(Types.VARCHAR, "col2", 60, 0, 0);
rs.addColumn(Types.VARCHAR, "col3", 500, 0, 0);
rs.addColumn(Types.BINARY, "col4", 128, 0, 0);
rs.addColumn(Types.BINARY, "col5", 512, 0, 0);
rs.addColumn(Types.NUMERIC, "col6", 0, 7, 15);
rs.addColumn(Types.VARCHAR, "col7", Integer.MAX_VALUE, 0, 0);

Database db = create(fileFormat);
db.copyTable("Test1", (ResultSet)Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[]{ResultSet.class},
rs));

Table t = db.getTable("Test1");
List<Column> columns = t.getColumns();
assertEquals(7, columns.size());

Column c = columns.get(0);
assertEquals("col1", c.getName());
assertEquals(DataType.LONG, c.getType());

c = columns.get(1);
assertEquals("col2", c.getName());
assertEquals(DataType.TEXT, c.getType());
assertEquals(120, c.getLength());

c = columns.get(2);
assertEquals("col3", c.getName());
assertEquals(DataType.MEMO, c.getType());
assertEquals(0, c.getLength());

c = columns.get(3);
assertEquals("col4", c.getName());
assertEquals(DataType.BINARY, c.getType());
assertEquals(128, c.getLength());

c = columns.get(4);
assertEquals("col5", c.getName());
assertEquals(DataType.OLE, c.getType());
assertEquals(0, c.getLength());

c = columns.get(5);
assertEquals("col6", c.getName());
assertEquals(DataType.NUMERIC, c.getType());
assertEquals(17, c.getLength());
assertEquals(7, c.getScale());
assertEquals(15, c.getPrecision());

c = columns.get(6);
assertEquals("col7", c.getName());
assertEquals(DataType.MEMO, c.getType());
assertEquals(0, c.getLength());
}
}



+ 303
- 279
test/src/java/com/healthmarketscience/jackcess/IndexCodesTest.java View File

@@ -27,7 +27,6 @@ King of Prussia, PA 19406

package com.healthmarketscience.jackcess;

import java.io.File;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.Arrays;
@@ -40,6 +39,7 @@ import java.util.regex.Pattern;
import junit.framework.TestCase;

import static com.healthmarketscience.jackcess.DatabaseTest.*;
import static com.healthmarketscience.jackcess.JetFormatTest.*;


/**
@@ -66,19 +66,21 @@ public class IndexCodesTest extends TestCase {

public void testIndexCodes() throws Exception
{
Database db = open(new File("test/data/testIndexCodes.mdb"));
for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX_CODES)) {
Database db = open(testDB);

for(Table t : db) {
for(Index index : t.getIndexes()) {
// System.out.println("Checking " + t.getName() + "." + index.getName());
checkIndexEntries(t, index);
for(Table t : db) {
for(Index index : t.getIndexes()) {
// System.out.println("Checking " + t.getName() + "." + index.getName());
checkIndexEntries(testDB, t, index);
}
}

db.close();
}
db.close();
}

private static void checkIndexEntries(Table t, Index index) throws Exception
private static void checkIndexEntries(final TestDB testDB, Table t, Index index) throws Exception
{
// index.initialize();
// System.out.println("Ind " + index);
@@ -90,7 +92,7 @@ public class IndexCodesTest extends TestCase {
Cursor.Position curPos = cursor.getSavepoint().getCurrentPosition();
boolean success = false;
try {
findRow(t, index, row, curPos);
findRow(testDB, t, index, row, curPos);
success = true;
} finally {
if(!success) {
@@ -103,7 +105,7 @@ public class IndexCodesTest extends TestCase {
}
private static void findRow(Table t, Index index,
private static void findRow(final TestDB testDB, Table t, Index index,
Map<String,Object> expectedRow,
Cursor.Position expectedPos)
throws Exception
@@ -123,7 +125,7 @@ public class IndexCodesTest extends TestCase {
return;
}
}
fail("Could not find expected row " + expectedRow + " starting at " +
fail("testDB: " + testDB + ";\nCould not find expected row " + expectedRow + " starting at " +
entryToString(startPos));
}

@@ -140,120 +142,134 @@ public class IndexCodesTest extends TestCase {

public void x_testCreateIsoFile() throws Exception
{
Database db = create(true);
for (final Database.FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
Database db = create(fileFormat, true);

Table t = new TableBuilder("test")
.addColumn(new ColumnBuilder("row", DataType.TEXT).toColumn())
.addColumn(new ColumnBuilder("data", DataType.TEXT).toColumn())
.toTable(db);
for(int i = 0; i < 256; ++i) {
String str = "AA" + ((char)i) + "AA";
t.addRow("row" + i, str);
}
Table t = new TableBuilder("test")
.addColumn(new ColumnBuilder("row", DataType.TEXT).toColumn())
.addColumn(new ColumnBuilder("data", DataType.TEXT).toColumn())
.toTable(db);
for(int i = 0; i < 256; ++i) {
String str = "AA" + ((char)i) + "AA";
t.addRow("row" + i, str);
}

db.close();
db.close();
}
}

public void x_testCreateAltIsoFile() throws Exception
{
Database db = openCopy(new File("/tmp/test_ind.mdb"), true);

Table t = db.getTable("Table1");
for (final TestDB testDB : TestDB.getSupportedForBasename(null)) {
// @todo Bank test dbFiles and create new TestDB here.
//Database db = openCopy(new File("/tmp/test_ind.mdb"), true);
Database db = openCopy(testDB, true);

Table t = db.getTable("Table1");

for(int i = 0; i < 256; ++i) {
String str = "AA" + ((char)i) + "AA";
t.addRow("row" + i, str,
(byte)42 + i, (short)53 + i, 13 * i,
(6.7d / i), null, null, true);
}

for(int i = 0; i < 256; ++i) {
String str = "AA" + ((char)i) + "AA";
t.addRow("row" + i, str,
(byte)42 + i, (short)53 + i, 13 * i,
(6.7d / i), null, null, true);
db.close();
}
db.close();
}

public void x_testWriteAllCodesMdb() throws Exception
{
Database db = create(true);

// Table t = new TableBuilder("Table1")
// .addColumn(new ColumnBuilder("key", DataType.TEXT).toColumn())
// .addColumn(new ColumnBuilder("data", DataType.TEXT).toColumn())
// .toTable(db);

// for(int i = 0; i <= 0xFFFF; ++i) {
// // skip non-char chars
// char c = (char)i;
// if(Character.isHighSurrogate(c) || Character.isLowSurrogate(c)) {
// continue;
// }
// String key = toUnicodeStr(c);
// String str = "AA" + c + "AA";
// t.addRow(key, str);
// }

Table t = new TableBuilder("Table5")
.addColumn(new ColumnBuilder("name", DataType.TEXT).toColumn())
.addColumn(new ColumnBuilder("data", DataType.TEXT).toColumn())
.toTable(db);

char c = (char)0x3041; // crazy 7F 02 ... A0
char c2 = (char)0x30A2; // crazy 7F 02 ...
char c3 = (char)0x2045; // inat 27 ... 1C
char c4 = (char)0x3043; // crazy 7F 03 ... A0
char c5 = (char)0x3046; // crazy 7F 04 ...
char c6 = (char)0x30F6; // crazy 7F 0D ... A0
char c7 = (char)0x3099; // unprint 03
char c8 = (char)0x0041; // A
char c9 = (char)0x002D; // - (unprint)
char c10 = (char)0x20E1; // unprint F2
char c11 = (char)0x309A; // unprint 04
char c12 = (char)0x01C4; // (long extra)
char c13 = (char)0x005F; // _ (long inline)
char c14 = (char)0xFFFE; // removed

char[] cs = new char[]{c7, c8, c3, c12, c13, c14, c, c2, c9};
addCombos(t, 0, "", cs, 5);

// t = new TableBuilder("Table2")
// .addColumn(new ColumnBuilder("data", DataType.TEXT).toColumn())
// .toTable(db);
// writeChars(0x0000, t);

// t = new TableBuilder("Table3")
// .addColumn(new ColumnBuilder("data", DataType.TEXT).toColumn())
// .toTable(db);
// writeChars(0x0400, t);


db.close();
for (final Database.FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
Database db = create(fileFormat, true);

// Table t = new TableBuilder("Table1")
// .addColumn(new ColumnBuilder("key", DataType.TEXT).toColumn())
// .addColumn(new ColumnBuilder("data", DataType.TEXT).toColumn())
// .toTable(db);

// for(int i = 0; i <= 0xFFFF; ++i) {
// // skip non-char chars
// char c = (char)i;
// if(Character.isHighSurrogate(c) || Character.isLowSurrogate(c)) {
// continue;
// }
// String key = toUnicodeStr(c);
// String str = "AA" + c + "AA";
// t.addRow(key, str);
// }

Table t = new TableBuilder("Table5")
.addColumn(new ColumnBuilder("name", DataType.TEXT).toColumn())
.addColumn(new ColumnBuilder("data", DataType.TEXT).toColumn())
.toTable(db);

char c = (char)0x3041; // crazy 7F 02 ... A0
char c2 = (char)0x30A2; // crazy 7F 02 ...
char c3 = (char)0x2045; // inat 27 ... 1C
char c4 = (char)0x3043; // crazy 7F 03 ... A0
char c5 = (char)0x3046; // crazy 7F 04 ...
char c6 = (char)0x30F6; // crazy 7F 0D ... A0
char c7 = (char)0x3099; // unprint 03
char c8 = (char)0x0041; // A
char c9 = (char)0x002D; // - (unprint)
char c10 = (char)0x20E1; // unprint F2
char c11 = (char)0x309A; // unprint 04
char c12 = (char)0x01C4; // (long extra)
char c13 = (char)0x005F; // _ (long inline)
char c14 = (char)0xFFFE; // removed

char[] cs = new char[]{c7, c8, c3, c12, c13, c14, c, c2, c9};
addCombos(t, 0, "", cs, 5);

// t = new TableBuilder("Table2")
// .addColumn(new ColumnBuilder("data", DataType.TEXT).toColumn())
// .toTable(db);

// writeChars(0x0000, t);

// t = new TableBuilder("Table3")
// .addColumn(new ColumnBuilder("data", DataType.TEXT).toColumn())
// .toTable(db);

// writeChars(0x0400, t);


db.close();
}
}

public void x_testReadAllCodesMdb() throws Exception
{
// Database db = openCopy(new File("/data2/jackcess_test/testAllIndexCodes.mdb"));
// Database db = openCopy(new File("/data2/jackcess_test/testAllIndexCodes_orig.mdb"));
// Database db = openCopy(new File("/data2/jackcess_test/testSomeMoreCodes.mdb"));
Database db = openCopy(new File("/data2/jackcess_test/testStillMoreCodes.mdb"));
Table t = db.getTable("Table5");

Index ind = t.getIndexes().iterator().next();
ind.initialize();
System.out.println("Ind " + ind);
for (final TestDB testDB : TestDB.getSupportedForBasename(null)) {

// Database db = openCopy(new File("/data2/jackcess_test/testAllIndexCodes.mdb"));
// Database db = openCopy(new File("/data2/jackcess_test/testAllIndexCodes_orig.mdb"));
// Database db = openCopy(new File("/data2/jackcess_test/testSomeMoreCodes.mdb"));
// @todo Bank test dbFiles and create new TestDB here.
//Database db = openCopy(new File("/data2/jackcess_test/testStillMoreCodes.mdb"));
Database db = openCopy(testDB);

Table t = db.getTable("Table5");

Index ind = t.getIndexes().iterator().next();
ind.initialize();

System.out.println("Ind " + ind);

Cursor cursor = Cursor.createIndexCursor(t, ind);
while(cursor.moveToNextRow()) {
System.out.println("=======");
String entryStr =
entryToString(cursor.getSavepoint().getCurrentPosition());
System.out.println("Entry Bytes: " + entryStr);
System.out.println("Value: " + cursor.getCurrentRow() + "; " +
toUnicodeStr(cursor.getCurrentRow().get("data")));
}

Cursor cursor = Cursor.createIndexCursor(t, ind);
while(cursor.moveToNextRow()) {
System.out.println("=======");
String entryStr =
entryToString(cursor.getSavepoint().getCurrentPosition());
System.out.println("Entry Bytes: " + entryStr);
System.out.println("Value: " + cursor.getCurrentRow() + "; " +
toUnicodeStr(cursor.getCurrentRow().get("data")));
db.close();
}

db.close();
}

private int addCombos(Table t, int rowNum, String s, char[] cs, int len)
@@ -285,201 +301,209 @@ public class IndexCodesTest extends TestCase {

public void x_testReadIsoMdb() throws Exception
{
// Database db = open(new File("/tmp/test_ind.mdb"));
// Database db = open(new File("/tmp/test_ind2.mdb"));
Database db = open(new File("/tmp/test_ind3.mdb"));
// Database db = open(new File("/tmp/test_ind4.mdb"));

Table t = db.getTable("Table1");
Index index = t.getIndex("B");
index.initialize();
System.out.println("Ind " + index);
for (final TestDB testDB : TestDB.getSupportedForBasename(null)) {
// Database db = open(new File("/tmp/test_ind.mdb"));
// Database db = open(new File("/tmp/test_ind2.mdb"));
// @todo Bank test dbFiles and create new TestDB here.
//Database db = open(new File("/tmp/test_ind3.mdb"));
Database db = open(testDB);
// Database db = open(new File("/tmp/test_ind4.mdb"));

Table t = db.getTable("Table1");
Index index = t.getIndex("B");
index.initialize();
System.out.println("Ind " + index);

Cursor cursor = Cursor.createIndexCursor(t, index);
while(cursor.moveToNextRow()) {
System.out.println("=======");
System.out.println("Savepoint: " + cursor.getSavepoint());
System.out.println("Value: " + cursor.getCurrentRow());
}

Cursor cursor = Cursor.createIndexCursor(t, index);
while(cursor.moveToNextRow()) {
System.out.println("=======");
System.out.println("Savepoint: " + cursor.getSavepoint());
System.out.println("Value: " + cursor.getCurrentRow());
db.close();
}
db.close();
}
public void x_testReverseIsoMdb() throws Exception
{
Database db = open(new File("/data2/jackcess_test/testAllIndexCodes3.mdb"));

Table t = db.getTable("Table1");
Index index = t.getIndexes().iterator().next();
index.initialize();
System.out.println("Ind " + index);

Pattern inlinePat = Pattern.compile("7F 4A 4A (.*)4A 4A 01 00");
Pattern unprintPat = Pattern.compile("01 01 01 80 (.+) 06 (.+) 00");
Pattern unprint2Pat = Pattern.compile("4A 4A 4A 4A 01 02 (.+) 00");
Pattern inatPat = Pattern.compile("7F 4A 4A (.*)4A 4A 01 02 02 (.+) 00");
Pattern inat2Pat = Pattern.compile("7F 4A 4A (.*)4A 4A 01 (02 02 (.+))?01 01 (.*)FF 02 80 FF 80 00");

Map<Character,String[]> inlineCodes = new TreeMap<Character,String[]>();
Map<Character,String[]> unprintCodes = new TreeMap<Character,String[]>();
Map<Character,String[]> unprint2Codes = new TreeMap<Character,String[]>();
Map<Character,String[]> inatInlineCodes = new TreeMap<Character,String[]>();
Map<Character,String[]> inatExtraCodes = new TreeMap<Character,String[]>();
Map<Character,String[]> inat2Codes = new TreeMap<Character,String[]>();
Map<Character,String[]> inat2ExtraCodes = new TreeMap<Character,String[]>();
Map<Character,String[]> inat2CrazyCodes = new TreeMap<Character,String[]>();
Cursor cursor = Cursor.createIndexCursor(t, index);
while(cursor.moveToNextRow()) {
// System.out.println("=======");
// System.out.println("Savepoint: " + cursor.getSavepoint());
// System.out.println("Value: " + cursor.getCurrentRow());
Cursor.Savepoint savepoint = cursor.getSavepoint();
String entryStr = entryToString(savepoint.getCurrentPosition());
for (final TestDB testDB : TestDB.getSupportedForBasename(null)) {
// @todo Bank test dbFiles and create new TestDB here.
//Database db = open(new File("/data2/jackcess_test/testAllIndexCodes3.mdb"));
Database db = open(testDB);

Table t = db.getTable("Table1");
Index index = t.getIndexes().iterator().next();
index.initialize();
System.out.println("Ind " + index);

Pattern inlinePat = Pattern.compile("7F 4A 4A (.*)4A 4A 01 00");
Pattern unprintPat = Pattern.compile("01 01 01 80 (.+) 06 (.+) 00");
Pattern unprint2Pat = Pattern.compile("4A 4A 4A 4A 01 02 (.+) 00");
Pattern inatPat = Pattern.compile("7F 4A 4A (.*)4A 4A 01 02 02 (.+) 00");
Pattern inat2Pat = Pattern.compile("7F 4A 4A (.*)4A 4A 01 (02 02 (.+))?01 01 (.*)FF 02 80 FF 80 00");

Map<Character,String[]> inlineCodes = new TreeMap<Character,String[]>();
Map<Character,String[]> unprintCodes = new TreeMap<Character,String[]>();
Map<Character,String[]> unprint2Codes = new TreeMap<Character,String[]>();
Map<Character,String[]> inatInlineCodes = new TreeMap<Character,String[]>();
Map<Character,String[]> inatExtraCodes = new TreeMap<Character,String[]>();
Map<Character,String[]> inat2Codes = new TreeMap<Character,String[]>();
Map<Character,String[]> inat2ExtraCodes = new TreeMap<Character,String[]>();
Map<Character,String[]> inat2CrazyCodes = new TreeMap<Character,String[]>();


Cursor cursor = Cursor.createIndexCursor(t, index);
while(cursor.moveToNextRow()) {
// System.out.println("=======");
// System.out.println("Savepoint: " + cursor.getSavepoint());
// System.out.println("Value: " + cursor.getCurrentRow());
Cursor.Savepoint savepoint = cursor.getSavepoint();
String entryStr = entryToString(savepoint.getCurrentPosition());

Map<String,Object> row = cursor.getCurrentRow();
String value = (String)row.get("data");
String key = (String)row.get("key");
char c = value.charAt(2);
System.out.println("=======");
System.out.println("RowId: " +
savepoint.getCurrentPosition().getRowId());
System.out.println("Entry: " + entryStr);
// System.out.println("Row: " + row);
System.out.println("Value: (" + key + ")" + value);
System.out.println("Char: " + c + ", " + (int)c + ", " +
toUnicodeStr(c));

String type = null;
if(entryStr.endsWith("01 00")) {

// handle inline codes
type = "INLINE";
Matcher m = inlinePat.matcher(entryStr);
m.find();
handleInlineEntry(m.group(1), c, inlineCodes);

} else if(entryStr.contains("01 01 01 80")) {

// handle most unprintable codes
type = "UNPRINTABLE";
Matcher m = unprintPat.matcher(entryStr);
m.find();
handleUnprintableEntry(m.group(2), c, unprintCodes);

} else if(entryStr.contains("01 02 02") &&
!entryStr.contains("FF 02 80 FF 80")) {

// handle chars w/ symbols
type = "CHAR_WITH_SYMBOL";
Matcher m = inatPat.matcher(entryStr);
m.find();
handleInternationalEntry(m.group(1), m.group(2), c,
inatInlineCodes, inatExtraCodes);

} else if(entryStr.contains("4A 4A 4A 4A 01 02")) {

// handle chars w/ symbols
type = "UNPRINTABLE_2";
Matcher m = unprint2Pat.matcher(entryStr);
m.find();
handleUnprintable2Entry(m.group(1), c, unprint2Codes);

} else if(entryStr.contains("FF 02 80 FF 80")) {

type = "CRAZY_INAT";
Matcher m = inat2Pat.matcher(entryStr);
m.find();
handleInternational2Entry(m.group(1), m.group(3), m.group(4), c,
inat2Codes, inat2ExtraCodes,
inat2CrazyCodes);

Map<String,Object> row = cursor.getCurrentRow();
String value = (String)row.get("data");
String key = (String)row.get("key");
char c = value.charAt(2);
System.out.println("=======");
System.out.println("RowId: " +
savepoint.getCurrentPosition().getRowId());
System.out.println("Entry: " + entryStr);
// System.out.println("Row: " + row);
System.out.println("Value: (" + key + ")" + value);
System.out.println("Char: " + c + ", " + (int)c + ", " +
toUnicodeStr(c));

String type = null;
if(entryStr.endsWith("01 00")) {

// handle inline codes
type = "INLINE";
Matcher m = inlinePat.matcher(entryStr);
m.find();
handleInlineEntry(m.group(1), c, inlineCodes);

} else if(entryStr.contains("01 01 01 80")) {
// handle most unprintable codes
type = "UNPRINTABLE";
Matcher m = unprintPat.matcher(entryStr);
m.find();
handleUnprintableEntry(m.group(2), c, unprintCodes);

} else if(entryStr.contains("01 02 02") &&
!entryStr.contains("FF 02 80 FF 80")) {

// handle chars w/ symbols
type = "CHAR_WITH_SYMBOL";
Matcher m = inatPat.matcher(entryStr);
m.find();
handleInternationalEntry(m.group(1), m.group(2), c,
inatInlineCodes, inatExtraCodes);
} else if(entryStr.contains("4A 4A 4A 4A 01 02")) {

// handle chars w/ symbols
type = "UNPRINTABLE_2";
Matcher m = unprint2Pat.matcher(entryStr);
m.find();
handleUnprintable2Entry(m.group(1), c, unprint2Codes);
} else if(entryStr.contains("FF 02 80 FF 80")) {

type = "CRAZY_INAT";
Matcher m = inat2Pat.matcher(entryStr);
m.find();
handleInternational2Entry(m.group(1), m.group(3), m.group(4), c,
inat2Codes, inat2ExtraCodes,
inat2CrazyCodes);

} else {

throw new RuntimeException("unhandled " + entryStr);
}
System.out.println("Type: " + type);
}
} else {

System.out.println("\n***CODES");
for(int i = 0; i <= 0xFFFF; ++i) {
throw new RuntimeException("unhandled " + entryStr);
}

if(i == 256) {
System.out.println("\n***EXTENDED CODES");
System.out.println("Type: " + type);
}

// skip non-char chars
char c = (char)i;
if(Character.isHighSurrogate(c) || Character.isLowSurrogate(c)) {
continue;
}
System.out.println("\n***CODES");
for(int i = 0; i <= 0xFFFF; ++i) {

if(c == (char)0xFFFE) {
// this gets replaced with FFFD, treat it the same
c = (char)0xFFFD;
}
if(i == 256) {
System.out.println("\n***EXTENDED CODES");
}

Character cc = c;
String[] chars = inlineCodes.get(cc);
if(chars != null) {
if((chars.length == 1) && (chars[0].length() == 0)) {
System.out.println("X");
} else {
System.out.println("S" + toByteString(chars));
// skip non-char chars
char c = (char)i;
if(Character.isHighSurrogate(c) || Character.isLowSurrogate(c)) {
continue;
}
continue;
}

chars = inatInlineCodes.get(cc);
if(chars != null) {
String[] extra = inatExtraCodes.get(cc);
System.out.println("I" + toByteString(chars) + "," +
toByteString(extra));
continue;
}
chars = unprintCodes.get(cc);
if(chars != null) {
System.out.println("U" + toByteString(chars));
continue;
}
if(c == (char)0xFFFE) {
// this gets replaced with FFFD, treat it the same
c = (char)0xFFFD;
}

chars = unprint2Codes.get(cc);
if(chars != null) {
if(chars.length > 1) {
throw new RuntimeException("long unprint codes");
Character cc = c;
String[] chars = inlineCodes.get(cc);
if(chars != null) {
if((chars.length == 1) && (chars[0].length() == 0)) {
System.out.println("X");
} else {
System.out.println("S" + toByteString(chars));
}
continue;
}

chars = inatInlineCodes.get(cc);
if(chars != null) {
String[] extra = inatExtraCodes.get(cc);
System.out.println("I" + toByteString(chars) + "," +
toByteString(extra));
continue;
}

chars = unprintCodes.get(cc);
if(chars != null) {
System.out.println("U" + toByteString(chars));
continue;
}
int val = Integer.parseInt(chars[0], 16) - 2;
String valStr = ByteUtil.toHexString(new byte[]{(byte)val}).trim();
System.out.println("P" + valStr);
continue;
}

chars = inat2Codes.get(cc);
if(chars != null) {
String [] crazyCodes = inat2CrazyCodes.get(cc);
String crazyCode = "";
if(crazyCodes != null) {
if((crazyCodes.length != 1) || !"A0".equals(crazyCodes[0])) {
throw new RuntimeException("CC " + Arrays.asList(crazyCodes));
chars = unprint2Codes.get(cc);
if(chars != null) {
if(chars.length > 1) {
throw new RuntimeException("long unprint codes");
}
crazyCode = "1";
int val = Integer.parseInt(chars[0], 16) - 2;
String valStr = ByteUtil.toHexString(new byte[]{(byte)val}).trim();
System.out.println("P" + valStr);
continue;
}

String[] extra = inat2ExtraCodes.get(cc);
System.out.println("Z" + toByteString(chars) + "," +
toByteString(extra) + "," +
crazyCode);
continue;
chars = inat2Codes.get(cc);
if(chars != null) {
String [] crazyCodes = inat2CrazyCodes.get(cc);
String crazyCode = "";
if(crazyCodes != null) {
if((crazyCodes.length != 1) || !"A0".equals(crazyCodes[0])) {
throw new RuntimeException("CC " + Arrays.asList(crazyCodes));
}
crazyCode = "1";
}

String[] extra = inat2ExtraCodes.get(cc);
System.out.println("Z" + toByteString(chars) + "," +
toByteString(extra) + "," +
crazyCode);
continue;
}

throw new RuntimeException("Unhandled char " + toUnicodeStr(c));
}
System.out.println("\n***END CODES");

throw new RuntimeException("Unhandled char " + toUnicodeStr(c));
db.close();
}
System.out.println("\n***END CODES");
db.close();
}

private static String toByteString(String[] chars)

+ 206
- 186
test/src/java/com/healthmarketscience/jackcess/IndexTest.java View File

@@ -27,7 +27,6 @@ King of Prussia, PA 19406

package com.healthmarketscience.jackcess;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -40,6 +39,7 @@ import java.util.TreeSet;
import junit.framework.TestCase;

import static com.healthmarketscience.jackcess.DatabaseTest.*;
import static com.healthmarketscience.jackcess.JetFormatTest.*;

/**
* @author James Ahlborn
@@ -84,131 +84,140 @@ public class IndexTest extends TestCase {
}

public void testPrimaryKey() throws Exception {
Table table = open().getTable("Table1");
Map<String, Boolean> foundPKs = new HashMap<String, Boolean>();
for(Index index : table.getIndexes()) {
foundPKs.put(index.getColumns().iterator().next().getName(),
index.isPrimaryKey());
for (final TestDB testDB : SUPPORTED_DBS_TEST) {
Table table = open(testDB).getTable("Table1");
Map<String, Boolean> foundPKs = new HashMap<String, Boolean>();
for(Index index : table.getIndexes()) {
foundPKs.put(index.getColumns().iterator().next().getName(),
index.isPrimaryKey());
}
Map<String, Boolean> expectedPKs = new HashMap<String, Boolean>();
expectedPKs.put("A", Boolean.TRUE);
expectedPKs.put("B", Boolean.FALSE);
assertEquals(expectedPKs, foundPKs);
}
Map<String, Boolean> expectedPKs = new HashMap<String, Boolean>();
expectedPKs.put("A", Boolean.TRUE);
expectedPKs.put("B", Boolean.FALSE);
assertEquals(expectedPKs, foundPKs);
}
public void testIndexSlots() throws Exception
{
Database mdb = open(new File("test/data/indexTest.mdb"));

Table table = mdb.getTable("Table1");
for(Index idx : table.getIndexes()) {
idx.initialize();
}
assertEquals(4, table.getIndexes().size());
assertEquals(4, table.getIndexSlotCount());
checkIndexColumns(table,
"id", "id",
"PrimaryKey", "id",
"Table2Table1", "otherfk1",
"Table3Table1", "otherfk2");
table = mdb.getTable("Table2");
for(Index idx : table.getIndexes()) {
idx.initialize();
}
assertEquals(2, table.getIndexes().size());
assertEquals(3, table.getIndexSlotCount());
checkIndexColumns(table,
"id", "id",
"PrimaryKey", "id");
for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX)) {
Database mdb = open(testDB);

table = mdb.getTable("Table3");
for(Index idx : table.getIndexes()) {
idx.initialize();
Table table = mdb.getTable("Table1");
for(Index idx : table.getIndexes()) {
idx.initialize();
}
assertEquals(4, table.getIndexes().size());
assertEquals(4, table.getIndexSlotCount());
checkIndexColumns(table,
"id", "id",
"PrimaryKey", "id",
"Table2Table1", "otherfk1",
"Table3Table1", "otherfk2");

table = mdb.getTable("Table2");
for(Index idx : table.getIndexes()) {
idx.initialize();
}
assertEquals(2, table.getIndexes().size());
assertEquals(3, table.getIndexSlotCount());
checkIndexColumns(table,
"id", "id",
"PrimaryKey", "id");

table = mdb.getTable("Table3");
for(Index idx : table.getIndexes()) {
idx.initialize();
}
assertEquals(2, table.getIndexes().size());
assertEquals(3, table.getIndexSlotCount());
checkIndexColumns(table,
"id", "id",
"PrimaryKey", "id");
}
assertEquals(2, table.getIndexes().size());
assertEquals(3, table.getIndexSlotCount());
checkIndexColumns(table,
"id", "id",
"PrimaryKey", "id");
}

public void testComplexIndex() throws Exception
{
// this file has an index with "compressed" entries and node pages
File origFile = new File("test/data/compIndexTest.mdb");
Database db = open(origFile);
Table t = db.getTable("Table1");
Index index = t.getIndexes().get(0);
assertFalse(index.isInitialized());
assertEquals(512, countRows(t));
assertEquals(512, index.getEntryCount());
db.close();

// copy to temp file and attempt to edit
db = openCopy(origFile);
t = db.getTable("Table1");
index = t.getIndexes().get(0);

System.out.println("IndexTest: Index type: " + index.getClass());
try {
t.addRow(99, "abc", "def");
if(index instanceof SimpleIndex) {
// SimpleIndex doesn't support writing these indexes
fail("Should have thrown UnsupportedOperationException");
}
} catch(UnsupportedOperationException e) {
// success
if(index instanceof BigIndex) {
throw e;
for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.COMP_INDEX)) {
// this file has an index with "compressed" entries and node pages
Database db = open(testDB);
Table t = db.getTable("Table1");
Index index = t.getIndexes().get(0);
assertFalse(index.isInitialized());
assertEquals(512, countRows(t));
assertEquals(512, index.getEntryCount());
db.close();

// copy to temp file and attempt to edit
db = openCopy(testDB);
t = db.getTable("Table1");
index = t.getIndexes().get(0);

System.out.println("IndexTest: Index type: " + index.getClass());
try {
t.addRow(99, "abc", "def");
if(index instanceof SimpleIndex) {
// SimpleIndex doesn't support writing these indexes
fail("Should have thrown UnsupportedOperationException");
}
} catch(UnsupportedOperationException e) {
// success
if(index instanceof BigIndex) {
throw e;
}
}
}
}

public void testEntryDeletion() throws Exception {
Table table = openCopy(new File("test/data/test.mdb")).getTable("Table1");
for (final TestDB testDB : SUPPORTED_DBS_TEST) {
Table table = openCopy(testDB).getTable("Table1");

for(int i = 0; i < 10; ++i) {
table.addRow("foo" + i, "bar" + i, (byte)42 + i, (short)53 + i, 13 * i,
(6.7d / i), null, null, true);
}
table.reset();
assertRowCount(12, table);
for(int i = 0; i < 10; ++i) {
table.addRow("foo" + i, "bar" + i, (byte)42 + i, (short)53 + i, 13 * i,
(6.7d / i), null, null, true);
}
table.reset();
assertRowCount(12, table);

for(Index index : table.getIndexes()) {
assertEquals(12, index.getEntryCount());
}
for(Index index : table.getIndexes()) {
assertEquals(12, index.getEntryCount());
}

table.reset();
table.getNextRow();
table.getNextRow();
table.deleteCurrentRow();
table.getNextRow();
table.deleteCurrentRow();
table.getNextRow();
table.getNextRow();
table.deleteCurrentRow();
table.getNextRow();
table.getNextRow();
table.getNextRow();
table.deleteCurrentRow();

table.reset();
assertRowCount(8, table);

for(Index index : table.getIndexes()) {
assertEquals(8, index.getEntryCount());
table.reset();
table.getNextRow();
table.getNextRow();
table.deleteCurrentRow();
table.getNextRow();
table.deleteCurrentRow();
table.getNextRow();
table.getNextRow();
table.deleteCurrentRow();
table.getNextRow();
table.getNextRow();
table.getNextRow();
table.deleteCurrentRow();

table.reset();
assertRowCount(8, table);

for(Index index : table.getIndexes()) {
assertEquals(8, index.getEntryCount());
}
}
}

public void testIgnoreNulls() throws Exception
{
Database db = openCopy(new File("test/data/testIndexProperties.mdb"));
for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX_PROPERTIES)) {
Database db = openCopy(testDB);

doTestIgnoreNulls(db, "TableIgnoreNulls1");
doTestIgnoreNulls(db, "TableIgnoreNulls2");
doTestIgnoreNulls(db, "TableIgnoreNulls1");
doTestIgnoreNulls(db, "TableIgnoreNulls2");

db.close();
db.close();
}
}

private void doTestIgnoreNulls(Database db, String tableName)
@@ -250,41 +259,43 @@ public class IndexTest extends TestCase {

public void testUnique() throws Exception
{
Database db = openCopy(new File("test/data/testIndexProperties.mdb"));

Table t = db.getTable("TableUnique1_temp");
Index index = t.getIndex("DataIndex");

doTestUnique(t, index, 1,
null, true,
"unique data", true,
null, true,
"more", false,
"stuff", false,
"unique data", false);

t = db.getTable("TableUnique2_temp");
index = t.getIndex("DataIndex");

doTestUnique(t, index, 2,
null, null, true,
"unique data", 42, true,
"unique data", null, true,
null, null, true,
"some", 42, true,
"more unique data", 13, true,
null, -4242, true,
"another row", -3462, false,
null, 49, false,
"more", null, false,
"unique data", 42, false,
"unique data", null, false,
null, -4242, false);
db.close();
for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX_PROPERTIES)) {
Database db = openCopy(testDB);

Table t = db.getTable("TableUnique1_temp");
Index index = t.getIndex("DataIndex");

doTestUnique(index, 1,
null, true,
"unique data", true,
null, true,
"more", false,
"stuff", false,
"unique data", false);

t = db.getTable("TableUnique2_temp");
index = t.getIndex("DataIndex");

doTestUnique(index, 2,
null, null, true,
"unique data", 42, true,
"unique data", null, true,
null, null, true,
"some", 42, true,
"more unique data", 13, true,
null, -4242, true,
"another row", -3462, false,
null, 49, false,
"more", null, false,
"unique data", 42, false,
"unique data", null, false,
null, -4242, false);

db.close();
}
}

private void doTestUnique(Table t, Index index, int numValues,
private void doTestUnique(Index index, int numValues,
Object... testData)
throws Exception
{
@@ -312,70 +323,79 @@ public class IndexTest extends TestCase {
}

public void testUniqueEntryCount() throws Exception {
Database db = openCopy(new File("test/data/test.mdb"));
Table table = db.getTable("Table1");
Index indA = table.getIndex("PrimaryKey");
Index indB = table.getIndex("B");
for (final TestDB testDB : SUPPORTED_DBS_TEST) {
Database db = openCopy(testDB);
Table table = db.getTable("Table1");
Index indA = table.getIndex("PrimaryKey");
Index indB = table.getIndex("B");

assertEquals(2, indA.getUniqueEntryCount());
assertEquals(2, indB.getUniqueEntryCount());
assertEquals(2, indA.getUniqueEntryCount());
assertEquals(2, indB.getUniqueEntryCount());

List<String> bElems = Arrays.asList("bar", null, "baz", "argle", null,
"bazzle", "37", "bar", "bar", "BAZ");
for(int i = 0; i < 10; ++i) {
table.addRow("foo" + i, bElems.get(i), (byte)42 + i, (short)53 + i,
13 * i, (6.7d / i), null, null, true);
}
List<String> bElems = Arrays.asList("bar", null, "baz", "argle", null,
"bazzle", "37", "bar", "bar", "BAZ");

assertEquals(12, indA.getEntryCount());
assertEquals(12, indB.getEntryCount());
assertEquals(12, indA.getUniqueEntryCount());
assertEquals(8, indB.getUniqueEntryCount());
for(int i = 0; i < 10; ++i) {
table.addRow("foo" + i, bElems.get(i), (byte)42 + i, (short)53 + i,
13 * i, (6.7d / i), null, null, true);
}

table = null;
indA = null;
indB = null;
assertEquals(12, indA.getEntryCount());
assertEquals(12, indB.getEntryCount());

table = db.getTable("Table1");
indA = table.getIndex("PrimaryKey");
indB = table.getIndex("B");
assertEquals(12, indA.getEntryCount());
assertEquals(12, indB.getEntryCount());
assertEquals(12, indA.getUniqueEntryCount());
assertEquals(8, indB.getUniqueEntryCount());

Cursor c = Cursor.createCursor(table);
assertTrue(c.moveToNextRow());
Map<String,Object> row = c.getCurrentRow();
assertEquals("abcdefg", row.get("A"));
assertEquals("hijklmnop", row.get("B"));
c.deleteCurrentRow();

assertEquals(11, indA.getEntryCount());
assertEquals(11, indB.getEntryCount());
assertEquals(12, indA.getUniqueEntryCount());
assertEquals(8, indB.getUniqueEntryCount());
db.close();
assertEquals(12, indA.getUniqueEntryCount());
assertEquals(8, indB.getUniqueEntryCount());

table = null;
indA = null;
indB = null;

table = db.getTable("Table1");
indA = table.getIndex("PrimaryKey");
indB = table.getIndex("B");

assertEquals(12, indA.getEntryCount());
assertEquals(12, indB.getEntryCount());

assertEquals(12, indA.getUniqueEntryCount());
assertEquals(8, indB.getUniqueEntryCount());

Cursor c = Cursor.createCursor(table);
assertTrue(c.moveToNextRow());

final Map<String,Object> row = c.getCurrentRow();
// Row order is arbitrary, so v2007 row order difference is valid
if (Database.FileFormat.V2007.equals(testDB.getExpectedFileFormat())) {
DatabaseTest.checkTestDBTable1RowA(testDB, table, row);
} else {
DatabaseTest.checkTestDBTable1RowABCDEFG(testDB, table, row);
}
c.deleteCurrentRow();

assertEquals(11, indA.getEntryCount());
assertEquals(11, indB.getEntryCount());

assertEquals(12, indA.getUniqueEntryCount());
assertEquals(8, indB.getUniqueEntryCount());

db.close();
}
}
public void testReplId() throws Exception
{
Database db = openCopy(new File("test/data/test.mdb"));
Table table = db.getTable("Table4");
for (final TestDB testDB : SUPPORTED_DBS_TEST) {
Database db = openCopy(testDB);
Table table = db.getTable("Table4");

for(int i = 0; i< 20; ++i) {
table.addRow("row" + i, Column.AUTO_NUMBER);
}
for(int i = 0; i< 20; ++i) {
table.addRow("row" + i, Column.AUTO_NUMBER);
}

assertEquals(20, table.getRowCount());
db.close();
assertEquals(20, table.getRowCount());

db.close();
}
}
private void checkIndexColumns(Table table, String... idxInfo)

+ 134
- 0
test/src/java/com/healthmarketscience/jackcess/JetFormatTest.java View File

@@ -0,0 +1,134 @@
package com.healthmarketscience.jackcess;

import junit.framework.TestCase;

import java.io.File;
import java.io.IOException;
import java.nio.channels.FileChannel;

/**
* @author Dan Rollo
* Date: Mar 5, 2010
* Time: 12:44:21 PM
*/
public final class JetFormatTest extends TestCase {

private static final File DIR_TEST_DATA = new File("test/data");

/**
* Defines known valid db test file base names.
*/
public static enum Basename {

BIG_INDEX("bigIndexTest"),
COMP_INDEX("compIndexTest"),
DEL_COL("delColTest"),
DEL("delTest"),
FIXED_NUMERIC("fixedNumericTest"),
FIXED_TEXT("fixedTextTest"),
INDEX_CURSOR("indexCursorTest"),
INDEX("indexTest"),
OVERFLOW("overflowTest"),
QUERY("queryTest"),
TEST("test"),
TEST2("test2"),
INDEX_CODES("testIndexCodes"),
INDEX_PROPERTIES("testIndexProperties"),
PROMOTION("testPromotion"),
;

private final String basename;

Basename(final String fileBasename) {
basename = fileBasename;
}

}

/** Defines currently supported db file formats. */
final static Database.FileFormat[] SUPPORTED_FILEFORMATS = new Database.FileFormat[] {
Database.FileFormat.V2000,
Database.FileFormat.V2003,
Database.FileFormat.V2007,
// @todo Uncomment these elements to run test other formats
};

/**
* Defines known valid test database files, and their jet format version.
*/
public static final class TestDB {

private final File dbFile;
private final Database.FileFormat expectedFileFormat;

private TestDB(final File databaseFile, final Database.FileFormat expectedDBFileFormat) {

dbFile = databaseFile;
expectedFileFormat = expectedDBFileFormat;
}

public final File getFile() { return dbFile; }
public final Database.FileFormat getExpectedFileFormat() { return expectedFileFormat; }
public final JetFormat getExpectedFormat() { return expectedFileFormat.getJetFormat(); }

public final String toString() {
return "dbFile: " + dbFile.getAbsolutePath()
+ "; expectedFileFormat: " + expectedFileFormat;
}

public static TestDB[] getSupportedForBasename(final Basename basename) {

final TestDB[] supportedTestDBs = new TestDB[SUPPORTED_FILEFORMATS.length];
int i = 0;
for (final Database.FileFormat fileFormat: SUPPORTED_FILEFORMATS) {
supportedTestDBs[i++] = new TestDB(
getFileForBasename(basename, fileFormat),
fileFormat);
}
return supportedTestDBs;
}

private static File getFileForBasename(Basename basename, Database.FileFormat fileFormat) {

return new File(DIR_TEST_DATA,
fileFormat.name() + "/" + basename.basename + fileFormat.name() +
fileFormat.getFileExtension());
}
}

static final TestDB UNSUPPORTED_TEST_V1997 = new TestDB(
TestDB.getFileForBasename(Basename.TEST, Database.FileFormat.V1997), Database.FileFormat.V1997);

static final TestDB[] SUPPORTED_DBS_TEST= TestDB.getSupportedForBasename(Basename.TEST);


public void testGetFormat() throws Exception {
try {
JetFormat.getFormat(null);
fail("npe");
} catch (NullPointerException e) {
assertNull(e.getMessage());
}

checkJetFormat(UNSUPPORTED_TEST_V1997);

for (final TestDB testDB : SUPPORTED_DBS_TEST) {
checkJetFormat(testDB);
}
}

private static void checkJetFormat(final TestDB testDB)
throws IOException {

final FileChannel channel = Database.openChannel(testDB.dbFile, false);
try {

final JetFormat fmtActual = JetFormat.getFormat(channel);
assertEquals("Unexpected JetFormat for dbFile: " + testDB.dbFile.getAbsolutePath(),
testDB.expectedFileFormat.getJetFormat(), fmtActual);

} finally {
channel.close();
}
}
}

+ 45
- 44
test/src/java/com/healthmarketscience/jackcess/RelationshipTest.java View File

@@ -27,13 +27,13 @@ King of Prussia, PA 19406

package com.healthmarketscience.jackcess;

import java.io.File;
import java.util.Arrays;
import java.util.List;

import junit.framework.TestCase;

import static com.healthmarketscience.jackcess.DatabaseTest.*;
import static com.healthmarketscience.jackcess.JetFormatTest.*;

/**
* @author James Ahlborn
@@ -45,50 +45,51 @@ public class RelationshipTest extends TestCase {
}

public void testSimple() throws Exception {
Database db = open(new File("test/data/indexTest.mdb"));
Table t1 = db.getTable("Table1");
Table t2 = db.getTable("Table2");
Table t3 = db.getTable("Table3");

List<Relationship> rels = db.getRelationships(t1, t2);
assertEquals(1, rels.size());
Relationship rel = rels.get(0);
assertEquals("Table2Table1", rel.getName());
assertEquals(t2, rel.getFromTable());
assertEquals(Arrays.asList(t2.getColumn("id")),
rel.getFromColumns());
assertEquals(t1, rel.getToTable());
assertEquals(Arrays.asList(t1.getColumn("otherfk1")),
rel.getToColumns());
assertTrue(rel.hasReferentialIntegrity());
assertEquals(0, rel.getFlags());
assertSameRelationships(rels, db.getRelationships(t2, t1));
rels = db.getRelationships(t2, t3);
assertTrue(db.getRelationships(t2, t3).isEmpty());
assertSameRelationships(rels, db.getRelationships(t3, t2));
rels = db.getRelationships(t1, t3);
assertEquals(1, rels.size());
rel = rels.get(0);
assertEquals("Table3Table1", rel.getName());
assertEquals(t3, rel.getFromTable());
assertEquals(Arrays.asList(t3.getColumn("id")),
rel.getFromColumns());
assertEquals(t1, rel.getToTable());
assertEquals(Arrays.asList(t1.getColumn("otherfk2")),
rel.getToColumns());
assertTrue(rel.hasReferentialIntegrity());
assertEquals(0, rel.getFlags());
assertSameRelationships(rels, db.getRelationships(t3, t1));

try {
db.getRelationships(t1, t1);
fail("IllegalArgumentException should have been thrown");
} catch(IllegalArgumentException ignored) {
// success
for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX)) {
Database db = open(testDB);
Table t1 = db.getTable("Table1");
Table t2 = db.getTable("Table2");
Table t3 = db.getTable("Table3");

List<Relationship> rels = db.getRelationships(t1, t2);
assertEquals(1, rels.size());
Relationship rel = rels.get(0);
assertEquals("Table2Table1", rel.getName());
assertEquals(t2, rel.getFromTable());
assertEquals(Arrays.asList(t2.getColumn("id")),
rel.getFromColumns());
assertEquals(t1, rel.getToTable());
assertEquals(Arrays.asList(t1.getColumn("otherfk1")),
rel.getToColumns());
assertTrue(rel.hasReferentialIntegrity());
assertEquals(0, rel.getFlags());
assertSameRelationships(rels, db.getRelationships(t2, t1));

rels = db.getRelationships(t2, t3);
assertTrue(db.getRelationships(t2, t3).isEmpty());
assertSameRelationships(rels, db.getRelationships(t3, t2));

rels = db.getRelationships(t1, t3);
assertEquals(1, rels.size());
rel = rels.get(0);
assertEquals("Table3Table1", rel.getName());
assertEquals(t3, rel.getFromTable());
assertEquals(Arrays.asList(t3.getColumn("id")),
rel.getFromColumns());
assertEquals(t1, rel.getToTable());
assertEquals(Arrays.asList(t1.getColumn("otherfk2")),
rel.getToColumns());
assertTrue(rel.hasReferentialIntegrity());
assertEquals(0, rel.getFlags());
assertSameRelationships(rels, db.getRelationships(t3, t1));

try {
db.getRelationships(t1, t1);
fail("IllegalArgumentException should have been thrown");
} catch(IllegalArgumentException ignored) {
// success
}
}

}

private void assertSameRelationships(

+ 57
- 0
test/src/java/com/healthmarketscience/jackcess/UsageMapTest.java View File

@@ -0,0 +1,57 @@
package com.healthmarketscience.jackcess;

import junit.framework.TestCase;

import java.io.File;
import java.io.IOException;

import static com.healthmarketscience.jackcess.JetFormatTest.*;

/**
* @author Dan Rollo
* Date: Mar 5, 2010
* Time: 2:21:22 PM
*/
public final class UsageMapTest extends TestCase {

public void testRead() throws Exception {
try {
Database.open(UNSUPPORTED_TEST_V1997.getFile());
fail("mdb v97 usage map unsupported");
} catch (IOException e) {
assertEquals(UsageMap.MSG_PREFIX_UNRECOGNIZED_MAP + 2, e.getMessage());
}

for (final TestDB testDB : SUPPORTED_DBS_TEST) {
final int expectedFirstPage;
final int expectedLastPage;
final Database.FileFormat expectedFileFormat = testDB.getExpectedFileFormat();
if (Database.FileFormat.V2000.equals(expectedFileFormat)) {
expectedFirstPage = 743;
expectedLastPage = 767;
} else if (Database.FileFormat.V2003.equals(expectedFileFormat)) {
expectedFirstPage = 16;
expectedLastPage = 799;
} else if (Database.FileFormat.V2007.equals(expectedFileFormat)) {
expectedFirstPage = 42;
expectedLastPage = 511;
} else {
throw new IllegalAccessException("Unknown file format: " + expectedFileFormat);
}
checkUsageMapRead(testDB.getFile(), expectedFirstPage, expectedLastPage);
}
}

private static void checkUsageMapRead(final File dbFile,
final int expectedFirstPage, final int expectedLastPage)
throws IOException {

final Database db = Database.open(dbFile);
final UsageMap usageMap = UsageMap.read(db,
PageChannel.PAGE_GLOBAL_USAGE_MAP,
PageChannel.ROW_GLOBAL_USAGE_MAP,
true);
assertEquals("Unexpected FirstPageNumber.", expectedFirstPage, usageMap.getFirstPageNumber());
assertEquals("Unexpected LastPageNumber.", expectedLastPage, usageMap.getLastPageNumber());
}
}

+ 64
- 61
test/src/java/com/healthmarketscience/jackcess/query/QueryTest.java View File

@@ -27,7 +27,6 @@ King of Prussia, PA 19406

package com.healthmarketscience.jackcess.query;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -45,6 +44,8 @@ import org.apache.commons.lang.StringUtils;
import static org.apache.commons.lang.SystemUtils.LINE_SEPARATOR;
import static com.healthmarketscience.jackcess.query.QueryFormat.*;

import static com.healthmarketscience.jackcess.JetFormatTest.*;


/**
* @author James Ahlborn
@@ -199,68 +200,70 @@ public class QueryTest extends TestCase

public void testReadQueries() throws Exception
{
Map<String,String> expectedQueries = new HashMap<String,String>();
expectedQueries.put(
"SelectQuery", multiline(
"SELECT DISTINCT Table1.*, Table2.col1, Table2.col2, Table3.col3",
"FROM (Table1 LEFT JOIN Table3 ON Table1.col1 = Table3.col1) INNER JOIN Table2 ON (Table3.col1 = Table2.col1) AND (Table3.col1 = Table2.col2)",
"WHERE (((Table2.col2)=\"foo\" Or (Table2.col2) In (\"buzz\",\"bazz\")))",
"ORDER BY Table2.col1;"));
expectedQueries.put(
"DeleteQuery", multiline(
"DELETE Table1.col1, Table1.col2, Table1.col3",
"FROM Table1",
"WHERE (((Table1.col1)>\"blah\"));"));
expectedQueries.put(
"AppendQuery",multiline(
"INSERT INTO Table3",
"SELECT [Table1].[col2], [Table2].[col2], [Table2].[col3]",
"FROM Table3, Table1 INNER JOIN Table2 ON [Table1].[col1]=[Table2].[col1];"));
expectedQueries.put(
"UpdateQuery",multiline(
"PARAMETERS User Name Text;",
"UPDATE Table1",
"SET Table1.col1 = \"foo\", Table1.col2 = [Table2].[col3], [[Table2]].[[col1]] = [User Name]",
"WHERE ((([Table2].[col1]) Is Not Null));"));
expectedQueries.put(
"MakeTableQuery",multiline(
"SELECT Max(Table2.col1) AS MaxOfcol1, Table2.col2, Table3.col2 INTO Table4",
"FROM (Table2 INNER JOIN Table1 ON Table2.col1 = Table1.col2) RIGHT JOIN Table3 ON Table1.col2 = Table3.col3",
"GROUP BY Table2.col2, Table3.col2",
"HAVING (((Max(Table2.col1))=\"buzz\") AND ((Table2.col2)<>\"blah\"));"));
expectedQueries.put(
"CrosstabQuery", multiline(
"TRANSFORM Count([Table2].[col2]) AS CountOfcol2",
"SELECT Table2_1.col1, [Table2].[col3], Avg(Table2_1.col2) AS AvgOfcol2",
"FROM (Table1 INNER JOIN Table2 ON [Table1].[col1]=[Table2].[col1]) INNER JOIN Table2 AS Table2_1 ON [Table2].[col1]=Table2_1.col3",
"WHERE ((([Table1].[col1])>\"10\") And ((Table2_1.col1) Is Not Null) And ((Avg(Table2_1.col2))>\"10\"))",
"GROUP BY Table2_1.col1, [Table2].[col3]",
"ORDER BY [Table2].[col3]",
"PIVOT [Table1].[col1];"));
expectedQueries.put(
"UnionQuery", multiline(
"Select Table1.col1, Table1.col2",
"where Table1.col1 = \"foo\"",
"UNION",
"Select Table2.col1, Table2.col2",
"UNION ALL Select Table3.col1, Table3.col2",
"where Table3.col3 > \"blah\";"));
expectedQueries.put(
"PassthroughQuery", multiline(
"ALTER TABLE Table4 DROP COLUMN col5;\0"));
expectedQueries.put(
"DataDefinitionQuery", multiline(
"CREATE TABLE Table5 (col1 CHAR, col2 CHAR);\0"));

Database db = DatabaseTest.open(new File("test/data/queryTest.mdb"));

for(Query q : db.getQueries()) {
assertEquals(expectedQueries.remove(q.getName()), q.toSQLString());
}
for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.QUERY)) {
Map<String,String> expectedQueries = new HashMap<String,String>();
expectedQueries.put(
"SelectQuery", multiline(
"SELECT DISTINCT Table1.*, Table2.col1, Table2.col2, Table3.col3",
"FROM (Table1 LEFT JOIN Table3 ON Table1.col1 = Table3.col1) INNER JOIN Table2 ON (Table3.col1 = Table2.col1) AND (Table3.col1 = Table2.col2)",
"WHERE (((Table2.col2)=\"foo\" Or (Table2.col2) In (\"buzz\",\"bazz\")))",
"ORDER BY Table2.col1;"));
expectedQueries.put(
"DeleteQuery", multiline(
"DELETE Table1.col1, Table1.col2, Table1.col3",
"FROM Table1",
"WHERE (((Table1.col1)>\"blah\"));"));
expectedQueries.put(
"AppendQuery",multiline(
"INSERT INTO Table3",
"SELECT [Table1].[col2], [Table2].[col2], [Table2].[col3]",
"FROM Table3, Table1 INNER JOIN Table2 ON [Table1].[col1]=[Table2].[col1];"));
expectedQueries.put(
"UpdateQuery",multiline(
"PARAMETERS User Name Text;",
"UPDATE Table1",
"SET Table1.col1 = \"foo\", Table1.col2 = [Table2].[col3], [[Table2]].[[col1]] = [User Name]",
"WHERE ((([Table2].[col1]) Is Not Null));"));
expectedQueries.put(
"MakeTableQuery",multiline(
"SELECT Max(Table2.col1) AS MaxOfcol1, Table2.col2, Table3.col2 INTO Table4",
"FROM (Table2 INNER JOIN Table1 ON Table2.col1 = Table1.col2) RIGHT JOIN Table3 ON Table1.col2 = Table3.col3",
"GROUP BY Table2.col2, Table3.col2",
"HAVING (((Max(Table2.col1))=\"buzz\") AND ((Table2.col2)<>\"blah\"));"));
expectedQueries.put(
"CrosstabQuery", multiline(
"TRANSFORM Count([Table2].[col2]) AS CountOfcol2",
"SELECT Table2_1.col1, [Table2].[col3], Avg(Table2_1.col2) AS AvgOfcol2",
"FROM (Table1 INNER JOIN Table2 ON [Table1].[col1]=[Table2].[col1]) INNER JOIN Table2 AS Table2_1 ON [Table2].[col1]=Table2_1.col3",
"WHERE ((([Table1].[col1])>\"10\") And ((Table2_1.col1) Is Not Null) And ((Avg(Table2_1.col2))>\"10\"))",
"GROUP BY Table2_1.col1, [Table2].[col3]",
"ORDER BY [Table2].[col3]",
"PIVOT [Table1].[col1];"));
expectedQueries.put(
"UnionQuery", multiline(
"Select Table1.col1, Table1.col2",
"where Table1.col1 = \"foo\"",
"UNION",
"Select Table2.col1, Table2.col2",
"UNION ALL Select Table3.col1, Table3.col2",
"where Table3.col3 > \"blah\";"));
expectedQueries.put(
"PassthroughQuery", multiline(
"ALTER TABLE Table4 DROP COLUMN col5;\0"));
expectedQueries.put(
"DataDefinitionQuery", multiline(
"CREATE TABLE Table5 (col1 CHAR, col2 CHAR);\0"));

Database db = DatabaseTest.open(testDB);

for(Query q : db.getQueries()) {
assertEquals(expectedQueries.remove(q.getName()), q.toSQLString());
}

assertTrue(expectedQueries.isEmpty());
assertTrue(expectedQueries.isEmpty());

db.close();
db.close();
}
}

private void doTestColumns(SelectQuery query) throws Exception

Loading…
Cancel
Save