Browse Source

merge modules branch

git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@1356 f203690c-595d-4dc9-a70b-905162fa7fd2
tags/jackcess-4.0.0
James Ahlborn 3 years ago
parent
commit
5468f8ffce

+ 2
- 1
pom.xml View File

<artifactId>jackcess</artifactId> <artifactId>jackcess</artifactId>
<name>Jackcess</name> <name>Jackcess</name>
<description>A pure Java library for reading from and writing to MS Access databases.</description> <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> <url>https://jackcess.sourceforge.io</url>
<inceptionYear>2005</inceptionYear> <inceptionYear>2005</inceptionYear>
<developers> <developers>
<extensions>true</extensions> <extensions>true</extensions>
<configuration> <configuration>
<instructions> <instructions>
<Automatic-Module-Name>com.healthmarketscience.jackcess</Automatic-Module-Name>
</instructions> </instructions>
</configuration> </configuration>
<executions> <executions>

+ 15
- 0
src/changes/changes.xml View File

<author email="javajedi@users.sf.net">Tim McCune</author> <author email="javajedi@users.sf.net">Tim McCune</author>
</properties> </properties>
<body> <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"> <release version="3.5.1" date="2020-09-10">
<action dev="jahlborn" type="update"> <action dev="jahlborn" type="update">
Add more static utility methods to DatabaseBuilder to enable more Add more static utility methods to DatabaseBuilder to enable more

+ 10
- 11
src/main/java/com/healthmarketscience/jackcess/Column.java View File

package com.healthmarketscience.jackcess; package com.healthmarketscience.jackcess;


import java.io.IOException; import java.io.IOException;
import java.sql.SQLException;
import java.util.Map; import java.util.Map;


import com.healthmarketscience.jackcess.complex.ComplexColumnInfo; import com.healthmarketscience.jackcess.complex.ComplexColumnInfo;
* @author James Ahlborn * @author James Ahlborn
* @usage _general_class_ * @usage _general_class_
*/ */
public interface Column
public interface Column
{ {
/** /**
* Meaningless placeholder object for inserting values in an autonumber * Meaningless placeholder object for inserting values in an autonumber
* @usage _general_field_ * @usage _general_field_
*/ */
public static final Object AUTO_NUMBER = "<AUTO_NUMBER>"; public static final Object AUTO_NUMBER = "<AUTO_NUMBER>";
/** /**
* Meaningless placeholder object for updating rows which indicates that a * Meaningless placeholder object for updating rows which indicates that a
* given column should keep its existing value. * given column should keep its existing value.
* @usage _general_field_ * @usage _general_field_
*/ */
public static final Object KEEP_VALUE = "<KEEP_VALUE>"; public static final Object KEEP_VALUE = "<KEEP_VALUE>";
/** /**
* @usage _general_method_ * @usage _general_method_
*/ */
/** /**
* @usage _general_method_ * @usage _general_method_
*/ */
public int getSQLType() throws SQLException;
public int getSQLType() throws IOException;


/** /**
* @usage _general_method_ * @usage _general_method_
* @usage _general_method_ * @usage _general_method_
*/ */
public PropertyMap getProperties() throws IOException; public PropertyMap getProperties() throws IOException;
/** /**
* Returns the column which tracks the version history for an "append only" * Returns the column which tracks the version history for an "append only"
* column. * column.
* @usage _intermediate_method_ * @usage _intermediate_method_
*/ */
public ColumnValidator getColumnValidator(); public ColumnValidator getColumnValidator();
/** /**
* Sets a new ColumnValidator. If {@code null}, resets to the value * Sets a new ColumnValidator. If {@code null}, resets to the value
* returned from the Database's ColumnValidatorFactory (if the factory * returned from the Database's ColumnValidatorFactory (if the factory
* @usage _intermediate_method_ * @usage _intermediate_method_
*/ */
public void setColumnValidator(ColumnValidator newValidator); public void setColumnValidator(ColumnValidator newValidator);
public Object setRowValue(Object[] rowArray, Object value); public Object setRowValue(Object[] rowArray, Object value);
public Object setRowValue(Map<String,Object> rowMap, Object value); public Object setRowValue(Map<String,Object> rowMap, Object value);
public Object getRowValue(Object[] rowArray); public Object getRowValue(Object[] rowArray);
public Object getRowValue(Map<String,?> rowMap); public Object getRowValue(Map<String,?> rowMap);
} }

