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 + -
显示快捷键?