git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@1356 f203690c-595d-4dc9-a70b-905162fa7fd2tags/jackcess-4.0.0
@@ -9,7 +9,7 @@ | |||
<artifactId>jackcess</artifactId> | |||
<name>Jackcess</name> | |||
<description>A pure Java library for reading from and writing to MS Access databases.</description> | |||
<version>3.5.2-SNAPSHOT</version> | |||
<version>4.0.0-SNAPSHOT</version> | |||
<url>https://jackcess.sourceforge.io</url> | |||
<inceptionYear>2005</inceptionYear> | |||
<developers> | |||
@@ -142,6 +142,7 @@ | |||
<extensions>true</extensions> | |||
<configuration> | |||
<instructions> | |||
<Automatic-Module-Name>com.healthmarketscience.jackcess</Automatic-Module-Name> | |||
</instructions> | |||
</configuration> | |||
<executions> |
@@ -4,6 +4,21 @@ | |||
<author email="javajedi@users.sf.net">Tim McCune</author> | |||
</properties> | |||
<body> | |||
<release version="4.0.0" date="TBD"> | |||
<action dev="jahlborn" type="update"> | |||
Add Automatic-Module-Name in order to make Jackcess safe to use in the | |||
module path in Java 9+ environments. | |||
</action> | |||
<action dev="jahlborn" type="update"> | |||
Make a few classes and constants public in order to facilitate use in | |||
different packages. | |||
</action> | |||
<action dev="jahlborn" type="update"> | |||
Alter access to java.sql classes so that usage is dependent on whether | |||
or not the module is loaded in Java 9+ environments. Tweak a few | |||
methods to no longer throw SQLException. | |||
</action> | |||
</release> | |||
<release version="3.5.1" date="2020-09-10"> | |||
<action dev="jahlborn" type="update"> | |||
Add more static utility methods to DatabaseBuilder to enable more |
@@ -17,7 +17,6 @@ limitations under the License. | |||
package com.healthmarketscience.jackcess; | |||
import java.io.IOException; | |||
import java.sql.SQLException; | |||
import java.util.Map; | |||
import com.healthmarketscience.jackcess.complex.ComplexColumnInfo; | |||
@@ -34,7 +33,7 @@ import com.healthmarketscience.jackcess.util.ColumnValidator; | |||
* @author James Ahlborn | |||
* @usage _general_class_ | |||
*/ | |||
public interface Column | |||
public interface Column | |||
{ | |||
/** | |||
* Meaningless placeholder object for inserting values in an autonumber | |||
@@ -43,14 +42,14 @@ public interface Column | |||
* @usage _general_field_ | |||
*/ | |||
public static final Object AUTO_NUMBER = "<AUTO_NUMBER>"; | |||
/** | |||
* Meaningless placeholder object for updating rows which indicates that a | |||
* given column should keep its existing value. | |||
* @usage _general_field_ | |||
*/ | |||
public static final Object KEEP_VALUE = "<KEEP_VALUE>"; | |||
/** | |||
* @usage _general_method_ | |||
*/ | |||
@@ -89,7 +88,7 @@ public interface Column | |||
/** | |||
* @usage _general_method_ | |||
*/ | |||
public int getSQLType() throws SQLException; | |||
public int getSQLType() throws IOException; | |||
/** | |||
* @usage _general_method_ | |||
@@ -149,7 +148,7 @@ public interface Column | |||
* @usage _general_method_ | |||
*/ | |||
public PropertyMap getProperties() throws IOException; | |||
/** | |||
* Returns the column which tracks the version history for an "append only" | |||
* column. | |||
@@ -162,7 +161,7 @@ public interface Column | |||
* @usage _intermediate_method_ | |||
*/ | |||
public ColumnValidator getColumnValidator(); | |||
/** | |||
* Sets a new ColumnValidator. If {@code null}, resets to the value | |||
* returned from the Database's ColumnValidatorFactory (if the factory | |||
@@ -173,12 +172,12 @@ public interface Column | |||
* @usage _intermediate_method_ | |||
*/ | |||
public void setColumnValidator(ColumnValidator newValidator); | |||
public Object setRowValue(Object[] rowArray, Object value); | |||
public Object setRowValue(Map<String,Object> rowMap, Object value); | |||
public Object getRowValue(Object[] rowArray); | |||
public Object getRowValue(Map<String,?> rowMap); | |||
} |
@@ -17,7 +17,6 @@ limitations under the License. | |||
package com.healthmarketscience.jackcess; | |||
import java.io.IOException; | |||
import java.sql.SQLException; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
@@ -93,7 +92,7 @@ public class ColumnBuilder { | |||
/** | |||
* Sets the type for the new column based on the given SQL type. | |||
*/ | |||
public ColumnBuilder setSQLType(int type) throws SQLException { | |||
public ColumnBuilder setSQLType(int type) throws IOException { | |||
return setSQLType(type, 0, null); | |||
} | |||
@@ -102,7 +101,7 @@ public class ColumnBuilder { | |||
* data length (in type specific units). | |||
*/ | |||
public ColumnBuilder setSQLType(int type, int lengthInUnits) | |||
throws SQLException | |||
throws IOException | |||
{ | |||
return setSQLType(type, lengthInUnits, null); | |||
} | |||
@@ -113,7 +112,7 @@ public class ColumnBuilder { | |||
*/ | |||
public ColumnBuilder setSQLType(int type, int lengthInUnits, | |||
Database.FileFormat fileFormat) | |||
throws SQLException | |||
throws IOException | |||
{ | |||
return setType(DataType.fromSQLType(type, lengthInUnits, fileFormat)); | |||
} |
@@ -19,7 +19,6 @@ package com.healthmarketscience.jackcess; | |||
import java.io.IOException; | |||
import java.math.BigDecimal; | |||
import java.math.BigInteger; | |||
import java.sql.SQLException; | |||
import java.sql.Types; | |||
import java.util.Date; | |||
import java.util.HashMap; | |||
@@ -28,6 +27,7 @@ import java.time.LocalDateTime; | |||
import com.healthmarketscience.jackcess.impl.DatabaseImpl; | |||
import com.healthmarketscience.jackcess.impl.JetFormat; | |||
import com.healthmarketscience.jackcess.impl.SqlHelper; | |||
/** | |||
* Supported access data types. | |||
@@ -356,11 +356,11 @@ public enum DataType { | |||
return _maxSize; | |||
} | |||
public int getSQLType() throws SQLException { | |||
public int getSQLType() throws IOException { | |||
if (_sqlType != null) { | |||
return _sqlType; | |||
} | |||
throw new SQLException("Unsupported data type: " + toString()); | |||
throw new JackcessException("Unsupported data type: " + toString()); | |||
} | |||
public int getMinScale() { | |||
@@ -472,24 +472,24 @@ public enum DataType { | |||
} | |||
public static DataType fromSQLType(int sqlType) | |||
throws SQLException | |||
throws IOException | |||
{ | |||
return fromSQLType(sqlType, 0, null); | |||
} | |||
public static DataType fromSQLType(int sqlType, int lengthInUnits) | |||
throws SQLException | |||
throws IOException | |||
{ | |||
return fromSQLType(sqlType, lengthInUnits, null); | |||
} | |||
public static DataType fromSQLType(int sqlType, int lengthInUnits, | |||
Database.FileFormat fileFormat) | |||
throws SQLException | |||
throws IOException | |||
{ | |||
DataType[] rtnArr = SQL_TYPES.get(sqlType); | |||
if(rtnArr == null) { | |||
throw new SQLException("Unsupported SQL type: " + sqlType); | |||
throw new JackcessException("Unsupported SQL type: " + sqlType); | |||
} | |||
JetFormat format = | |||
((fileFormat != null) ? | |||
@@ -533,8 +533,7 @@ public enum DataType { | |||
DataType altType) | |||
{ | |||
try { | |||
java.lang.reflect.Field sqlTypeField = Types.class.getField(typeName); | |||
Integer value = (Integer)sqlTypeField.get(null); | |||
Integer value = SqlHelper.INSTANCE.getNewSqlType(typeName); | |||
SQL_TYPES.put(value, new DataType[]{type}); | |||
if(altType != null) { | |||
ALT_SQL_TYPES.put(value, altType); |
@@ -423,10 +423,8 @@ class CalculatedColumnUtil | |||
buffer.put(intValBytes); | |||
} catch(ArithmeticException e) { | |||
throw (IOException) | |||
new IOException(withErrorContext( | |||
"Numeric value '" + inValue + "' out of range")) | |||
.initCause(e); | |||
throw new IOException( | |||
withErrorContext("Numeric value '" + inValue + "' out of range"), e); | |||
} | |||
} | |||
@@ -29,9 +29,6 @@ import java.nio.ByteBuffer; | |||
import java.nio.ByteOrder; | |||
import java.nio.CharBuffer; | |||
import java.nio.charset.Charset; | |||
import java.sql.Blob; | |||
import java.sql.Clob; | |||
import java.sql.SQLException; | |||
import java.time.DateTimeException; | |||
import java.time.Duration; | |||
import java.time.Instant; | |||
@@ -441,7 +438,7 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl>, DateTimeConte | |||
} | |||
@Override | |||
public int getSQLType() throws SQLException { | |||
public int getSQLType() throws IOException { | |||
return _type.getSQLType(); | |||
} | |||
@@ -860,10 +857,8 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl>, DateTimeConte | |||
// too big) | |||
buffer.putLong(decVal.movePointRight(4).longValueExact()); | |||
} catch(ArithmeticException e) { | |||
throw (IOException) | |||
new IOException(withErrorContext( | |||
"Currency value '" + inValue + "' out of range")) | |||
.initCause(e); | |||
throw new IOException( | |||
withErrorContext("Currency value '" + inValue + "' out of range"), e); | |||
} | |||
} | |||
@@ -936,10 +931,8 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl>, DateTimeConte | |||
} | |||
buffer.put(intValBytes); | |||
} catch(ArithmeticException e) { | |||
throw (IOException) | |||
new IOException(withErrorContext( | |||
"Numeric value '" + inValue + "' out of range")) | |||
.initCause(e); | |||
throw new IOException( | |||
withErrorContext("Numeric value '" + inValue + "' out of range"), e); | |||
} | |||
} | |||
@@ -1836,14 +1829,8 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl>, DateTimeConte | |||
return null; | |||
} else if(value instanceof CharSequence) { | |||
return (CharSequence)value; | |||
} else if(value instanceof Clob) { | |||
try { | |||
Clob c = (Clob)value; | |||
// note, start pos is 1-based | |||
return c.getSubString(1L, (int)c.length()); | |||
} catch(SQLException e) { | |||
throw (IOException)(new IOException(e.getMessage())).initCause(e); | |||
} | |||
} else if(SqlHelper.INSTANCE.isClob(value)) { | |||
return SqlHelper.INSTANCE.getClobString(value); | |||
} else if(value instanceof Reader) { | |||
char[] buf = new char[8 * 1024]; | |||
StringBuilder sout = new StringBuilder(); | |||
@@ -1869,18 +1856,10 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl>, DateTimeConte | |||
return null; | |||
} else if(value instanceof byte[]) { | |||
return (byte[])value; | |||
} else if(value instanceof OleUtil.OleBlobImpl) { | |||
return ((OleUtil.OleBlobImpl)value).getBytes(); | |||
} else if(value instanceof Blob) { | |||
try { | |||
Blob b = (Blob)value; | |||
// note, start pos is 1-based | |||
return b.getBytes(1L, (int)b.length()); | |||
} catch(SQLException e) { | |||
throw (IOException)(new IOException(e.getMessage())).initCause(e); | |||
} | |||
} else if(value instanceof RawData) { | |||
return ((RawData)value).getBytes(); | |||
} else if(value instanceof InMemoryBlob) { | |||
return ((InMemoryBlob)value).getBytes(); | |||
} else if(SqlHelper.INSTANCE.isBlob(value)) { | |||
return SqlHelper.INSTANCE.getBlobBytes(value); | |||
} | |||
ByteArrayOutputStream bout = new ByteArrayOutputStream(); | |||
@@ -2302,7 +2281,7 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl>, DateTimeConte | |||
/** | |||
* Wrapper for raw column data which can be re-written. | |||
*/ | |||
private static class RawData implements Serializable | |||
private static final class RawData implements Serializable, InMemoryBlob | |||
{ | |||
private static final long serialVersionUID = 0L; | |||
@@ -2312,7 +2291,8 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl>, DateTimeConte | |||
_bytes = bytes; | |||
} | |||
private byte[] getBytes() { | |||
@Override | |||
public byte[] getBytes() { | |||
return _bytes; | |||
} | |||
@@ -2788,4 +2768,9 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl>, DateTimeConte | |||
return LocalDateTime.ofInstant(inst, db.getZoneId()); | |||
} | |||
} | |||
/** internal interface for types which hold bytes in memory */ | |||
static interface InMemoryBlob { | |||
public byte[] getBytes() throws IOException; | |||
} | |||
} |
@@ -2149,8 +2149,9 @@ public class DatabaseImpl implements Database, DateTimeContext | |||
/** | |||
* Returns the password mask retrieved from the given header page and | |||
* format, or {@code null} if this format does not use a password mask. | |||
* @usage _advanced_method_ | |||
*/ | |||
static byte[] getPasswordMask(ByteBuffer buffer, JetFormat format) | |||
public static byte[] getPasswordMask(ByteBuffer buffer, JetFormat format) | |||
{ | |||
// get extra password mask if necessary (the extra password mask is | |||
// generated from the database creation date stored in the header) |
@@ -63,9 +63,9 @@ public abstract class JetFormat { | |||
private static final byte CODE_VERSION_16 = 0x5; | |||
/** location of the engine name in the header */ | |||
static final int OFFSET_ENGINE_NAME = 0x4; | |||
public static final int OFFSET_ENGINE_NAME = 0x4; | |||
/** length of the engine name in the header */ | |||
static final int LENGTH_ENGINE_NAME = 0xF; | |||
public static final int LENGTH_ENGINE_NAME = 0xF; | |||
/** amount of initial data to be read to determine database type */ | |||
private static final int HEADER_LENGTH = 21; | |||
@@ -463,7 +463,7 @@ public class OleUtil | |||
} | |||
static final class OleBlobImpl implements OleBlob | |||
static final class OleBlobImpl implements OleBlob, ColumnImpl.InMemoryBlob | |||
{ | |||
private byte[] _bytes; | |||
private ContentImpl _content; | |||
@@ -502,6 +502,7 @@ public class OleUtil | |||
return _bytes.length; | |||
} | |||
@Override | |||
public byte[] getBytes() throws IOException { | |||
if(_bytes == null) { | |||
throw new IOException("blob is closed"); |
@@ -32,7 +32,8 @@ public class PageChannel implements Channel, Flushable { | |||
static final int INVALID_PAGE_NUMBER = -1; | |||
static final ByteOrder DEFAULT_BYTE_ORDER = ByteOrder.LITTLE_ENDIAN; | |||
/** default byte order of access mdb files */ | |||
public static final ByteOrder DEFAULT_BYTE_ORDER = ByteOrder.LITTLE_ENDIAN; | |||
/** invalid page header, used when deallocating old pages. data pages | |||
generally have 4 interesting bytes at the beginning which we want to |
@@ -0,0 +1,71 @@ | |||
/* | |||
Copyright (c) 2021 James Ahlborn | |||
Licensed under the Apache License, Version 2.0 (the "License"); | |||
you may not use this file except in compliance with the License. | |||
You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
*/ | |||
package com.healthmarketscience.jackcess.impl; | |||
import java.io.IOException; | |||
/** | |||
* Helper class to isolate the java.sql module interactions from the core of | |||
* jackcess (in java 9+ environments). If the module is enabled (indicating | |||
* that the application is already using sql constructs), then jackcess will | |||
* seamlessly interact with sql types. If the module is not enabled | |||
* (indicating that the application is not using any sql constructs), then | |||
* jackcess will not require the module in order to function otherwise | |||
* normally. | |||
* | |||
* This base class is the "fallback" class if the java.sql module is not | |||
* available. | |||
* | |||
* @author James Ahlborn | |||
*/ | |||
public class SqlHelper { | |||
public static final SqlHelper INSTANCE = loadInstance(); | |||
public SqlHelper() {} | |||
public boolean isBlob(Object value) { | |||
return false; | |||
} | |||
public byte[] getBlobBytes(Object value) throws IOException { | |||
throw new UnsupportedOperationException(); | |||
} | |||
public boolean isClob(Object value) { | |||
return false; | |||
} | |||
public CharSequence getClobString(Object value) throws IOException { | |||
throw new UnsupportedOperationException(); | |||
} | |||
public Integer getNewSqlType(String typeName) throws Exception { | |||
throw new UnsupportedOperationException(); | |||
} | |||
private static final SqlHelper loadInstance() { | |||
// attempt to load the implementation of this class which works with | |||
// java.sql classes. if that fails, use this fallback instance instead. | |||
try { | |||
return (SqlHelper) | |||
Class.forName("com.healthmarketscience.jackcess.impl.SqlHelperImpl") | |||
.newInstance(); | |||
} catch(Throwable ignored) {} | |||
return new SqlHelper(); | |||
} | |||
} |
@@ -0,0 +1,73 @@ | |||
/* | |||
Copyright (c) 2021 James Ahlborn | |||
Licensed under the Apache License, Version 2.0 (the "License"); | |||
you may not use this file except in compliance with the License. | |||
You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
*/ | |||
package com.healthmarketscience.jackcess.impl; | |||
import java.io.IOException; | |||
import java.sql.Blob; | |||
import java.sql.Clob; | |||
import java.sql.SQLException; | |||
import java.sql.Types; | |||
/** | |||
* Implementation of SqlHelperImpl which works with the java.sql modules | |||
* classes. This class is used if the java.sql module is enabled in the | |||
* application. | |||
* | |||
* @author James Ahlborn | |||
*/ | |||
public class SqlHelperImpl extends SqlHelper { | |||
public SqlHelperImpl() {} | |||
@Override | |||
public boolean isBlob(Object value) { | |||
return (value instanceof Blob); | |||
} | |||
@Override | |||
public byte[] getBlobBytes(Object value) throws IOException { | |||
try { | |||
Blob b = (Blob)value; | |||
// note, start pos is 1-based | |||
return b.getBytes(1L, (int)b.length()); | |||
} catch(SQLException e) { | |||
throw new IOException(e.getMessage(), e); | |||
} | |||
} | |||
@Override | |||
public boolean isClob(Object value) { | |||
return (value instanceof Clob); | |||
} | |||
@Override | |||
public CharSequence getClobString(Object value) throws IOException { | |||
try { | |||
Clob c = (Clob)value; | |||
// note, start pos is 1-based | |||
return c.getSubString(1L, (int)c.length()); | |||
} catch(SQLException e) { | |||
throw new IOException(e.getMessage(), e); | |||
} | |||
} | |||
@Override | |||
public Integer getNewSqlType(String typeName) throws Exception { | |||
java.lang.reflect.Field sqlTypeField = Types.class.getField(typeName); | |||
return (Integer)sqlTypeField.get(null); | |||
} | |||
} |
@@ -16,6 +16,13 @@ limitations under the License. | |||
package com.healthmarketscience.jackcess.util; | |||
import com.healthmarketscience.jackcess.ColumnBuilder; | |||
import com.healthmarketscience.jackcess.DataType; | |||
import com.healthmarketscience.jackcess.Database; | |||
import com.healthmarketscience.jackcess.Table; | |||
import com.healthmarketscience.jackcess.TableBuilder; | |||
import com.healthmarketscience.jackcess.impl.ByteUtil; | |||
import com.healthmarketscience.jackcess.impl.DatabaseImpl; | |||
import java.io.BufferedReader; | |||
import java.io.EOFException; | |||
import java.io.File; | |||
@@ -29,14 +36,6 @@ import java.util.List; | |||
import java.util.regex.Matcher; | |||
import java.util.regex.Pattern; | |||
import com.healthmarketscience.jackcess.ColumnBuilder; | |||
import com.healthmarketscience.jackcess.DataType; | |||
import com.healthmarketscience.jackcess.Database; | |||
import com.healthmarketscience.jackcess.Table; | |||
import com.healthmarketscience.jackcess.TableBuilder; | |||
import com.healthmarketscience.jackcess.impl.ByteUtil; | |||
import com.healthmarketscience.jackcess.impl.DatabaseImpl; | |||
/** | |||
* Utility class for importing tables to an Access database from other | |||
* sources. See the {@link Builder} for convenient configuration of the | |||
@@ -64,7 +63,7 @@ public class ImportUtil | |||
* @return a List of Columns | |||
*/ | |||
public static List<ColumnBuilder> toColumns(ResultSetMetaData md) | |||
throws SQLException | |||
throws SQLException, IOException | |||
{ | |||
List<ColumnBuilder> columns = new ArrayList<ColumnBuilder>(); | |||
for (int i = 1; i <= md.getColumnCount(); i++) { | |||
@@ -494,7 +493,7 @@ public class ImportUtil | |||
return table.getName(); | |||
} catch(SQLException e) { | |||
throw (IOException)new IOException(e.getMessage()).initCause(e); | |||
throw new IOException(e.getMessage(), e); | |||
} | |||
} | |||
@@ -15,9 +15,12 @@ | |||
<item name="Downloads" href="https://sourceforge.net/project/showfiles.php?group_id=134943"/> | |||
<item name="SourceForge Project" href="https://sourceforge.net/projects/jackcess/"/> | |||
<item name="Cookbook" href="cookbook.html"/> | |||
<item name="Upgrading to Jackcess 3.5.x" href="jackcess-3_5.html"/> | |||
<item name="Upgrading to Jackcess 3.x" href="jackcess-3.html"/> | |||
<item name="Upgrading to Jackcess 2.x" href="jackcess-2.html"/> | |||
<item name="Upgrading to Jackcess 4.x" href="jackcess-4.html"/> | |||
<item name="Upgrading to Older Versions" href="jackcess_upgrades.html" collapse="true"> | |||
<item name="Jackcess 3.5.x" href="jackcess-3_5.html"/> | |||
<item name="Jackcess 3.x" href="jackcess-3.html"/> | |||
<item name="Jackcess 2.x" href="jackcess-2.html"/> | |||
</item> | |||
<item name="FAQ" href="faq.html"/> | |||
<item name="Support" href="https://sourceforge.net/projects/jackcess/support"/> | |||
<item name="Jackcess Encrypt" href="https://jackcessencrypt.sourceforge.io/"/> |
@@ -19,6 +19,18 @@ | |||
Questions</a> for more info. | |||
</p> | |||
<subsection name="Java 9+ Compatibility (2021-TBD)"> | |||
<p> | |||
While Jackcess <i>still only requires Java 8+</i>, as of the 4.0.0 | |||
release it now includes an Automatic-Module-Name of | |||
<code>com.healthmarketscience.jackcess</code> in its manifest. This | |||
allows it to be used safely in the module path for Java 9+ projects. | |||
</p> | |||
<p> | |||
This release is binary compatible with the 3.x release series. | |||
</p> | |||
</subsection> | |||
<subsection name="Java 8+ Support (2019-02-08)"> | |||
<p> | |||
Jackcess now requires Java 8+ as of the 3.0.0 release. All third | |||
@@ -77,10 +89,8 @@ if(row != null) { | |||
<li>Creating a new table and writing data into it: | |||
<source>Database db = DatabaseBuilder.create(Database.FileFormat.V2000, new File("new.mdb")); | |||
Table newTable = new TableBuilder("NewTable") | |||
.addColumn(new ColumnBuilder("a") | |||
.setSQLType(Types.INTEGER)) | |||
.addColumn(new ColumnBuilder("b") | |||
.setSQLType(Types.VARCHAR)) | |||
.addColumn(new ColumnBuilder("a", DataType.LONG)) | |||
.addColumn(new ColumnBuilder("b", DataType.TEXT)) | |||
.toTable(db); | |||
newTable.addRow(1, "foo"); | |||
</source> |
@@ -15,7 +15,7 @@ | |||
behavior of Jackcess out of the box. The old behavior is still | |||
available, but you must now configure it explicitly. | |||
<ul> | |||
<li><b>DateTypeType default has been changed to | |||
<li><b>DateTimeType default has been changed to | |||
LOCAL_DATE_TIME.</b></li> | |||
<ul> | |||
<li>The Jackcess API was originally built using the Date type |
@@ -0,0 +1,64 @@ | |||
<?xml version="1.0"?> | |||
<document> | |||
<properties> | |||
<author email="jahlborn@users.sf.net">James Ahlborn</author> | |||
<title>Upgrading from Jackcess 3.x (or 3.5.x) to 4.x</title> | |||
</properties> | |||
<body> | |||
<section name="Jackcess 4.0"> | |||
<subsection name="Just give it to me straight"> | |||
<p> | |||
Jackcess 4.x is largely binary compatible with the previous 3.x (and | |||
3.5.x) versions. In order to be more "module friendly", the | |||
exceptions thrown from a few infrequently used methods have changed | |||
from <code>SQLException</code> to <code>IOException</code>. Other | |||
than that, code compiled against the 3.x series should work fine | |||
with the 4.x series. | |||
</p> | |||
<p> | |||
Even though Jackcess is now Java 9+ module compatible, <i>it still | |||
only requires Java 8+</i>. However, Jackcess can now be safely used | |||
in the module path of a Java 9+ project (with the module name of | |||
<code>com.healthmarketscience.jackcess</code>). There are a few | |||
features which require additional core Java modules to be enabled | |||
(but these modules are not required if the corresponding features | |||
are not utilized). | |||
<ul> | |||
<li><b>java.sql</b></li> | |||
<ul> | |||
<li>This module is necessary if Jackcess will need to interact | |||
with any of the classes from the <code>java.sql</code> package | |||
(e.g. handling <code>Clob</code>/<code>Blob</code> or using | |||
<code>ImportUtil</code>).</li> | |||
</ul> | |||
<li><b>java.scripting</b></li> | |||
<ul> | |||
<li>This module is necessary if expression evaluation is | |||
enabled (the default) and the database includes expressions | |||
(e.g. default values, calculated columns, validation | |||
rules, etc.).</li> | |||
</ul> | |||
</ul> | |||
</p> | |||
<h4>Working with Jackcess Encrypt</h4> | |||
<p> | |||
If you are using the <a href="https://jackcessencrypt.sourceforge.io/">Jackcess Encrypt</a> | |||
project, then you will need to use a version compatible with the | |||
relevant Jackess API. Fortunately, the major versions match, so | |||
it's pretty simple: | |||
</p> | |||
<ul> | |||
<li>Jackcess 4.x -> Jackcess Encrypt 4.y</li> | |||
<li>Jackcess 3.x -> Jackcess Encrypt 3.y</li> | |||
<li>Jackcess 2.x -> Jackcess Encrypt 2.y</li> | |||
<li>Jackcess 1.x -> Jackcess Encrypt 1.y</li> | |||
</ul> | |||
</subsection> | |||
</section> | |||
</body> | |||
</document> |
@@ -0,0 +1,22 @@ | |||
<?xml version="1.0"?> | |||
<document> | |||
<properties> | |||
<author email="jahlborn@users.sf.net">James Ahlborn</author> | |||
<title>Upgrading to Older Versions</title> | |||
</properties> | |||
<body> | |||
<section name="Upgrading to Older Versions"> | |||
<subsection name="Overview"> | |||
<table> | |||
<tr><th>Document</th></tr> | |||
<tr><td><a href="jackcess-3_5.html">Upgrading to Jackcess 3.5.x</a></td></tr> | |||
<tr><td><a href="jackcess-3.html">Upgrading to Jackcess 3.x</a></td></tr> | |||
<tr><td><a href="jackcess-2.html">Upgrading to Jackcess 2.x</a></td></tr> | |||
</table> | |||
</subsection> | |||
</section> | |||
</body> | |||
</document> |
@@ -415,7 +415,7 @@ public class TestUtil | |||
Assert.assertEquals(expectedLdt, found); | |||
} | |||
static void copyFile(File srcFile, File dstFile) | |||
public static void copyFile(File srcFile, File dstFile) | |||
throws IOException | |||
{ | |||
// FIXME should really be using commons io FileUtils here, but don't want | |||
@@ -441,7 +441,7 @@ public class TestUtil | |||
} | |||
} | |||
static File createTempFile(boolean keep) throws Exception { | |||
public static File createTempFile(boolean keep) throws Exception { | |||
File tmp = File.createTempFile("databaseTest", ".mdb"); | |||
if(keep) { | |||
System.out.println("Created " + tmp); |
@@ -6,7 +6,6 @@ import java.io.InputStream; | |||
import java.nio.charset.Charset; | |||
import java.nio.channels.FileChannel; | |||
import java.nio.channels.NonWritableChannelException; | |||
import java.sql.SQLException; | |||
import java.util.ArrayList; | |||
import java.util.EnumSet; | |||
import java.util.List; | |||
@@ -14,6 +13,7 @@ import java.util.Set; | |||
import com.healthmarketscience.jackcess.DataType; | |||
import com.healthmarketscience.jackcess.Database; | |||
import com.healthmarketscience.jackcess.JackcessException; | |||
import static com.healthmarketscience.jackcess.Database.*; | |||
import com.healthmarketscience.jackcess.DatabaseBuilder; | |||
import com.healthmarketscience.jackcess.PropertyMap; | |||
@@ -292,7 +292,7 @@ public class JetFormatTest extends TestCase { | |||
Integer sqlType = null; | |||
try { | |||
sqlType = dt.getSQLType(); | |||
} catch(SQLException ignored) {} | |||
} catch(JackcessException ignored) {} | |||
if(sqlType != null) { | |||
assertEquals(dt, DataType.fromSQLType(sqlType)); |