瀏覽代碼

Ignore column validators for read-only dbs. This will avoid irrelevant failures when reading databases which have invalid column properties. Fixes #150

git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@1240 f203690c-595d-4dc9-a70b-905162fa7fd2
tags/jackcess-2.2.1
James Ahlborn 5 年之前
父節點
當前提交
112cb827e9

+ 5
- 0
NOTICE.txt 查看文件

Many of the financial functions have been originally copied from the Apache
POI project (Apache Software Foundation) and the UCanAccess Project. They
have been then modified and adapted so that they are integrated with Jackcess,
in a consistent manner. The Apache POI and UCanAccess projects are licensed
under Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.

+ 20
- 2
src/changes/changes.xml 查看文件

<body> <body>
<release version="2.2.1" date="TBD"> <release version="2.2.1" date="TBD">
<action dev="jahlborn" type="update"> <action dev="jahlborn" type="update">
Implement IsNumeric function. Add support for hex/oct integer
strings.
Implement the majority of the missing standard functions:
FormatCurrency, FormatDateTime, FormatNumber, FormatPercent, Val,
DateAdd, DateDiff, DatePart, MonthName, WeekdayName, DDB, IPmt, PPmt,
Rate, SLN, SYD, Format, Replace, StrConv. (Note that the internal API
for the expr package has changed in an incompatible way. However,
since the API is still experimental, this was deemed acceptable for a
minor version.). Note that many of the financial functions were
copied and adpated from the Apache POI and UCanAccess projects (which
are both under the Apache License 2.0).
</action>
<action dev="jahlborn" type="update">
Implement more type coercion methods for expressions. Add support for
hex/oct integer strings. Add support for number strings with commas.
Add support for coercing numeric String to a date/time value. Add
support for date/time values with implicit (current) year.
</action>
<action dev="jahlborn" type="fix" system="SourceForge2" issue="150">
Ignore column validators for read-only dbs. This will avoid
irrelevant failures when reading databases which have invalid column
properties.
</action> </action>
</release> </release>
<release version="2.2.0" date="2018-09-08" <release version="2.2.0" date="2018-09-08"

+ 1
- 1
src/main/java/com/healthmarketscience/jackcess/expr/package-info.java 查看文件

* *
* <table border="1" width="25%" cellpadding="3" cellspacing="0"> * <table border="1" width="25%" cellpadding="3" cellspacing="0">
* <tr class="TableHeadingColor" align="left"><th>Function</th><th>Supported</th></tr> * <tr class="TableHeadingColor" align="left"><th>Function</th><th>Supported</th></tr>
* <tr class="TableRowColor"><td>Format[$]</td><td></td></tr>
* <tr class="TableRowColor"><td>Format[$]</td><td>Partial</td></tr>
* <tr class="TableRowColor"><td>InStr</td><td>Y</td></tr> * <tr class="TableRowColor"><td>InStr</td><td>Y</td></tr>
* <tr class="TableRowColor"><td>InStrRev</td><td>Y</td></tr> * <tr class="TableRowColor"><td>InStrRev</td><td>Y</td></tr>
* <tr class="TableRowColor"><td>LCase[$]</td><td>Y</td></tr> * <tr class="TableRowColor"><td>LCase[$]</td><td>Y</td></tr>

+ 6
- 0
src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java 查看文件

} }


void initColumnValidator() throws IOException { void initColumnValidator() throws IOException {

if(getDatabase().isReadOnly()) {
// validators are irrelevant for read-only databases
return;
}

// first initialize any "external" (user-defined) validator // first initialize any "external" (user-defined) validator
setColumnValidator(null); setColumnValidator(null);



+ 13
- 3
src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java 查看文件

private final File _file; private final File _file;
/** the simple name of the database */ /** the simple name of the database */
private final String _name; private final String _name;
/** whether or not this db is read-only */
private final boolean _readOnly;
/** Buffer to hold database pages */ /** Buffer to hold database pages */
private ByteBuffer _buffer; private ByteBuffer _buffer;
/** ID of the Tables system object */ /** ID of the Tables system object */
} }


