blob: aa082a5ee1db95ee74b678b6f2e6aad86b740865 [file] [log] [blame]
/*
* Copyright (c) 2007-2013, 2015 Eike Stepper (Berlin, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eike Stepper - initial API and implementation
* Kai Schlamp - bug 282976: [DB] Influence Mappings through EAnnotations
*/
package org.eclipse.net4j.db;
import org.eclipse.net4j.util.io.ExtendedDataInput;
import org.eclipse.net4j.util.io.ExtendedDataOutput;
import org.eclipse.net4j.util.io.ExtendedIOUtil;
import org.eclipse.net4j.util.io.IOUtil;
import org.eclipse.net4j.util.io.TMPUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Enumerates the SQL data types that are compatible with the DB framework.
*
* @author Eike Stepper
* @noextend This interface is not intended to be extended by clients.
*/
public enum DBType
{
BOOLEAN(16)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
return writeValueBoolean(out, resultSet, column, canBeNull);
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
return readValueBoolean(in, statement, column, canBeNull, getCode());
}
},
BIT(-7)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
return writeValueBoolean(out, resultSet, column, canBeNull);
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
return readValueBoolean(in, statement, column, canBeNull, getCode());
}
},
TINYINT(-6)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
byte value = resultSet.getByte(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeBoolean(false);
return null;
}
out.writeBoolean(true);
}
out.writeByte(value);
return value;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
if (canBeNull && !in.readBoolean())
{
statement.setNull(column, getCode());
return null;
}
byte value = in.readByte();
statement.setByte(column, value);
return value;
}
},
SMALLINT(5)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
short value = resultSet.getShort(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeBoolean(false);
return null;
}
out.writeBoolean(true);
}
out.writeShort(value);
return value;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
if (canBeNull && !in.readBoolean())
{
statement.setNull(column, getCode());
return null;
}
short value = in.readShort();
statement.setShort(column, value);
return value;
}
},
INTEGER(4)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
int value = resultSet.getInt(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeBoolean(false);
return null;
}
out.writeBoolean(true);
}
out.writeInt(value);
return value;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
if (canBeNull && !in.readBoolean())
{
statement.setNull(column, getCode());
return null;
}
int value = in.readInt();
statement.setInt(column, value);
return value;
}
},
BIGINT(-5)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
long value = resultSet.getLong(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeBoolean(false);
return null;
}
out.writeBoolean(true);
}
out.writeLong(value);
return value;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
if (canBeNull && !in.readBoolean())
{
statement.setNull(column, getCode());
return null;
}
long value = in.readLong();
statement.setLong(column, value);
return value;
}
},
FLOAT(6)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
float value = resultSet.getFloat(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeBoolean(false);
return null;
}
out.writeBoolean(true);
}
out.writeFloat(value);
return value;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
if (canBeNull && !in.readBoolean())
{
statement.setNull(column, getCode());
return null;
}
float value = in.readFloat();
statement.setFloat(column, value);
return value;
}
},
REAL(7)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
float value = resultSet.getFloat(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeBoolean(false);
return null;
}
out.writeBoolean(true);
}
out.writeFloat(value);
return value;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
if (canBeNull && !in.readBoolean())
{
statement.setNull(column, getCode());
return null;
}
float value = in.readFloat();
statement.setFloat(column, value);
return value;
}
},
DOUBLE(8)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
double value = resultSet.getDouble(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeBoolean(false);
return null;
}
out.writeBoolean(true);
}
out.writeDouble(value);
return value;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
if (canBeNull && !in.readBoolean())
{
statement.setNull(column, getCode());
return null;
}
double value = in.readDouble();
statement.setDouble(column, value);
return value;
}
},
NUMERIC(2)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
throw new UnsupportedOperationException("SQL NULL has to be considered");
// BigDecimal value = resultSet.getBigDecimal(column);
// BigInteger valueUnscaled = value.unscaledValue();
//
// byte[] byteArray = valueUnscaled.toByteArray();
// out.writeInt(byteArray.length);
// out.write(byteArray);
// out.writeInt(value.scale());
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
throw new UnsupportedOperationException("SQL NULL has to be considered");
// byte[] bytes = in.readByteArray();
// int scale = in.readInt();
// BigInteger valueUnscaled = new BigInteger(bytes);
// BigDecimal value = new BigDecimal(valueUnscaled, scale);
//
// // TODO: Read out the precision, scale information and bring the big decimal to the correct form.
// statement.setBigDecimal(column, value);
}
},
DECIMAL(3)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
throw new UnsupportedOperationException("SQL NULL has to be considered");
// BigDecimal value = resultSet.getBigDecimal(column);
// BigInteger valueUnscaled = value.unscaledValue();
//
// byte[] byteArray = valueUnscaled.toByteArray();
// out.writeInt(byteArray.length);
// out.write(byteArray);
// out.writeInt(value.scale());
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
throw new UnsupportedOperationException("SQL NULL has to be considered");
// byte[] bytes = in.readByteArray();
// int scale = in.readInt();
//
// BigInteger valueUnscaled = new BigInteger(bytes);
// BigDecimal value = new BigDecimal(valueUnscaled, scale);
// statement.setBigDecimal(column, value);
}
},
CHAR(1)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
String value = resultSet.getString(column);
out.writeString(value);
return value;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
String value = in.readString();
statement.setString(column, value);
return value;
}
},
VARCHAR(12)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
String value = resultSet.getString(column);
out.writeString(value);
return value;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
String value = in.readString();
statement.setString(column, value);
return value;
}
},
LONGVARCHAR(-1, "LONG VARCHAR") //$NON-NLS-1$
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
String value = resultSet.getString(column);
out.writeString(value);
return value;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
String value = in.readString();
statement.setString(column, value);
return value;
}
},
CLOB(2005)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
Reader value = null;
try
{
value = resultSet.getCharacterStream(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeBoolean(false);
return null;
}
out.writeBoolean(true);
}
return ExtendedIOUtil.writeCharacterStream(out, value);
}
finally
{
IOUtil.close(value);
}
}
@Override
public Object readValueWithResult(final ExtendedDataInput in, PreparedStatement statement, int column,
boolean canBeNull) throws SQLException, IOException
{
if (canBeNull && !in.readBoolean())
{
statement.setNull(column, getCode());
return null;
}
ReaderWithLength value = ReaderWithLength.create(in);
long length = value.getLength();
statement.setCharacterStream(column, value, (int)length);
return length;
}
},
DATE(91)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
java.sql.Date value = resultSet.getDate(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeBoolean(false);
return null;
}
out.writeBoolean(true);
}
long longValue = value.getTime();
out.writeLong(longValue);
return longValue;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
if (canBeNull && !in.readBoolean())
{
statement.setNull(column, getCode());
return null;
}
long value = in.readLong();
statement.setDate(column, new java.sql.Date(value));
return value;
}
},
TIME(92)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
java.sql.Time value = resultSet.getTime(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeBoolean(false);
return null;
}
out.writeBoolean(true);
}
long longValue = value.getTime();
out.writeLong(longValue);
return longValue;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
if (canBeNull && !in.readBoolean())
{
statement.setNull(column, getCode());
return null;
}
long value = in.readLong();
statement.setTime(column, new java.sql.Time(value));
return value;
}
},
TIMESTAMP(93)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
java.sql.Timestamp value = resultSet.getTimestamp(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeBoolean(false);
return null;
}
out.writeBoolean(true);
}
out.writeLong(value.getTime());
out.writeInt(value.getNanos());
return value;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
if (canBeNull && !in.readBoolean())
{
statement.setNull(column, getCode());
return null;
}
long value = in.readLong();
int nanos = in.readInt();
java.sql.Timestamp timeStamp = new java.sql.Timestamp(value);
timeStamp.setNanos(nanos);
statement.setTimestamp(column, timeStamp);
return timeStamp;
}
},
BINARY(-2)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
byte[] value = resultSet.getBytes(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeBoolean(false);
return null;
}
out.writeBoolean(true);
}
out.writeInt(value.length);
out.write(value);
return value;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
if (canBeNull && !in.readBoolean())
{
statement.setNull(column, getCode());
return null;
}
byte[] value = in.readByteArray();
statement.setBytes(column, value);
return value;
}
},
VARBINARY(-3)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
byte[] value = resultSet.getBytes(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeBoolean(false);
return null;
}
out.writeBoolean(true);
}
out.writeInt(value.length);
out.write(value);
return value;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
if (canBeNull && !in.readBoolean())
{
statement.setNull(column, getCode());
return null;
}
byte[] value = in.readByteArray();
statement.setBytes(column, value);
return value;
}
},
LONGVARBINARY(-4, "LONG VARBINARY") //$NON-NLS-1$
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
byte[] value = resultSet.getBytes(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeBoolean(false);
return null;
}
out.writeBoolean(true);
}
out.writeInt(value.length);
out.write(value);
return value;
}
@Override
public Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
if (canBeNull && !in.readBoolean())
{
statement.setNull(column, getCode());
return null;
}
byte[] value = in.readByteArray();
statement.setBytes(column, value);
return value;
}
},
BLOB(2004)
{
@Override
public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
InputStream value = null;
try
{
value = resultSet.getBinaryStream(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeBoolean(false);
return null;
}
out.writeBoolean(true);
}
return ExtendedIOUtil.writeBinaryStream(out, value);
}
finally
{
IOUtil.close(value);
}
}
@Override
public Object readValueWithResult(final ExtendedDataInput in, PreparedStatement statement, int column,
boolean canBeNull) throws SQLException, IOException
{
if (canBeNull && !in.readBoolean())
{
statement.setNull(column, getCode());
return null;
}
InputStreamWithLength value = InputStreamWithLength.create(in);
long length = value.getLength();
statement.setBinaryStream(column, value, (int)length);
return length;
}
};
private static final int BOOLEAN_NULL = -1;
private static final int BOOLEAN_FALSE = 0;
private static final int BOOLEAN_TRUE = 1;
private int code;
private String keyword;
private DBType(int code, String keyword)
{
this.code = code;
this.keyword = keyword;
}
private DBType(int code)
{
this(code, null);
}
public int getCode()
{
return code;
}
public String getKeyword()
{
return keyword == null ? super.toString() : keyword;
}
@Override
public String toString()
{
return getKeyword();
}
/**
* @since 3.0
*/
public void writeValue(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
writeValueWithResult(out, resultSet, column, canBeNull);
}
/**
* @since 4.1
*/
public abstract Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column,
boolean canBeNull) throws SQLException, IOException;
/**
* @since 3.0
*/
public void readValue(ExtendedDataInput in, PreparedStatement statement, int column, boolean canBeNull)
throws SQLException, IOException
{
readValueWithResult(in, statement, column, canBeNull);
}
/**
* @since 4.1
*/
public abstract Object readValueWithResult(ExtendedDataInput in, PreparedStatement statement, int column,
boolean canBeNull) throws SQLException, IOException;
private static Boolean writeValueBoolean(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)
throws SQLException, IOException
{
boolean value = resultSet.getBoolean(column);
if (canBeNull)
{
if (resultSet.wasNull())
{
out.writeByte(BOOLEAN_NULL);
return null;
}
out.writeByte(value ? BOOLEAN_TRUE : BOOLEAN_FALSE);
return value;
}
out.writeBoolean(value);
return value;
}
private static Boolean readValueBoolean(ExtendedDataInput in, PreparedStatement statement, int column,
boolean canBeNull, int sqlType) throws IOException, SQLException
{
if (canBeNull)
{
byte opcode = in.readByte();
switch (opcode)
{
case BOOLEAN_NULL:
statement.setNull(column, sqlType);
return null;
case BOOLEAN_FALSE:
statement.setBoolean(column, false);
return false;
case BOOLEAN_TRUE:
statement.setBoolean(column, true);
return true;
default:
throw new IOException("Invalid boolean opcode: " + opcode);
}
}
boolean value = in.readBoolean();
statement.setBoolean(column, value);
return value;
}
/**
* @since 3.0
*/
public static DBType getTypeByKeyword(String keyword)
{
DBType[] values = DBType.values();
for (int i = 0; i < values.length; i++)
{
DBType dbType = values[i];
if (dbType.getKeyword().equalsIgnoreCase(keyword))
{
return dbType;
}
}
return null;
}
/**
* @since 4.2
*/
public static DBType getTypeByCode(int code)
{
DBType[] values = DBType.values();
for (int i = 0; i < values.length; i++)
{
DBType dbType = values[i];
if (dbType.getCode() == code)
{
return dbType;
}
}
return null;
}
/**
* @author Eike Stepper
*/
private static final class InputStreamWithLength extends FileInputStream
{
private final File file;
private final long length;
private InputStreamWithLength(File file, long length) throws FileNotFoundException
{
super(file);
this.file = file;
this.length = length;
}
public long getLength()
{
return length;
}
@Override
public void close() throws IOException
{
super.close();
file.delete();
}
public static InputStreamWithLength create(final ExtendedDataInput in) throws IOException
{
// new Reader()
// {
// @Override
// public int read(char[] cbuf, int off, int len) throws IOException
// {
// return IOUtil.EOF;
// }
//
// @Override
// public void close() throws IOException
// {
// // Do nothing
// }
// };
FileOutputStream fileOutputStream = null;
try
{
File tempFile = TMPUtil.createTempFile("lob_", ".tmp");
fileOutputStream = new FileOutputStream(tempFile);
long length = ExtendedIOUtil.readBinaryStream(in, fileOutputStream);
return new InputStreamWithLength(tempFile, length);
}
finally
{
IOUtil.close(fileOutputStream);
}
}
}
/**
* @author Eike Stepper
*/
private static final class ReaderWithLength extends FileReader
{
private final File file;
private final long length;
private ReaderWithLength(File file, long length) throws FileNotFoundException
{
super(file);
this.file = file;
this.length = length;
}
public long getLength()
{
return length;
}
@Override
public void close() throws IOException
{
super.close();
file.delete();
}
public static ReaderWithLength create(final ExtendedDataInput in) throws IOException
{
// new Reader()
// {
// @Override
// public int read(char[] cbuf, int off, int len) throws IOException
// {
// return IOUtil.EOF;
// }
//
// @Override
// public void close() throws IOException
// {
// // Do nothing
// }
// };
FileWriter fileWriter = null;
try
{
File tempFile = TMPUtil.createTempFile("lob_", ".tmp");
fileWriter = new FileWriter(tempFile);
long length = ExtendedIOUtil.readCharacterStream(in, fileWriter);
return new ReaderWithLength(tempFile, length);
}
finally
{
IOUtil.close(fileWriter);
}
}
}
}