+ 3
- 4
src/main/java/com/healthmarketscience/jackcess/ColumnBuilder.java View File

package com.healthmarketscience.jackcess; package com.healthmarketscience.jackcess;


import java.io.IOException; import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;


/** /**
* Sets the type for the new column based on the given SQL type. * 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); return setSQLType(type, 0, null);
} }


* data length (in type specific units). * data length (in type specific units).
*/ */
public ColumnBuilder setSQLType(int type, int lengthInUnits) public ColumnBuilder setSQLType(int type, int lengthInUnits)
throws SQLException
throws IOException
{ {
return setSQLType(type, lengthInUnits, null); return setSQLType(type, lengthInUnits, null);
} }
*/ */
public ColumnBuilder setSQLType(int type, int lengthInUnits, public ColumnBuilder setSQLType(int type, int lengthInUnits,
Database.FileFormat fileFormat) Database.FileFormat fileFormat)
throws SQLException
throws IOException
{ {
return setType(DataType.fromSQLType(type, lengthInUnits, fileFormat)); return setType(DataType.fromSQLType(type, lengthInUnits, fileFormat));
} }

+ 8
- 9
src/main/java/com/healthmarketscience/jackcess/DataType.java View File

import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.sql.SQLException;
import java.sql.Types; import java.sql.Types;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;


import com.healthmarketscience.jackcess.impl.DatabaseImpl; import com.healthmarketscience.jackcess.impl.DatabaseImpl;
import com.healthmarketscience.jackcess.impl.JetFormat; import com.healthmarketscience.jackcess.impl.JetFormat;
import com.healthmarketscience.jackcess.impl.SqlHelper;


/** /**
* Supported access data types. * Supported access data types.
return _maxSize; return _maxSize;
} }


public int getSQLType() throws SQLException {
public int getSQLType() throws IOException {
if (_sqlType != null) { if (_sqlType != null) {
return _sqlType; return _sqlType;
} }
throw new SQLException("Unsupported data type: " + toString());
throw new JackcessException("Unsupported data type: " + toString());
} }


public int getMinScale() { public int getMinScale() {
} }


public static DataType fromSQLType(int sqlType) public static DataType fromSQLType(int sqlType)
throws SQLException
throws IOException
{ {
return fromSQLType(sqlType, 0, null); return fromSQLType(sqlType, 0, null);
} }


public static DataType fromSQLType(int sqlType, int lengthInUnits) public static DataType fromSQLType(int sqlType, int lengthInUnits)
throws SQLException
throws IOException
{ {
return fromSQLType(sqlType, lengthInUnits, null); return fromSQLType(sqlType, lengthInUnits, null);
} }


public static DataType fromSQLType(int sqlType, int lengthInUnits, public static DataType fromSQLType(int sqlType, int lengthInUnits,
Database.FileFormat fileFormat) Database.FileFormat fileFormat)
throws SQLException
throws IOException
{ {
DataType[] rtnArr = SQL_TYPES.get(sqlType); DataType[] rtnArr = SQL_TYPES.get(sqlType);
if(rtnArr == null) { if(rtnArr == null) {
throw new SQLException("Unsupported SQL type: " + sqlType);
throw new JackcessException("Unsupported SQL type: " + sqlType);
} }
JetFormat format = JetFormat format =
((fileFormat != null) ? ((fileFormat != null) ?
DataType altType) DataType altType)
{ {
try { 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}); SQL_TYPES.put(value, new DataType[]{type});
if(altType != null) { if(altType != null) {
ALT_SQL_TYPES.put(value, altType); ALT_SQL_TYPES.put(value, altType);

+ 2
- 4
src/main/java/com/healthmarketscience/jackcess/impl/CalculatedColumnUtil.java View File

buffer.put(intValBytes); buffer.put(intValBytes);


} catch(ArithmeticException e) { } 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);
} }
} }



+ 19
- 34
src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java View File

import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.SQLException;
import java.time.DateTimeException; import java.time.DateTimeException;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
} }


@Override @Override
public int getSQLType() throws SQLException {
public int getSQLType() throws IOException {
return _type.getSQLType(); return _type.getSQLType();
} }


// too big) // too big)
buffer.putLong(decVal.movePointRight(4).longValueExact()); buffer.putLong(decVal.movePointRight(4).longValueExact());
} catch(ArithmeticException e) { } 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);
} }
} }


} }
buffer.put(intValBytes); buffer.put(intValBytes);
} catch(ArithmeticException e) { } 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);
} }
} }


return null; return null;
} else if(value instanceof CharSequence) { } else if(value instanceof CharSequence) {
return (CharSequence)value; 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) { } else if(value instanceof Reader) {
char[] buf = new char[8 * 1024]; char[] buf = new char[8 * 1024];
StringBuilder sout = new StringBuilder(); StringBuilder sout = new StringBuilder();
return null; return null;
} else if(value instanceof byte[]) { } else if(value instanceof byte[]) {
return (byte[])value; 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(); ByteArrayOutputStream bout = new ByteArrayOutputStream();
/** /**
* Wrapper for raw column data which can be re-written. * 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; private static final long serialVersionUID = 0L;


_bytes = bytes; _bytes = bytes;
} }


private byte[] getBytes() {
@Override
public byte[] getBytes() {
return _bytes; return _bytes;
} }


return LocalDateTime.ofInstant(inst, db.getZoneId()); return LocalDateTime.ofInstant(inst, db.getZoneId());
} }
} }

/** internal interface for types which hold bytes in memory */
static interface InMemoryBlob {
public byte[] getBytes() throws IOException;
}
} }

