Browse Source

isolate java.sql usage so that the module is not required for core jackcess usage

git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/modules@1350 f203690c-595d-4dc9-a70b-905162fa7fd2
tags/jackcess-4.0.0
James Ahlborn 3 years ago
parent
commit
23f397f625

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

@@ -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);
}

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

@@ -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));
}

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

@@ -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);

+ 15
- 26
src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java View File

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

@@ -1836,14 +1833,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 +1860,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 +2285,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 +2295,8 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl>, DateTimeConte
_bytes = bytes;
}

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

@@ -2788,4 +2772,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;
}
}

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

@@ -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");

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

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

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

@@ -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 (IOException)(new IOException(e.getMessage())).initCause(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 (IOException)(new IOException(e.getMessage())).initCause(e);
}
}

@Override
public Integer getNewSqlType(String typeName) throws Exception {
java.lang.reflect.Field sqlTypeField = Types.class.getField(typeName);
return (Integer)sqlTypeField.get(null);
}
}

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

@@ -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++) {

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

@@ -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));

Loading…
Cancel
Save