DatabaseImpl db = new DatabaseImpl(mdbFile, channel, closeChannel, autoSync, DatabaseImpl db = new DatabaseImpl(mdbFile, channel, closeChannel, autoSync,
null, charset, timeZone, provider);
null, charset, timeZone, provider,
readOnly);
success = true; success = true;
return db; return db;


transferDbFrom(channel, getResourceAsStream(details.getEmptyFilePath())); transferDbFrom(channel, getResourceAsStream(details.getEmptyFilePath()));
channel.force(true); channel.force(true);
DatabaseImpl db = new DatabaseImpl(mdbFile, channel, closeChannel, autoSync, DatabaseImpl db = new DatabaseImpl(mdbFile, channel, closeChannel, autoSync,
fileFormat, charset, timeZone, null);
fileFormat, charset, timeZone, null,
false);
success = true; success = true;
return db; return db;
} finally { } finally {
*/ */
protected DatabaseImpl(File file, FileChannel channel, boolean closeChannel, protected DatabaseImpl(File file, FileChannel channel, boolean closeChannel,
boolean autoSync, FileFormat fileFormat, Charset charset, boolean autoSync, FileFormat fileFormat, Charset charset,
TimeZone timeZone, CodecProvider provider)
TimeZone timeZone, CodecProvider provider,
boolean readOnly)
throws IOException throws IOException
{ {
_file = file; _file = file;
_name = getName(file); _name = getName(file);
_readOnly = readOnly;
_format = JetFormat.getFormat(channel); _format = JetFormat.getFormat(channel);
_charset = ((charset == null) ? getDefaultCharset(_format) : charset); _charset = ((charset == null) ? getDefaultCharset(_format) : charset);
_columnOrder = getDefaultColumnOrder(); _columnOrder = getDefaultColumnOrder();
return _name; return _name;
} }


public boolean isReadOnly() {
return _readOnly;
}

/** /**
* @usage _advanced_method_ * @usage _advanced_method_
*/ */

+ 4
- 4
src/main/java/com/healthmarketscience/jackcess/impl/expr/DefaultTextFunctions.java 查看文件

} }
}); });


