1 /*
2   Copyright (c) 2010, 2021, Oracle and/or its affiliates.
3 
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License, version 2.0,
6   as published by the Free Software Foundation.
7 
8   This program is also distributed with certain software (including
9   but not limited to OpenSSL) that is licensed under separate terms,
10   as designated in a particular file or component or in included license
11   documentation.  The authors of MySQL hereby grant you an additional
12   permission to link the program and your derivative works with the
13   separately licensed software that they have included with MySQL.
14 
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License, version 2.0, for more details.
19 
20   You should have received a copy of the GNU General Public License
21   along with this program; if not, write to the Free Software
22   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 package com.mysql.cluster.crund;
26 
27 import java.sql.Connection;
28 import java.sql.DriverManager;
29 import java.sql.SQLException;
30 import java.sql.Statement;
31 import java.sql.PreparedStatement;
32 import java.sql.ResultSet;
33 
34 import com.mysql.cluster.crund.CrundDriver.XMode;
35 
36 class JdbcS extends CrundSLoad {
37     // JDBC settings
38     protected String jdbcDriver;
39     protected String url;
40     protected String username;
41     protected String password;
42 
43     // JDBC resources
44     protected Class jdbcDriverClass;
45     protected Connection connection;
46     protected String sqlIns0;
47     protected String sqlSel0;
48     protected String sqlUpd0;
49     protected String sqlDel0;
50     protected String sqlDelAll;
51     protected PreparedStatement ins0;
52     protected PreparedStatement sel0;
53     protected PreparedStatement upd0;
54     protected PreparedStatement del0;
55     protected PreparedStatement delAll;
56 
JdbcS(CrundDriver driver)57     public JdbcS(CrundDriver driver) {
58         super(driver);
59     }
60 
61     // ----------------------------------------------------------------------
62     // JDBC intializers/finalizers
63     // ----------------------------------------------------------------------
64 
initProperties()65     protected void initProperties() {
66         out.println();
67         out.print("setting jdbc properties ...");
68 
69         final StringBuilder msg = new StringBuilder();
70         final String eol = System.getProperty("line.separator");
71 
72         // load the JDBC driver class
73         jdbcDriver = driver.props.getProperty("jdbc.driver");
74         if (jdbcDriver == null) {
75             throw new RuntimeException("Missing property: jdbc.driver");
76         }
77         try {
78             Class.forName(jdbcDriver);
79         } catch (ClassNotFoundException e) {
80             out.println("Cannot load JDBC driver '" + jdbcDriver
81                         + "' from classpath '"
82                         + System.getProperty("java.class.path") + "'");
83             throw new RuntimeException(e);
84         }
85 
86         url = driver.props.getProperty("jdbc.url");
87         if (url == null) {
88             throw new RuntimeException("Missing property: jdbc.url");
89         }
90 
91         username = driver.props.getProperty("jdbc.user");
92         password = driver.props.getProperty("jdbc.password");
93 
94         if (msg.length() == 0) {
95             out.println("     [ok]");
96         } else {
97             driver.hasIgnoredSettings = true;
98             out.println();
99             out.print(msg.toString());
100         }
101 
102         name = url.substring(0, 10); // shortcut will do
103      }
104 
printProperties()105     protected void printProperties() {
106         out.println("jdbc.driver:                    " + jdbcDriver);
107         out.println("jdbc.url:                       " + url);
108         out.println("jdbc.user:                      \"" + username + "\"");
109         out.println("jdbc.password:                  \"" + password + "\"");
110     }
111 
init()112     public void init() throws Exception {
113         super.init();
114         assert (jdbcDriverClass == null);
115 
116         // load the JDBC driver class
117         out.print("loading jdbc driver ...");
118         out.flush();
119         try {
120             jdbcDriverClass = Class.forName(jdbcDriver);
121         } catch (ClassNotFoundException e) {
122             out.println("Cannot load JDBC driver '" + jdbcDriver
123                         + "' from classpath '"
124                         + System.getProperty("java.class.path") + "'");
125             throw new RuntimeException(e);
126         }
127         out.println("         [ok: " + jdbcDriverClass.getName() + "]");
128     }
129 
close()130     public void close() throws Exception {
131         assert (jdbcDriverClass != null);
132 
133         //out.println();
134         jdbcDriverClass = null;
135 
136         super.close();
137     }
138 
139     // ----------------------------------------------------------------------
140     // JDBC datastore operations
141     // ----------------------------------------------------------------------
142 
initConnection()143     public void initConnection() throws SQLException {
144         assert (jdbcDriverClass != null);
145         assert (connection == null);
146 
147         out.println();
148         out.println("initializing jdbc resources ...");
149 
150         // create a connection to the database
151         out.print("starting jdbc connection ...");
152         out.flush();
153         try {
154             connection = DriverManager.getConnection(url, username, password);
155         } catch (SQLException e) {
156             out.println("Cannot connect to database '" + url + "'");
157             throw new RuntimeException(e);
158         }
159         out.println("    [ok: " + url + "]");
160 
161         out.print("setting isolation level ...");
162         out.flush();
163         // ndb storage engine only supports READ_COMMITTED
164         final int il = Connection.TRANSACTION_READ_COMMITTED;
165         connection.setTransactionIsolation(il);
166         out.print("     [ok: ");
167         switch (connection.getTransactionIsolation()) {
168         case Connection.TRANSACTION_READ_UNCOMMITTED:
169             out.print("READ_UNCOMMITTED");
170             break;
171         case Connection.TRANSACTION_READ_COMMITTED:
172             out.print("READ_COMMITTED");
173             break;
174         case Connection.TRANSACTION_REPEATABLE_READ:
175             out.print("REPEATABLE_READ");
176             break;
177         case Connection.TRANSACTION_SERIALIZABLE:
178             out.print("SERIALIZABLE");
179             break;
180         default:
181             assert false;
182         }
183         out.println("]");
184 
185         initPreparedStatements();
186     }
187 
closeConnection()188     public void closeConnection() throws SQLException {
189         assert (connection != null);
190 
191         out.println();
192         out.println("releasing jdbc resources ...");
193 
194         closePreparedStatements();
195 
196         out.print("closing jdbc connection ...");
197         out.flush();
198         connection.close();
199         connection = null;
200         out.println("     [ok]");
201     }
202 
clearData()203     public void clearData() throws SQLException {
204         connection.setAutoCommit(false);
205         out.print("deleting all rows ...");
206         out.flush();
207         final int d = delAll.executeUpdate();
208         connection.commit();
209         out.println("           [S: " + d + "]");
210     }
211 
initPreparedStatements()212     public void initPreparedStatements() throws SQLException {
213         assert (connection != null);
214         assert (ins0 == null);
215         assert (sel0 == null);
216         assert (upd0 == null);
217         assert (del0 == null);
218 
219         out.print("using lock mode for reads ...");
220         out.flush();
221         final String lm;
222         switch (driver.lockMode) {
223         case none:
224             lm = "";
225             break;
226         case shared:
227             lm = " LOCK IN share mode";
228             break;
229         case exclusive:
230             lm = " FOR UPDATE";
231             break;
232         default:
233             lm = "";
234             assert false;
235         }
236         out.println("   [ok: " + "SELECT" + lm + ";]");
237 
238         out.print("compiling jdbc statements ...");
239         out.flush();
240 
241         sqlIns0 = "INSERT INTO S (c0, c1, c2, c3, c5, c6, c7, c8) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
242         sqlSel0 = "SELECT * FROM S WHERE c0=?" + lm;
243         sqlUpd0 = "UPDATE S SET c1 = ?, c2 = ?, c3 = ?, c5 = ?, c6 = ?, c7 = ?, c8 = ? WHERE c0=?";
244         sqlDel0 = "DELETE FROM S WHERE c0=?";
245         sqlDelAll = "DELETE FROM S";
246 
247         ins0 = connection.prepareStatement(sqlIns0);
248         sel0 = connection.prepareStatement(sqlSel0);
249         upd0 = connection.prepareStatement(sqlUpd0);
250         del0 = connection.prepareStatement(sqlDel0);
251         delAll = connection.prepareStatement(sqlDelAll);
252 
253         out.println("   [ok]");
254     }
255 
closePreparedStatements()256     protected void closePreparedStatements() throws SQLException {
257         assert (ins0 != null);
258         assert (sel0 != null);
259         assert (upd0 != null);
260         assert (del0 != null);
261         assert (delAll != null);
262 
263         out.print("closing jdbc statements ...");
264         out.flush();
265         ins0.close();
266         ins0 = null;
267         sel0.close();
268         sel0 = null;
269         upd0.close();
270         upd0 = null;
271         del0.close();
272         del0 = null;
273         delAll.close();
274         delAll = null;
275         out.println("     [ok]");
276     }
277 
278     // ----------------------------------------------------------------------
279 
runInsert(XMode mode, int[] id)280     protected void runInsert(XMode mode, int[] id) throws SQLException {
281         final String name = "S_insAttr," + mode;
282         final int n = id.length;
283         driver.beginOp(name);
284         connection.setAutoCommit(mode == XMode.indy);
285         for(int i = 0; i < n; i++)
286             insert(mode, id[i]);
287         if (mode == XMode.bulk)
288             ins0.executeBatch();
289         if (mode != XMode.indy)
290             connection.commit();
291         driver.finishOp(name, n);
292     }
293 
insert(XMode mode, int id)294     protected void insert(XMode mode, int id) throws SQLException {
295         final int i = id;
296         final String str = Integer.toString(i);
297         ins0.setString(1, str); // key
298         ins0.setString(2, str);
299         ins0.setInt(3, i);
300         ins0.setInt(4, i);
301         ins0.setString(5, str);
302         ins0.setString(6, str);
303         ins0.setString(7, str);
304         ins0.setString(8, str);
305         if (mode == XMode.bulk) {
306             ins0.addBatch();
307         } else {
308             int cnt = ins0.executeUpdate();
309             assert (cnt == 1);
310         }
311     }
312 
313     // ----------------------------------------------------------------------
314 
runLookup(XMode mode, int[] id)315     protected void runLookup(XMode mode, int[] id) throws SQLException {
316         final String name = "S_getAttr," + mode;
317         final int n = id.length;
318         driver.beginOp(name);
319         connection.setAutoCommit(mode == XMode.indy);
320         if (mode != XMode.bulk) {
321             for(int i = 0; i < n; i++)
322                 lookup(id[i]);
323             if (mode != XMode.indy)
324                 connection.commit();
325         } else {
326             lookup(id);
327             connection.commit();
328         }
329         driver.finishOp(name, n);
330     }
331 
lookup(int[] id)332     protected void lookup(int[] id) throws SQLException {
333         final int n = id.length;
334 
335         // use dynamic SQL for generic bulk queries
336         // The mysql jdbc driver requires property allowMultiQueries=true
337         // passed to DriverManager.getConnection() or in URL
338         // jdbc:mysql://localhost/crunddb?allowMultiQueries=true
339         final StringBuilder sb = new StringBuilder();
340         for (int i = 0; i < n; i++)
341             sb.append(sqlSel0.replace("?", "'" + id[i] + "'")).append(";");
342         final String q = sb.toString();
343         final Statement s = connection.createStatement();
344 
345         // allow for multi/single result sets with single/multi rows
346         boolean hasRS = s.execute(q);
347         int i = 0;
348         while (hasRS) {
349             final ResultSet rs = s.getResultSet();
350             while (rs.next())
351                 check(id[i++], rs);
352             hasRS = s.getMoreResults();
353         }
354         verify(n, i);
355     }
356 
lookup(int id)357     protected void lookup(int id) throws SQLException {
358         sel0.setString(1, Integer.toString(id)); // key
359         final ResultSet rs = sel0.executeQuery();
360         int i = 0;
361         while (rs.next()) {
362             check(id, rs);
363             i++;
364         }
365         verify(1, i);
366         rs.close();
367     }
368 
check(int id, ResultSet rs)369     protected void check(int id, ResultSet rs) throws SQLException {
370         // XXX not verifying at this time
371         String ac0 = rs.getString(1);
372         String c1 = rs.getString(2);
373         int c2 = rs.getInt(3);
374         int c3 = rs.getInt(4);
375         int c4 = rs.getInt(5);
376         String c5 = rs.getString(6);
377         String c6 = rs.getString(7);
378         String c7 = rs.getString(8);
379         String c8 = rs.getString(9);
380         String c9 = rs.getString(10);
381         String c10 = rs.getString(11);
382         String c11 = rs.getString(12);
383         String c12 = rs.getString(13);
384         String c13 = rs.getString(14);
385         String c14 = rs.getString(15);
386     }
387 
388     // ----------------------------------------------------------------------
389 
runUpdate(XMode mode, int[] id)390     protected void runUpdate(XMode mode, int[] id) throws SQLException {
391         final String name = "S_setAttr," + mode;
392         final int n = id.length;
393         driver.beginOp(name);
394         connection.setAutoCommit(mode == XMode.indy);
395         for(int i = 0; i < n; i++)
396             update(mode, id[i]);
397         if (mode == XMode.bulk)
398             upd0.executeBatch();
399         if (mode != XMode.indy)
400             connection.commit();
401         driver.finishOp(name, n);
402     }
403 
update(XMode mode, int id)404     protected void update(XMode mode, int id) throws SQLException {
405         final String str0 = Integer.toString(id);
406         final int r = -id;
407         final String str1 = Integer.toString(r);
408         upd0.setString(1, str1);
409         upd0.setInt(2, r);
410         upd0.setInt(3, r);
411         upd0.setString(4, str1);
412         upd0.setString(5, str1);
413         upd0.setString(6, str1);
414         upd0.setString(7, str1);
415         upd0.setString(8, str0); // key
416         if (mode == XMode.bulk) {
417             upd0.addBatch();
418         } else {
419             int cnt = upd0.executeUpdate();
420             assert (cnt == 1);
421         }
422     }
423 
424     // ----------------------------------------------------------------------
425 
runDelete(XMode mode, int[] id)426     protected void runDelete(XMode mode, int[] id) throws SQLException {
427         final String name = "S_del," + mode;
428         final int n = id.length;
429         driver.beginOp(name);
430         connection.setAutoCommit(mode == XMode.indy);
431         for(int i = 0; i < n; i++)
432             delete(mode, id[i]);
433         if (mode == XMode.bulk)
434             del0.executeBatch();
435         if (mode != XMode.indy)
436             connection.commit();
437         driver.finishOp(name, n);
438     }
439 
delete(XMode mode, int id)440     protected void delete(XMode mode, int id) throws SQLException {
441         final String str = Integer.toString(id);
442         del0.setString(1, str);
443         if (mode == XMode.bulk) {
444             del0.addBatch();
445         } else {
446             int cnt = del0.executeUpdate();
447             assert (cnt == 1);
448         }
449     }
450 
451     // ----------------------------------------------------------------------
452 
clearPersistenceContext()453     protected void clearPersistenceContext() {
454         // nothing to do as we're not caching beyond Tx scope
455     }
456 }
457