/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2011-2013, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.db.reverse; import java.math.BigDecimal; import java.math.BigInteger; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.apache.sis.feature.FeatureExt; import org.apache.sis.storage.DataStoreException; import org.geotoolkit.db.DefaultJDBCFeatureStore; import org.geotoolkit.db.JDBCFeatureStoreUtilities; import org.geotoolkit.db.dialect.SQLDialect; /** * Description of a table column. * * @author Johann Sorel (Geomatys) */ public class ColumnMetaModel { public static enum Type{ /** value is automaticaly generated by the database */ AUTO, /** value will not be generated by the database, must be provided */ NON_INCREMENTING, /** value is automaticaly generated by the database using a sequence */ SEQUENCED } private final String schema; private final String table; private final String name; private final int sqlType; private final String sqlTypeName; private final Class clazz; private final Type type; private final String sequenceName; /** * @param name column name * @param sqlType sql type * @param sqlTypeName sql type name * @param clazz best java matching type * @param type if column is a primary key column, define how value is found */ public ColumnMetaModel(String schema, String table, String name, int sqlType, String sqlTypeName, Class clazz, Type type) { this(schema, table, name,sqlType,sqlTypeName,clazz,type,null); } /** * @param name column name * @param sqlType sql type * @param sqlTypeName sql type name * @param clazz best java matching type * @param type if column is a primary key column, define how value is found * @param sequenceName the sequence name if type SEQUENCED */ public ColumnMetaModel(String schema, String table, String name, int sqlType, String sqlTypeName, Class clazz, Type type, String sequenceName) { this.schema = schema; this.table = table; this.name = name; this.sqlType = sqlType; this.sqlTypeName = sqlTypeName; this.clazz = clazz; this.type = type; this.sequenceName = sequenceName; } public String getSchema() { return schema; } public String getTable() { return table; } public String getName() { return name; } public int getSqlType() { return sqlType; } public String getSqlTypeName() { return sqlTypeName; } public Class getJavaType() { return clazz; } public Type getType() { return type; } public String getSequenceName() { return sequenceName; } @Override public String toString() { final StringBuilder sb = new StringBuilder(name); sb.append('['); sb.append(sqlType); sb.append(','); sb.append(sqlTypeName); sb.append(','); sb.append(type); sb.append(']'); return sb.toString(); } /** * Calculate the next column value. */ public Object nextColumnValue(final DefaultJDBCFeatureStore store, final Connection cx) throws SQLException, DataStoreException { Object next = null; final SQLDialect dialect = store.getDialect(); if(type == Type.AUTO){ next = dialect.nextValue(this, cx); } else if(type == Type.SEQUENCED){ next = dialect.nextValue(this, cx); } else { // generate a default value if possible if (Number.class.isAssignableFrom(clazz)) { //search the max value. final StringBuilder sql = new StringBuilder(); sql.append("SELECT MAX("); dialect.encodeColumnName(sql, getName()); sql.append(") FROM "); dialect.encodeSchemaAndTableName(sql, schema, table); final Statement st = cx.createStatement(); ResultSet rs = null; try { rs = st.executeQuery(sql.toString()); rs.next(); next = rs.getObject(1); } finally { JDBCFeatureStoreUtilities.closeSafe(store.getLogger(),null, st, rs); } if(next == null){ // This probably means there was no data in the table, set to 1 // TODO: probably better to do a count to check... but if this // value already exists the db will throw an error when it tries // to insert next = 1; }else if (clazz == Short.class || clazz == Integer.class || clazz == Long.class || BigInteger.class.isAssignableFrom(clazz) || BigDecimal.class.isAssignableFrom(clazz) ) { next = ((Number)next).longValue() +1; }else if (clazz == Float.class){ next = Math.nextUp( ((Number)next).floatValue() ); }else if (clazz == Double.class){ next = Math.nextUp( ((Number)next).doubleValue() ); }else{ //can't calculate for other types next = 1; } } else if (CharSequence.class.isAssignableFrom(clazz)) { //generate a random string next = FeatureExt.createDefaultFeatureId(); } if (next == null) { throw new DataStoreException("Cannot generate key value for column of type: " + clazz.getName()); } } return next; } }