public static final Function FORMAT = registerFunc(new FuncVar("Format", 1, 4) {
public static final Function FORMAT = registerStringFunc(new FuncVar("Format", 1, 4) {
@Override @Override
protected Value evalVar(EvalContext ctx, Value[] params) { protected Value evalVar(EvalContext ctx, Value[] params) {


String fmtStr = params[1].getAsString(ctx); String fmtStr = params[1].getAsString(ctx);
int firstDay = DefaultDateFunctions.getFirstDayParam(ctx, params, 2); int firstDay = DefaultDateFunctions.getFirstDayParam(ctx, params, 2);
int firstWeekType = DefaultDateFunctions.getFirstWeekTypeParam(ctx, params, 3); int firstWeekType = DefaultDateFunctions.getFirstWeekTypeParam(ctx, params, 3);
return FormatUtil.format(ctx, expr, fmtStr, firstDay, firstWeekType); return FormatUtil.format(ctx, expr, fmtStr, firstDay, firstWeekType);
} }
}); });
private static String nchars(int num, char c) { private static String nchars(int num, char c) {
StringBuilder sb = new StringBuilder(num); StringBuilder sb = new StringBuilder(num);
nchars(sb, num, c); nchars(sb, num, c);
sb.append(c); sb.append(c);
} }
} }
private static String trim(String str, boolean doLeft, boolean doRight) { private static String trim(String str, boolean doLeft, boolean doRight) {
int start = 0; int start = 0;
int end = str.length(); int end = str.length();

+ 22
- 17
src/main/java/com/healthmarketscience/jackcess/util/CustomLinkResolver.java 查看文件

* <pre> * <pre>
* // attempt to load the linkeeFileName as a custom file * // attempt to load the linkeeFileName as a custom file
* Object customFile = loadCustomFile(linkerDb, linkeeFileName); * Object customFile = loadCustomFile(linkerDb, linkeeFileName);
*
*
* if(customFile != null) { * if(customFile != null) {
* // this is a custom file, create and return relevant temp db * // this is a custom file, create and return relevant temp db
* return createTempDb(customFile, getDefaultFormat(), isDefaultInMemory(), * return createTempDb(customFile, getDefaultFormat(), isDefaultInMemory(),
* getDefaultTempDirectory()); * getDefaultTempDirectory());
* } * }
*
*
* // not a custmom file, load using the default behavior * // not a custmom file, load using the default behavior
* return LinkResolver.DEFAULT.resolveLinkedDatabase(linkerDb, linkeeFileName); * return LinkResolver.DEFAULT.resolveLinkedDatabase(linkerDb, linkeeFileName);
* </pre> * </pre>
*
*
* @see #loadCustomFile * @see #loadCustomFile
* @see #createTempDb * @see #createTempDb
* @see LinkResolver#DEFAULT * @see LinkResolver#DEFAULT
*/ */
public Database resolveLinkedDatabase(Database linkerDb, String linkeeFileName) public Database resolveLinkedDatabase(Database linkerDb, String linkeeFileName)
throws IOException
throws IOException
{ {
Object customFile = loadCustomFile(linkerDb, linkeeFileName); Object customFile = loadCustomFile(linkerDb, linkeeFileName);
if(customFile != null) { if(customFile != null) {
return createTempDb(customFile, getDefaultFormat(), isDefaultInMemory(),
getDefaultTempDirectory());
// if linker is read-only, open linkee read-only
boolean readOnly = ((linkerDb instanceof DatabaseImpl) ?
((DatabaseImpl)linkerDb).isReadOnly() : false);
return createTempDb(customFile, getDefaultFormat(), isDefaultInMemory(),
getDefaultTempDirectory(), readOnly);
} }
return LinkResolver.DEFAULT.resolveLinkedDatabase(linkerDb, linkeeFileName); return LinkResolver.DEFAULT.resolveLinkedDatabase(linkerDb, linkeeFileName);
} }
* *
* @return the temp db for holding the linked table info * @return the temp db for holding the linked table info
*/ */
protected Database createTempDb(Object customFile, FileFormat format,
boolean inMemory, File tempDir)
protected Database createTempDb(Object customFile, FileFormat format,
boolean inMemory, File tempDir,
boolean readOnly)
throws IOException throws IOException
{ {
File dbFile = null; File dbFile = null;
} }


TempDatabaseImpl.initDbChannel(channel, format); TempDatabaseImpl.initDbChannel(channel, format);
TempDatabaseImpl db = new TempDatabaseImpl(this, customFile, dbFile,
channel, format);
TempDatabaseImpl db = new TempDatabaseImpl(this, customFile, dbFile,
channel, format, readOnly);
success = true; success = true;
return db; return db;


ByteUtil.closeQuietly((Closeable)customFile); ByteUtil.closeQuietly((Closeable)customFile);
} }
} }
/** /**
* Called by {@link #resolveLinkedDatabase} to determine whether the * Called by {@link #resolveLinkedDatabase} to determine whether the
* linkeeFileName should be treated as a custom file (thus utiliziing a temp * linkeeFileName should be treated as a custom file (thus utiliziing a temp
private final Object _customFile; private final Object _customFile;


protected TempDatabaseImpl(CustomLinkResolver resolver, Object customFile, protected TempDatabaseImpl(CustomLinkResolver resolver, Object customFile,
File file, FileChannel channel,
FileFormat fileFormat)
File file, FileChannel channel,
FileFormat fileFormat, boolean readOnly)
throws IOException throws IOException
{ {
super(file, channel, true, false, fileFormat, null, null, null);
super(file, channel, true, false, fileFormat, null, null, null,
readOnly);
_resolver = resolver; _resolver = resolver;
_customFile = customFile; _customFile = customFile;
} }


@Override @Override
protected TableImpl getTable(String name, boolean includeSystemTables)
throws IOException
protected TableImpl getTable(String name, boolean includeSystemTables)
throws IOException
{ {
TableImpl table = super.getTable(name, includeSystemTables); TableImpl table = super.getTable(name, includeSystemTables);
if((table == null) &&
if((table == null) &&
_resolver.loadCustomTable(this, _customFile, name)) { _resolver.loadCustomTable(this, _customFile, name)) {
table = super.getTable(name, includeSystemTables); table = super.getTable(name, includeSystemTables);
} }

+ 7
- 2
src/main/java/com/healthmarketscience/jackcess/util/LinkResolver.java 查看文件



import com.healthmarketscience.jackcess.Database; import com.healthmarketscience.jackcess.Database;
import com.healthmarketscience.jackcess.DatabaseBuilder; import com.healthmarketscience.jackcess.DatabaseBuilder;
import com.healthmarketscience.jackcess.impl.DatabaseImpl;


/** /**
* Resolver for linked databases. * Resolver for linked databases.
* @author James Ahlborn * @author James Ahlborn
* @usage _intermediate_class_ * @usage _intermediate_class_
*/ */
public interface LinkResolver
public interface LinkResolver
{ {
/** /**
* default link resolver used if none provided * default link resolver used if none provided
String linkeeFileName) String linkeeFileName)
throws IOException throws IOException
{ {
return DatabaseBuilder.open(new File(linkeeFileName));
// if linker is read-only, open linkee read-only
boolean readOnly = ((linkerDb instanceof DatabaseImpl) ?
((DatabaseImpl)linkerDb).isReadOnly() : false);
return new DatabaseBuilder(new File(linkeeFileName))
.setReadOnly(readOnly).open();
} }
}; };



+ 8
- 6
src/test/java/com/healthmarketscience/jackcess/util/CustomLinkResolverTest.java 查看文件

Table t1 = db.getTable("Table1"); Table t1 = db.getTable("Table1");
assertNotNull(t1); assertNotNull(t1);
assertNotSame(db, t1.getDatabase()); assertNotSame(db, t1.getDatabase());
assertTable(createExpectedTable(createExpectedRow("id", 0, assertTable(createExpectedTable(createExpectedRow("id", 0,
"data1", "row0"), "data1", "row0"),
createExpectedRow("id", 1, createExpectedRow("id", 1,
Database linkerDb, String linkeeFileName) throws IOException Database linkerDb, String linkeeFileName) throws IOException
{ {
return (("testFile1.txt".equals(linkeeFileName) || return (("testFile1.txt".equals(linkeeFileName) ||
"testFile2.txt".equals(linkeeFileName)) ?
"testFile2.txt".equals(linkeeFileName)) ?
linkeeFileName : null); linkeeFileName : null);
} }


for(int i = 0; i < 3; ++i) { for(int i = 0; i < 3; ++i) {
t.addRow(i, "row" + i); t.addRow(i, "row" + i);
} }
return true; return true;


} else if("OtherTable2".equals(tableName)) { } else if("OtherTable2".equals(tableName)) {
for(int i = 3; i < 6; ++i) { for(int i = 3; i < 6; ++i) {
t.addRow(i, "row" + i); t.addRow(i, "row" + i);
} }
return true; return true;


} else if("Table4".equals(tableName)) { } else if("Table4".equals(tableName)) {


@Override @Override
protected Database createTempDb(Object customFile, FileFormat format, protected Database createTempDb(Object customFile, FileFormat format,
boolean inMemory, File tempDir)
boolean inMemory, File tempDir,
boolean readOnly)
throws IOException throws IOException
{ {
inMemory = "testFile1.txt".equals(customFile); inMemory = "testFile1.txt".equals(customFile);
return super.createTempDb(customFile, format, inMemory, tempDir);
return super.createTempDb(customFile, format, inMemory, tempDir,
readOnly);
} }
} }
} }

Loading…
取消
儲存