1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.jdbc;
17
18 import static org.junit.jupiter.api.Assertions.*;
19 import static org.mockito.Mockito.*;
20
21 import java.io.IOException;
22 import java.io.PrintWriter;
23 import java.io.Reader;
24 import java.io.StringReader;
25 import java.io.StringWriter;
26 import java.sql.Connection;
27 import java.sql.SQLException;
28 import java.sql.Statement;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Properties;
32
33 import javax.sql.DataSource;
34
35 import org.apache.ibatis.BaseDataTest;
36 import org.apache.ibatis.datasource.pooled.PooledDataSource;
37 import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
38 import org.apache.ibatis.io.Resources;
39 import org.junit.jupiter.api.Disabled;
40 import org.junit.jupiter.api.Test;
41 import org.mockito.Mockito;
42
43 class ScriptRunnerTest extends BaseDataTest {
44
45 private static final String LINE_SEPARATOR = System.lineSeparator();
46
47 @Test
48 @Disabled("This fails with HSQLDB 2.0 due to the create index statements in the schema script")
49 void shouldRunScriptsBySendingFullScriptAtOnce() throws Exception {
50 DataSource ds = createUnpooledDataSource(JPETSTORE_PROPERTIES);
51 Connection conn = ds.getConnection();
52 ScriptRunner runner = new ScriptRunner(conn);
53 runner.setSendFullScript(true);
54 runner.setAutoCommit(true);
55 runner.setStopOnError(false);
56 runner.setErrorLogWriter(null);
57 runner.setLogWriter(null);
58 conn.close();
59 runJPetStoreScripts(runner);
60 assertProductsTableExistsAndLoaded();
61 }
62
63 @Test
64 void shouldRunScriptsUsingConnection() throws Exception {
65 DataSource ds = createUnpooledDataSource(JPETSTORE_PROPERTIES);
66 try (Connection conn = ds.getConnection()) {
67 ScriptRunner runner = new ScriptRunner(conn);
68 runner.setAutoCommit(true);
69 runner.setStopOnError(false);
70 runner.setErrorLogWriter(null);
71 runner.setLogWriter(null);
72 runJPetStoreScripts(runner);
73 }
74 assertProductsTableExistsAndLoaded();
75 }
76
77 @Test
78 void shouldRunScriptsUsingProperties() throws Exception {
79 Properties props = Resources.getResourceAsProperties(JPETSTORE_PROPERTIES);
80 DataSource dataSource = new UnpooledDataSource(
81 props.getProperty("driver"),
82 props.getProperty("url"),
83 props.getProperty("username"),
84 props.getProperty("password"));
85 ScriptRunner runner = new ScriptRunner(dataSource.getConnection());
86 runner.setAutoCommit(true);
87 runner.setStopOnError(false);
88 runner.setErrorLogWriter(null);
89 runner.setLogWriter(null);
90 runJPetStoreScripts(runner);
91 assertProductsTableExistsAndLoaded();
92 }
93
94 @Test
95 void shouldReturnWarningIfEndOfLineTerminatorNotFound() throws Exception {
96 DataSource ds = createUnpooledDataSource(JPETSTORE_PROPERTIES);
97 String resource = "org/apache/ibatis/jdbc/ScriptMissingEOLTerminator.sql";
98 try (Connection conn = ds.getConnection();
99 Reader reader = Resources.getResourceAsReader(resource)) {
100 ScriptRunner runner = new ScriptRunner(conn);
101 runner.setAutoCommit(true);
102 runner.setStopOnError(false);
103 runner.setErrorLogWriter(null);
104 runner.setLogWriter(null);
105
106 try {
107 runner.runScript(reader);
108 fail("Expected script runner to fail due to missing end of line terminator.");
109 } catch (Exception e) {
110 assertTrue(e.getMessage().contains("end-of-line terminator"));
111 }
112 }
113 }
114
115 @Test
116 void commentAferStatementDelimiterShouldNotCauseRunnerFail() throws Exception {
117 DataSource ds = createUnpooledDataSource(JPETSTORE_PROPERTIES);
118 String resource = "org/apache/ibatis/jdbc/ScriptCommentAfterEOLTerminator.sql";
119 try (Connection conn = ds.getConnection();
120 Reader reader = Resources.getResourceAsReader(resource)) {
121 ScriptRunner runner = new ScriptRunner(conn);
122 runner.setAutoCommit(true);
123 runner.setStopOnError(true);
124 runner.setErrorLogWriter(null);
125 runner.setLogWriter(null);
126 runJPetStoreScripts(runner);
127 runner.runScript(reader);
128 }
129 }
130
131 @Test
132 void shouldReturnWarningIfNotTheCurrentDelimiterUsed() throws Exception {
133 DataSource ds = createUnpooledDataSource(JPETSTORE_PROPERTIES);
134 String resource = "org/apache/ibatis/jdbc/ScriptChangingDelimiterMissingDelimiter.sql";
135 try (Connection conn = ds.getConnection();
136 Reader reader = Resources.getResourceAsReader(resource)) {
137 ScriptRunner runner = new ScriptRunner(conn);
138 runner.setAutoCommit(false);
139 runner.setStopOnError(true);
140 runner.setErrorLogWriter(null);
141 runner.setLogWriter(null);
142 try {
143 runner.runScript(reader);
144 fail("Expected script runner to fail due to the usage of invalid delimiter.");
145 } catch (Exception e) {
146 assertTrue(e.getMessage().contains("end-of-line terminator"));
147 }
148 }
149 }
150
151 @Test
152 void changingDelimiterShouldNotCauseRunnerFail() throws Exception {
153 DataSource ds = createUnpooledDataSource(JPETSTORE_PROPERTIES);
154 String resource = "org/apache/ibatis/jdbc/ScriptChangingDelimiter.sql";
155 try (Connection conn = ds.getConnection();
156 Reader reader = Resources.getResourceAsReader(resource)) {
157 ScriptRunner runner = new ScriptRunner(conn);
158 runner.setAutoCommit(false);
159 runner.setStopOnError(true);
160 runner.setErrorLogWriter(null);
161 runner.setLogWriter(null);
162 runJPetStoreScripts(runner);
163 runner.runScript(reader);
164 }
165 }
166
167 @Test
168 void testLogging() throws Exception {
169 DataSource ds = createUnpooledDataSource(JPETSTORE_PROPERTIES);
170 try (Connection conn = ds.getConnection()) {
171 ScriptRunner runner = new ScriptRunner(conn);
172 runner.setAutoCommit(true);
173 runner.setStopOnError(false);
174 runner.setErrorLogWriter(null);
175 runner.setSendFullScript(false);
176 StringWriter sw = new StringWriter();
177 PrintWriter logWriter = new PrintWriter(sw);
178 runner.setLogWriter(logWriter);
179
180 Reader reader = new StringReader("select userid from account where userid = 'j2ee';");
181 runner.runScript(reader);
182
183 assertEquals(
184 "select userid from account where userid = 'j2ee'" + LINE_SEPARATOR
185 + LINE_SEPARATOR + "USERID\t" + LINE_SEPARATOR
186 + "j2ee\t" + LINE_SEPARATOR, sw.toString());
187 }
188 }
189
190 @Test
191 void testLoggingFullScipt() throws Exception {
192 DataSource ds = createUnpooledDataSource(JPETSTORE_PROPERTIES);
193 try (Connection conn = ds.getConnection()) {
194 ScriptRunner runner = new ScriptRunner(conn);
195 runner.setAutoCommit(true);
196 runner.setStopOnError(false);
197 runner.setErrorLogWriter(null);
198 runner.setSendFullScript(true);
199 StringWriter sw = new StringWriter();
200 PrintWriter logWriter = new PrintWriter(sw);
201 runner.setLogWriter(logWriter);
202
203 Reader reader = new StringReader("select userid from account where userid = 'j2ee';");
204 runner.runScript(reader);
205
206 assertEquals(
207 "select userid from account where userid = 'j2ee';" + LINE_SEPARATOR
208 + LINE_SEPARATOR + "USERID\t" + LINE_SEPARATOR
209 + "j2ee\t" + LINE_SEPARATOR, sw.toString());
210 }
211 }
212
213 private void runJPetStoreScripts(ScriptRunner runner) throws IOException, SQLException {
214 runScript(runner, JPETSTORE_DDL);
215 runScript(runner, JPETSTORE_DATA);
216 }
217
218 private void assertProductsTableExistsAndLoaded() throws IOException, SQLException {
219 PooledDataSource ds = createPooledDataSource(JPETSTORE_PROPERTIES);
220 try (Connection conn = ds.getConnection()) {
221 SqlRunner executor = new SqlRunner(conn);
222 List<Map<String, Object>> products = executor.selectAll("SELECT * FROM PRODUCT");
223 assertEquals(16, products.size());
224 } finally {
225 ds.forceCloseAll();
226 }
227 }
228
229 @Test
230 void shouldAcceptDelimiterVariations() throws Exception {
231 Connection conn = mock(Connection.class);
232 Statement stmt = mock(Statement.class);
233 when(conn.createStatement()).thenReturn(stmt);
234 when(stmt.getUpdateCount()).thenReturn(-1);
235 ScriptRunner runner = new ScriptRunner(conn);
236
237 String sql = "-- @DELIMITER | \n"
238 + "line 1;\n"
239 + "line 2;\n"
240 + "|\n"
241 + "// @DELIMITER ;\n"
242 + "line 3; \n"
243 + "-- //@deLimiTer $ blah\n"
244 + "line 4$\n"
245 + "// //@DELIMITER %\n"
246 + "line 5%\n";
247 Reader reader = new StringReader(sql);
248 runner.runScript(reader);
249
250 verify(stmt, Mockito.times(1)).execute(eq("line 1;" + LINE_SEPARATOR + "line 2;" + LINE_SEPARATOR + LINE_SEPARATOR));
251 verify(stmt, Mockito.times(1)).execute(eq("line 3" + LINE_SEPARATOR));
252 verify(stmt, Mockito.times(1)).execute(eq("line 4" + LINE_SEPARATOR));
253 verify(stmt, Mockito.times(1)).execute(eq("line 5" + LINE_SEPARATOR));
254 }
255
256 @Test
257 void test() {
258 StringBuilder sb = new StringBuilder();
259 StringBuilder sb2 = y(sb);
260 assertSame(sb, sb2);
261 }
262
263 private StringBuilder y(StringBuilder sb) {
264 sb.append("ABC");
265 return sb;
266 }
267
268 @Test
269 void shouldAcceptMultiCharDelimiter() throws Exception {
270 Connection conn = mock(Connection.class);
271 Statement stmt = mock(Statement.class);
272 when(conn.createStatement()).thenReturn(stmt);
273 when(stmt.getUpdateCount()).thenReturn(-1);
274 ScriptRunner runner = new ScriptRunner(conn);
275
276 String sql = "-- @DELIMITER || \n"
277 + "line 1;\n"
278 + "line 2;\n"
279 + "||\n"
280 + "// @DELIMITER ;\n"
281 + "line 3; \n";
282 Reader reader = new StringReader(sql);
283 runner.runScript(reader);
284
285 verify(stmt, Mockito.times(1)).execute(eq("line 1;" + LINE_SEPARATOR + "line 2;" + LINE_SEPARATOR + LINE_SEPARATOR));
286 verify(stmt, Mockito.times(1)).execute(eq("line 3" + LINE_SEPARATOR));
287 }
288 }