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