View Javadoc

1   // Copyright 2011 Leo Przybylski. All rights reserved.
2   //
3   // Redistribution and use in source and binary forms, with or without modification, are
4   // permitted provided that the following conditions are met:
5   //
6   //    1. Redistributions of source code must retain the above copyright notice, this list of
7   //       conditions and the following disclaimer.
8   //
9   //    2. Redistributions in binary form must reproduce the above copyright notice, this list
10  //       of conditions and the following disclaimer in the documentation and/or other materials
11  //       provided with the distribution.
12  //
13  // THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR IMPLIED
14  // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
15  // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
16  // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17  // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18  // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19  // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20  // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
21  // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22  //
23  // The views and conclusions contained in the software and documentation are those of the
24  // authors and should not be interpreted as representing official policies, either expressed
25  // or implied, of Leo Przybylski.
26  package liquibase.snapshot.ext;
27  
28  import liquibase.database.Database;
29  import liquibase.database.jvm.JdbcConnection;
30  import liquibase.database.typeconversion.TypeConverterFactory;
31  import liquibase.database.core.MySQLDatabase;
32  import liquibase.database.structure.*;
33  import liquibase.diff.DiffStatusListener;
34  import liquibase.exception.DatabaseException;
35  import liquibase.executor.*;
36  import liquibase.snapshot.*;
37  import liquibase.servicelocator.ServiceLocator;
38  import liquibase.snapshot.DatabaseSnapshot;
39  import liquibase.sqlgenerator.SqlGenerator;
40  import liquibase.statement.core.GetViewDefinitionStatement;
41  import liquibase.statement.core.SelectSequencesStatement;
42  import liquibase.statement.SqlStatement;
43  
44  import java.lang.reflect.ParameterizedType;
45  import java.lang.reflect.Type;
46  import java.lang.reflect.TypeVariable;
47  import java.math.BigInteger;
48  import java.sql.DatabaseMetaData;
49  import java.sql.ResultSet;
50  import java.sql.SQLException;
51  import java.sql.Statement;
52  import java.text.ParseException;
53  import java.util.ArrayList;
54  import java.util.HashMap;
55  import java.util.List;
56  import java.util.Map;
57  import java.util.Set;
58  
59  import static liquibase.ext.Constants.EXTENSION_PRIORITY;
60  
61  /**
62   * Detect sequences created with the {@link MysqlSequenceGenerator} hack.
63   *
64   * @author Leo Przybylski (leo [at] rsmart.com)
65   */
66  public class MySQLDatabaseSnapshotGenerator extends liquibase.snapshot.jvm.MySQLDatabaseSnapshotGenerator {
67  
68      public int getPriority(Database database) {
69          return EXTENSION_PRIORITY;
70      }
71  
72      protected View readView(final String name, final Database database) throws DatabaseException {
73          final String schemaName = convertFromDatabaseName(database.getDefaultSchemaName());
74          View view = new View();
75          view.setName(name);
76          view.setSchema(null);
77          view.setRawSchemaName(null);
78          view.setRawCatalogName(database.getDefaultCatalogName());
79          try {
80              view.setDefinition(database.getViewDefinition(schemaName, name));
81          } catch (DatabaseException e) {
82              throw new DatabaseException("Error getting " + database.getConnection().getURL() + " view with " + new GetViewDefinitionStatement(view.getSchema(), name), e);
83          }
84  
85          return view;
86      }
87  
88      protected void readViews(DatabaseSnapshot snapshot, String schema, DatabaseMetaData databaseMetaData) throws SQLException, DatabaseException {
89          Database database = snapshot.getDatabase();
90          updateListeners("Reading views for " + database.toString() + " ...");
91          
92          ResultSet rs = databaseMetaData.getTables(database.convertRequestedSchemaToCatalog(schema), database.convertRequestedSchemaToSchema(schema), null, new String[]{"VIEW"});
93          try {
94              while (rs.next()) {
95                  final String name = convertFromDatabaseName(rs.getString("TABLE_NAME"));
96                  final View view = readView(name, database);
97                  if (database.isSystemView(view.getRawCatalogName(), view.getRawSchemaName(), view.getName())) {
98                      continue;
99                  }
100                 
101                 snapshot.getViews().add(view);
102             }
103         } finally {
104             try {
105                 rs.close();
106             } catch (SQLException ignore) { }
107         }
108     }
109 
110     protected void readSequences(final DatabaseSnapshot snapshot,                                  
111                                  final String schema, 
112                                  final DatabaseMetaData databaseMetaData) throws DatabaseException {
113         final Database database = snapshot.getDatabase();
114 
115         updateListeners("Reading sequences for " + database.toString() + " ...");
116 
117         final String convertedSchemaName = database.convertRequestedSchemaToSchema(schema);
118         try {
119             final ResultSet rs = databaseMetaData.getTables(null, convertedSchemaName, null, new String[] { "TABLE" });
120             while (rs.next()) {
121                 final String sequenceName = rs.getString("TABLE_NAME");
122                 if (isSequence(sequenceName, databaseMetaData)) {
123                     final Sequence seq = new Sequence();
124                     seq.setName(sequenceName.trim());
125                     // seq.setSchema(convertedSchemaName);
126                     snapshot.getSequences().add(seq);
127                 }
128             }   
129         }
130         catch (SQLException sqle) {
131             throw new DatabaseException(sqle);
132         }
133     }
134 
135     protected boolean isSequence(final String tableName, final DatabaseMetaData databaseMetaData) throws SQLException {
136         final ResultSet rs = databaseMetaData.getColumns(null, null, tableName, null);
137         Integer count = 0;
138         boolean hasId = false;
139         while (rs.next()) {
140             count++;
141             hasId = rs.getString("IS_AUTOINCREMENT").equalsIgnoreCase("yes");
142         }
143 
144         return hasId && count == 1;
145     }
146 
147 }