+ 2
- 1
src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java View File

/** /**
* Returns the password mask retrieved from the given header page and * Returns the password mask retrieved from the given header page and
* format, or {@code null} if this format does not use a password mask. * 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 // get extra password mask if necessary (the extra password mask is
// generated from the database creation date stored in the header) // generated from the database creation date stored in the header)

+ 2
- 2
src/main/java/com/healthmarketscience/jackcess/impl/JetFormat.java View File

private static final byte CODE_VERSION_16 = 0x5; private static final byte CODE_VERSION_16 = 0x5;


/** location of the engine name in the header */ /** 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 */ /** 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 */ /** amount of initial data to be read to determine database type */
private static final int HEADER_LENGTH = 21; private static final int HEADER_LENGTH = 21;



+ 2
- 1
src/main/java/com/healthmarketscience/jackcess/impl/OleUtil.java View File

} }




static final class OleBlobImpl implements OleBlob
static final class OleBlobImpl implements OleBlob, ColumnImpl.InMemoryBlob
{ {
private byte[] _bytes; private byte[] _bytes;
private ContentImpl _content; private ContentImpl _content;
return _bytes.length; return _bytes.length;
} }


@Override
public byte[] getBytes() throws IOException { public byte[] getBytes() throws IOException {
if(_bytes == null) { if(_bytes == null) {
throw new IOException("blob is closed"); throw new IOException("blob is closed");

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



static final int INVALID_PAGE_NUMBER = -1; 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 /** invalid page header, used when deallocating old pages. data pages
generally have 4 interesting bytes at the beginning which we want to generally have 4 interesting bytes at the beginning which we want to

+ 71
- 0
src/main/java/com/healthmarketscience/jackcess/impl/SqlHelper.java View File

/*
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();
}
}

+ 73
- 0
src/main/java/com/healthmarketscience/jackcess/impl/SqlHelperImpl.java View File

/*
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);
}
}

+ 9
- 10
src/main/java/com/healthmarketscience/jackcess/util/ImportUtil.java View File



package com.healthmarketscience.jackcess.util; 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.BufferedReader;
import java.io.EOFException; import java.io.EOFException;
import java.io.File; import java.io.File;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; 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 * Utility class for importing tables to an Access database from other
* sources. See the {@link Builder} for convenient configuration of the * sources. See the {@link Builder} for convenient configuration of the
* @return a List of Columns * @return a List of Columns
*/ */
public static List<ColumnBuilder> toColumns(ResultSetMetaData md) public static List<ColumnBuilder> toColumns(ResultSetMetaData md)
throws SQLException
throws SQLException, IOException
{ {
List<ColumnBuilder> columns = new ArrayList<ColumnBuilder>(); List<ColumnBuilder> columns = new ArrayList<ColumnBuilder>();
for (int i = 1; i <= md.getColumnCount(); i++) { for (int i = 1; i <= md.getColumnCount(); i++) {
return table.getName(); return table.getName();


} catch(SQLException e) { } catch(SQLException e) {
throw (IOException)new IOException(e.getMessage()).initCause(e);
throw new IOException(e.getMessage(), e);
} }
} }



+ 6
- 3
src/site/site.xml View File

<item name="Downloads" href="https://sourceforge.net/project/showfiles.php?group_id=134943"/> <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="SourceForge Project" href="https://sourceforge.net/projects/jackcess/"/>
<item name="Cookbook" href="cookbook.html"/> <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="FAQ" href="faq.html"/>
<item name="Support" href="https://sourceforge.net/projects/jackcess/support"/> <item name="Support" href="https://sourceforge.net/projects/jackcess/support"/>
<item name="Jackcess Encrypt" href="https://jackcessencrypt.sourceforge.io/"/> <item name="Jackcess Encrypt" href="https://jackcessencrypt.sourceforge.io/"/>

+ 14
- 4
src/site/xdoc/index.xml View File

Questions</a> for more info. Questions</a> for more info.
</p> </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)"> <subsection name="Java 8+ Support (2019-02-08)">
<p> <p>
Jackcess now requires Java 8+ as of the 3.0.0 release. All third Jackcess now requires Java 8+ as of the 3.0.0 release. All third
<li>Creating a new table and writing data into it: <li>Creating a new table and writing data into it:
<source>Database db = DatabaseBuilder.create(Database.FileFormat.V2000, new File("new.mdb")); <source>Database db = DatabaseBuilder.create(Database.FileFormat.V2000, new File("new.mdb"));
Table newTable = new TableBuilder("NewTable") 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); .toTable(db);
newTable.addRow(1, "foo"); newTable.addRow(1, "foo");
</source> </source>

+ 1
- 1
src/site/xdoc/jackcess-3_5.xml View File

behavior of Jackcess out of the box. The old behavior is still behavior of Jackcess out of the box. The old behavior is still
available, but you must now configure it explicitly. available, but you must now configure it explicitly.
<ul> <ul>
<li><b>DateTypeType default has been changed to
<li><b>DateTimeType default has been changed to
LOCAL_DATE_TIME.</b></li> LOCAL_DATE_TIME.</b></li>
<ul> <ul>
<li>The Jackcess API was originally built using the Date type <li>The Jackcess API was originally built using the Date type

+ 64
- 0
src/site/xdoc/jackcess-4.xml View File

<?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 -&gt; Jackcess Encrypt 4.y</li>
<li>Jackcess 3.x -&gt; Jackcess Encrypt 3.y</li>
<li>Jackcess 2.x -&gt; Jackcess Encrypt 2.y</li>
<li>Jackcess 1.x -&gt; Jackcess Encrypt 1.y</li>
</ul>
</subsection>
</section>

</body>
</document>

+ 22
- 0
src/site/xdoc/jackcess_upgrades.xml View File

<?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>

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

Assert.assertEquals(expectedLdt, found); Assert.assertEquals(expectedLdt, found);
} }


