All Downloads are FREE. Search and download functionalities are using the official Maven repository.

liquibase.snapshot.jvm.MySQLDatabaseSnapshotGenerator Maven / Gradle / Ivy

There is a newer version: 4.30.0
Show newest version
package liquibase.snapshot.jvm;

import liquibase.database.Database;
import liquibase.database.jvm.JdbcConnection;
import liquibase.database.structure.ForeignKeyInfo;
import liquibase.database.typeconversion.TypeConverterFactory;
import liquibase.database.core.MySQLDatabase;
import liquibase.database.structure.Column;
import liquibase.exception.DatabaseException;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MySQLDatabaseSnapshotGenerator extends JdbcDatabaseSnapshotGenerator {
	
	/**
	 * Table schema cache 
	 */
	private static Map>> schemaCache = new HashMap>>();

    public int getPriority(Database database) {
        return PRIORITY_DATABASE;
    }

    public boolean supports(Database database) {
        return database instanceof MySQLDatabase;
    }

    /**
     * MySQL specific implementation
     */
    @Override
    protected void getColumnTypeAndDefValue(Column columnInfo, ResultSet rs, Database database) throws SQLException, DatabaseException {

    	String columnTypeName = rs.getString("TYPE_NAME");
        String columnName     = rs.getString("COLUMN_NAME");
        String tableName      = rs.getString("TABLE_NAME");
        String schemaName     = rs.getString("TABLE_CAT");
        
        Map> tableSchema = new HashMap>();
        
        if (!schemaCache.containsKey(tableName)) {
        	
        	Statement selectStatement = ((JdbcConnection) database.getConnection()).getUnderlyingConnection().createStatement();
            ResultSet rsColumnType = selectStatement.executeQuery("DESC "+database.escapeTableName(schemaName, tableName));
            
            while(rsColumnType.next()) {
            	List colSchema = new ArrayList();
            	colSchema.add(rsColumnType.getString("Type"));
            	colSchema.add(rsColumnType.getString("Default"));
            	tableSchema.put(rsColumnType.getString("Field"), colSchema);
            }
            
            rsColumnType.close();
            
            schemaCache.put(tableName, tableSchema);
        	
        }
        
        tableSchema = schemaCache.get(tableName);
        
        // Parse ENUM and SET column types correctly
        if (columnTypeName.toLowerCase().startsWith("enum") || columnTypeName.toLowerCase().startsWith("set")) {       	

        	columnInfo.setTypeName(tableSchema.get(columnName).get(0));
        	try {
        		String tmpDefaultValue = (String) TypeConverterFactory.getInstance().findTypeConverter(database).convertDatabaseValueToObject(tableSchema.get(columnName).get(1), columnInfo.getDataType(), columnInfo.getColumnSize(), columnInfo.getDecimalDigits(), database);
        		if ("".equals(tmpDefaultValue)) {
        			columnInfo.setDefaultValue(null);
        		} else {
        			columnInfo.setDefaultValue(tmpDefaultValue);
        		}
        	} catch (ParseException e) {
        		throw new DatabaseException(e);
        	}
        	
        // TEXT and BLOB column types always have null as default value 
        } else if (columnTypeName.toLowerCase().equals("text") || columnTypeName.toLowerCase().equals("blob")) {
        	columnInfo.setTypeName(columnTypeName);
        	columnInfo.setDefaultValue(null);
        	
        // Parsing TIMESTAMP database.convertDatabaseValueToObject() produces incorrect results
        // eg. for default value 0000-00-00 00:00:00 we have 0002-11-30T00:00:00.0 as parsing result
        } else if (columnTypeName.toLowerCase().equals("timestamp") && !"CURRENT_TIMESTAMP".equals(tableSchema.get(columnName).get(1))) {
        	columnInfo.setTypeName(columnTypeName);
        	columnInfo.setDefaultValue(tableSchema.get(columnName).get(1));
        } else {
        	super.getColumnTypeAndDefValue(columnInfo, rs, database);
        }
    }

    @Override
    protected String convertPrimaryKeyName(String pkName) throws SQLException {
        if (pkName.equals("PRIMARY")) {
            return null;
        } else {
            return pkName;
        }
    }

    @Override
    protected ForeignKeyInfo fillForeignKeyInfo(ResultSet rs) throws DatabaseException, SQLException {
        ForeignKeyInfo fkinfo= super.fillForeignKeyInfo(rs);
        //MySQL in reality doesn't has schemas. It has databases that can have relations like schemas.
        fkinfo.setPkTableSchema(convertFromDatabaseName(rs.getString("PKTABLE_CAT")));
        fkinfo.setFkSchema(convertFromDatabaseName(rs.getString("FKTABLE_CAT")));
        return fkinfo;
    }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy