package org.test4j.module.dbfit.environment; import java.math.BigDecimal; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Time; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import org.test4j.module.database.environment.DBEnvironment; import org.test4j.module.database.environment.normalise.NameNormaliser; import org.test4j.module.database.utility.DBHelper; import org.test4j.module.dbfit.model.DbParameterAccessor; /** * Encapsulates support for the Derby database (also known as JavaDB). Operates * in Client mode. * * @see EmbeddedDerbyEnvironment */ @SuppressWarnings("rawtypes") public class DbFitDerbyEnvironment extends DbFitAbstractDBEnvironment { public DbFitDerbyEnvironment(DBEnvironment dbEnvironment) { super(dbEnvironment); } private TypeMapper typeMapper = new DerbyTypeMapper(); private static final String paramNamePattern = "@([A-Za-z0-9_]+)"; private static final Pattern paramRegex = Pattern.compile(paramNamePattern); @Override public Pattern getParameterPattern() { return paramRegex; } public Map<String, DbParameterAccessor> getAllColumns(final String tableOrViewName) throws SQLException { String qry = "SELECT COLUMNNAME, COLUMNDATATYPE " + "FROM SYS.SYSCOLUMNS WHERE REFERENCEID = " + "(SELECT TABLEID FROM SYS.SYSTABLES WHERE TABLENAME = ?)"; return readIntoParams(tableOrViewName, qry); } private Map<String, DbParameterAccessor> readIntoParams(String tableOrViewName, String query) throws SQLException { checkConnectionValid(this.connect()); PreparedStatement dc = null; ResultSet rs = null; try { dc = this.connect().prepareStatement(query); dc.setString(1, tableOrViewName); rs = dc.executeQuery(); Map<String, DbParameterAccessor> allParams = new HashMap<String, DbParameterAccessor>(); int position = 0; while (rs.next()) { String columnName = rs.getString(1); String dataType = rs.getString(2); DbParameterAccessor dbp = new DbParameterAccessor(columnName, DbParameterAccessor.INPUT, typeMapper.getJDBCSQLTypeForDBType(dataType), getJavaClass(dataType), position++); allParams.put(NameNormaliser.normaliseName(columnName), dbp); } return allParams; } finally { DBHelper.closeResultSet(rs); rs = null; DBHelper.closeStatement(dc); dc = null; } } public Map<String, DbParameterAccessor> getAllProcedureParameters(String procName) throws SQLException { throw new UnsupportedOperationException(); } public Class getJavaClass(final String dataType) { return typeMapper.getJavaClassForDBType(dataType); } /** * Interface for mapping of db types to java types. */ interface TypeMapper { Class getJavaClassForDBType(final String dbDataType); int getJDBCSQLTypeForDBType(final String dbDataType); } /** * From http://db.apache.org/derby/docs/10.4/ref/ref-single.html */ public static class DerbyTypeMapper implements TypeMapper { private static final List<String> stringTypes = Arrays.asList(new String[] { "CHAR", "CHARACTER", "LONG VARCHAR", "VARCHAR", "XML", "CHAR VARYING", "CHARACTER VARYING", "LONG VARCHAR FOR BIT DATA", "VARCHAR FOR BIT DATA" }); private static final List<String> intTypes = Arrays.asList(new String[] { "INTEGER", "INT" }); private static final List<String> longTypes = Arrays.asList(new String[] { "BIGINT", }); private static final List<String> doubleTypes = Arrays.asList(new String[] { "DOUBLE", "DOUBLE PRECISION", "FLOAT" }); private static final List<String> floatTypes = Arrays.asList(new String[] { "REAL" }); private static final List<String> shortTypes = Arrays.asList(new String[] { "SMALLINT" }); private static final List<String> decimalTypes = Arrays.asList(new String[] { "DECIMAL", "DEC", "NUMERIC" }); private static final List<String> dateTypes = Arrays.asList(new String[] { "DATE" }); private static final List<String> timestampTypes = Arrays.asList(new String[] { "TIMESTAMP", }); private static final List<String> timeTypes = Arrays.asList(new String[] { "TIME" }); public Class getJavaClassForDBType(final String dbDataType) { String dataType = normaliseTypeName(dbDataType); if (stringTypes.contains(dataType)) return String.class; if (decimalTypes.contains(dataType)) return BigDecimal.class; if (intTypes.contains(dataType)) return Integer.class; if (timeTypes.contains(dataType)) return Time.class; if (dateTypes.contains(dataType)) return java.sql.Date.class; if (floatTypes.contains(dataType)) return Float.class; if (shortTypes.contains(dataType)) return Short.class; if (doubleTypes.contains(dataType)) return Double.class; if (longTypes.contains(dataType)) return Long.class; if (timestampTypes.contains(dataType)) return java.sql.Timestamp.class; throw new UnsupportedOperationException("Type '" + dbDataType + "' is not supported for Derby"); } public int getJDBCSQLTypeForDBType(final String dbDataType) { String dataType = normaliseTypeName(dbDataType); if (stringTypes.contains(dataType)) return java.sql.Types.VARCHAR; if (decimalTypes.contains(dataType)) return java.sql.Types.DECIMAL; if (intTypes.contains(dataType) || shortTypes.contains(dataType)) return java.sql.Types.INTEGER; if (floatTypes.contains(dataType)) return java.sql.Types.FLOAT; if (doubleTypes.contains(dataType)) return java.sql.Types.DOUBLE; if (longTypes.contains(dataType)) return java.sql.Types.BIGINT; if (timestampTypes.contains(dataType)) return java.sql.Types.TIMESTAMP; if (timeTypes.contains(dataType)) return java.sql.Types.TIME; if (dateTypes.contains(dataType)) return java.sql.Types.DATE; throw new UnsupportedOperationException("Type '" + dbDataType + "' is not supported for Derby"); } private static String normaliseTypeName(String type) { if (type != null && !"".equals(type)) { String dataType = type.toUpperCase().trim(); // remove any size declarations such as CHAR(nn) int idxLeftPara = dataType.indexOf('('); if (idxLeftPara > 0) { dataType = dataType.substring(0, idxLeftPara); } // remove any modifiers such as CHAR NOT NULL, but keep support // for INTEGER UNSIGNED. Yes, I know this is funky coding, but // it works, just see the unit tests! ;) idxLeftPara = dataType.indexOf(" NOT NULL"); if (idxLeftPara > 0) { dataType = dataType.substring(0, idxLeftPara); } idxLeftPara = dataType.indexOf(" NULL"); if (idxLeftPara > 0) { dataType = dataType.substring(0, idxLeftPara); } return dataType; } else { throw new IllegalArgumentException("You must specify a valid type for conversions"); } } } public String getFieldQuato() { return ""; } }