1 21 22 package org.apache.derbyTesting.functionTests.tests.jdbcapi; 23 24 import java.sql.CallableStatement ; 25 import java.sql.Connection ; 26 import java.sql.SQLException ; 27 import java.sql.Statement ; 28 import java.sql.PreparedStatement ; 29 import java.sql.ResultSet ; 30 31 import java.util.Collection ; 32 import java.util.HashSet ; 33 import java.util.Collections ; 34 35 import org.apache.derby.tools.ij; 36 37 77 public class SetQueryTimeoutTest 78 { 79 private static final int TIMEOUT = 1; private static final int CONNECTIONS = 100; 81 82 private static void printSQLException(SQLException e) 83 { 84 while (e != null) 85 { 86 e.printStackTrace(); 87 e = e.getNextException(); 88 } 89 } 90 91 99 private static class TestFailedException 100 extends 101 Exception 102 { 103 private Throwable cause; 104 105 public TestFailedException(Throwable t) 106 { 107 super(); 108 cause = t; 109 } 110 111 public TestFailedException(String message) 112 { 113 super(message); 114 cause = null; 115 } 116 117 public TestFailedException(String message, Throwable t) 118 { 119 super(message); 120 cause = t; 121 } 122 123 public String toString() 124 { 125 if (cause != null) { 126 return super.toString() + ": " + cause.toString(); 127 } else { 128 return super.toString(); 129 } 130 } 131 132 public void printStackTrace() 133 { 134 super.printStackTrace(); 135 if (cause != null) { 136 if (cause instanceof SQLException ) { 137 SetQueryTimeoutTest.printSQLException((SQLException )cause); 138 } else { 139 cause.printStackTrace(); 140 } 141 } 142 } 143 } 144 145 150 private static void exec(Connection connection, 151 String queryString, 152 Collection ignoreExceptions) 153 throws 154 TestFailedException 155 { 156 Statement statement = null; 157 try { 158 statement = connection.createStatement(); 159 statement.execute(queryString); 160 } catch (SQLException e) { 161 String sqlState = e.getSQLState(); 162 if (!ignoreExceptions.contains(sqlState)) { 163 throw new TestFailedException(e); } 165 } finally { 166 if (statement != null) { 167 try { 168 statement.close(); 169 } catch (SQLException ee) { 170 throw new TestFailedException(ee); 176 } 177 } 178 } 179 } 180 181 private static void exec(Connection connection, 183 String queryString) 184 throws 185 TestFailedException 186 { 187 exec(connection, queryString, Collections.EMPTY_SET); 188 } 189 190 private static void dropTables(Connection conn, String tablePrefix) 191 throws 192 TestFailedException 193 { 194 Collection ignore = new HashSet (); 195 ignore.add("42Y55"); 196 197 exec(conn, "drop table " + tablePrefix + "_orig", ignore); 198 exec(conn, "drop table " + tablePrefix + "_copy", ignore); 199 } 200 201 private static void prepareTables(Connection conn, String tablePrefix) 202 throws 203 TestFailedException 204 { 205 System.out.println("Initializing tables with prefix " + tablePrefix); 206 207 dropTables(conn, tablePrefix); 208 209 exec(conn, 210 "create table " + tablePrefix + "_orig (a int)"); 211 212 exec(conn, 213 "create table " + tablePrefix + "_copy (a int)"); 214 215 exec(conn, 216 "insert into " 217 + tablePrefix + "_orig" 218 + " values(0),(1),(2),(3),(4),(5),(6)"); 219 } 220 221 224 public static int delay(int seconds, int value) 225 throws 226 SQLException 227 { 228 try { 229 Thread.sleep(seconds * 1000); 230 } catch (InterruptedException e) { 231 } 233 return value; 234 } 235 236 private static void prepareForTimedQueries(Connection conn) 237 throws 238 TestFailedException 239 { 240 System.out.println("Preparing for testing queries with timeout"); 241 242 try { 243 conn.setAutoCommit(true); 244 } catch (SQLException e) { 245 throw new TestFailedException("Should not happen", e); 246 } 247 248 try { 249 exec(conn, "DROP FUNCTION DELAY"); 250 } catch (Exception e) { 251 } 253 254 exec(conn, "CREATE FUNCTION DELAY(SECONDS INTEGER, VALUE INTEGER) RETURNS INTEGER PARAMETER STYLE JAVA NO SQL LANGUAGE JAVA EXTERNAL NAME 'org.apache.derbyTesting.functionTests.tests.jdbcapi.SetQueryTimeoutTest.delay'"); 255 256 prepareTables(conn, "t"); 257 } 258 259 private static String getFetchQuery(String tablePrefix) 260 { 261 269 return "select a from " + tablePrefix + "_orig where mod(DELAY(1,a),3)=0"; 270 } 271 272 private static String getExecQuery(String tablePrefix) 273 { 274 return "insert into " 275 + tablePrefix + "_copy select a from " 276 + tablePrefix + "_orig where DELAY(1,1)=1"; 277 } 278 279 private static class StatementExecutor 280 extends 281 Thread 282 { 283 private PreparedStatement statement; 284 private boolean doFetch; 285 private int timeout; 286 private SQLException sqlException; 287 private String name; 288 private long highestRunTime; 289 290 public StatementExecutor(PreparedStatement statement, 291 boolean doFetch, 292 int timeout) 293 { 294 this.statement = statement; 295 this.doFetch = doFetch; 296 this.timeout = timeout; 297 highestRunTime = 0; 298 sqlException = null; 299 if (timeout > 0) { 300 try { 301 statement.setQueryTimeout(timeout); 302 } catch (SQLException e) { 303 sqlException = e; 304 } 305 } 306 } 307 308 private void setHighestRunTime(long runTime) 309 { 310 synchronized (this) { 311 highestRunTime = runTime; 312 } 313 } 314 315 public long getHighestRunTime() 316 { 317 synchronized (this) { 318 return highestRunTime; 319 } 320 } 321 322 private boolean fetchRow(ResultSet resultSet) 323 throws 324 SQLException 325 { 326 long startTime = System.currentTimeMillis(); 327 boolean hasNext = resultSet.next(); 328 long endTime = System.currentTimeMillis(); 329 long runTime = endTime - startTime; 330 if (runTime > highestRunTime) setHighestRunTime(runTime); 331 return hasNext; 332 } 333 334 public void run() 335 { 336 if (sqlException != null) 337 return; 338 339 ResultSet resultSet = null; 340 341 try { 342 if (doFetch) { 343 long startTime = System.currentTimeMillis(); 344 resultSet = statement.executeQuery(); 345 long endTime = System.currentTimeMillis(); 346 setHighestRunTime(endTime - startTime); 347 while (fetchRow(resultSet)) { 348 yield(); 349 } 350 } else { 351 long startTime = System.currentTimeMillis(); 352 statement.execute(); 353 long endTime = System.currentTimeMillis(); 354 setHighestRunTime(endTime - startTime); 355 } 356 } catch (SQLException e) { 357 synchronized (this) { 358 sqlException = e; 359 } 360 } finally { 361 if (resultSet != null) { 362 try { 363 resultSet.close(); 364 } catch (SQLException ex) { 365 if (sqlException != null) { 366 System.err.println("Discarding previous exception"); 367 sqlException.printStackTrace(); 368 } 369 sqlException = ex; 370 } 371 } 372 } 373 } 374 375 public SQLException getSQLException() 376 { 377 synchronized (this) { 378 return sqlException; 379 } 380 } 381 } 382 383 388 private static void expectException(String expectSqlState, 389 SQLException sqlException, 390 String failMsg) 391 throws 392 TestFailedException 393 { 394 if (sqlException == null) { 395 throw new TestFailedException(failMsg); 396 } else { 397 String sqlState = sqlException.getSQLState(); 398 if (!expectSqlState.equals(sqlState)) { 399 throw new TestFailedException(sqlException); 400 } 401 } 402 } 403 404 private static PreparedStatement prepare(Connection conn, String query) 406 throws 407 TestFailedException 408 { 409 try { 410 return conn.prepareStatement(query); 411 } catch (SQLException e) { 412 throw new TestFailedException(e); 413 } 414 } 415 416 419 private static void testTimeoutWithFetch(Connection conn1, 420 Connection conn2) 421 throws 422 TestFailedException 423 { 424 System.out.println("Testing timeout with fetch operations"); 425 426 try { 427 conn1.setAutoCommit(false); 428 conn2.setAutoCommit(false); 429 } catch (SQLException e) { 430 throw new TestFailedException("Should not happen", e); 431 } 432 433 439 PreparedStatement statementA = prepare(conn1, getFetchQuery("t")); 440 PreparedStatement statementB = prepare(conn1, getFetchQuery("t")); 441 PreparedStatement statementC = prepare(conn2, getFetchQuery("t")); 442 PreparedStatement statementD = prepare(conn2, getFetchQuery("t")); 443 444 StatementExecutor[] statementExecutor = new StatementExecutor[4]; 445 statementExecutor[0] = new StatementExecutor(statementA, true, TIMEOUT); 446 statementExecutor[1] = new StatementExecutor(statementB, true, 0); 447 statementExecutor[2] = new StatementExecutor(statementC, true, 0); 448 statementExecutor[3] = new StatementExecutor(statementD, true, 0); 449 450 for (int i = 3; i >= 0; --i) { 451 statementExecutor[i].start(); 452 } 453 454 for (int i = 0; i < 4; ++i) { 455 try { 456 statementExecutor[i].join(); 457 } catch (InterruptedException e) { 458 throw new TestFailedException("Should never happen", e); 459 } 460 } 461 462 478 expectException("XCL52", 479 statementExecutor[0].getSQLException(), 480 "fetch did not time out. Highest execution time: " 481 + statementExecutor[0].getHighestRunTime() + " ms"); 482 483 System.out.println("Statement 0 timed out"); 484 485 for (int i = 1; i < 4; ++i) { 486 SQLException sqlException = statementExecutor[i].getSQLException(); 487 if (sqlException != null) { 488 throw new TestFailedException("Unexpected exception in " + i, 489 sqlException); 490 } 491 System.out.println("Statement " + i + " completed"); 492 } 493 494 try { 495 statementA.close(); 496 statementB.close(); 497 statementC.close(); 498 statementD.close(); 499 conn1.commit(); 500 conn2.commit(); 501 } catch (SQLException e) { 502 throw new TestFailedException(e); 503 } 504 } 505 506 509 private static void testTimeoutWithExec(Connection [] connections) 510 throws 511 TestFailedException 512 { 513 System.out.println("Testing timeout with an execute operation"); 514 515 for (int i = 0; i < connections.length; ++i) { 516 try { 517 connections[i].setAutoCommit(true); 518 } catch (SQLException e) { 519 throw new TestFailedException("Should not happen", e); 520 } 521 } 522 523 PreparedStatement statements[] = new PreparedStatement [connections.length]; 524 for (int i = 0; i < statements.length; ++i) { 525 statements[i] = prepare(connections[i], getExecQuery("t")); 526 } 527 528 StatementExecutor[] executors = new StatementExecutor[statements.length]; 529 for (int i = 0; i < executors.length; ++i) { 530 int timeout = 531 (i % 2 == 0) 532 ? TIMEOUT 533 : 0; 534 executors[i] = new StatementExecutor(statements[i], false, timeout); 535 } 536 537 for (int i = 0; i < executors.length; ++i) { 538 executors[i].start(); 539 } 540 541 for (int i = 0; i < executors.length; ++i) { 542 try { 543 executors[i].join(); 544 } catch (InterruptedException e) { 545 throw new TestFailedException("Should never happen", e); 546 } 547 } 548 549 565 for (int i = 0; i < executors.length; ++i) { 566 int timeout = 567 (i % 2 == 0) 568 ? TIMEOUT 569 : 0; 570 if (timeout > 0) { 571 expectException("XCL52", 572 executors[i].getSQLException(), 573 "exec did not time out. Execution time: " 574 + executors[i].getHighestRunTime() + " ms"); 575 } else { 576 SQLException sqlException = executors[i].getSQLException(); 577 if (sqlException != null) { 578 throw new TestFailedException(sqlException); 579 } 580 } 581 } 582 583 System.out.println("Statements that should time out timed out, and statements that should complete completed"); 584 585 for (int i = 0; i < statements.length; ++i) { 586 try { 587 statements[i].close(); 588 } catch (SQLException e) { 589 throw new TestFailedException(e); 590 } 591 } 592 } 593 594 private static void testInvalidTimeoutValue(Connection conn) 595 throws 596 TestFailedException 597 { 598 System.out.println("Testing setting a negative timeout value"); 599 600 try { 601 conn.setAutoCommit(true); 602 } catch (SQLException e) { 603 throw new TestFailedException("Should not happen", e); 604 } 605 606 PreparedStatement stmt = null; 608 try { 609 stmt = conn.prepareStatement("select * from sys.systables"); 610 } catch (SQLException e) { 611 throw new TestFailedException("Should not happen", e); 612 } 613 614 try { 616 stmt.setQueryTimeout(-1); 617 } catch (SQLException e) { 618 expectException("XJ074", e, 619 "negative timeout value should give exception"); 620 } 621 622 System.out.println("Negative timeout value caused exception, as expected"); 623 624 ResultSet rs = null; 626 try { 627 rs = stmt.executeQuery(); 628 System.out.println("Execute returned a ResultSet"); 629 rs.close(); 630 } catch (SQLException e) { 631 throw new TestFailedException("Should not happen", e); 632 } finally { 633 try { 634 stmt.close(); 635 } catch (SQLException e) { 636 throw new TestFailedException("close should not throw", e); 642 } 643 } 644 } 645 646 647 private static void testTimeoutWithExecuteUpdate(Connection conn) 648 throws TestFailedException 649 { 650 System.out.println("Testing timeout with executeUpdate call."); 651 try{ 652 Statement stmt = conn.createStatement(); 653 stmt.setQueryTimeout(TIMEOUT); 654 stmt.executeUpdate(getExecQuery("t")); 655 } catch (SQLException sqle) { 656 expectException("XCL52", sqle, "Should have timed out."); 657 } 658 } 659 660 661 private static void testRememberTimeoutValue(Connection conn) 662 throws TestFailedException 663 { 664 String sql = getFetchQuery("t"); 665 try { 666 Statement stmt = conn.createStatement(); 667 testStatementRemembersTimeout(stmt); 668 PreparedStatement ps = conn.prepareStatement(sql); 669 testStatementRemembersTimeout(ps); 670 CallableStatement cs = conn.prepareCall(sql); 671 testStatementRemembersTimeout(cs); 672 } catch (SQLException sqle) { 673 throw new TestFailedException("Should not happen", sqle); 674 } 675 } 676 677 679 private static void testStatementRemembersTimeout(Statement stmt) 680 throws SQLException , TestFailedException 681 { 682 System.out.println("Testing that Statement remembers timeout."); 683 stmt.setQueryTimeout(1); 684 for (int i = 0; i < 3; i++) { 685 try { 686 ResultSet rs = stmt.executeQuery(getFetchQuery("t")); 687 while (rs.next()); 688 throw new TestFailedException("Should have timed out."); 689 } catch (SQLException sqle) { 690 expectException("XCL52", sqle, "Should have timed out."); 691 } 692 } 693 stmt.close(); 694 } 695 696 698 private static void testStatementRemembersTimeout(PreparedStatement ps) 699 throws SQLException , TestFailedException 700 { 701 String name = (ps instanceof CallableStatement ) ? 702 "CallableStatement" : "PreparedStatement"; 703 System.out.println("Testing that " + name + " remembers timeout."); 704 ps.setQueryTimeout(1); 705 for (int i = 0; i < 3; i++) { 706 try { 707 ResultSet rs = ps.executeQuery(); 708 while (rs.next()); 709 throw new TestFailedException("Should have timed out."); 710 } catch (SQLException sqle) { 711 expectException("XCL52", sqle, "Should have timed out."); 712 } 713 } 714 ps.close(); 715 } 716 717 720 public static void main(String [] args) 721 { 722 new SetQueryTimeoutTest().go(args); 723 } 724 725 730 public void go(String [] args) 731 { 732 System.out.println("Test SetQueryTimeoutTest starting"); 733 734 Connection [] connections = new Connection [CONNECTIONS]; 735 for (int i = 0; i < connections.length; ++i) { 736 connections[i] = null; 737 } 738 739 try { 740 ij.getPropertyArg(args); 744 for (int i = 0; i < connections.length; ++i) { 745 connections[i] = ij.startJBMS(); 746 } 747 748 System.out.println("Got connections"); 749 750 for (int i = 0; i < connections.length; ++i) { 751 connections[i].setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); 752 } 753 754 prepareForTimedQueries(connections[0]); 755 testTimeoutWithFetch(connections[0], connections[1]); 756 testTimeoutWithExec(connections); 757 testInvalidTimeoutValue(connections[0]); 758 testRememberTimeoutValue(connections[0]); 759 testTimeoutWithExecuteUpdate(connections[0]); 760 761 System.out.println("Test SetQueryTimeoutTest PASSED"); 762 } catch (Throwable e) { 763 System.out.println("Test SetQueryTimeoutTest FAILED"); 764 e.printStackTrace(); 765 } finally { 766 for (int i = connections.length - 1; i >= 0; --i) { 767 if (connections[i] != null) { 768 try { 769 connections[i].close(); 770 } catch (SQLException ex) { 771 printSQLException(ex); 772 } 773 } 774 } 775 System.out.println("Closed connections"); 776 } 777 } 778 } 779 | Popular Tags |