/*
* Copyright 2000-2013 Enonic AS
* http://www.enonic.com/license
*/
package com.enonic.cms.upgrade.task;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.util.StringUtils;
import com.enonic.cms.framework.jdbc.dialect.Db2Dialect;
import com.enonic.cms.upgrade.UpgradeContext;
final class UpgradeModel0212
extends AbstractUpgradeTask
{
public UpgradeModel0212()
{
super( 212 );
}
@Override
protected boolean canModelUpgrade( UpgradeContext context )
{
context.logInfo( "Looking for columns in the database that have length 256 and value more than 255 characters and are indexed..." );
final Map<LargeIndexedColumn, List<String>> xtraLarges = new HashMap<LargeIndexedColumn, List<String>>();
try
{
for ( LargeIndexedColumn column : LargeIndexedColumn.values() )
{
List<String> keys = column.query( context );
if ( !keys.isEmpty() )
{
xtraLarges.put( column, keys );
}
}
if ( xtraLarges.isEmpty() )
{
context.logInfo( "Upgrade check ok." );
return true;
}
String plural = ( xtraLarges.size() == 1) ? "" : "s";
context.logWarning( "Column" + plural + " with value more than 255 characters found:" );
for ( Map.Entry<LargeIndexedColumn, List<String>> xtraLarge : xtraLarges.entrySet() )
{
final LargeIndexedColumn column = xtraLarge.getKey();
final List<String> ids = xtraLarge.getValue();
final String message = column.message( context, ids );
context.logWarning( message );
}
context.logWarning( "\nThe length of value in column" + plural + " above will be reduced." );
}
catch ( Exception ex )
{
context.logError( ex.getMessage(), ex );
return false;
}
return true;
}
private enum LargeIndexedColumn
{
bda_sFileName
{
String getTable()
{
return "tBinaryData";
}
String getIdColumn()
{
return "bda_lKey";
}
},
cat_sName
{
String getTable()
{
return "tCategory";
}
String getIdColumn()
{
return "cat_lKey";
}
},
han_sClass
{
String getTable()
{
return "tContentHandler";
}
String getIdColumn()
{
return "han_lKey";
}
},
cob_sName
{
String getTable()
{
return "tContentObject";
}
String getIdColumn()
{
return "cob_lKey";
}
},
cov_sTitle
{
String getTable()
{
return "tContentVersion";
}
String getIdColumn()
{
return "cov_lKey";
}
@Override
String message( final UpgradeContext context, final List<String> ids )
throws Exception
{
List<String> keyPair = new ArrayList<String>();
for ( String covlKey : ids )
{
String sql = "SELECT cov_con_lKey FROM tContentVersion WHERE cov_lKey = " + covlKey;
List<String> conlKeys = context.getJdbcTemplate().query( sql, new IdExtractor( "cov_con_lKey" ) );
keyPair.add( covlKey + ":" + conlKeys.get( 0 ) );
}
return "\nTable [" + this.getTable() + "], Column [" + this.name() + "], ID [" + this.getIdColumn() + ":con_lKey] = '" +
StringUtils.collectionToCommaDelimitedString( keyPair ) + "'";
}
},
grp_sName
{
String getTable()
{
return "tGroup";
}
String getIdColumn()
{
return "grp_hKey";
}
},
mei_sName
{
String getTable()
{
return "tMenuItem";
}
String getIdColumn()
{
return "mei_lKey";
}
},
mei_sURL
{
String getTable()
{
return "tMenuItem";
}
String getIdColumn()
{
return "mei_lKey";
}
},
usr_sUID
{
String getTable()
{
return "tUser";
}
String getIdColumn()
{
return "usr_hKey";
}
},
usr_sEmail
{
String getTable()
{
return "tUser";
}
String getIdColumn()
{
return "usr_hKey";
}
};
abstract String getTable();
abstract String getIdColumn();
List<String> query( UpgradeContext context )
throws Exception
{
String sql = "SELECT " + this.getIdColumn() + " FROM " + this.getTable() + " WHERE @length@(" + this.name() + ") > 255";
return context.getJdbcTemplate().query( sql, this.extractor() );
}
ResultSetExtractor<List<String>> extractor()
{
return new IdExtractor( this.getIdColumn() );
}
String message( final UpgradeContext context, final List<String> ids )
throws Exception
{
return "\nTable [" + this.getTable() + "], Column [" + this.name() + "], ID [" + this.getIdColumn() + "] = '" +
StringUtils.collectionToCommaDelimitedString( ids ) + "'";
}
}
private static class IdExtractor
implements ResultSetExtractor<List<String>>
{
private final String idColumn;
private IdExtractor( final String idColumn )
{
this.idColumn = idColumn;
}
public List<String> extractData( ResultSet rs )
throws SQLException, DataAccessException
{
List<String> ids = new ArrayList<String>();
while ( rs.next() )
{
final String id = rs.getString( idColumn );
ids.add( id );
}
return ids;
}
}
public void upgrade( final UpgradeContext context )
throws Exception
{
context.logInfo( " ########## Reduce size of VARCHAR(256) to size VARCHAR(255) for columns which indexed ########## " );
context.logInfo( "Add temporary column with index '2' type VARCHAR (255)" );
addTemporaryColumns( context );
context.logInfo( "Insert values from old columns to new with index '2'" );
setValueTemporaryColumns( context );
context.logInfo( "Drop all current constraints on modified tables" );
dropTableConstraints( context );
context.logInfo( "Drop old columns type VARCHAR(256)" );
dropTableColumns( context );
context.logInfo( "Add new columns type VARCHAR (255)" );
createNewColumns( context );
context.logInfo( "Rollback values from columns with index '2' to new" );
setValueNewColumns( context );
context.logInfo( "Drop temporary columns" );
dropTableConstraints( context );
dropTemporaryColumns( context );
context.logInfo( "Re-create all constraints on modified tables" );
createTableConstraints( context );
}
private void addTemporaryColumns( final UpgradeContext context )
throws Exception
{
context.getJdbcTemplate().execute( "ALTER TABLE tUser ADD usr_sEmail2 @varchar(255)@" );
context.getJdbcTemplate().execute( "ALTER TABLE tUser ADD usr_sUID2 @varchar(255)@" );
context.getJdbcTemplate().execute( "ALTER TABLE tMenuItem ADD mei_sURL2 @varchar(255)@" );
context.getJdbcTemplate().execute( "ALTER TABLE tMenuItem ADD mei_sName2 @varchar(255)@" );
context.getJdbcTemplate().execute( "ALTER TABLE tGroup ADD grp_sName2 @varchar(255)@" );
context.getJdbcTemplate().execute( "ALTER TABLE tContentVersion ADD cov_sTitle2 @varchar(255)@" );
context.getJdbcTemplate().execute( "ALTER TABLE tContentObject ADD cob_sName2 @varchar(255)@" );
context.getJdbcTemplate().execute( "ALTER TABLE tContentHandler ADD han_sClass2 @varchar(255)@" );
context.getJdbcTemplate().execute( "ALTER TABLE tCategory ADD cat_sName2 @varchar(255)@" );
context.getJdbcTemplate().execute( "ALTER TABLE tBinaryData ADD bda_sFileName2 @varchar(255)@" );
context.reorganizeTablesForDb2( "tUser", "tMenuItem", "tGroup", "tContentVersion", "tContentObject", "tContentHandler", "tCategory",
"tBinaryData" );
}
private void setValueTemporaryColumns( final UpgradeContext context )
throws Exception
{
context.getJdbcTemplate().execute( "UPDATE tUser SET usr_sEmail2 = @substring@(usr_sEmail, 1, 255)" );
context.getJdbcTemplate().execute( "UPDATE tUser SET usr_sUID2 = @substring@(usr_sUID, 1, 255)" );
context.getJdbcTemplate().execute( "UPDATE tMenuItem SET mei_sURL2 = @substring@(mei_sURL, 1, 255)" );
context.getJdbcTemplate().execute( "UPDATE tMenuItem SET mei_sName2 = @substring@(mei_sName, 1, 255)" );
context.getJdbcTemplate().execute( "UPDATE tGroup SET grp_sName2 = @substring@(grp_sName, 1, 255)" );
context.getJdbcTemplate().execute( "UPDATE tContentVersion SET cov_sTitle2 = @substring@(cov_sTitle, 1, 255)" );
context.getJdbcTemplate().execute( "UPDATE tContentObject SET cob_sName2 = @substring@(cob_sName, 1, 255)" );
context.getJdbcTemplate().execute( "UPDATE tContentHandler SET han_sClass2 = @substring@(han_sClass, 1, 255)" );
context.getJdbcTemplate().execute( "UPDATE tCategory SET cat_sName2 = @substring@(cat_sName, 1, 255)" );
context.getJdbcTemplate().execute( "UPDATE tBinaryData SET bda_sFileName2 = @substring@(bda_sFileName, 1, 255)" );
}
private void dropTableConstraints( final UpgradeContext context )
throws Exception
{
context.dropTableConstraints( "tUser", true );
context.dropTableConstraints( "tMenuItem", true );
context.dropTableConstraints( "tGroup", true );
context.dropTableConstraints( "tContentVersion", true );
context.dropTableConstraints( "tContentObject", true );
context.dropTableConstraints( "tContentHandler", true );
context.dropTableConstraints( "tCategory", true );
context.dropTableConstraints( "tBinaryData", true );
}
private void dropTableColumns( final UpgradeContext context )
throws Exception
{
context.getJdbcTemplate().execute( "ALTER TABLE tUser DROP column usr_sEmail" );
context.getJdbcTemplate().execute( "ALTER TABLE tUser DROP column usr_sUID" );
context.getJdbcTemplate().execute( "ALTER TABLE tMenuItem DROP column mei_sURL" );
context.getJdbcTemplate().execute( "ALTER TABLE tMenuItem DROP column mei_sName" );
context.getJdbcTemplate().execute( "ALTER TABLE tGroup DROP column grp_sName" );
context.getJdbcTemplate().execute( "ALTER TABLE tContentVersion DROP column cov_sTitle" );
context.getJdbcTemplate().execute( "ALTER TABLE tContentObject DROP column cob_sName" );
context.getJdbcTemplate().execute( "ALTER TABLE tContentHandler DROP column han_sClass" );
context.getJdbcTemplate().execute( "ALTER TABLE tCategory DROP column cat_sName" );
context.getJdbcTemplate().execute( "ALTER TABLE tBinaryData DROP column bda_sFileName" );
context.reorganizeTablesForDb2( "tUser", "tMenuItem", "tGroup", "tContentVersion", "tContentObject", "tContentHandler", "tCategory",
"tBinaryData" );
}
private void createNewColumns( final UpgradeContext context )
throws Exception
{
context.getJdbcTemplate().execute( "ALTER TABLE tUser ADD usr_sEmail @varchar(255)@ DEFAULT '-'" );
context.getJdbcTemplate().execute( "ALTER TABLE tUser ADD usr_sUID @varchar(255)@ DEFAULT '-' NOT NULL" );
context.getJdbcTemplate().execute( "ALTER TABLE tMenuItem ADD mei_sURL @varchar(255)@ DEFAULT '-'" );
context.getJdbcTemplate().execute( "ALTER TABLE tMenuItem ADD mei_sName @varchar(255)@ DEFAULT '-' NOT NULL" );
context.getJdbcTemplate().execute( "ALTER TABLE tGroup ADD grp_sName @varchar(255)@ DEFAULT '-' NOT NULL" );
context.getJdbcTemplate().execute( "ALTER TABLE tContentVersion ADD cov_sTitle @varchar(255)@ DEFAULT '-' NOT NULL" );
context.getJdbcTemplate().execute( "ALTER TABLE tContentObject ADD cob_sName @varchar(255)@ DEFAULT '-' NOT NULL" );
context.getJdbcTemplate().execute( "ALTER TABLE tContentHandler ADD han_sClass @varchar(255)@ DEFAULT '-' NOT NULL" );
context.getJdbcTemplate().execute( "ALTER TABLE tCategory ADD cat_sName @varchar(255)@ DEFAULT '-' NOT NULL" );
context.getJdbcTemplate().execute( "ALTER TABLE tBinaryData ADD bda_sFileName @varchar(255)@ DEFAULT '-'" );
context.reorganizeTablesForDb2( "tUser", "tMenuItem", "tGroup", "tContentVersion", "tContentObject", "tContentHandler", "tCategory",
"tBinaryData" );
}
private void setValueNewColumns( final UpgradeContext context )
throws Exception
{
context.getJdbcTemplate().execute( "UPDATE tUser SET usr_sEmail = usr_sEmail2" );
context.getJdbcTemplate().execute( "UPDATE tUser SET usr_sUID = usr_sUID2" );
context.getJdbcTemplate().execute( "UPDATE tMenuItem SET mei_sURL = mei_sURL2" );
context.getJdbcTemplate().execute( "UPDATE tMenuItem SET mei_sName = mei_sName2" );
context.getJdbcTemplate().execute( "UPDATE tGroup SET grp_sName = grp_sName2" );
context.getJdbcTemplate().execute( "UPDATE tContentVersion SET cov_sTitle = cov_sTitle2" );
context.getJdbcTemplate().execute( "UPDATE tContentObject SET cob_sName = cob_sName2" );
context.getJdbcTemplate().execute( "UPDATE tContentHandler SET han_sClass = han_sClass2" );
context.getJdbcTemplate().execute( "UPDATE tCategory SET cat_sName = cat_sName2" );
context.getJdbcTemplate().execute( "UPDATE tBinaryData SET bda_sFileName = bda_sFileName2" );
trimStringForDb2( context );
}
private boolean isDb2Database( final UpgradeContext context )
{
return ( context.getDialect() instanceof Db2Dialect );
}
private void trimStringForDb2( final UpgradeContext context )
throws Exception
{
if ( isDb2Database( context ) )
{
context.logWarning( "Db2Dialect: Trim indexed VARCHAR columns" );
for ( LargeIndexedColumn column : LargeIndexedColumn.values() )
{
context.getJdbcTemplate().execute( "UPDATE " + column.getTable() + " SET " + column.name() + " = " + "RTRIM(" + column.name() + ")" );
}
}
}
private void dropTemporaryColumns( final UpgradeContext context )
throws Exception
{
context.getJdbcTemplate().execute( "ALTER TABLE tUser DROP column usr_sEmail2" );
context.getJdbcTemplate().execute( "ALTER TABLE tUser DROP column usr_sUID2" );
context.getJdbcTemplate().execute( "ALTER TABLE tMenuItem DROP column mei_sURL2" );
context.getJdbcTemplate().execute( "ALTER TABLE tMenuItem DROP column mei_sName2" );
context.getJdbcTemplate().execute( "ALTER TABLE tGroup DROP column grp_sName2" );
context.getJdbcTemplate().execute( "ALTER TABLE tContentVersion DROP column cov_sTitle2" );
context.getJdbcTemplate().execute( "ALTER TABLE tContentObject DROP column cob_sName2" );
context.getJdbcTemplate().execute( "ALTER TABLE tContentHandler DROP column han_sClass2" );
context.getJdbcTemplate().execute( "ALTER TABLE tCategory DROP column cat_sName2" );
context.getJdbcTemplate().execute( "ALTER TABLE tBinaryData DROP column bda_sFileName2" );
context.reorganizeTablesForDb2( "tUser", "tMenuItem", "tGroup", "tContentVersion", "tContentObject", "tContentHandler", "tCategory",
"tBinaryData" );
}
private void createTableConstraints( final UpgradeContext context )
throws Exception
{
context.createTableConstraints( "tUser", true );
context.createTableConstraints( "tMenuItem", true );
context.createTableConstraints( "tGroup", true );
context.createTableConstraints( "tContentVersion", true );
context.createTableConstraints( "tContentObject", true );
context.createTableConstraints( "tContentHandler", true );
context.createTableConstraints( "tCategory", true );
context.createTableConstraints( "tBinaryData", true );
}
}