/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* 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.
*/
package com.liferay.portal.verify;
import com.liferay.portal.kernel.dao.db.DB;
import com.liferay.portal.kernel.dao.db.DBManagerUtil;
import com.liferay.portal.kernel.dao.db.DBType;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.LoggingTimer;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
/**
* @author Douglas Wong
*/
public class VerifySQLServer extends VerifyProcess {
protected void convertColumnsToUnicode() {
try (LoggingTimer loggingTimer = new LoggingTimer()) {
dropNonunicodeTableIndexes();
StringBundler sb = new StringBundler(12);
sb.append("select sysobjects.name as table_name, syscolumns.name ");
sb.append("AS column_name, systypes.name as data_type, ");
sb.append("syscolumns.length, syscolumns.isnullable as ");
sb.append("is_nullable FROM sysobjects inner join syscolumns on ");
sb.append("sysobjects.id = syscolumns.id inner join systypes on ");
sb.append("syscolumns.xtype = systypes.xtype where ");
sb.append("(sysobjects.xtype = 'U') and (sysobjects.category != ");
sb.append("2) and ");
sb.append(_FILTER_NONUNICODE_DATA_TYPES);
sb.append(" and ");
sb.append(_FILTER_EXCLUDED_TABLES);
sb.append(" order by sysobjects.name, syscolumns.colid");
String sql = sb.toString();
try (PreparedStatement ps = connection.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
String tableName = rs.getString("table_name");
if (!isPortalTableName(tableName)) {
continue;
}
String columnName = rs.getString("column_name");
String dataType = rs.getString("data_type");
int length = rs.getInt("length");
boolean nullable = rs.getBoolean("is_nullable");
if (dataType.equals("varchar")) {
convertVarcharColumn(
tableName, columnName, length, nullable);
}
else if (dataType.equals("ntext") ||
dataType.equals("text")) {
convertTextColumn(tableName, columnName, nullable);
}
}
for (String addPrimaryKeySQL : _addPrimaryKeySQLs) {
runSQL(addPrimaryKeySQL);
}
}
catch (Exception e) {
_log.error(e, e);
}
}
}
protected void convertTextColumn(
String tableName, String columnName, boolean nullable)
throws Exception {
if (_log.isInfoEnabled()) {
_log.info(
"Updating " + tableName + "." + columnName + " to use " +
"nvarchar(max)");
}
StringBundler sb = new StringBundler(4);
sb.append("alter table ");
sb.append(tableName);
sb.append(" add temp nvarchar(max)");
if (!nullable) {
sb.append(" not null");
}
runSQL(sb.toString());
runSQL("update " + tableName + " set temp = " + columnName);
runSQL("alter table " + tableName + " drop column " + columnName);
runSQL(
"exec sp_rename \'" + tableName + ".temp\', \'" + columnName +
"\', \'column\'");
}
protected void convertVarcharColumn(
String tableName, String columnName, int length, boolean nullable)
throws Exception {
if (_log.isInfoEnabled()) {
_log.info(
"Updating " + tableName + "." + columnName +
" to use nvarchar");
}
StringBundler sb = new StringBundler(8);
sb.append("alter table ");
sb.append(tableName);
sb.append(" alter column ");
sb.append(columnName);
sb.append(" nvarchar(");
if (length == -1) {
sb.append("max");
}
else {
sb.append(length);
}
sb.append(StringPool.CLOSE_PARENTHESIS);
if (!nullable) {
sb.append(" not null");
}
runSQL(sb.toString());
}
@Override
protected void doVerify() throws Exception {
DB db = DBManagerUtil.getDB();
if (db.getDBType() != DBType.SQLSERVER) {
return;
}
convertColumnsToUnicode();
}
protected void dropNonunicodeTableIndexes() {
StringBundler sb = new StringBundler(14);
sb.append("select distinct sysobjects.name as table_name, ");
sb.append("sysindexes.name as index_name FROM sysobjects inner join ");
sb.append("sysindexes on sysobjects.id = sysindexes.id inner join ");
sb.append("syscolumns on sysobjects.id = syscolumns.id inner join ");
sb.append("sysindexkeys on ((sysobjects.id = sysindexkeys.id) and ");
sb.append("(syscolumns.colid = sysindexkeys.colid) and ");
sb.append("(sysindexes.indid = sysindexkeys.indid)) inner join ");
sb.append("systypes on syscolumns.xtype = systypes.xtype where ");
sb.append("(sysobjects.type = 'U') and (sysobjects.category != 2) ");
sb.append("and ");
sb.append(_FILTER_NONUNICODE_DATA_TYPES);
sb.append(" and ");
sb.append(_FILTER_EXCLUDED_TABLES);
sb.append(" order by sysobjects.name, sysindexes.name");
String sql = sb.toString();
try (PreparedStatement ps = connection.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
String tableName = rs.getString("table_name");
if (!isPortalTableName(tableName)) {
continue;
}
String indexName = rs.getString("index_name");
if (_log.isInfoEnabled()) {
_log.info("Dropping index " + tableName + "." + indexName);
}
String indexNameUpperCase = StringUtil.toUpperCase(indexName);
if (indexNameUpperCase.startsWith("PK")) {
String primaryKeyColumnNames = StringUtil.merge(
getPrimaryKeyColumnNames(indexName));
runSQL(
"alter table " + tableName + " drop constraint " +
indexName);
_addPrimaryKeySQLs.add(
"alter table " + tableName + " add primary key (" +
primaryKeyColumnNames + ")");
}
else {
runSQL("drop index " + indexName + " on " + tableName);
}
}
}
catch (Exception e) {
_log.error(e, e);
}
}
protected List<String> getPrimaryKeyColumnNames(String indexName) {
List<String> columnNames = new ArrayList<>();
StringBundler sb = new StringBundler(9);
sb.append("select distinct syscolumns.name as column_name from ");
sb.append("sysobjects inner join syscolumns on sysobjects.id = ");
sb.append("syscolumns.id inner join sysindexes on sysobjects.id = ");
sb.append("sysindexes.id inner join sysindexkeys on ((sysobjects.id ");
sb.append("= sysindexkeys.id) and (syscolumns.colid = ");
sb.append("sysindexkeys.colid) and (sysindexes.indid = ");
sb.append("sysindexkeys.indid)) where sysindexes.name = '");
sb.append(indexName);
sb.append("'");
String sql = sb.toString();
try (PreparedStatement ps = connection.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
String columnName = rs.getString("column_name");
columnNames.add(columnName);
}
}
catch (Exception e) {
_log.error(e, e);
}
return columnNames;
}
private static final String _FILTER_EXCLUDED_TABLES =
"(sysobjects.name not like 'Counter') and (sysobjects.name not like " +
"'QUARTZ%')";
private static final String _FILTER_NONUNICODE_DATA_TYPES =
"((systypes.name = 'ntext') OR (systypes.name = 'text') OR " +
"(systypes.name = 'varchar'))";
private static final Log _log = LogFactoryUtil.getLog(
VerifySQLServer.class);
private final List<String> _addPrimaryKeySQLs = new ArrayList<>();
}