1 19 package com.mysql.jdbc; 20 21 import java.io.BufferedInputStream ; 22 import java.io.BufferedOutputStream ; 23 import java.io.ByteArrayOutputStream ; 24 import java.io.EOFException ; 25 import java.io.FileInputStream ; 26 import java.io.IOException ; 27 import java.io.InputStream ; 28 import java.io.OutputStreamWriter ; 29 30 import java.lang.ref.SoftReference ; 31 32 import java.net.Socket ; 33 34 import java.security.NoSuchAlgorithmException ; 35 36 import java.sql.SQLException ; 37 import java.sql.SQLWarning ; 38 39 import java.util.ArrayList ; 40 import java.util.Properties ; 41 import java.util.zip.Deflater ; 42 import java.util.zip.Inflater ; 43 44 45 53 public class MysqlIO { 54 static final int NULL_LENGTH = ~0; 55 static final int COMP_HEADER_LENGTH = 3; 56 static final int MIN_COMPRESS_LEN = 50; 57 static final int HEADER_LENGTH = 4; 58 private static int maxBufferSize = 65535; 59 private static final int CLIENT_COMPRESS = 32; 61 private static final int CLIENT_CONNECT_WITH_DB = 8; 62 private static final int CLIENT_FOUND_ROWS = 2; 63 private static final int CLIENT_IGNORE_SPACE = 256; 65 private static final int CLIENT_LOCAL_FILES = 128; 67 68 70 private static final int CLIENT_LONG_FLAG = 4; 71 private static final int CLIENT_LONG_PASSWORD = 1; 73 private static final int CLIENT_PROTOCOL_41 = 512; private static final int CLIENT_INTERACTIVE = 1024; 75 private static final int CLIENT_SSL = 2048; 76 private static final int CLIENT_RESERVED = 16384; private static final int CLIENT_SECURE_CONNECTION = 32768; 78 private static final String FALSE_SCRAMBLE = "xxxxxxxx"; 79 80 84 private static String jvmPlatformCharset = null; 85 86 static { 87 OutputStreamWriter outWriter = null; 88 89 try { 95 outWriter = new OutputStreamWriter (new ByteArrayOutputStream ()); 96 jvmPlatformCharset = outWriter.getEncoding(); 97 } finally { 98 try { 99 outWriter.close(); 100 } catch (IOException ioEx) { 101 } 103 } 104 } 105 106 private Buffer reusablePacket = null; 112 private Buffer sendPacket = null; 113 private Buffer sharedSendPacket = null; 114 115 116 117 private BufferedOutputStream mysqlOutput = null; 119 private com.mysql.jdbc.Connection connection; 120 private Deflater deflater = null; 121 private Inflater inflater = null; 122 123 124 125 127 128 129 131 132 133 private InputStream mysqlInput = null; 135 private RowData streamingData = null; 136 137 private SQLWarning warningChain = null; 141 142 143 private Socket mysqlConnection = null; 144 private SocketFactory socketFactory = null; 145 146 private SoftReference loadFileBufRef; 153 154 private SoftReference splitBufRef; 160 private String host = null; 161 private String seed; 162 private String serverVersion = null; 163 private String socketFactoryClassName = null; 164 private byte[] packetHeaderBuf = new byte[4]; 165 private boolean clearStreamBeforeEachQuery = false; 166 private boolean colDecimalNeedsBump = false; private boolean has41NewNewProt = false; 168 169 170 private boolean hasLongColumnInfo = false; 171 private boolean isInteractiveClient = false; 172 173 177 private boolean platformDbCharsetMatches = true; 178 private boolean profileSql = false; 179 180 181 private boolean use41Extensions = false; 182 private boolean useCompression = false; 183 private boolean useNewLargePackets = false; 184 private boolean useNewUpdateCounts = false; private byte packetSequence = 0; 186 private byte protocolVersion = 0; 187 private int clientParam = 0; 188 189 private int maxAllowedPacket = 1024 * 1024; 191 private int maxThreeBytes = 255 * 255 * 255; 192 private int port = 3306; 193 private int serverMajorVersion = 0; 194 private int serverMinorVersion = 0; 195 private int serverSubMinorVersion = 0; 196 197 211 protected MysqlIO(String host, int port, String socketFactoryClassName, 212 Properties props, com.mysql.jdbc.Connection conn, int socketTimeout) 213 throws IOException , java.sql.SQLException { 214 this.connection = conn; 215 this.reusablePacket = new Buffer(this.connection.getNetBufferLength()); 216 this.port = port; 217 this.host = host; 218 this.socketFactoryClassName = socketFactoryClassName; 219 this.socketFactory = createSocketFactory(); 220 this.mysqlConnection = socketFactory.connect(this.host, props); 221 this.clearStreamBeforeEachQuery = this.connection.alwaysClearStream(); 222 223 if (socketTimeout != 0) { 224 try { 225 this.mysqlConnection.setSoTimeout(socketTimeout); 226 } catch (Exception ex) { 227 228 } 229 } 230 231 this.mysqlConnection = this.socketFactory.beforeHandshake(); 232 233 if (!this.connection.isUsingUnbufferedInput()) { 234 this.mysqlInput = new BufferedInputStream (this.mysqlConnection 235 .getInputStream(), 16384); 236 } else { 237 this.mysqlInput = this.mysqlConnection.getInputStream(); 238 } 239 240 this.mysqlOutput = new BufferedOutputStream (this.mysqlConnection 241 .getOutputStream(), 16384); 242 this.isInteractiveClient = this.connection.isInteractiveClient(); 243 } 244 245 250 protected void setProfileSql(boolean flag) { 251 this.profileSql = flag; 252 } 253 254 271 protected ResultSet getResultSet(long columnCount, int maxRows, 272 int resultSetType, boolean streamResults, String catalog) 273 throws Exception { 274 Buffer packet; Field[] fields = new Field[(int) columnCount]; 276 277 for (int i = 0; i < columnCount; i++) { 279 packet = readPacket(); 280 fields[i] = unpackField(packet, false); 281 } 282 283 packet = reuseAndReadPacket(this.reusablePacket); 284 285 RowData rowData = null; 286 287 if (!streamResults) { 288 ArrayList rows = new ArrayList (); 289 290 byte[][] rowBytes = nextRow((int) columnCount); 292 int rowCount = 0; 293 294 if (rowBytes != null) { 295 rows.add(rowBytes); 296 rowCount = 1; 297 } 298 299 while ((rowBytes != null) && (rowCount < maxRows)) { 300 rowBytes = nextRow((int) columnCount); 301 302 if (rowBytes != null) { 303 rows.add(rowBytes); 304 rowCount++; 305 } else { 306 if (Driver.TRACE) { 307 Debug.msg(this, "* NULL Row *"); 308 } 309 } 310 } 311 312 if (rowCount <= maxRows) { 318 clearInputStream(); 319 } 320 321 if (Driver.TRACE) { 322 Debug.msg(this, 323 "* Fetched " + rows.size() + " rows from server *"); 324 } 325 326 rowData = new RowDataStatic(rows); 327 reclaimLargeReusablePacket(); 328 } else { 329 rowData = new RowDataDynamic(this, (int) columnCount); 330 this.streamingData = rowData; 331 } 332 333 return buildResultSetWithRows(catalog, fields, rowData, resultSetType); 334 } 335 336 339 protected final void forceClose() { 340 try { 341 if (this.mysqlInput != null) { 342 this.mysqlInput.close(); 343 } 344 } catch (IOException ioEx) { 345 this.mysqlInput = null; 348 } 349 350 try { 351 if (this.mysqlOutput != null) { 352 this.mysqlOutput.close(); 353 } 354 } catch (IOException ioEx) { 355 this.mysqlOutput = null; 358 } 359 360 try { 361 if (this.mysqlConnection != null) { 362 this.mysqlConnection.close(); 363 } 364 } catch (IOException ioEx) { 365 this.mysqlConnection = null; 368 } 369 } 370 371 376 protected boolean hasLongColumnInfo() { 377 return this.hasLongColumnInfo; 378 } 379 380 389 protected final Field unpackField(Buffer packet, 390 boolean extractDefaultValues) { 391 if (this.use41Extensions) { 392 if (this.has41NewNewProt) { 395 int catalogNameStart = packet.getPosition() + 1; 396 int catalogNameLength = packet.fastSkipLenString(); 397 } 398 399 int databaseNameStart = packet.getPosition() + 1; 400 int databaseNameLength = packet.fastSkipLenString(); 401 402 int tableNameStart = packet.getPosition() + 1; 403 int tableNameLength = packet.fastSkipLenString(); 404 405 int originalTableNameStart = packet.getPosition() + 1; 407 int originalTableNameLength = packet.fastSkipLenString(); 408 409 int nameStart = packet.getPosition() + 1; 411 int nameLength = packet.fastSkipLenString(); 412 413 int originalColumnNameStart = packet.getPosition() + 1; 415 int originalColumnNameLength = packet.fastSkipLenString(); 416 417 packet.readByte(); 418 419 int charSetNumber = packet.readInt(); 420 421 int colLength = 0; 422 423 if (this.has41NewNewProt) { 424 colLength = (int) packet.readLong(); 426 } else { 427 colLength = packet.readLongInt(); 428 } 429 430 int colType = packet.readByte() & 0xff; 431 432 short colFlag = 0; 433 434 if (this.hasLongColumnInfo) { 435 colFlag = (short) (packet.readInt()); 436 } else { 437 colFlag = (short) (packet.readByte() & 0xff); 438 } 439 440 int colDecimals = packet.readByte() & 0xff; 441 442 int defaultValueStart = -1; 443 int defaultValueLength = -1; 444 445 if (extractDefaultValues) { 446 defaultValueStart = packet.getPosition() + 1; 447 defaultValueLength = packet.fastSkipLenString(); 448 } 449 450 Field field = new Field(this.connection, packet.getByteBuffer(), 451 databaseNameStart, databaseNameLength, tableNameStart, 452 tableNameLength, originalTableNameStart, 453 originalTableNameLength, nameStart, nameLength, 454 originalColumnNameStart, originalColumnNameLength, 455 colLength, colType, colFlag, colDecimals, 456 defaultValueStart, defaultValueLength, charSetNumber); 457 458 return field; 459 } else { 460 int tableNameStart = packet.getPosition() + 1; 461 int tableNameLength = packet.fastSkipLenString(); 462 int nameStart = packet.getPosition() + 1; 463 int nameLength = packet.fastSkipLenString(); 464 int colLength = packet.readnBytes(); 465 int colType = packet.readnBytes(); 466 packet.readByte(); 468 short colFlag = 0; 469 470 if (this.hasLongColumnInfo) { 471 colFlag = (short) (packet.readInt()); 472 } else { 473 colFlag = (short) (packet.readByte() & 0xff); 474 } 475 476 int colDecimals = (packet.readByte() & 0xff); 477 478 if (this.colDecimalNeedsBump) { 479 colDecimals++; 480 } 481 482 Field field = new Field(this.connection, packet.getBufferSource(), 483 nameStart, nameLength, tableNameStart, tableNameLength, 484 colLength, colType, colFlag, colDecimals); 485 486 return field; 487 } 488 } 489 490 493 protected void checkForCharsetMismatch() { 494 if (this.connection.useUnicode() 495 && (this.connection.getEncoding() != null)) { 496 String encodingToCheck = jvmPlatformCharset; 497 498 if (encodingToCheck == null) { 499 encodingToCheck = System.getProperty("file.encoding"); 500 } 501 502 if (encodingToCheck == null) { 503 this.platformDbCharsetMatches = false; 504 } else { 505 this.platformDbCharsetMatches = encodingToCheck.equals(this.connection 506 .getEncoding()); 507 } 508 } 509 } 510 511 static int getMaxBuf() { 512 return maxBufferSize; 513 } 514 515 520 final int getServerMajorVersion() { 521 return this.serverMajorVersion; 522 } 523 524 529 final int getServerMinorVersion() { 530 return this.serverMinorVersion; 531 } 532 533 538 final int getServerSubMinorVersion() { 539 return this.serverSubMinorVersion; 540 } 541 542 547 String getServerVersion() { 548 return this.serverVersion; 549 } 550 551 562 void doHandshake(String user, String password, String database) 563 throws java.sql.SQLException { 564 Buffer buf = readPacket(); 566 567 this.protocolVersion = buf.readByte(); 569 570 if (this.protocolVersion == -1) { 571 try { 572 this.mysqlConnection.close(); 573 } catch (Exception e) { 574 ; } 576 577 int errno = 2000; 578 579 errno = buf.readInt(); 580 581 String serverErrorMessage = buf.readString(); 582 583 StringBuffer errorBuf = new StringBuffer (" message from server: \""); 584 errorBuf.append(serverErrorMessage); 585 errorBuf.append("\""); 586 587 String xOpen = SQLError.mysqlToXOpen(errno); 588 589 throw new SQLException (SQLError.get(xOpen) + ", " 590 + errorBuf.toString(), xOpen, errno); 591 } 592 593 this.serverVersion = buf.readString(); 594 595 int point = this.serverVersion.indexOf("."); 597 598 if (point != -1) { 599 try { 600 int n = Integer.parseInt(this.serverVersion.substring(0, point)); 601 this.serverMajorVersion = n; 602 } catch (NumberFormatException NFE1) { 603 ; 604 } 605 606 String remaining = this.serverVersion.substring(point + 1, 607 this.serverVersion.length()); 608 point = remaining.indexOf("."); 609 610 if (point != -1) { 611 try { 612 int n = Integer.parseInt(remaining.substring(0, point)); 613 this.serverMinorVersion = n; 614 } catch (NumberFormatException nfe) { 615 ; 616 } 617 618 remaining = remaining.substring(point + 1, remaining.length()); 619 620 int pos = 0; 621 622 while (pos < remaining.length()) { 623 if ((remaining.charAt(pos) < '0') 624 || (remaining.charAt(pos) > '9')) { 625 break; 626 } 627 628 pos++; 629 } 630 631 try { 632 int n = Integer.parseInt(remaining.substring(0, pos)); 633 this.serverSubMinorVersion = n; 634 } catch (NumberFormatException nfe) { 635 ; 636 } 637 } 638 } 639 640 if (versionMeetsMinimum(4, 0, 8)) { 641 this.maxThreeBytes = (256 * 256 * 256) - 1; 642 this.useNewLargePackets = true; 643 } else { 644 this.maxThreeBytes = 255 * 255 * 255; 645 this.useNewLargePackets = false; 646 } 647 648 this.colDecimalNeedsBump = versionMeetsMinimum(3, 23, 0); 649 this.colDecimalNeedsBump = !versionMeetsMinimum(3, 23, 15); this.useNewUpdateCounts = versionMeetsMinimum(3, 22, 5); 651 652 long threadId = buf.readLong(); 653 seed = buf.readString(); 654 655 if (Driver.TRACE) { 656 Debug.msg(this, "Protocol Version: " + (int) this.protocolVersion); 657 Debug.msg(this, "Server Version: " + this.serverVersion); 658 Debug.msg(this, "Thread ID: " + threadId); 659 Debug.msg(this, "Crypt Seed: " + seed); 660 } 661 662 int serverCapabilities = 0; 663 664 if (buf.getPosition() < buf.getBufLength()) { 665 serverCapabilities = buf.readInt(); 666 } 667 668 if (versionMeetsMinimum(4, 1, 1)) { 669 int position = buf.getPosition(); 670 671 672 int serverLanguage = buf.readInt(); buf.readInt(); 674 buf.setPosition(position + 16); 675 676 String seedPart2 = buf.readString(); 677 StringBuffer newSeed = new StringBuffer (20); 678 newSeed.append(seed); 679 newSeed.append(seedPart2); 680 this.seed = newSeed.toString(); 681 } 682 683 if (((serverCapabilities & CLIENT_COMPRESS) != 0) 684 && this.connection.useCompression()) { 685 clientParam |= CLIENT_COMPRESS; 686 } 687 688 if ((database != null) && (database.length() > 0)) { 689 clientParam |= CLIENT_CONNECT_WITH_DB; 690 } 691 692 if (((serverCapabilities & CLIENT_SSL) == 0) 693 && this.connection.useSSL()) { 694 this.connection.setUseSSL(false); 695 } 696 697 if ((serverCapabilities & CLIENT_LONG_FLAG) != 0) { 698 clientParam |= CLIENT_LONG_FLAG; 700 this.hasLongColumnInfo = true; 701 } 702 703 clientParam |= CLIENT_FOUND_ROWS; 705 706 if (this.connection.allowLoadLocalInfile()) { 707 clientParam |= CLIENT_LOCAL_FILES; 708 } 709 710 if (isInteractiveClient) { 711 clientParam |= CLIENT_INTERACTIVE; 712 } 713 714 if (this.protocolVersion > 9) { 716 clientParam |= CLIENT_LONG_PASSWORD; } else { 718 clientParam &= ~CLIENT_LONG_PASSWORD; 719 } 720 721 if (versionMeetsMinimum(4, 1, 0)) { 725 if (versionMeetsMinimum(4, 1, 1)) { 726 clientParam |= CLIENT_PROTOCOL_41; 727 this.has41NewNewProt = true; 728 } else { 729 clientParam |= CLIENT_RESERVED; 730 this.has41NewNewProt = false; 731 } 732 733 this.use41Extensions = true; 734 } 735 736 int passwordLength = 16; 737 int userLength = 0; 738 int databaseLength = 0; 739 740 if (user != null) { 741 userLength = user.length(); 742 } 743 744 if (database != null) { 745 databaseLength = database.length(); 746 } 747 748 int packLength = (userLength + passwordLength + databaseLength) + 7 749 + HEADER_LENGTH; 750 Buffer packet = null; 751 752 if (!connection.useSSL()) { 753 if ((serverCapabilities & CLIENT_SECURE_CONNECTION) != 0) { 754 clientParam |= CLIENT_SECURE_CONNECTION; 755 756 if (versionMeetsMinimum(4, 1, 1)) { 757 secureAuth411(packLength, serverCapabilities, clientParam, 758 user, password, database); 759 } else { 760 secureAuth(packLength, serverCapabilities, clientParam, 761 user, password, database); 762 } 763 } else { 764 packet = new Buffer(packLength); 765 766 if ((clientParam & CLIENT_RESERVED) != 0) { 767 if (versionMeetsMinimum(4, 1, 1)) { 768 packet.writeLong(clientParam); 769 packet.writeLong(this.maxThreeBytes); 770 771 packet.writeByte((byte) 8); 775 776 packet.writeBytesNoNull(new byte[23]); 778 } else { 779 packet.writeLong(clientParam); 780 packet.writeLong(this.maxThreeBytes); 781 } 782 } else { 783 packet.writeInt((int) clientParam); 784 packet.writeLongInt(this.maxThreeBytes); 785 } 786 787 packet.writeString(user); 789 790 if (this.protocolVersion > 9) { 791 packet.writeString(Util.newCrypt(password, this.seed)); 792 } else { 793 packet.writeString(Util.oldCrypt(password, this.seed)); 794 } 795 796 if (((serverCapabilities & CLIENT_CONNECT_WITH_DB) != 0) 797 && (database != null) && (database.length() > 0)) { 798 packet.writeString(database); 799 } 800 801 send(packet); 802 } 803 } else { 804 boolean doSecureAuth = false; 805 806 if ((serverCapabilities & CLIENT_SECURE_CONNECTION) != 0) { 807 clientParam |= CLIENT_SECURE_CONNECTION; 808 doSecureAuth = true; 809 } 810 811 clientParam |= CLIENT_SSL; 812 packet = new Buffer(packLength); 813 814 if ((clientParam & CLIENT_RESERVED) != 0) { 815 packet.writeLong(clientParam); 816 } else { 817 packet.writeInt((int) clientParam); 818 } 819 820 send(packet); 821 822 javax.net.ssl.SSLSocketFactory sslFact = (javax.net.ssl.SSLSocketFactory) javax.net.ssl.SSLSocketFactory 823 .getDefault(); 824 825 try { 826 this.mysqlConnection = sslFact.createSocket(this.mysqlConnection, 827 this.host, this.port, true); 828 829 ((javax.net.ssl.SSLSocket) this.mysqlConnection) 832 .setEnabledProtocols(new String [] { "TLSv1" }); 833 ((javax.net.ssl.SSLSocket) this.mysqlConnection).startHandshake(); 834 this.mysqlInput = new BufferedInputStream (this.mysqlConnection 835 .getInputStream(), 16384); 836 this.mysqlOutput = new BufferedOutputStream (this.mysqlConnection 837 .getOutputStream(), 16384); 838 this.mysqlOutput.flush(); 839 } catch (IOException ioEx) { 840 StringBuffer message = new StringBuffer (SQLError.get( 841 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE)); 842 message.append(": "); 843 message.append(ioEx.getClass().getName()); 844 message.append(", underlying cause: "); 845 message.append(ioEx.getMessage()); 846 847 if (!this.connection.useParanoidErrorMessages()) { 848 message.append(Util.stackTraceToString(ioEx)); 849 } 850 851 throw new java.sql.SQLException (message.toString(), 852 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE, 0); 853 } 854 855 packet.clear(); 856 857 if (doSecureAuth) { 858 if (versionMeetsMinimum(4, 1, 1)) { 859 secureAuth411(packLength, serverCapabilities, clientParam, 860 user, password, database); 861 } else { 862 secureAuth(packLength, serverCapabilities, clientParam, 863 user, password, database); 864 } 865 } else { 866 if ((clientParam & CLIENT_RESERVED) != 0) { 867 packet.writeLong(clientParam); 868 packet.writeLong(this.maxThreeBytes); 869 } else { 870 packet.writeInt((int) clientParam); 871 packet.writeLongInt(this.maxThreeBytes); 872 } 873 874 packet.writeString(user); 876 877 if (this.protocolVersion > 9) { 878 packet.writeString(Util.newCrypt(password, seed)); 879 } else { 880 packet.writeString(Util.oldCrypt(password, seed)); 881 } 882 883 if (((serverCapabilities & CLIENT_CONNECT_WITH_DB) != 0) 884 && (database != null) && (database.length() > 0)) { 885 packet.writeString(database); 886 } 887 888 send(packet); 889 } 890 } 891 892 if (!versionMeetsMinimum(4, 1, 1)) { 896 checkErrorPacket(); 897 } 898 899 if (((serverCapabilities & CLIENT_COMPRESS) != 0) 903 && this.connection.useCompression()) { 904 this.deflater = new Deflater (); 907 this.useCompression = true; 908 this.mysqlInput = new CompressedInputStream(this.mysqlInput); 909 } 910 911 if (((serverCapabilities & CLIENT_CONNECT_WITH_DB) == 0) 912 && (database != null) && (database.length() > 0)) { 913 try { 914 sendCommand(MysqlDefs.INIT_DB, database, null); 915 } catch (Exception ex) { 916 throw new SQLException (ex.toString(), 917 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE); 918 } 919 } 920 } 921 922 933 final byte[][] nextRow(int columnCount) throws Exception { 934 Buffer rowPacket = checkErrorPacket(); 937 938 int offset = 0; 943 944 rowPacket.setPosition(rowPacket.getPosition() - 1); 952 953 byte[][] rowData = new byte[columnCount][]; 954 955 if (!rowPacket.isLastDataPacket()) { 956 for (int i = 0; i < columnCount; i++) { 957 rowData[i] = rowPacket.readLenByteArray(offset); 958 959 if (Driver.TRACE) { 960 if (rowData[i] == null) { 961 Debug.msg(this, "Field value: NULL"); 962 } else { 963 Debug.msg(this, "Field value: " + rowData[i].toString()); 964 } 965 } 966 } 967 968 return rowData; 969 } 970 971 return null; 972 } 973 974 979 final void quit() throws SQLException { 980 Buffer packet = new Buffer(6); 981 this.packetSequence = -1; 982 packet.writeByte((byte) MysqlDefs.QUIT); 983 send(packet); 984 forceClose(); 985 } 986 987 993 Buffer getSharedSendPacket() { 994 if (this.sharedSendPacket == null) { 995 this.sharedSendPacket = new Buffer(this.connection 996 .getNetBufferLength()); 997 } 998 999 return this.sharedSendPacket; 1000 } 1001 1002 void closeStreamer(RowData streamer) throws SQLException { 1003 if (this.streamingData == null) { 1004 throw new SQLException ("Attempt to close streaming result set " 1005 + streamer 1006 + " when no streaming result set was registered. This is an internal error."); 1007 } 1008 1009 if (streamer != this.streamingData) { 1010 throw new SQLException ("Attempt to close streaming result set " 1011 + streamer + " that was not registered." 1012 + " Only one streaming result set may be open and in use per-connection. Ensure that you have called .close() on " 1013 + " any active result sets before attempting more queries."); 1014 } 1015 1016 this.streamingData = null; 1017 } 1018 1019 1022 void resetMaxBuf() { 1023 this.maxAllowedPacket = this.connection.getMaxAllowedPacket(); 1024 } 1025 1026 1040 final Buffer sendCommand(int command, String extraData, Buffer queryPacket) 1041 throws Exception { 1042 checkForOutstandingStreamingData(); 1043 1044 try { 1045 if (this.clearStreamBeforeEachQuery) { 1046 clearInputStream(); 1047 } 1048 1049 if (queryPacket == null) { 1057 int packLength = HEADER_LENGTH + COMP_HEADER_LENGTH + 1 1058 + ((extraData != null) ? extraData.length() : 0) + 2; 1059 1060 if (this.sendPacket == null) { 1061 this.sendPacket = new Buffer(packLength); 1062 } 1063 1064 this.packetSequence = -1; 1065 this.sendPacket.clear(); 1066 1067 if (this.useCompression) { 1069 this.sendPacket.setPosition(this.sendPacket.getPosition() 1070 + COMP_HEADER_LENGTH); 1071 } 1072 1073 this.sendPacket.writeByte((byte) command); 1074 1075 if ((command == MysqlDefs.INIT_DB) 1076 || (command == MysqlDefs.CREATE_DB) 1077 || (command == MysqlDefs.DROP_DB) 1078 || (command == MysqlDefs.QUERY)) { 1079 this.sendPacket.writeStringNoNull(extraData); 1080 } else if (command == MysqlDefs.PROCESS_KILL) { 1081 long id = new Long (extraData).longValue(); 1082 this.sendPacket.writeLong(id); 1083 } else if ((command == MysqlDefs.RELOAD) 1084 && (this.protocolVersion > 9)) { 1085 Debug.msg(this, "Reload"); 1086 1087 } 1089 1090 send(this.sendPacket); 1091 } else { 1092 this.packetSequence = -1; 1093 send(queryPacket); } 1095 } catch (SQLException sqlEx) { 1096 throw sqlEx; 1098 } catch (Exception ex) { 1099 String underlyingMessage = ex.getMessage(); 1100 1101 throw new java.sql.SQLException (SQLError.get( 1102 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE) + ": " 1103 + ex.getClass().getName() + ", " 1104 + ((underlyingMessage != null) ? underlyingMessage 1105 : "no message given by JVM"), 1106 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE, 0); 1107 } 1108 1109 return checkErrorPacket(command); 1110 } 1111 1112 1129 final ResultSet sqlQuery(String query, int maxRows, 1130 String characterEncoding, Connection conn, int resultSetType, 1131 boolean streamResults, String catalog) throws Exception { 1132 int packLength = HEADER_LENGTH + 1 + (query.length() * 2) + 2; 1136 1137 if (this.sendPacket == null) { 1138 this.sendPacket = new Buffer(packLength); 1139 } else { 1140 this.sendPacket.clear(); 1141 } 1142 1143 this.sendPacket.writeByte((byte) MysqlDefs.QUERY); 1144 1145 if (characterEncoding != null) { 1146 SingleByteCharsetConverter converter = this.connection 1147 .getCharsetConverter(characterEncoding); 1148 1149 if (this.platformDbCharsetMatches) { 1150 this.sendPacket.writeStringNoNull(query, characterEncoding, 1151 converter); 1152 } else { 1153 if (StringUtils.startsWithIgnoreCaseAndWs(query, "LOAD DATA")) { 1154 this.sendPacket.writeBytesNoNull(query.getBytes()); 1155 } else { 1156 this.sendPacket.writeStringNoNull(query, characterEncoding, 1157 converter); 1158 } 1159 } 1160 } else { 1161 this.sendPacket.writeStringNoNull(query); 1162 } 1163 1164 return sqlQueryDirect(this.sendPacket, maxRows, conn, resultSetType, 1165 streamResults, catalog); 1166 } 1167 1168 1182 final ResultSet sqlQueryDirect(Buffer queryPacket, int maxRows, 1183 Connection conn, int resultSetType, boolean streamResults, 1184 String catalog) throws Exception { 1185 StringBuffer profileMsgBuf = null; long queryStartTime = 0; 1187 1188 if (this.profileSql) { 1189 profileMsgBuf = new StringBuffer (); 1190 queryStartTime = System.currentTimeMillis(); 1191 1192 byte[] queryBuf = queryPacket.getByteBuffer(); 1193 1194 String query = new String (queryBuf, 5, 1196 (queryPacket.getPosition() - 5)); 1197 profileMsgBuf.append("Query\t\""); 1198 profileMsgBuf.append(query); 1199 profileMsgBuf.append("\"\texecution time:\t"); 1200 } 1201 1202 Buffer resultPacket = sendCommand(MysqlDefs.QUERY, null, queryPacket); 1204 1205 if (this.profileSql) { 1206 long executionTime = System.currentTimeMillis() - queryStartTime; 1207 profileMsgBuf.append(executionTime); 1208 profileMsgBuf.append("\t"); 1209 } 1210 1211 resultPacket.setPosition(resultPacket.getPosition() - 1); 1212 1213 long columnCount = resultPacket.readFieldLength(); 1214 1215 if (Driver.TRACE) { 1216 Debug.msg(this, "Column count: " + columnCount); 1217 } 1218 1219 if (columnCount == 0) { 1220 if (this.profileSql) { 1221 System.err.println(profileMsgBuf.toString()); 1222 } 1223 1224 return buildResultSetWithUpdates(resultPacket); 1225 } else if (columnCount == Buffer.NULL_LENGTH) { 1226 String charEncoding = null; 1227 1228 if (this.connection.useUnicode()) { 1229 charEncoding = this.connection.getEncoding(); 1230 } 1231 1232 String fileName = null; 1233 1234 if (this.platformDbCharsetMatches) { 1235 fileName = ((charEncoding != null) 1236 ? resultPacket.readString(charEncoding) 1237 : resultPacket.readString()); 1238 } else { 1239 fileName = resultPacket.readString(); 1240 } 1241 1242 return sendFileToServer(fileName); 1243 } else { 1244 long fetchStartTime = 0; 1245 1246 if (this.profileSql) { 1247 fetchStartTime = System.currentTimeMillis(); 1248 } 1249 1250 com.mysql.jdbc.ResultSet results = getResultSet(columnCount, 1251 maxRows, resultSetType, streamResults, catalog); 1252 1253 if (this.profileSql) { 1254 long fetchElapsedTime = System.currentTimeMillis() 1255 - fetchStartTime; 1256 profileMsgBuf.append("result set fetch time:\t"); 1257 profileMsgBuf.append(fetchElapsedTime); 1258 System.err.println(profileMsgBuf.toString()); 1259 } 1260 1261 return results; 1262 } 1263 } 1264 1265 1270 String getHost() { 1271 return this.host; 1272 } 1273 1274 1284 boolean versionMeetsMinimum(int major, int minor, int subminor) { 1285 if (getServerMajorVersion() >= major) { 1286 if (getServerMajorVersion() == major) { 1287 if (getServerMinorVersion() >= minor) { 1288 if (getServerMinorVersion() == minor) { 1289 return (getServerSubMinorVersion() >= subminor); 1290 } else { 1291 return true; 1293 } 1294 } else { 1295 return false; 1297 } 1298 } else { 1299 return true; 1301 } 1302 } else { 1303 return false; 1304 } 1305 } 1306 1307 private final int readFully(InputStream in, byte[] b, int off, int len) 1308 throws IOException { 1309 if (len < 0) { 1310 throw new IndexOutOfBoundsException (); 1311 } 1312 1313 int n = 0; 1314 1315 while (n < len) { 1316 int count = in.read(b, off + n, len - n); 1317 1318 if (count < 0) { 1319 throw new EOFException (); 1320 } 1321 1322 n += count; 1323 } 1324 1325 return n; 1326 } 1327 1328 1336 private final Buffer readPacket() throws SQLException { 1337 try { 1338 int lengthRead = readFully(mysqlInput, this.packetHeaderBuf, 0, 4); 1339 1340 if (lengthRead < 4) { 1341 forceClose(); 1342 throw new IOException ("Unexpected end of input stream"); 1343 } 1344 1345 int packetLength = ((int) (this.packetHeaderBuf[0] & 0xff)) 1346 + (((int) (this.packetHeaderBuf[1] & 0xff)) << 8) 1347 + (((int) (this.packetHeaderBuf[2] & 0xff)) << 16); 1348 1349 byte multiPacketSeq = this.packetHeaderBuf[3]; 1350 1351 byte[] buffer = new byte[packetLength + 1]; 1353 readFully(this.mysqlInput, buffer, 0, packetLength); 1354 buffer[packetLength] = 0; 1355 1356 Buffer packet = new Buffer(buffer); 1357 1358 return packet; 1359 } catch (IOException ioEx) { 1360 StringBuffer message = new StringBuffer (SQLError.get( 1361 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE)); 1362 message.append(": "); 1363 message.append(ioEx.getClass().getName()); 1364 message.append(", underlying cause: "); 1365 message.append(ioEx.getMessage()); 1366 1367 if (!this.connection.useParanoidErrorMessages()) { 1368 message.append(Util.stackTraceToString(ioEx)); 1369 } 1370 1371 throw new java.sql.SQLException (message.toString(), 1372 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE, 0); 1373 } 1374 } 1375 1376 private com.mysql.jdbc.ResultSet buildResultSetWithRows(String catalog, 1377 com.mysql.jdbc.Field[] fields, RowData rows, int resultSetConcurrency) 1378 throws SQLException { 1379 switch (resultSetConcurrency) { 1380 case java.sql.ResultSet.CONCUR_READ_ONLY: 1381 return new com.mysql.jdbc.ResultSet(catalog, fields, rows, 1382 this.connection); 1383 1384 case java.sql.ResultSet.CONCUR_UPDATABLE: 1385 return new com.mysql.jdbc.UpdatableResultSet(catalog, fields, rows, 1386 this.connection); 1387 1388 default: 1389 return new com.mysql.jdbc.ResultSet(catalog, fields, rows, 1390 this.connection); 1391 } 1392 } 1393 1394 private com.mysql.jdbc.ResultSet buildResultSetWithUpdates( 1395 Buffer resultPacket) throws SQLException { 1396 long updateCount = -1; 1397 long updateID = -1; 1398 String info = null; 1399 1400 try { 1401 if (this.useNewUpdateCounts) { 1402 updateCount = resultPacket.newReadLength(); 1403 updateID = resultPacket.newReadLength(); 1404 } else { 1405 updateCount = (long) resultPacket.readLength(); 1406 updateID = (long) resultPacket.readLength(); 1407 } 1408 1409 if (this.connection.isReadInfoMsgEnabled()) { 1410 if (this.use41Extensions) { 1411 int serverStatus = resultPacket.readInt(); 1412 int warningCount = resultPacket.readInt(); 1413 1414 resultPacket.readByte(); } 1416 1417 info = resultPacket.readString(); 1418 } 1419 } catch (Exception ex) { 1420 throw new java.sql.SQLException (SQLError.get( 1421 SQLError.SQL_STATE_GENERAL_ERROR) + ": " 1422 + ex.getClass().getName(), SQLError.SQL_STATE_GENERAL_ERROR, -1); 1423 } 1424 1425 if (Driver.TRACE) { 1426 Debug.msg(this, "Update Count = " + updateCount); 1427 } 1428 1429 ResultSet updateRs = new ResultSet(updateCount, updateID); 1430 1431 if (info != null) { 1432 updateRs.setServerInfo(info); 1433 } 1434 1435 return updateRs; 1436 } 1437 1438 1441 private void reclaimLargeReusablePacket() { 1442 if ((this.reusablePacket != null) 1443 && (this.reusablePacket.getBufLength() > 1048576)) { 1444 this.reusablePacket = new Buffer(this.connection.getNetBufferLength()); 1445 } 1446 } 1447 1448 1458 private final Buffer reuseAndReadPacket(Buffer reuse) 1459 throws SQLException { 1460 try { 1461 reuse.setWasMultiPacket(false); 1462 1463 int lengthRead = readFully(mysqlInput, this.packetHeaderBuf, 0, 4); 1464 1465 if (lengthRead < 4) { 1466 forceClose(); 1467 throw new IOException ("Unexpected end of input stream"); 1468 } 1469 1470 int packetLength = ((int) (this.packetHeaderBuf[0] & 0xff)) 1471 + (((int) (this.packetHeaderBuf[1] & 0xff)) << 8) 1472 + (((int) (this.packetHeaderBuf[2] & 0xff)) << 16); 1473 1474 byte multiPacketSeq = this.packetHeaderBuf[3]; 1475 1476 reuse.setPosition(0); 1479 reuse.setSendLength(0); 1480 1481 if (reuse.getByteBuffer().length <= packetLength) { 1488 reuse.setByteBuffer(new byte[packetLength + 1]); 1489 } 1490 1491 reuse.setBufLength(packetLength); 1493 1494 readFully(this.mysqlInput, reuse.getByteBuffer(), 0, packetLength); 1496 1497 boolean isMultiPacket = false; 1498 1499 if (packetLength == maxThreeBytes) { 1500 reuse.setPosition((int) maxThreeBytes); 1501 1502 int packetEndPoint = packetLength; 1503 1504 isMultiPacket = true; 1506 1507 lengthRead = readFully(mysqlInput, this.packetHeaderBuf, 0, 4); 1508 1509 if (lengthRead < 4) { 1510 forceClose(); 1511 throw new IOException ("Unexpected end of input stream"); 1512 } 1513 1514 packetLength = ((int) (this.packetHeaderBuf[0] & 0xff)) 1515 + (((int) (this.packetHeaderBuf[1] & 0xff)) << 8) 1516 + (((int) (this.packetHeaderBuf[2] & 0xff)) << 16); 1517 1518 Buffer multiPacket = new Buffer(packetLength); 1519 boolean firstMultiPkt = true; 1520 1521 while (true) { 1522 if (!firstMultiPkt) { 1523 lengthRead = readFully(mysqlInput, 1524 this.packetHeaderBuf, 0, 4); 1525 1526 if (lengthRead < 4) { 1527 forceClose(); 1528 throw new IOException ( 1529 "Unexpected end of input stream"); 1530 } 1531 1532 packetLength = ((int) (this.packetHeaderBuf[0] & 0xff)) 1533 + (((int) (this.packetHeaderBuf[1] & 0xff)) << 8) 1534 + (((int) (this.packetHeaderBuf[2] & 0xff)) << 16); 1535 } else { 1536 firstMultiPkt = false; 1537 } 1538 1539 if (!this.useNewLargePackets && (packetLength == 1)) { 1540 clearInputStream(); 1541 1542 break; 1543 } else if (packetLength < this.maxThreeBytes) { 1544 byte newPacketSeq = this.packetHeaderBuf[3]; 1545 1546 if (newPacketSeq != (multiPacketSeq + 1)) { 1547 throw new IOException ( 1548 "Packets received out of order"); 1549 } 1550 1551 multiPacketSeq = newPacketSeq; 1552 1553 multiPacket.setPosition(0); 1555 multiPacket.setSendLength(0); 1556 1557 multiPacket.setBufLength(packetLength); 1559 1560 byte[] byteBuf = multiPacket.getByteBuffer(); 1562 int lengthToWrite = packetLength; 1563 1564 int bytesRead = readFully(this.mysqlInput, byteBuf, 0, 1565 packetLength); 1566 1567 if (bytesRead != lengthToWrite) { 1568 throw new SQLException ( 1569 "Short read from server, expected " 1570 + lengthToWrite + " bytes, received only " 1571 + bytesRead + ".", 1572 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE); 1573 } 1574 1575 reuse.writeBytesNoNull(byteBuf, 0, lengthToWrite); 1576 1577 packetEndPoint += lengthToWrite; 1578 1579 break; } 1581 1582 byte newPacketSeq = this.packetHeaderBuf[3]; 1583 1584 if (newPacketSeq != (multiPacketSeq + 1)) { 1585 throw new IOException ("Packets received out of order"); 1586 } 1587 1588 multiPacketSeq = newPacketSeq; 1589 1590 multiPacket.setPosition(0); 1592 multiPacket.setSendLength(0); 1593 1594 multiPacket.setBufLength(packetLength); 1596 1597 byte[] byteBuf = multiPacket.getByteBuffer(); 1599 int lengthToWrite = packetLength; 1600 1601 int bytesRead = readFully(this.mysqlInput, byteBuf, 0, 1602 packetLength); 1603 1604 if (bytesRead != lengthToWrite) { 1605 throw new SQLException ( 1606 "Short read from server, expected " + lengthToWrite 1607 + " bytes, received only " + bytesRead + ".", 1608 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE); 1609 } 1610 1611 reuse.writeBytesNoNull(byteBuf, 0, lengthToWrite); 1612 1613 packetEndPoint += lengthToWrite; 1614 } 1615 1616 reuse.setPosition(0); 1618 reuse.setWasMultiPacket(true); 1619 } 1620 1621 if (!isMultiPacket) { 1622 reuse.getByteBuffer()[packetLength] = 0; } 1624 1625 return reuse; 1626 } catch (IOException ioEx) { 1627 StringBuffer message = new StringBuffer (SQLError.get( 1628 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE)); 1629 message.append(": "); 1630 message.append(ioEx.getClass().getName()); 1631 message.append(", underlying cause: "); 1632 message.append(ioEx.getMessage()); 1633 1634 if (!this.connection.useParanoidErrorMessages()) { 1635 message.append(Util.stackTraceToString(ioEx)); 1636 } 1637 1638 throw new java.sql.SQLException (message.toString(), 1639 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE, 0); 1640 } 1641 } 1642 1643 1650 private final void send(Buffer packet) throws SQLException { 1651 int l = packet.getPosition(); 1652 send(packet, l); 1653 1654 if (packet == this.sharedSendPacket) { 1658 reclaimLargeSharedSendPacket(); 1659 } 1660 } 1661 1662 private final void send(Buffer packet, int packetLen) 1663 throws SQLException { 1664 try { 1665 if (packetLen > this.maxAllowedPacket) { 1666 throw new PacketTooBigException(packetLen, this.maxAllowedPacket); 1667 } 1668 1669 if ((serverMajorVersion >= 4) && (packetLen >= maxThreeBytes)) { 1670 sendSplitPackets(packet); 1671 } else { 1672 this.packetSequence++; 1673 1674 Buffer packetToSend = packet; 1675 1676 packetToSend.setPosition(0); 1677 1678 if (this.useCompression) { 1679 packetToSend = compressPacket(packet, 0, packetLen, 1680 HEADER_LENGTH); 1681 packetLen = packetToSend.getPosition(); 1682 } else { 1683 packetToSend.writeLongInt(packetLen - HEADER_LENGTH); 1684 packetToSend.writeByte(this.packetSequence); 1685 } 1686 1687 this.mysqlOutput.write(packetToSend.getByteBuffer(), 0, 1688 packetLen); 1689 this.mysqlOutput.flush(); 1690 } 1691 1692 if (packet == this.sharedSendPacket) { 1696 reclaimLargeSharedSendPacket(); 1697 } 1698 } catch (IOException ioEx) { 1699 StringBuffer message = new StringBuffer (SQLError.get( 1700 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE)); 1701 message.append(": "); 1702 message.append(ioEx.getClass().getName()); 1703 message.append(", underlying cause: "); 1704 message.append(ioEx.getMessage()); 1705 1706 if (!this.connection.useParanoidErrorMessages()) { 1707 message.append(Util.stackTraceToString(ioEx)); 1708 } 1709 1710 throw new java.sql.SQLException (message.toString(), 1711 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE, 0); 1712 } 1713 } 1714 1715 1724 private final ResultSet sendFileToServer(String fileName) 1725 throws SQLException { 1726 Buffer filePacket = (loadFileBufRef == null) ? null 1727 : (Buffer) (loadFileBufRef 1728 .get()); 1729 1730 int packetLength = Math.min(this.connection.getMaxAllowedPacket() 1731 - (HEADER_LENGTH * 3), 1732 alignPacketSize(this.connection.getMaxAllowedPacket() - 16, 4096) 1733 - (HEADER_LENGTH * 3)); 1734 1735 try { 1740 if (filePacket == null) { 1741 filePacket = new Buffer((int) (packetLength + HEADER_LENGTH)); 1742 loadFileBufRef = new SoftReference (filePacket); 1743 } 1744 } catch (OutOfMemoryError oom) { 1745 this.reusablePacket.clear(); 1749 send(this.reusablePacket); 1750 1751 throw new SQLException ("Unable to allocate packet of size '" 1752 + (packetLength + HEADER_LENGTH) 1753 + "' for LOAD DATA LOCAL INFILE. Either increase heap space available to your JVM, or adjust the MySQL server variable 'max_allowed_packet'", 1754 SQLError.SQL_STATE_MEMORY_ALLOCATION_FAILURE); 1755 } 1756 1757 filePacket.clear(); 1758 send(filePacket, 0); 1759 1760 byte[] fileBuf = new byte[packetLength]; 1761 1762 BufferedInputStream fileIn = null; 1763 1764 try { 1765 fileIn = new BufferedInputStream (new FileInputStream (fileName)); 1766 1767 int bytesRead = 0; 1768 1769 while ((bytesRead = fileIn.read(fileBuf)) != -1) { 1770 filePacket.clear(); 1771 filePacket.writeBytesNoNull(fileBuf, 0, bytesRead); 1772 send(filePacket); 1773 } 1774 } catch (IOException ioEx) { 1775 StringBuffer messageBuf = new StringBuffer ("Unable to open file "); 1776 1777 if (!this.connection.useParanoidErrorMessages()) { 1778 messageBuf.append("'"); 1779 1780 if (fileName != null) { 1781 messageBuf.append(fileName); 1782 } 1783 1784 messageBuf.append("'"); 1785 } 1786 1787 messageBuf.append("for 'LOAD DATA LOCAL INFILE' command."); 1788 1789 if (!this.connection.useParanoidErrorMessages()) { 1790 messageBuf.append("Due to underlying IOException: "); 1791 messageBuf.append(Util.stackTraceToString(ioEx)); 1792 } 1793 1794 throw new SQLException (messageBuf.toString(), 1795 SQLError.SQL_STATE_ILLEGAL_ARGUMENT); 1796 } finally { 1797 if (fileIn != null) { 1798 try { 1799 fileIn.close(); 1800 } catch (Exception ex) { 1801 throw new SQLException ("Unable to close local file during LOAD DATA LOCAL INFILE command", 1802 SQLError.SQL_STATE_GENERAL_ERROR); 1803 } 1804 1805 fileIn = null; 1806 } else { 1807 filePacket.clear(); 1809 send(filePacket); 1810 } 1811 } 1812 1813 filePacket.clear(); 1815 send(filePacket); 1816 1817 Buffer resultPacket = checkErrorPacket(); 1818 1819 return buildResultSetWithUpdates(resultPacket); 1820 } 1821 1822 1830 private Buffer checkErrorPacket() throws SQLException { 1831 return checkErrorPacket(-1); 1832 } 1833 1834 1845 private Buffer checkErrorPacket(int command) throws SQLException { 1846 int statusCode = 0; 1847 Buffer resultPacket = null; 1848 1849 try { 1850 resultPacket = reuseAndReadPacket(this.reusablePacket); 1855 statusCode = resultPacket.readByte(); 1856 } catch (SQLException sqlEx) { 1857 throw sqlEx; 1859 } catch (Exception fallThru) { 1860 String underlyingMessage = fallThru.getMessage(); 1861 1862 throw new java.sql.SQLException (SQLError.get( 1863 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE) + ": " 1864 + fallThru.getClass().getName() + ", " 1865 + ((underlyingMessage != null) ? underlyingMessage 1866 : "no message given by JVM"), 1867 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE, 0); 1868 } 1869 1870 if (statusCode == (byte) 0xff) { 1872 String serverErrorMessage; 1873 int errno = 2000; 1874 1875 if (this.protocolVersion > 9) { 1876 errno = resultPacket.readInt(); 1877 1878 String xOpen = null; 1879 1880 serverErrorMessage = resultPacket.readString(); 1881 1882 if (serverErrorMessage.startsWith("#")) { 1883 if (serverErrorMessage.length() > 6) { 1885 xOpen = serverErrorMessage.substring(1, 6); 1886 serverErrorMessage = serverErrorMessage.substring(6); 1887 1888 if (xOpen.equals("HY000")) { 1889 xOpen = SQLError.mysqlToXOpen(errno); 1890 } 1891 } else { 1892 xOpen = SQLError.mysqlToXOpen(errno); 1893 } 1894 } else { 1895 xOpen = SQLError.mysqlToXOpen(errno); 1896 } 1897 1898 clearInputStream(); 1899 1900 StringBuffer errorBuf = new StringBuffer ( 1901 " message from server: \""); 1902 errorBuf.append(serverErrorMessage); 1903 errorBuf.append("\""); 1904 1905 throw new SQLException (SQLError.get(xOpen) + ", " 1906 + errorBuf.toString(), xOpen, errno); 1907 } else { 1908 serverErrorMessage = resultPacket.readString(); 1909 clearInputStream(); 1910 1911 if (serverErrorMessage.indexOf("Unknown column") != -1) { 1912 throw new java.sql.SQLException (SQLError.get( 1913 SQLError.SQL_STATE_COLUMN_NOT_FOUND) + ", " 1914 + serverErrorMessage, 1915 SQLError.SQL_STATE_COLUMN_NOT_FOUND, -1); 1916 } else { 1917 StringBuffer errorBuf = new StringBuffer ( 1918 " message from server: \""); 1919 errorBuf.append(serverErrorMessage); 1920 errorBuf.append("\""); 1921 1922 throw new java.sql.SQLException (SQLError.get( 1923 SQLError.SQL_STATE_GENERAL_ERROR) + ", " 1924 + errorBuf.toString(), 1925 SQLError.SQL_STATE_GENERAL_ERROR, -1); 1926 } 1927 } 1928 } 1929 1930 return resultPacket; 1931 } 1932 1933 1941 private final void sendSplitPackets(Buffer packet) 1942 throws SQLException { 1943 try { 1944 Buffer headerPacket = (splitBufRef == null) ? null 1954 : (Buffer) (splitBufRef 1955 .get()); 1956 1957 if (headerPacket == null) { 1963 headerPacket = new Buffer((int) (maxThreeBytes + HEADER_LENGTH)); 1964 splitBufRef = new SoftReference (headerPacket); 1965 } 1966 1967 int len = packet.getPosition(); 1968 int splitSize = (int) maxThreeBytes; 1969 int originalPacketPos = HEADER_LENGTH; 1970 byte[] origPacketBytes = packet.getByteBuffer(); 1971 byte[] headerPacketBytes = headerPacket.getByteBuffer(); 1972 1973 if (Driver.DEBUG) { 1974 System.out.println("\n\nSending split packets for packet of " 1975 + len + " bytes:\n"); 1976 } 1977 1978 while (len >= maxThreeBytes) { 1979 headerPacket.setPosition(0); 1980 headerPacket.writeLongInt(splitSize); 1981 this.packetSequence++; 1982 headerPacket.writeByte(this.packetSequence); 1983 System.arraycopy(origPacketBytes, originalPacketPos, 1984 headerPacketBytes, 4, splitSize); 1985 this.mysqlOutput.write(headerPacketBytes, 0, 1986 splitSize + HEADER_LENGTH); 1987 this.mysqlOutput.flush(); 1988 1989 if (Driver.DEBUG) { 1990 System.out.print(" total packet length (header & data) " 1991 + (splitSize + HEADER_LENGTH) + "\nheader: "); 1992 headerPacket.dumpHeader(); 1993 System.out.println(); 1994 System.out.print("last eight bytes: "); 1995 headerPacket.dumpNBytes(((splitSize + HEADER_LENGTH) - 8), 8); 1996 System.out.println(); 1997 } 1998 1999 originalPacketPos += splitSize; 2000 len -= splitSize; 2001 } 2002 2003 headerPacket.clear(); 2007 headerPacket.setPosition(0); 2008 headerPacket.writeLongInt(len - HEADER_LENGTH); 2009 this.packetSequence++; 2010 headerPacket.writeByte(this.packetSequence); 2011 2012 if (len != 0) { 2013 System.arraycopy(origPacketBytes, originalPacketPos, 2014 headerPacketBytes, 4, len - HEADER_LENGTH); 2015 } 2016 2017 this.mysqlOutput.write(headerPacket.getByteBuffer(), 0, len); 2018 this.mysqlOutput.flush(); 2019 2020 if (Driver.DEBUG) { 2021 System.out.print(" total packet length (header & data) " + len 2022 + ",\nheader: "); 2023 headerPacket.dumpHeader(); 2024 System.out.println(); 2025 System.out.print("last packet bytes: "); 2026 headerPacket.dumpNBytes(0, len); 2027 System.out.println(); 2028 } 2029 } catch (IOException ioEx) { 2030 StringBuffer message = new StringBuffer (SQLError.get( 2031 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE)); 2032 message.append(": "); 2033 message.append(ioEx.getClass().getName()); 2034 message.append(", underlying cause: "); 2035 message.append(ioEx.getMessage()); 2036 2037 if (!this.connection.useParanoidErrorMessages()) { 2038 message.append(Util.stackTraceToString(ioEx)); 2039 } 2040 2041 throw new java.sql.SQLException (message.toString(), 2042 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE, 0); 2043 } 2044 } 2045 2046 private int alignPacketSize(int a, int l) { 2047 return ((((a) + (l)) - 1) & ~((l) - 1)); 2048 } 2049 2050 private void checkForOutstandingStreamingData() throws SQLException { 2051 if (this.streamingData != null) { 2052 if (!this.connection.getClobberStreamingResults()) { 2053 throw new SQLException ("Streaming result set " 2054 + this.streamingData + " is still active." 2055 + " Only one streaming result set may be open and in use per-connection. Ensure that you have called .close() on " 2056 + " any active result sets before attempting more queries."); 2057 } else { 2058 this.streamingData.getOwner().realClose(false); 2060 2061 clearInputStream(); 2063 } 2064 } 2065 } 2066 2067 private void clearInputStream() throws SQLException { 2068 try { 2069 int len = this.mysqlInput.available(); 2070 2071 while (len > 0) { 2072 this.mysqlInput.skip(len); 2073 len = this.mysqlInput.available(); 2074 } 2075 } catch (IOException ioEx) { 2076 throw new SQLException ("I/O error while clearing input stream of old results", 2077 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE); 2078 } 2079 } 2080 2081 private Buffer compressPacket(Buffer packet, int offset, int packetLen, 2082 int headerLength) throws SQLException { 2083 packet.writeLongInt(packetLen - headerLength); 2084 packet.writeByte((byte) 0); 2086 int lengthToWrite = 0; 2087 int compressedLength = 0; 2088 byte[] bytesToCompress = packet.getByteBuffer(); 2089 byte[] compressedBytes = null; 2090 int offsetWrite = 0; 2091 2092 if (true ) { 2093 lengthToWrite = packetLen; 2094 compressedBytes = packet.getByteBuffer(); 2095 compressedLength = 0; 2096 offsetWrite = offset; 2097 } else { 2098 compressedBytes = new byte[bytesToCompress.length * 2]; 2099 2100 this.deflater.reset(); 2101 this.deflater.setInput(bytesToCompress, offset, packetLen); 2102 this.deflater.finish(); 2103 2104 int compLen = this.deflater.deflate(compressedBytes); 2105 2106 if (compLen > packetLen) { 2107 lengthToWrite = packetLen; 2108 compressedBytes = packet.getByteBuffer(); 2109 compressedLength = 0; 2110 offsetWrite = offset; 2111 } else { 2112 lengthToWrite = compLen; 2113 headerLength += COMP_HEADER_LENGTH; 2114 compressedLength = packetLen; 2115 } 2116 } 2117 2118 Buffer compressedPacket = new Buffer(packetLen + headerLength); 2119 2120 compressedPacket.setPosition(0); 2121 compressedPacket.writeLongInt(lengthToWrite); 2122 compressedPacket.writeByte(this.packetSequence); 2123 compressedPacket.writeLongInt(compressedLength); 2124 compressedPacket.writeBytesNoNull(compressedBytes, offsetWrite, 2125 lengthToWrite); 2126 2127 return compressedPacket; 2128 } 2129 2130 private SocketFactory createSocketFactory() throws SQLException { 2131 try { 2132 if (socketFactoryClassName == null) { 2133 throw new SQLException ("No name specified for socket factory", 2134 SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE); 2135 } 2136 2137 return (SocketFactory) (Class.forName(socketFactoryClassName) 2138 .newInstance()); 2139 } catch (Exception ex) { 2140 throw new SQLException ("Could not create socket factory '" 2141 + socketFactoryClassName + "' due to underlying exception: " 2142 + ex.toString(), 2143 SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE); 2144 } 2145 } 2146 2147 2150 private void reclaimLargeSharedSendPacket() { 2151 if ((this.sharedSendPacket != null) 2152 && (this.sharedSendPacket.getBufLength() > 1048576)) { 2153 this.sharedSendPacket = new Buffer(this.connection 2154 .getNetBufferLength()); 2155 } 2156 } 2157 2158 2170 private void secureAuth(int packLength, int serverCapabilities, 2171 long clientParam, String user, String password, String database) 2172 throws SQLException { 2173 Buffer packet = new Buffer(packLength); 2175 2176 if (this.use41Extensions) { 2177 if (versionMeetsMinimum(4, 1, 1)) { 2178 packet.writeLong(clientParam); 2179 packet.writeLong(this.maxThreeBytes); 2180 2181 packet.writeByte((byte) 8); 2185 2186 packet.writeBytesNoNull(new byte[23]); 2188 } else { 2189 packet.writeLong(clientParam); 2190 packet.writeLong(this.maxThreeBytes); 2191 } 2192 } else { 2193 packet.writeInt((int) clientParam); 2194 packet.writeLongInt(this.maxThreeBytes); 2195 } 2196 2197 packet.writeString(user); 2199 2200 if (password.length() != 0) { 2201 2202 packet.writeString(FALSE_SCRAMBLE); 2203 } else { 2204 2205 packet.writeString(""); 2206 } 2207 2208 if (((serverCapabilities & CLIENT_CONNECT_WITH_DB) != 0) 2209 && (database != null) && (database.length() > 0)) { 2210 packet.writeString(database); 2211 } 2212 2213 send(packet); 2214 2215 if (password.length() > 0) { 2219 Buffer b = readPacket(); 2220 2221 b.setPosition(0); 2222 2223 byte[] replyAsBytes = b.getByteBuffer(); 2224 2225 if ((replyAsBytes.length == 25) && (replyAsBytes[0] != 0)) { 2226 if (replyAsBytes[0] != '*') { 2228 try { 2229 2230 byte[] buff = Security.passwordHashStage1(password); 2231 2232 2233 byte[] passwordHash = new byte[buff.length]; 2234 System.arraycopy(buff, 0, passwordHash, 0, buff.length); 2235 2236 2237 passwordHash = Security.passwordHashStage2(passwordHash, 2238 replyAsBytes); 2239 2240 byte[] packetDataAfterSalt = new byte[replyAsBytes.length 2241 - 5]; 2242 2243 System.arraycopy(replyAsBytes, 4, packetDataAfterSalt, 2244 0, replyAsBytes.length - 5); 2245 2246 byte[] mysqlScrambleBuff = new byte[20]; 2247 2248 2249 Security.passwordCrypt(packetDataAfterSalt, 2250 mysqlScrambleBuff, passwordHash, 20); 2251 2252 2253 Security.passwordCrypt(mysqlScrambleBuff, buff, buff, 20); 2254 2255 Buffer packet2 = new Buffer(25); 2256 packet2.writeBytesNoNull(buff); 2257 2258 this.packetSequence++; 2259 2260 send(packet2, 24); 2261 } catch (NoSuchAlgorithmException nse) { 2262 throw new SQLException ( 2263 "Failed to create message digest 'SHA-1' for authentication. " 2264 + " You must use a JDK that supports JCE to be able to use secure connection authentication", 2265 SQLError.SQL_STATE_GENERAL_ERROR); 2266 } 2267 } else { 2268 try { 2269 2270 byte[] passwordHash = Security.createKeyFromOldPassword(password); 2271 2272 2273 byte[] netReadPos4 = new byte[replyAsBytes.length - 5]; 2274 2275 System.arraycopy(replyAsBytes, 4, netReadPos4, 0, 2276 replyAsBytes.length - 5); 2277 2278 byte[] mysqlScrambleBuff = new byte[20]; 2279 2280 2281 Security.passwordCrypt(netReadPos4, mysqlScrambleBuff, 2282 passwordHash, 20); 2283 2284 2285 String scrambledPassword = Util.scramble(new String ( 2286 mysqlScrambleBuff), password); 2287 2288 Buffer packet2 = new Buffer(packLength); 2289 2290 packet2.writeString(scrambledPassword); 2291 this.packetSequence++; 2292 2293 send(packet2, 24); 2294 } catch (NoSuchAlgorithmException nse) { 2295 throw new SQLException ( 2296 "Failed to create message digest 'SHA-1' for authentication. " 2297 + " You must use a JDK that supports JCE to be able to use secure connection authentication", 2298 SQLError.SQL_STATE_GENERAL_ERROR); 2299 } 2300 } 2301 } 2302 } 2303 } 2304 2305 2317 private void secureAuth411(int packLength, int serverCapabilities, 2318 long clientParam, String user, String password, String database) 2319 throws SQLException { 2320 Buffer packet = new Buffer(packLength); 2339 2340 if (this.use41Extensions) { 2341 if (versionMeetsMinimum(4, 1, 1)) { 2342 packet.writeLong(this.clientParam); 2343 packet.writeLong(this.maxThreeBytes); 2344 2345 packet.writeByte((byte) 8); 2349 2350 packet.writeBytesNoNull(new byte[23]); 2352 } else { 2353 packet.writeLong(this.clientParam); 2354 packet.writeLong(this.maxThreeBytes); 2355 } 2356 } else { 2357 packet.writeInt((int) this.clientParam); 2358 packet.writeLongInt(this.maxThreeBytes); 2359 } 2360 2361 packet.writeString(user); 2363 2364 if (password.length() != 0) { 2365 packet.writeByte((byte) 0x14); 2366 2367 try { 2368 packet.writeBytesNoNull(Security.scramble411(password, this.seed)); 2369 } catch (NoSuchAlgorithmException nse) { 2370 throw new SQLException ( 2371 "Failed to create message digest 'SHA-1' for authentication. " 2372 + " You must use a JDK that supports JCE to be able to use secure connection authentication", 2373 SQLError.SQL_STATE_GENERAL_ERROR); 2374 } 2375 } else { 2376 2377 packet.writeByte((byte) 0); 2378 } 2379 2380 if (((serverCapabilities & CLIENT_CONNECT_WITH_DB) != 0) 2381 && (database != null) && (database.length() > 0)) { 2382 packet.writeString(database); 2383 } 2384 2385 send(packet); 2386 2387 byte savePacketSequence = this.packetSequence++; 2388 2389 Buffer reply = checkErrorPacket(); 2390 2391 if (reply.isLastDataPacket()) { 2392 2396 this.packetSequence = ++savePacketSequence; 2397 packet.clear(); 2398 2399 String seed323 = this.seed.substring(0, 8); 2400 packet.writeString(Util.newCrypt(password, seed323)); 2401 send(packet); 2402 2403 2404 checkErrorPacket(); 2405 } 2406 } 2407} 2408 | Popular Tags |