/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* 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 org.jkiss.dbeaver.model.impl.jdbc.data.handlers;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.model.data.DBDDataFormatter;
import org.jkiss.dbeaver.model.data.DBDDataFormatterProfile;
import org.jkiss.dbeaver.model.data.DBDDisplayFormat;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.exec.DBCResultSet;
import org.jkiss.dbeaver.model.exec.DBCSession;
import org.jkiss.dbeaver.model.exec.DBCStatement;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCPreparedStatement;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCResultSet;
import org.jkiss.dbeaver.model.impl.data.DateTimeCustomValueHandler;
import org.jkiss.dbeaver.model.messages.ModelMessages;
import org.jkiss.dbeaver.model.struct.DBSTypedObject;
import java.sql.SQLException;
import java.sql.Types;
import java.text.Format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* JDBC string value handler
*/
public class JDBCDateTimeValueHandler extends DateTimeCustomValueHandler {
protected static final SimpleDateFormat DEFAULT_DATETIME_FORMAT = new SimpleDateFormat("''" + DBConstants.DEFAULT_TIMESTAMP_FORMAT + "''");
protected static final SimpleDateFormat DEFAULT_DATE_FORMAT = new SimpleDateFormat("''" + DBConstants.DEFAULT_DATE_FORMAT + "''");
protected static final SimpleDateFormat DEFAULT_TIME_FORMAT = new SimpleDateFormat("''" + DBConstants.DEFAULT_TIME_FORMAT + "''");
public JDBCDateTimeValueHandler(DBDDataFormatterProfile formatterProfile)
{
super(formatterProfile);
}
@Override
public Object fetchValueObject(@NotNull DBCSession session, @NotNull DBCResultSet resultSet, @NotNull DBSTypedObject type, int index) throws DBCException {
try {
if (resultSet instanceof JDBCResultSet) {
JDBCResultSet dbResults = (JDBCResultSet) resultSet;
// It seems that some drivers doesn't support reading date/time values with explicit calendar
// So let's use simple version
switch (type.getTypeID()) {
case Types.TIME:
case Types.TIME_WITH_TIMEZONE:
return dbResults.getTime(index + 1);
case Types.DATE:
return dbResults.getDate(index + 1);
default:
return dbResults.getTimestamp(index + 1);
}
} else {
return resultSet.getAttributeValue(index);
}
}
catch (SQLException e) {
if (e.getCause() instanceof ParseException) {
// [SQLite] workaround.
try {
//return getValueFromObject(session, type, ((JDBCResultSet) resultSet).getObject(index + 1), false);
// Do not convert to Date object because table column has STRING type
// and it will be converted in string at late binding stage making incorrect string value: Date.toString()
return ((JDBCResultSet) resultSet).getObject(index + 1);
} catch (SQLException e1) {
// Ignore
log.debug("Can't retrieve datetime object");
}
}
throw new DBCException(e, session.getDataSource());
}
}
@Override
public void bindValueObject(@NotNull DBCSession session, @NotNull DBCStatement statement, @NotNull DBSTypedObject type, int index, @Nullable Object value) throws DBCException {
try {
JDBCPreparedStatement dbStat = (JDBCPreparedStatement)statement;
// JDBC uses 1-based indexes
if (value == null) {
dbStat.setNull(index + 1, type.getTypeID());
} else {
switch (type.getTypeID()) {
case Types.TIME:
case Types.TIME_WITH_TIMEZONE:
dbStat.setTime(index + 1, getTimeValue(value));
break;
case Types.DATE:
dbStat.setDate(index + 1, getDateValue(value));
break;
default:
dbStat.setTimestamp(index + 1, getTimestampValue(value));
break;
}
}
}
catch (SQLException e) {
throw new DBCException(ModelMessages.model_jdbc_exception_could_not_bind_statement_parameter, e);
}
}
@NotNull
@Override
public String getValueDisplayString(@NotNull DBSTypedObject column, Object value, @NotNull DBDDisplayFormat format)
{
if (format == DBDDisplayFormat.NATIVE) {
Format nativeFormat = getNativeValueFormat(column);
if (nativeFormat != null) {
return nativeFormat.format(value);
}
}
return super.getValueDisplayString(column, value, format);
}
@Nullable
protected Format getNativeValueFormat(DBSTypedObject type) {
switch (type.getTypeID()) {
case Types.TIMESTAMP:
return DEFAULT_DATETIME_FORMAT;
case Types.TIMESTAMP_WITH_TIMEZONE:
return DEFAULT_DATETIME_FORMAT;
case Types.TIME:
return DEFAULT_TIME_FORMAT;
case Types.TIME_WITH_TIMEZONE:
return DEFAULT_TIME_FORMAT;
case Types.DATE:
return DEFAULT_DATE_FORMAT;
}
return null;
}
@NotNull
protected String getFormatterId(DBSTypedObject column)
{
switch (column.getTypeID()) {
case Types.TIME: return DBDDataFormatter.TYPE_NAME_TIME;
case Types.DATE: return DBDDataFormatter.TYPE_NAME_DATE;
default: return DBDDataFormatter.TYPE_NAME_TIMESTAMP;
}
}
@Nullable
protected static java.sql.Time getTimeValue(Object value)
{
if (value instanceof java.sql.Time) {
return (java.sql.Time) value;
} else if (value instanceof Date) {
return new java.sql.Time(((Date) value).getTime());
} else if (value != null) {
return java.sql.Time.valueOf(value.toString());
} else {
return null;
}
}
@Nullable
protected static java.sql.Date getDateValue(Object value)
{
if (value instanceof java.sql.Date) {
return (java.sql.Date) value;
} else if (value instanceof Date) {
return new java.sql.Date(((Date) value).getTime());
} else if (value != null) {
return java.sql.Date.valueOf(value.toString());
} else {
return null;
}
}
@Nullable
protected static java.sql.Timestamp getTimestampValue(Object value)
{
if (value instanceof java.sql.Timestamp) {
return (java.sql.Timestamp) value;
} else if (value instanceof Date) {
return new java.sql.Timestamp(((Date) value).getTime());
} else if (value != null) {
return java.sql.Timestamp.valueOf(value.toString());
} else {
return null;
}
}
protected static String getTwoDigitValue(int value)
{
if (value < 10) {
return "0" + value;
} else {
return String.valueOf(value);
}
}
}