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