/*
* Copyright (c) 2008, SQL Power Group Inc.
*
* This file is part of SQL Power Library.
*
* SQL Power Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* SQL Power 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ca.sqlpower.sql.jdbcwrapper;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;
import ca.sqlpower.sql.CachedRowSet;
import ca.sqlpower.sql.SQL;
public class SQLServerDatabaseMetaDataDecorator extends DatabaseMetaDataDecorator {
private static final Logger logger = Logger.getLogger(SQLServerDatabaseMetaDataDecorator.class);
public SQLServerDatabaseMetaDataDecorator(DatabaseMetaData delegate, ConnectionDecorator connectionDecorator) {
super(delegate, connectionDecorator);
}
/**
* Augments the Microsoft-supplied getColumns() result set with the JDBC4
* IS_AUTOINCREMENT column. The value of this extra column is determined by
* the presence of the substring <code>" identity"</code> in the column's type name.
*/
@Override
public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException {
ResultSet rs = super.getColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern);
CachedRowSet crs = new CachedRowSet();
boolean fudgeAutoInc = SQL.findColumnIndex(rs, "IS_AUTOINCREMENT") == -1;
if (fudgeAutoInc) {
crs.populate(rs, null, "IS_AUTOINCREMENT");
} else {
crs.populate(rs);
}
rs.close();
if (fudgeAutoInc) {
int autoIncColNum = crs.findColumn("IS_AUTOINCREMENT");
int defaultColNum = crs.findColumn("COLUMN_DEF");
while (crs.next()) {
// populate auto-increment column
if (logger.isDebugEnabled()) {
logger.debug("Examining col " + crs.getString(4) + " (" + crs.getString(6) + ")");
}
if (crs.getString(6) != null && crs.getString(6).toLowerCase().indexOf(" identity") >= 0) {
crs.updateString(autoIncColNum, "YES");
logger.debug(" AUTO-INC!");
} else {
crs.updateString(autoIncColNum, "NO");
logger.debug(" NOT AUTO-INC!");
}
// strip parentheses from default values (see bug 1693)
crs.updateString(defaultColNum, stripParens(crs.getString(defaultColNum)));
}
crs.beforeFirst();
}
return crs;
}
/**
* SQL Server tends to put parentheses around column default values, and we
* have to strip them off in this wrapper to provide forward-engineering
* compatibility with other platforms (notably MySQL). This method is used
* by the getColumns() wrapper to strip off those parentheses.
* <p>
* See <a href="http://trillian.sqlpower.ca/bugzilla/show_bug.cgi?id=1693">bug
* 1693</a> for details.
*
* @param original
* The original default value, which might be surrounded by one
* or more balanced sets of parentheses. This argument may be null,
* in which case null will be returned.
* @return The original value with all balanced sets of parentheses that
* completely surrounded the value removed. If the original value
* was null, the return value will be null.
*/
public static String stripParens(String original) {
if (original == null) return null;
Pattern p = Pattern.compile("\\((.*)\\)");
Matcher m = p.matcher(original);
while (m.matches()) {
original = m.group(1);
m = p.matcher(original);
}
return original;
}
@Override
protected ResultSetDecorator wrap (ResultSet rs) throws SQLException {
return new SQLServerResultSetDecorator(wrap(rs.getStatement()), rs);
}
@Override
protected StatementDecorator wrap (Statement statement) {
return new SQLServerStatementDecorator(connectionDecorator, statement);
}
}