package org.hibernate.cfg.reveng;
import java.sql.DatabaseMetaData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.hibernate.JDBCException;
import org.hibernate.cfg.JDBCBinderException;
import org.hibernate.cfg.reveng.dialect.MetaDataDialect;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Index;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UniqueKey;
import org.hibernate.tool.util.TableNameQualifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class IndexProcessor {
private static final Logger log = LoggerFactory.getLogger(IndexProcessor.class);
public static void processIndices(
MetaDataDialect metaDataDialect,
String defaultSchema,
String defaultCatalog,
Table table) {
Map<String, Index> indexes = new HashMap<String, Index>(); // indexname (String) -> Index
Map<String, UniqueKey> uniquekeys = new HashMap<String, UniqueKey>(); // name (String) -> UniqueKey
Map<Column, List<UniqueKey>> uniqueColumns = new HashMap<Column, List<UniqueKey>>(); // Column -> List<Index>
Iterator<Map<String, Object>> indexIterator = null;
try {
Map<String,Object> indexRs = null;
indexIterator = metaDataDialect.getIndexInfo(getCatalogForDBLookup(table.getCatalog(), defaultCatalog), getSchemaForDBLookup(table.getSchema(), defaultSchema), table.getName());
while (indexIterator.hasNext() ) {
indexRs = indexIterator.next();
String indexName = (String) indexRs.get("INDEX_NAME");
String columnName = (String) indexRs.get("COLUMN_NAME");
boolean unique = !((Boolean)indexRs.get("NON_UNIQUE")).booleanValue();
if (columnName != null || indexName != null) { // both can be non-null with statistical indexs which we don't have any use for.
if(unique) {
UniqueKey key = uniquekeys.get(indexName);
if (key==null) {
key = new UniqueKey();
key.setName(indexName);
key.setTable(table);
table.addUniqueKey(key);
uniquekeys.put(indexName, key);
}
if(indexes.containsKey(indexName) ) {
throw new JDBCBinderException("UniqueKey exists also as Index! ");
}
Column column = getColumn(metaDataDialect, table, columnName);
key.addColumn(column);
if (unique && key.getColumnSpan()==1) {
// make list of columns that has the chance of being unique
List<UniqueKey> l = uniqueColumns.get(column);
if (l == null) {
l = new ArrayList<UniqueKey>();
uniqueColumns.put(column, l);
}
l.add(key);
}
}
else {
Index index = indexes.get(indexName);
if(index==null) {
index = new Index();
index.setName(indexName);
index.setTable(table);
table.addIndex(index);
indexes.put(indexName, index);
}
if(uniquekeys.containsKey(indexName) ) {
throw new JDBCBinderException("Index exists also as Unique! ");
}
Column column = getColumn(metaDataDialect, table, columnName);
index.addColumn(column);
}
}
else {
if(DatabaseMetaData.tableIndexStatistic != ((Short)indexRs.get("TYPE")).shortValue() ) {
log.warn("Index was not statistical, but no column name was found in " + indexName);
}
}
}
}
catch (JDBCException t) {
log.warn("Exception while trying to get indexinfo on " + TableNameQualifier.qualify(table.getCatalog(), table.getSchema(), table.getName() ) + "=" + t.getMessage() );
// Bug #604761 Oracle getIndexInfo() needs major grants And other dbs sucks too ;)
// http://sourceforge.net/tracker/index.php?func=detail&aid=604761&group_id=36044&atid=415990
}
finally {
if (indexIterator != null) {
try {
metaDataDialect.close(indexIterator);
} catch(JDBCException se) {
log.warn("Exception while trying to close resultset for index meta data",se);
}
}
}
// mark columns that are unique TODO: multiple columns are not unique on their own.
Iterator<Entry<Column, List<UniqueKey>>> uniqueColumnIterator = uniqueColumns.entrySet().iterator();
while (uniqueColumnIterator.hasNext() ) {
Entry<Column, List<UniqueKey>> entry = uniqueColumnIterator.next();
Column col = entry.getKey();
Iterator<UniqueKey> keys = entry.getValue().iterator();
while (keys.hasNext() ) {
UniqueKey key = keys.next();
if(key.getColumnSpan()==1) {
col.setUnique(true);
}
}
}
Iterator<Entry<String, UniqueKey>> iterator = uniquekeys.entrySet().iterator();
while(iterator.hasNext()) {
// if keyset has no overlaps with primary key (table.getPrimaryKey())
// if only key matches then mark as setNaturalId(true);
iterator.next();
}
}
private static String getCatalogForDBLookup(String catalog, String defaultCatalog) {
return catalog==null?defaultCatalog:catalog;
}
private static String getSchemaForDBLookup(String schema, String defaultSchema) {
return schema==null?defaultSchema:schema;
}
private static Column getColumn(MetaDataDialect metaDataDialect, Table table, String columnName) {
Column column = new Column();
column.setName(quote(columnName, metaDataDialect));
Column existing = table.getColumn(column);
if(existing!=null) {
column = existing;
}
return column;
}
private static String quote(String columnName, MetaDataDialect metaDataDialect) {
if(columnName==null) return columnName;
if(metaDataDialect.needQuote(columnName)) {
if(columnName.length()>1 && columnName.charAt(0)=='`' && columnName.charAt(columnName.length()-1)=='`') {
return columnName; // avoid double quoting
}
return "`" + columnName + "`";
} else {
return columnName;
}
}
}