static void copyFile(File srcFile, File dstFile)
public static void copyFile(File srcFile, File dstFile)
throws IOException throws IOException
{ {
// FIXME should really be using commons io FileUtils here, but don't want // FIXME should really be using commons io FileUtils here, but don't want
} }
} }


static File createTempFile(boolean keep) throws Exception {
public static File createTempFile(boolean keep) throws Exception {
File tmp = File.createTempFile("databaseTest", ".mdb"); File tmp = File.createTempFile("databaseTest", ".mdb");
if(keep) { if(keep) {
System.out.println("Created " + tmp); System.out.println("Created " + tmp);

+ 2
- 2
src/test/java/com/healthmarketscience/jackcess/impl/JetFormatTest.java View File

import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.nio.channels.NonWritableChannelException; import java.nio.channels.NonWritableChannelException;
import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;


import com.healthmarketscience.jackcess.DataType; import com.healthmarketscience.jackcess.DataType;
import com.healthmarketscience.jackcess.Database; import com.healthmarketscience.jackcess.Database;
import com.healthmarketscience.jackcess.JackcessException;
import static com.healthmarketscience.jackcess.Database.*; import static com.healthmarketscience.jackcess.Database.*;
import com.healthmarketscience.jackcess.DatabaseBuilder; import com.healthmarketscience.jackcess.DatabaseBuilder;
import com.healthmarketscience.jackcess.PropertyMap; import com.healthmarketscience.jackcess.PropertyMap;
Integer sqlType = null; Integer sqlType = null;
try { try {
sqlType = dt.getSQLType(); sqlType = dt.getSQLType();
} catch(SQLException ignored) {}
} catch(JackcessException ignored) {}


if(sqlType != null) { if(sqlType != null) {
assertEquals(dt, DataType.fromSQLType(sqlType)); assertEquals(dt, DataType.fromSQLType(sqlType));

Loading…
Cancel
Save