| 1 26 27 package org.objectweb.cjdbc.driver; 28 29 import java.io.IOException ; 30 import java.net.Socket ; 31 import java.sql.ResultSet ; 32 import java.sql.SQLException ; 33 import java.sql.SQLWarning ; 34 import java.sql.Savepoint ; 35 import java.util.HashMap ; 36 import java.util.Iterator ; 37 import java.util.Map ; 38 import java.util.Properties ; 39 40 import org.objectweb.cjdbc.common.exceptions.AuthenticationException; 41 import org.objectweb.cjdbc.common.exceptions.NoMoreBackendException; 42 import org.objectweb.cjdbc.common.exceptions.NoMoreControllerException; 43 import org.objectweb.cjdbc.common.exceptions.NotImplementedException; 44 import org.objectweb.cjdbc.common.exceptions.ProtocolException; 45 import org.objectweb.cjdbc.common.exceptions.driver.DriverSQLException; 46 import org.objectweb.cjdbc.common.exceptions.driver.protocol.BackendDriverException; 47 import org.objectweb.cjdbc.common.exceptions.driver.protocol.ControllerCoreException; 48 import org.objectweb.cjdbc.common.exceptions.driver.protocol.SerializableException; 49 import org.objectweb.cjdbc.common.sql.AbstractRequest; 50 import org.objectweb.cjdbc.common.sql.AbstractWriteRequest; 51 import org.objectweb.cjdbc.common.sql.SelectRequest; 52 import org.objectweb.cjdbc.common.sql.StoredProcedure; 53 import org.objectweb.cjdbc.common.sql.filters.AbstractBlobFilter; 54 import org.objectweb.cjdbc.common.stream.CJDBCInputStream; 55 import org.objectweb.cjdbc.common.stream.CJDBCOutputStream; 56 import org.objectweb.cjdbc.common.util.Constants; 57 import org.objectweb.cjdbc.driver.connectpolicy.AbstractControllerConnectPolicy; 58 import org.objectweb.cjdbc.driver.protocol.Commands; 59 import org.objectweb.cjdbc.driver.protocol.SQLDataSerialization; 60 import org.objectweb.cjdbc.driver.protocol.TypeTag; 61 62 79 public class Connection implements java.sql.Connection  80 { 81 82 protected boolean controllerNeedsSqlSkeleton = false; 83 84 85 protected boolean isClosed = false; 86 87 protected String escapeChar = "\'"; 88 89 90 protected ControllerInfo controllerInfo = null; 91 92 94 protected Driver driver = null; 95 96 97 protected Socket socket; 98 99 protected CJDBCInputStream socketInput; 100 101 protected CJDBCOutputStream socketOutput; 102 103 static final String LINE_SEPARATOR = System 105 .getProperty("line.separator"); 106 107 109 110 protected boolean autoCommit = true; 111 112 113 protected boolean readOnly = false; 114 115 116 boolean writeExecutedInTransaction = false; 117 118 119 public static final int DEFAULT_TRANSACTION_ISOLATION_LEVEL = -1; 120 121 protected int isolationLevel = DEFAULT_TRANSACTION_ISOLATION_LEVEL; 122 123 124 protected long transactionId = 0; 125 126 127 protected SQLWarning firstWarning = null; 128 129 130 protected DatabaseMetaData metaData = null; 131 132 133 private final CjdbcUrl cjdbcUrl; 134 135 136 protected String vdbUser = null; 137 protected String vdbPassword = null; 138 139 private AbstractBlobFilter blobFilter; 140 private boolean connectionPooling = true; 141 142 protected boolean escapeBackslash = true; 144 protected boolean escapeSingleQuote = true; 145 146 protected boolean driverProcessed = true; 148 149 protected String preparedStatementBooleanTrue = "'1'"; 151 protected String preparedStatementBooleanFalse = "'0'"; 152 153 private boolean closeSocketOnGC = true; 154 155 159 160 175 176 public Connection(Driver driver, Socket socket, CJDBCInputStream in, 177 CJDBCOutputStream out, CjdbcUrl cjdbcUrl, ControllerInfo controller, 178 String userName, String password) throws AuthenticationException, 179 IOException , ProtocolException 180 { 181 this.driver = driver; 182 this.socket = socket; 183 this.socketInput = in; 184 this.socketOutput = out; 185 this.cjdbcUrl = cjdbcUrl; 186 this.controllerInfo = controller; 187 this.vdbUser = userName; 188 this.vdbPassword = password; 189 190 if (!in.readBoolean()) throw new AuthenticationException(in.readUTF()); 192 193 this.controllerNeedsSqlSkeleton = in.readBoolean(); 194 String sfilter = in.readUTF(); 195 this.blobFilter = AbstractBlobFilter.getBlobFilterInstance(sfilter); 196 197 setUrlParametersOptionsOnConnection(cjdbcUrl); 198 if (cjdbcUrl.isDebugEnabled()) 199 System.out.println("New connection:" + this.toString()); 200 } 201 202 207 private void setUrlParametersOptionsOnConnection(CjdbcUrl cjdbcUrl) 208 { 209 HashMap cjdbcUrlParameters = cjdbcUrl.getParameters(); 210 211 String booleanTrue = (String ) cjdbcUrlParameters 212 .get(Driver.BOOLEAN_TRUE_PROPERTY); 213 if (booleanTrue != null) 214 setPreparedStatementBooleanTrue(booleanTrue); 215 216 String booleanFalse = (String ) cjdbcUrlParameters 217 .get(Driver.BOOLEAN_FALSE_PROPERTY); 218 if (booleanFalse != null) 219 setPreparedStatementBooleanFalse(booleanFalse); 220 221 String escapeBaskslash = (String ) cjdbcUrlParameters 222 .get(Driver.ESCAPE_BACKSLASH_PROPERTY); 223 if (escapeBaskslash != null) 224 setEscapeBackslash(new Boolean (escapeBaskslash).booleanValue()); 225 226 String escapeQuote = (String ) cjdbcUrlParameters 227 .get(Driver.ESCAPE_SINGLE_QUOTE_PROPERTY); 228 if (escapeQuote != null) 229 setEscapeSingleQuote(new Boolean (escapeQuote).booleanValue()); 230 231 String escapeCharacter = (String ) cjdbcUrlParameters 232 .get(Driver.ESCAPE_CHARACTER_PROPERTY); 233 if (escapeCharacter != null) 234 setEscapeChar(escapeCharacter); 235 236 String isDriverProcessed = (String ) cjdbcUrlParameters 237 .get(Driver.DRIVER_PROCESSED_PROPERTY); 238 if (isDriverProcessed != null) 239 setDriverProcessed(Boolean.valueOf(isDriverProcessed).booleanValue()); 240 241 this.connectionPooling = !"false".equals(cjdbcUrlParameters 243 .get(Driver.CONNECTION_POOLING_PROPERTY)); 244 245 if (cjdbcUrl.isDebugEnabled()) 246 { 247 for (Iterator iter = cjdbcUrlParameters.entrySet().iterator(); iter 249 .hasNext();) 250 { 251 Map.Entry e = (Map.Entry ) iter.next(); 252 String param = (String ) e.getKey(); 253 if (!Driver.driverProperties.contains(param)) 254 System.out.println("Unrecognized driver parameter: " + param + " = " 255 + (String ) e.getValue()); 256 } 257 } 258 } 259 260 263 protected void finalize() throws Throwable  264 { 265 if (this.closeSocketOnGC) 266 { 267 Throwable t = null; 268 try 269 { 270 rollback(); 271 } 272 catch (Exception e) 273 { 274 t = e; 275 } 276 try 277 { 278 close(); 279 } 280 catch (Exception e) 281 { 282 t = e; 283 } 284 285 if (t != null) 286 { 287 throw t; 288 } 289 290 } 291 super.finalize(); 292 } 293 294 299 public String getUrl() 300 { 301 return cjdbcUrl.getUrl(); 302 } 303 304 309 public String getUserName() 310 { 311 return vdbUser; 312 } 313 314 319 public String getPassword() 320 { 321 return vdbPassword; 322 } 323 324 329 public ControllerInfo getControllerInfo() 330 { 331 return controllerInfo; 332 } 333 334 338 342 public void clearWarnings() 343 { 344 firstWarning = null; 345 } 346 347 350 private void throwSQLExceptionIfClosed(String message) 351 throws DriverSQLException 352 { 353 if (isClosed) 354 throw new DriverSQLException(message); 355 } 356 357 360 private void throwSQLExceptionIfClosed() throws DriverSQLException 361 { 362 throwSQLExceptionIfClosed("Tried to operate on a closed Connection"); 364 } 365 366 373 public void close() throws DriverSQLException 374 { 375 synchronized (this) { 377 throwSQLExceptionIfClosed(); 378 isClosed = true; 379 385 } 386 387 if (connectionPooling) 388 { try 390 { 391 if (cjdbcUrl.isDebugEnabled()) 392 System.out.println("Resetting connection and adding it to the pool"); 393 autoCommit = true; 394 readOnly = false; 395 socketOutput.writeInt(Commands.Reset); 396 socketOutput.flush(); 397 } 398 catch (IOException e) 399 { 400 throw new DriverSQLException("I/O Error while closing the connection\n" 401 + e.getLocalizedMessage(), e); 402 } 403 404 synchronized (driver.pendingConnectionClosing) 406 { 407 if (!driver.connectionClosingThreadisAlive) 408 { if (cjdbcUrl.isDebugEnabled()) 410 System.out.println("Starting a new connection closing thread"); 411 ConnectionClosingThread t = new ConnectionClosingThread(driver); 412 t.start(); 413 } 414 driver.pendingConnectionClosing.add(this); 416 } 417 } 418 else 419 { try 421 { 422 driver = null; if (socketOutput != null) 426 { 427 if (cjdbcUrl.isDebugEnabled()) 428 System.out.println("Closing connection"); 429 socketOutput.writeInt(Commands.Close); 430 socketOutput.flush(); 431 if (socketInput != null) 432 { receiveBoolean(); 439 socketInput.close(); 440 } 441 socketOutput.close(); 442 } 443 444 if (socket != null) 445 socket.close(); 446 } 447 catch (Exception ignore) 448 { 449 } 450 } 451 } 452 453 464 public synchronized void commit() throws DriverSQLException 465 { 466 throwSQLExceptionIfClosed(); 467 if (autoCommit) 468 throw new DriverSQLException( 469 "Trying to commit a connection in autocommit mode"); 470 471 long firstTransactionId = this.transactionId; 472 try 473 { 474 socketOutput.writeInt(Commands.Commit); 475 socketOutput.flush(); 476 this.transactionId = receiveLong(); 478 writeExecutedInTransaction = false; 479 if (cjdbcUrl.isDebugEnabled()) 480 System.out.println("New transaction " + transactionId 481 + " has been started"); 482 } 483 catch (SerializableException e) 484 { 485 throw new DriverSQLException(e); 486 } 487 catch (IOException e) 488 { 489 throw new DriverSQLException( 490 "I/O Error occured around commit of transaction '" 491 + firstTransactionId + "\n" + e.getLocalizedMessage(), e); 492 } 493 } 494 495 505 public java.sql.Statement createStatement() throws DriverSQLException 506 { 507 throwSQLExceptionIfClosed(); 508 return new Statement(this); 509 } 510 511 521 public java.sql.Statement createStatement(int resultSetType, 522 int resultSetConcurrency) throws SQLException  523 { 524 throwSQLExceptionIfClosed(); 525 Statement s = new Statement(this); 526 s.setResultSetType(resultSetType); 527 s.setResultSetConcurrency(resultSetConcurrency); 528 return s; 529 } 530 531 538 public boolean getAutoCommit() throws DriverSQLException 539 { 540 throwSQLExceptionIfClosed(); 541 return this.autoCommit; 542 } 543 544 553 public java.sql.DatabaseMetaData getMetaData() throws DriverSQLException 554 { 555 throwSQLExceptionIfClosed(); 556 if (metaData == null) 557 { 558 metaData = new DatabaseMetaData(this); 559 } 560 return metaData; 561 } 562 563 570 public synchronized String getCatalog() throws DriverSQLException 571 { 572 throwSQLExceptionIfClosed(); 573 try 574 { 575 socketOutput.writeInt(Commands.ConnectionGetCatalog); 576 socketOutput.flush(); 577 578 if (cjdbcUrl.isDebugEnabled()) 579 System.out.println("Connection.getCatalog"); 580 581 return receiveString(); 582 } 583 catch (SerializableException e) 584 { 585 throw new DriverSQLException(e); 586 } 587 catch (IOException e) 588 { 589 throw wrapIOExceptionInDriverSQLException("getCatalog", e); 590 } 591 } 592 593 599 public synchronized ResultSet getCatalogs() throws DriverSQLException 600 { 601 throwSQLExceptionIfClosed(); 602 String myName = "Connection.getCatalogs"; 603 try 604 { 605 socketOutput.writeInt(Commands.ConnectionGetCatalogs); 606 socketOutput.flush(); 607 608 if (cjdbcUrl.isDebugEnabled()) 609 System.out.println(myName); 610 611 return receiveResultSet(myName); 612 } 613 catch (SerializableException e) 614 { 615 throw new DriverSQLException(e); 616 } 617 catch (IOException e) 618 { 619 throw wrapIOExceptionInDriverSQLException("getCatalogs", e); 620 } 621 } 622 623 protected synchronized java.sql.ResultSet getProcedures(String catalog, 624 String schemaPattern, String procedureNamePattern) 625 throws DriverSQLException 626 { 627 throwSQLExceptionIfClosed(); 628 String myName = "Connection.getProcedures"; 629 try 630 { 631 socketOutput.writeInt(Commands.DatabaseMetaDataGetProcedures); 632 socketOutput.writeUTF(catalog); 633 socketOutput.writeUTF(schemaPattern); 634 socketOutput.writeUTF(procedureNamePattern); 635 socketOutput.flush(); 636 637 if (cjdbcUrl.isDebugEnabled()) 638 System.out.println(myName + "(" + catalog + "," + schemaPattern + "," 639 + procedureNamePattern + ")"); 640 641 return receiveResultSet(myName); 642 } 643 catch (SerializableException e) 644 { 645 throw new DriverSQLException(e); 646 } 647 catch (IOException e) 648 { 649 throw wrapIOExceptionInDriverSQLException("getProcedures", e); 650 } 651 } 652 653 protected synchronized java.sql.ResultSet getProcedureColumns(String catalog, 654 String schemaPattern, String procedureNamePattern, 655 String columnNamePattern) throws DriverSQLException 656 { 657 throwSQLExceptionIfClosed(); 658 String myName = "Connection.getProcedureColumns"; 659 try 660 { 661 socketOutput.writeInt(Commands.DatabaseMetaDataGetProcedureColumns); 662 socketOutput.writeUTF(catalog); 663 socketOutput.writeUTF(schemaPattern); 664 socketOutput.writeUTF(procedureNamePattern); 665 socketOutput.writeUTF(columnNamePattern); 666 socketOutput.flush(); 667 668 if (cjdbcUrl.isDebugEnabled()) 669 System.out.println(myName + "(" + catalog + "," + schemaPattern + "," 670 + procedureNamePattern + "," + columnNamePattern + ")"); 671 672 return receiveResultSet(myName); 673 } 674 catch (SerializableException e) 675 { 676 throw new DriverSQLException(e); 677 } 678 catch (IOException e) 679 { 680 throw wrapIOExceptionInDriverSQLException("getProcedureColumns", e); 681 } 682 } 683 684 697 public int getTransactionIsolation() throws DriverSQLException 698 { 699 throwSQLExceptionIfClosed(); 700 if (isolationLevel == DEFAULT_TRANSACTION_ISOLATION_LEVEL) 703 return java.sql.Connection.TRANSACTION_READ_UNCOMMITTED; 704 return isolationLevel; 705 } 706 707 713 public java.util.Map getTypeMap() throws SQLException  714 { 715 throw new NotImplementedException("getTypeMap()"); 716 } 717 718 724 public SQLWarning getWarnings() 725 { 726 return firstWarning; 727 } 728 729 736 public boolean isClosed() 737 { 738 return isClosed; 739 } 740 741 748 public boolean isReadOnly() 749 { 750 return readOnly; 751 } 752 753 761 public String nativeSQL(String query) 762 { 763 return query; 764 } 765 766 774 public java.sql.CallableStatement prepareCall(String sql) throws SQLException  775 { 776 throwSQLExceptionIfClosed(); 777 return prepareCall(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, 778 java.sql.ResultSet.CONCUR_READ_ONLY); 779 } 780 781 790 public java.sql.CallableStatement prepareCall(String sql, int resultSetType, 791 int resultSetConcurrency) throws SQLException  792 { 793 throwSQLExceptionIfClosed(); 794 CallableStatement c = new CallableStatement(this, sql); 795 c.setResultSetType(resultSetType); 796 c.setResultSetConcurrency(resultSetConcurrency); 797 return c; 798 } 799 800 811 public java.sql.PreparedStatement prepareStatement(String sql) 812 throws SQLException  813 { 814 throwSQLExceptionIfClosed(); 815 return new PreparedStatement(this, sql); 816 } 817 818 829 public java.sql.PreparedStatement prepareStatement(String sql, 830 int resultSetType, int resultSetConcurrency) throws SQLException  831 { 832 throwSQLExceptionIfClosed(); 833 PreparedStatement s = new PreparedStatement(this, sql); 834 s.setResultSetType(resultSetType); 835 s.setResultSetConcurrency(resultSetConcurrency); 836 return s; 837 } 838 839 848 public synchronized void rollback() throws DriverSQLException 849 { 850 throwSQLExceptionIfClosed(); 851 if (autoCommit) 852 throw new DriverSQLException( 853 "Trying to rollback a connection in autocommit mode"); 854 855 long initialTransactionId = this.transactionId; 856 try 857 { 858 socketOutput.writeInt(Commands.Rollback); 859 socketOutput.flush(); 860 this.transactionId = receiveLong(); 862 writeExecutedInTransaction = false; 863 864 if (cjdbcUrl.isDebugEnabled()) 865 System.out 866 .println("Transaction " + transactionId + " has been started"); 867 } 868 catch (SerializableException e) 869 { 870 throw new DriverSQLException(e); 871 } 872 catch (IOException e) 873 { 874 throw new DriverSQLException( 875 "I/O Error occured around rollback of transaction '" 876 + initialTransactionId + "\n" + e.getLocalizedMessage(), e); 877 } 878 } 879 880 898 public synchronized void setAutoCommit(boolean autoCommit) 899 throws DriverSQLException 900 { 901 throwSQLExceptionIfClosed(); 902 if (this.autoCommit == autoCommit) 903 return; 904 905 if (autoCommit) 906 { try 908 { 909 if (cjdbcUrl.isDebugEnabled()) 910 System.out.println("Setting connection in autocommit mode"); 911 socketOutput.writeInt(Commands.SetAutoCommit); 912 socketOutput.flush(); 913 914 receiveBoolean(); 915 writeExecutedInTransaction = false; 916 transactionId = 0; 917 this.autoCommit = true; 918 return; 919 920 } 921 catch (SerializableException se) 922 { 923 throw new DriverSQLException(se); 924 } 925 catch (IOException e) 926 { 927 throw new DriverSQLException( 928 "Error while trying to enable autocommit\n" 929 + e.getLocalizedMessage(), e); 930 } 931 } 932 else 933 { try 935 { 936 socketOutput.writeInt(Commands.Begin); 937 socketOutput.flush(); 938 939 transactionId = receiveLong(); 940 |