/*
*
* SchemaCrawler
* http://sourceforge.net/projects/schemacrawler
* Copyright (c) 2000-2013, 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.ArrayList;
import java.util.Collections;
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 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 ArrayList<Column> incrementingColumns = new ArrayList<>(incrementingColumnsList
.size());
for (int i = 0; i < incrementingColumnsList.size(); i++)
{
final IncrementingColumn incrementingColumn = incrementingColumnsList
.get(i);
incrementingColumns.add(i, incrementingColumn.getColumn());
if (incrementingColumn.getColumnIncrement() != null)
{
minIncrement = Math.min(minIncrement,
incrementingColumn.getColumnIncrement());
maxIncrement = Math.max(maxIncrement,
incrementingColumn.getColumnIncrement());
}
}
Collections.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.get(0)
.getColumnDataType();
final int columnSize = incrementingColumns.get(0).getSize();
for (int i = 1; i < incrementingColumns.size(); i++)
{
if (!columnDataType
.equals(incrementingColumns.get(i).getColumnDataType())
|| columnSize != incrementingColumns.get(i).getSize())
{
addLint(table,
"incrementing columns don't have the same data-type",
incrementingColumns);
break;
}
}
}
private Multimap<String, IncrementingColumn> findIncrementingColumns(final List<Column> columns)
{
if (columns == null || columns.size() <= 1)
{
return new Multimap<>();
}
final Pattern pattern = Pattern.compile("(.*[^0-9])([0-9]+)");
final Map<String, Integer> incrementingColumnsMap = new HashMap<>();
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<>(incrementingColumnsMap
.keySet());
for (final String columnNameBase: columnNameBases)
{
if (incrementingColumnsMap.get(columnNameBase) == 1)
{
incrementingColumnsMap.remove(columnNameBase);
}
}
final Multimap<String, IncrementingColumn> incrementingColumns = new Multimap<>();
for (final Column column: columns)
{
final String columnName = Utility.convertForComparison(column.getName());
if (incrementingColumnsMap.containsKey(columnName))
{
incrementingColumns
.add(columnName, new IncrementingColumn("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(columnIncrement,
column));
}
}
}
return incrementingColumns;
}
}