1 package liquibase.executor;
2
3 import java.io.IOException;
4 import java.io.Writer;
5 import java.util.ArrayList;
6 import java.util.List;
7 import java.util.Map;
8
9 import liquibase.database.Database;
10 import liquibase.database.core.MSSQLDatabase;
11 import liquibase.database.core.SybaseASADatabase;
12 import liquibase.database.core.SybaseDatabase;
13 import liquibase.exception.DatabaseException;
14 import liquibase.servicelocator.LiquibaseService;
15 import liquibase.sql.visitor.SqlVisitor;
16 import liquibase.sqlgenerator.SqlGeneratorFactory;
17 import liquibase.statement.CallableSqlStatement;
18 import liquibase.statement.SqlStatement;
19 import liquibase.statement.core.GetNextChangeSetSequenceValueStatement;
20 import liquibase.statement.core.LockDatabaseChangeLogStatement;
21 import liquibase.statement.core.RawSqlStatement;
22 import liquibase.statement.core.SelectFromDatabaseChangeLogLockStatement;
23 import liquibase.statement.core.UnlockDatabaseChangeLogStatement;
24 import liquibase.util.StreamUtil;
25
26 @LiquibaseService(skip = true)
27 public class LoggingExecutor extends AbstractExecutor implements Executor {
28
29 private Writer output;
30 private Executor delegatedReadExecutor;
31
32 public LoggingExecutor(Executor delegatedExecutor, Writer output, Database database) {
33 this.output = output;
34 this.delegatedReadExecutor = delegatedExecutor;
35 setDatabase(database);
36 }
37
38 @Override
39 public void execute(SqlStatement sql) throws DatabaseException {
40 outputStatement(sql);
41 }
42
43 @Override
44 public int update(SqlStatement sql) throws DatabaseException {
45 if (sql instanceof LockDatabaseChangeLogStatement) {
46 return 1;
47 } else if (sql instanceof UnlockDatabaseChangeLogStatement) {
48 return 1;
49 }
50
51 outputStatement(sql);
52
53 return 0;
54 }
55
56 @Override
57 public void execute(SqlStatement sql, List<SqlVisitor> sqlVisitors) throws DatabaseException {
58 outputStatement(sql, sqlVisitors);
59 }
60
61 @Override
62 public int update(SqlStatement sql, List<SqlVisitor> sqlVisitors) throws DatabaseException {
63 outputStatement(sql, sqlVisitors);
64 return 0;
65 }
66
67 @Override
68 public Map call(CallableSqlStatement csc, List declaredParameters, List<SqlVisitor> sqlVisitors)
69 throws DatabaseException {
70 throw new DatabaseException("Do not know how to output callable statement");
71 }
72
73 @Override
74 public void comment(String message) throws DatabaseException {
75 try {
76 output.write(database.getLineComment());
77 output.write(" ");
78 output.write(message);
79 output.write(StreamUtil.getLineSeparator());
80 } catch (IOException e) {
81 throw new DatabaseException(e);
82 }
83 }
84
85 private void outputStatement(SqlStatement sql) throws DatabaseException {
86 outputStatement(sql, new ArrayList<SqlVisitor>());
87 }
88
89 private void outputStatement(SqlStatement sql, List<SqlVisitor> sqlVisitors) throws DatabaseException {
90 try {
91 if (SqlGeneratorFactory.getInstance().requiresCurrentDatabaseMetadata(sql, database)) {
92 throw new DatabaseException(sql.getClass().getSimpleName()
93 + " requires access to up to date database metadata which is not available in SQL output mode");
94 }
95 for (String statement : applyVisitors(sql, sqlVisitors)) {
96 if (statement == null) {
97 continue;
98 }
99 output.write(statement);
100
101 if (database instanceof MSSQLDatabase || database instanceof SybaseDatabase
102 || database instanceof SybaseASADatabase) {
103 output.write(StreamUtil.getLineSeparator());
104 output.write("GO");
105
106
107
108 } else {
109 String endDelimiter = ";";
110 if (sql instanceof RawSqlStatement) {
111 endDelimiter = ((RawSqlStatement) sql).getEndDelimiter();
112 }
113 if (!statement.endsWith(endDelimiter)) {
114 output.write(endDelimiter);
115 }
116 }
117 output.write(StreamUtil.getLineSeparator());
118 output.write(StreamUtil.getLineSeparator());
119 }
120 } catch (IOException e) {
121 throw new DatabaseException(e);
122 }
123 }
124
125 @Override
126 public Object queryForObject(SqlStatement sql, Class requiredType) throws DatabaseException {
127 if (sql instanceof SelectFromDatabaseChangeLogLockStatement) {
128 return false;
129 }
130 return delegatedReadExecutor.queryForObject(sql, requiredType);
131 }
132
133 @Override
134 public Object queryForObject(SqlStatement sql, Class requiredType, List<SqlVisitor> sqlVisitors)
135 throws DatabaseException {
136 return delegatedReadExecutor.queryForObject(sql, requiredType, sqlVisitors);
137 }
138
139 @Override
140 public long queryForLong(SqlStatement sql) throws DatabaseException {
141 return delegatedReadExecutor.queryForLong(sql);
142 }
143
144 @Override
145 public long queryForLong(SqlStatement sql, List<SqlVisitor> sqlVisitors) throws DatabaseException {
146 return delegatedReadExecutor.queryForLong(sql, sqlVisitors);
147 }
148
149 @Override
150 public int queryForInt(SqlStatement sql) throws DatabaseException {
151 try {
152 return delegatedReadExecutor.queryForInt(sql);
153 } catch (DatabaseException e) {
154 if (sql instanceof GetNextChangeSetSequenceValueStatement) {
155 return 0;
156 }
157 throw e;
158 }
159 }
160
161 @Override
162 public int queryForInt(SqlStatement sql, List<SqlVisitor> sqlVisitors) throws DatabaseException {
163 return delegatedReadExecutor.queryForInt(sql, sqlVisitors);
164 }
165
166 @Override
167 public List queryForList(SqlStatement sql, Class elementType) throws DatabaseException {
168 return delegatedReadExecutor.queryForList(sql, elementType);
169 }
170
171 @Override
172 public List queryForList(SqlStatement sql, Class elementType, List<SqlVisitor> sqlVisitors)
173 throws DatabaseException {
174 return delegatedReadExecutor.queryForList(sql, elementType, sqlVisitors);
175 }
176
177 @Override
178 public List<Map> queryForList(SqlStatement sql) throws DatabaseException {
179 return delegatedReadExecutor.queryForList(sql);
180 }
181
182 @Override
183 public List<Map> queryForList(SqlStatement sql, List<SqlVisitor> sqlVisitors) throws DatabaseException {
184 return delegatedReadExecutor.queryForList(sql, sqlVisitors);
185 }
186
187 @Override
188 public boolean updatesDatabase() {
189 return false;
190 }
191 }