diff options
author | James Ahlborn <jtahlborn@yahoo.com> | 2021-01-21 01:15:35 +0000 |
---|---|---|
committer | James Ahlborn <jtahlborn@yahoo.com> | 2021-01-21 01:15:35 +0000 |
commit | 5468f8ffce2edb2a786aecdf5d07ecab6969af1c (patch) | |
tree | e042d2f137b1475c422382ab8f30bfa2d43fd603 /src/main/java | |
parent | 02e1648130171296b27231dbd780eb32e44edc5f (diff) | |
parent | 65d69efe9f464d306dfc5783bc891baee812ef48 (diff) | |
download | jackcess-5468f8ffce2edb2a786aecdf5d07ecab6969af1c.tar.gz jackcess-5468f8ffce2edb2a786aecdf5d07ecab6969af1c.zip |
merge modules branch
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@1356 f203690c-595d-4dc9-a70b-905162fa7fd2
Diffstat (limited to 'src/main/java')
12 files changed, 203 insertions, 77 deletions
diff --git a/src/main/java/com/healthmarketscience/jackcess/Column.java b/src/main/java/com/healthmarketscience/jackcess/Column.java index 333f977..d05fb2a 100644 --- a/src/main/java/com/healthmarketscience/jackcess/Column.java +++ b/src/main/java/com/healthmarketscience/jackcess/Column.java @@ -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); } diff --git a/src/main/java/com/healthmarketscience/jackcess/ColumnBuilder.java b/src/main/java/com/healthmarketscience/jackcess/ColumnBuilder.java index 48fa1cf..e063448 100644 --- a/src/main/java/com/healthmarketscience/jackcess/ColumnBuilder.java +++ b/src/main/java/com/healthmarketscience/jackcess/ColumnBuilder.java @@ -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)); } diff --git a/src/main/java/com/healthmarketscience/jackcess/DataType.java b/src/main/java/com/healthmarketscience/jackcess/DataType.java index 6070dbd..d191dc1 100644 --- a/src/main/java/com/healthmarketscience/jackcess/DataType.java +++ b/src/main/java/com/healthmarketscience/jackcess/DataType.java @@ -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); diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/CalculatedColumnUtil.java b/src/main/java/com/healthmarketscience/jackcess/impl/CalculatedColumnUtil.java index 8e3802b..0ded048 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/CalculatedColumnUtil.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/CalculatedColumnUtil.java @@ -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); } } diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java index 07c798b..ff221a7 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java @@ -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; + } } diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java index 532eb65..1ff129e 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java @@ -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) diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/JetFormat.java b/src/main/java/com/healthmarketscience/jackcess/impl/JetFormat.java index 2d2f0af..8a3aa64 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/JetFormat.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/JetFormat.java @@ -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; diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/OleUtil.java b/src/main/java/com/healthmarketscience/jackcess/impl/OleUtil.java index a67a54d..7708b11 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/OleUtil.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/OleUtil.java @@ -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"); diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/PageChannel.java b/src/main/java/com/healthmarketscience/jackcess/impl/PageChannel.java index 101a3e0..efd8be2 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/PageChannel.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/PageChannel.java @@ -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 diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/SqlHelper.java b/src/main/java/com/healthmarketscience/jackcess/impl/SqlHelper.java new file mode 100644 index 0000000..91fc4b6 --- /dev/null +++ b/src/main/java/com/healthmarketscience/jackcess/impl/SqlHelper.java @@ -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(); + } +} diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/SqlHelperImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/SqlHelperImpl.java new file mode 100644 index 0000000..079613f --- /dev/null +++ b/src/main/java/com/healthmarketscience/jackcess/impl/SqlHelperImpl.java @@ -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); + } +} diff --git a/src/main/java/com/healthmarketscience/jackcess/util/ImportUtil.java b/src/main/java/com/healthmarketscience/jackcess/util/ImportUtil.java index 2fd6455..c4c3625 100644 --- a/src/main/java/com/healthmarketscience/jackcess/util/ImportUtil.java +++ b/src/main/java/com/healthmarketscience/jackcess/util/ImportUtil.java @@ -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); } } |