abstractjdbc1connection.java
来自「PostgreSQL7.4.6 for Linux」· Java 代码 · 共 1,864 行 · 第 1/4 页
JAVA
1,864 行
//TODO: handle parameter status messages int l_len = pgStream.ReceiveIntegerR(4); String l_pStatus = encoding.decode(pgStream.Receive(l_len-4)); if (Driver.logDebug) Driver.debug("ParameterStatus="+ l_pStatus); break; default: if (Driver.logDebug) Driver.debug("invalid state="+ (char)beresp); throw new PSQLException("postgresql.con.setup", PSQLState.CONNECTION_UNABLE_TO_CONNECT); } } while (beresp != 'Z'); // read ReadyForQuery if (pgStream.ReceiveIntegerR(4) != 5) throw new PSQLException("postgresql.con.setup", PSQLState.CONNECTION_UNABLE_TO_CONNECT); //TODO: handle transaction status char l_tStatus = (char)pgStream.ReceiveChar(); // "pg_encoding_to_char(1)" will return 'EUC_JP' for a backend compiled with multibyte, // otherwise it's hardcoded to 'SQL_ASCII'. // If the backend doesn't know about multibyte we can't assume anything about the encoding // used, so we denote this with 'UNKNOWN'. //Note: begining with 7.2 we should be using pg_client_encoding() which //is new in 7.2. However it isn't easy to conditionally call this new //function, since we don't yet have the information as to what server //version we are talking to. Thus we will continue to call //getdatabaseencoding() until we drop support for 7.1 and older versions //or until someone comes up with a conditional way to run one or //the other function depending on server version that doesn't require //two round trips to the server per connection final String encodingQuery = "case when pg_encoding_to_char(1) = 'SQL_ASCII' then 'UNKNOWN' else getdatabaseencoding() end"; // Set datestyle and fetch db encoding in a single call, to avoid making // more than one round trip to the backend during connection startup. BaseResultSet resultSet = execSQL("set datestyle to 'ISO'; select version(), " + encodingQuery + ";"); if (! resultSet.next()) { throw new PSQLException("postgresql.con.failed.bad.encoding", PSQLState.CONNECTION_UNABLE_TO_CONNECT); } String version = resultSet.getString(1); dbVersionNumber = extractVersionNumber(version); String dbEncoding = resultSet.getString(2); encoding = Encoding.getEncoding(dbEncoding, p_info.getProperty("charSet")); //In 7.3 we are forced to do a second roundtrip to handle the case //where a database may not be running in autocommit mode //jdbc by default assumes autocommit is on until setAutoCommit(false) //is called. Therefore we need to ensure a new connection is //initialized to autocommit on. //We also set the client encoding so that the driver only needs //to deal with utf8. We can only do this in 7.3 because multibyte //support is now always included if (haveMinimumServerVersion("7.3")) { BaseResultSet acRset = //TODO: if protocol V3 we can set the client encoding in startup execSQL("set client_encoding = 'UNICODE'"); //set encoding to be unicode encoding = Encoding.getEncoding("UNICODE", null); } // Initialise object handling initObjectTypes(); // Mark the connection as ok, and cleanup PG_STATUS = CONNECTION_OK; } private void openConnectionV2(String host, int port, Properties info, String database, String url, Driver d, String password) throws SQLException { PGProtocolVersionMajor = 2; if (Driver.logDebug) Driver.debug("Using Protocol Version2"); // Now we need to construct and send an ssl startup packet try { if (useSSL) { if (Driver.logDebug) Driver.debug("Asking server if it supports ssl"); pgStream.SendInteger(8,4); pgStream.SendInteger(80877103,4); // now flush the ssl packets to the backend pgStream.flush(); // Now get the response from the backend, either an error message // or an authentication request int beresp = pgStream.ReceiveChar(); if (Driver.logDebug) Driver.debug("Server response was (S=Yes,N=No): "+(char)beresp); switch (beresp) { case 'E': // An error occured, so pass the error message to the // user. // // The most common one to be thrown here is: // "User authentication failed" // throw new PSQLException("postgresql.con.misc", PSQLState.CONNECTION_REJECTED, pgStream.ReceiveString(encoding)); case 'N': // Server does not support ssl throw new PSQLException("postgresql.con.sslnotsupported", PSQLState.CONNECTION_FAILURE); case 'S': // Server supports ssl if (Driver.logDebug) Driver.debug("server does support ssl"); Driver.makeSSL(pgStream); break; default: throw new PSQLException("postgresql.con.sslfail", PSQLState.CONNECTION_FAILURE); } } } catch (IOException e) { throw new PSQLException("postgresql.con.failed", PSQLState.CONNECTION_UNABLE_TO_CONNECT, e); } // Now we need to construct and send a startup packet try { new StartupPacket(PGProtocolVersionMajor, PGProtocolVersionMinor, PG_USER, database).writeTo(pgStream); // now flush the startup packets to the backend pgStream.flush(); // Now get the response from the backend, either an error message // or an authentication request int areq = -1; // must have a value here do { int beresp = pgStream.ReceiveChar(); String salt = null; byte [] md5Salt = new byte[4]; switch (beresp) { case 'E': // An error occured, so pass the error message to the // user. // // The most common one to be thrown here is: // "User authentication failed" // throw new PSQLException("postgresql.con.misc", PSQLState.CONNECTION_REJECTED, pgStream.ReceiveString(encoding)); case 'R': // Get the type of request areq = pgStream.ReceiveIntegerR(4); // Get the crypt password salt if there is one if (areq == AUTH_REQ_CRYPT) { byte[] rst = new byte[2]; rst[0] = (byte)pgStream.ReceiveChar(); rst[1] = (byte)pgStream.ReceiveChar(); salt = new String(rst, 0, 2); if (Driver.logDebug) Driver.debug("Crypt salt=" + salt); } // Or get the md5 password salt if there is one if (areq == AUTH_REQ_MD5) { md5Salt[0] = (byte)pgStream.ReceiveChar(); md5Salt[1] = (byte)pgStream.ReceiveChar(); md5Salt[2] = (byte)pgStream.ReceiveChar(); md5Salt[3] = (byte)pgStream.ReceiveChar(); if (Driver.logDebug) { String md5SaltString = ""; for (int i=0; i<md5Salt.length; i++) { md5SaltString += " " + md5Salt[i]; } Driver.debug("MD5 salt=" + md5SaltString); } } // now send the auth packet switch (areq) { case AUTH_REQ_OK: break; case AUTH_REQ_KRB4: if (Driver.logDebug) Driver.debug("postgresql: KRB4"); throw new PSQLException("postgresql.con.kerb4", PSQLState.CONNECTION_REJECTED); case AUTH_REQ_KRB5: if (Driver.logDebug) Driver.debug("postgresql: KRB5"); throw new PSQLException("postgresql.con.kerb5", PSQLState.CONNECTION_REJECTED); case AUTH_REQ_PASSWORD: if (Driver.logDebug) Driver.debug("postgresql: PASSWORD"); pgStream.SendInteger(5 + password.length(), 4); pgStream.Send(password.getBytes()); pgStream.SendInteger(0, 1); pgStream.flush(); break; case AUTH_REQ_CRYPT: if (Driver.logDebug) Driver.debug("postgresql: CRYPT"); String crypted = UnixCrypt.crypt(salt, password); pgStream.SendInteger(5 + crypted.length(), 4); pgStream.Send(crypted.getBytes()); pgStream.SendInteger(0, 1); pgStream.flush(); break; case AUTH_REQ_MD5: if (Driver.logDebug) Driver.debug("postgresql: MD5"); byte[] digest = MD5Digest.encode(PG_USER, password, md5Salt); pgStream.SendInteger(5 + digest.length, 4); pgStream.Send(digest); pgStream.SendInteger(0, 1); pgStream.flush(); break; default: throw new PSQLException("postgresql.con.auth", PSQLState.CONNECTION_REJECTED, new Integer(areq)); } break; default: throw new PSQLException("postgresql.con.authfail", PSQLState.CONNECTION_REJECTED); } } while (areq != AUTH_REQ_OK); } catch (IOException e) { //Should be passing exception as arg. throw new PSQLException("postgresql.con.failed", PSQLState.CONNECTION_UNABLE_TO_CONNECT, e); } // As of protocol version 2.0, we should now receive the cancellation key and the pid int beresp; do { beresp = pgStream.ReceiveChar(); switch (beresp) { case 'K': pid = pgStream.ReceiveIntegerR(4); ckey = pgStream.ReceiveIntegerR(4); break; case 'E': throw new PSQLException("postgresql.con.backend", PSQLState.CONNECTION_UNABLE_TO_CONNECT, pgStream.ReceiveString(encoding)); case 'N': addWarning(pgStream.ReceiveString(encoding)); break; default: throw new PSQLException("postgresql.con.setup", PSQLState.CONNECTION_UNABLE_TO_CONNECT); } } while (beresp == 'N'); // Expect ReadyForQuery packet do { beresp = pgStream.ReceiveChar(); switch (beresp) { case 'Z': break; case 'N': addWarning(pgStream.ReceiveString(encoding)); break; case 'E': throw new PSQLException("postgresql.con.backend", PSQLState.CONNECTION_UNABLE_TO_CONNECT, pgStream.ReceiveString(encoding)); default: throw new PSQLException("postgresql.con.setup", PSQLState.CONNECTION_UNABLE_TO_CONNECT); } } while (beresp == 'N'); // "pg_encoding_to_char(1)" will return 'EUC_JP' for a backend compiled with multibyte, // otherwise it's hardcoded to 'SQL_ASCII'. // If the backend doesn't know about multibyte we can't assume anything about the encoding // used, so we denote this with 'UNKNOWN'. //Note: begining with 7.2 we should be using pg_client_encoding() which //is new in 7.2. However it isn't easy to conditionally call this new //function, since we don't yet have the information as to what server //version we are talking to. Thus we will continue to call //getdatabaseencoding() until we drop support for 7.1 and older versions //or until someone comes up with a conditional way to run one or //the other function depending on server version that doesn't require //two round trips to the server per connection final String encodingQuery = "case when pg_encoding_to_char(1) = 'SQL_ASCII' then 'UNKNOWN' else getdatabaseencoding() end"; // Set datestyle and fetch db encoding in a single call, to avoid making // more than one round trip to the backend during connection startup. BaseResultSet resultSet = execSQL("set datestyle to 'ISO'; select version(), " + encodingQuery + ";"); if (! resultSet.next()) { throw new PSQLException("postgresql.con.failed.bad.encoding", PSQLState.CONNECTION_UNABLE_TO_CONNECT); } String version = resultSet.getString(1); dbVersionNumber = extractVersionNumber(version); String dbEncoding = resultSet.getString(2); encoding = Encoding.getEncoding(dbEncoding, info.getProperty("charSet")); //TODO: remove this once the set is done as part of V3protocol connection initiation if (haveMinimumServerVersion("7.4")) { BaseResultSet acRset = execSQL("set client_encoding = 'UNICODE'"); //set encoding to be unicode encoding = Encoding.getEncoding("UNICODE", null); } //In 7.3 we are forced to do a second roundtrip to handle the case //where a database may not be running in autocommit mode //jdbc by default assumes autocommit is on until setAutoCommit(false) //is called. Therefore we need to ensure a new connection is //initialized to autocommit on. //We also set the client encoding so that the driver only needs //to deal with utf8. We can only do this in 7.3+ because multibyte //support is now always included if (haveMinimumServerVersion("7.3") && !haveMinimumServerVersion("7.4")) { BaseResultSet acRset = execSQL("set client_encoding = 'UNICODE'; show autocommit"); //set encoding to be unicode encoding = Encoding.getEncoding("UNICODE", null); if (!acRset.next()) { throw new PSQLException("postgresql.con.failed.bad.autocommit", PSQLState.CONNECTION_UNABLE_TO_CONNECT); } //if autocommit is currently off we need to turn it on //note that we will be in a transaction because the select above //will have initiated the transaction so we need a commit //to make the setting permanent if (acRset.getString(1).equals("off")) { execSQL("set autocommit = on; commit;"); } } // Initialise object handling initObjectTypes(); // Mark the connection as ok, and cleanup PG_STATUS = CONNECTION_OK; } /* * Return the instance of org.postgresql.Driver * that created this connection */ public Driver getDriver() { return this_driver; } /* * This adds a warning to the warning chain. * @param msg message to add */ public void addWarning(String msg) { // Add the warning to the chain if (firstWarning != null) firstWarning.setNextWarning(new SQLWarning(msg)); else firstWarning = new SQLWarning(msg); // Now check for some specific messages // This is obsolete in 6.5, but I've left it in here so if we need to use this // technique again, we'll know where to place it. // // This is generated by the SQL "show datestyle" //if (msg.startsWith("NOTICE:") && msg.indexOf("DateStyle")>0) { //// 13 is the length off "DateStyle is " //msg = msg.substring(msg.indexOf("DateStyle is ")+13); // //for(int i=0;i<dateStyles.length;i+=2) //if (msg.startsWith(dateStyles[i])) //currentDateStyle=i+1; // this is the index of the format //} } /** Simple query execution. */ public BaseResultSet execSQL (String s) throws SQLException { final Object[] nullarr = new Object[0]; BaseStatement stat = (BaseStatement) createStatement(); return QueryExecutor.execute(new String[] { s }, nullarr, stat); } /* * In SQL, a result table can be retrieved through a cursor that * is named. The current row of a result can be updated or deleted * using a positioned update/delete statement that references the * cursor name. * * We support one cursor per connection. * * setCursorName sets the cursor name. * * @param cursor the cursor name * @exception SQLException if a database access error occurs */ public void setCursorName(String cursor) throws SQLException { this.cursor = cursor; } /* * getCursorName gets the cursor name. * * @return the current cursor name * @exception SQLException if a database access error occurs */ public String getCursorName() throws SQLException { return cursor; } /* * We are required to bring back certain information by * the DatabaseMetaData class. These functions do that. * * Method getURL() brings back the URL (good job we saved it) * * @return the url * @exception SQLException just in case... */ public String getURL() throws SQLException { return this_url;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?