/*
*
* SchemaCrawler
* http://sourceforge.net/projects/schemacrawler
* Copyright (c) 2000-2012, Sualeh Fatehi.
*
* 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;
* either version 2.1 of the License, or (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
package schemacrawler.tools.linter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import schemacrawler.schema.Column;
import schemacrawler.schema.ColumnDataType;
import schemacrawler.schema.Table;
import schemacrawler.tools.lint.BaseLinter;
import sf.util.Multimap;
import sf.util.Utility;
public class LinterTableWithIncrementingColumns
extends BaseLinter
{
private class IncrementingColumn
{
private final Integer columnIncrement;
private final Column column;
IncrementingColumn(final String columnNameBase,
final String columnIncrement,
final Column column)
{
if (columnIncrement == null)
{
this.columnIncrement = null;
}
else
{
this.columnIncrement = new Integer(columnIncrement);
}
this.column = column;
}
public Column getColumn()
{
return column;
}
public Integer getColumnIncrement()
{
return columnIncrement;
}
}
@Override
public String getDescription()
{
return getSummary();
}
@Override
public String getSummary()
{
return "incrementing columns";
}
@Override
protected void lint(final Table table)
{
if (table == null)
{
throw new IllegalArgumentException("No table provided");
}
final Multimap<String, IncrementingColumn> incrementingColumns = findIncrementingColumns(table
.getColumns());
for (final List<IncrementingColumn> incrementingColumnsList: incrementingColumns
.values())
{
addIncrementingColumnsLints(table, incrementingColumnsList);
}
}
private void addIncrementingColumnsLints(final Table table,
final List<IncrementingColumn> incrementingColumnsList)
{
int minIncrement = Integer.MAX_VALUE;
int maxIncrement = 0;
final Column[] incrementingColumns = new Column[incrementingColumnsList
.size()];
for (int i = 0; i < incrementingColumnsList.size(); i++)
{
final IncrementingColumn incrementingColumn = incrementingColumnsList
.get(i);
incrementingColumns[i] = incrementingColumn.getColumn();
if (incrementingColumn.getColumnIncrement() != null)
{
minIncrement = Math.min(minIncrement,
incrementingColumn.getColumnIncrement());
maxIncrement = Math.max(maxIncrement,
incrementingColumn.getColumnIncrement());
}
}
Arrays.sort(incrementingColumns);
addLint(table, getSummary(), incrementingColumns);
// Check for increments that are not consecutive
if (maxIncrement - minIncrement + 1 != incrementingColumnsList.size())
{
addLint(table,
"incrementing columns are not consecutive",
incrementingColumns);
}
// Check for consistent column data-types
final ColumnDataType columnDataType = incrementingColumns[0].getType();
final int columnSize = incrementingColumns[0].getSize();
for (int i = 1; i < incrementingColumns.length; i++)
{
if (!columnDataType.equals(incrementingColumns[1].getType())
|| columnSize != incrementingColumns[1].getSize())
{
addLint(table,
"incrementing columns don't have the same data-type",
incrementingColumns);
break;
}
}
}
private Multimap<String, IncrementingColumn> findIncrementingColumns(final Column[] columns)
{
if (columns == null || columns.length <= 1)
{
return new Multimap<String, IncrementingColumn>();
}
final Pattern pattern = Pattern.compile("([^0-9]*)([0-9]+)");
final Map<String, Integer> incrementingColumnsMap = new HashMap<String, Integer>();
for (final Column column: columns)
{
final String columnName = Utility.convertForComparison(column.getName());
incrementingColumnsMap.put(columnName, 1);
final Matcher matcher = pattern.matcher(columnName);
if (matcher.matches())
{
final String columnNameBase = matcher.group(1);
if (incrementingColumnsMap.containsKey(columnNameBase))
{
incrementingColumnsMap
.put(columnNameBase, incrementingColumnsMap.get(columnNameBase) + 1);
}
else
{
incrementingColumnsMap.put(columnNameBase, 1);
}
}
}
final Set<String> columnNameBases = new HashSet<String>(incrementingColumnsMap
.keySet());
for (final String columnNameBase: columnNameBases)
{
if (incrementingColumnsMap.get(columnNameBase) == 1)
{
incrementingColumnsMap.remove(columnNameBase);
}
}
final Multimap<String, IncrementingColumn> incrementingColumns = new Multimap<String, IncrementingColumn>();
for (final Column column: columns)
{
final String columnName = Utility.convertForComparison(column.getName());
if (incrementingColumnsMap.containsKey(columnName))
{
incrementingColumns.add(columnName, new IncrementingColumn(columnName,
"0",
column));
}
final Matcher matcher = pattern.matcher(columnName);
if (matcher.matches())
{
final String columnNameBase = matcher.group(1);
final String columnIncrement = matcher.group(2);
if (incrementingColumnsMap.containsKey(columnNameBase))
{
incrementingColumns.add(columnNameBase,
new IncrementingColumn(columnNameBase,
columnIncrement,
column));
}
}
}
return incrementingColumns;
}
}