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

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

+ 15
- 26
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();
} }


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

+ 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 (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



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

+ 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