⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 monetconnection.java

📁 这个是内存数据库的客户端
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
/* * The contents of this file are subject to the MonetDB Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * The Original Code is the MonetDB Database System. * * The Initial Developer of the Original Code is CWI. * Portions created by CWI are Copyright (C) 1997-2007 CWI. * All Rights Reserved. */package nl.cwi.monetdb.jdbc;import java.sql.*;import java.util.*;import java.io.*;import java.nio.*;import java.security.*;import nl.cwi.monetdb.jdbc.util.*;/** * A Connection suitable for the MonetDB database. * <br /><br /> * This connection represents a connection (session) to a MonetDB * database. SQL statements are executed and results are returned within * the context of a connection. This Connection object holds a physical * connection to the MonetDB database. * <br /><br /> * A Connection object's database should able to provide information * describing its tables, its supported SQL grammar, its stored * procedures, the capabilities of this connection, and so on. This * information is obtained with the getMetaData method.<br /> * Note: By default a Connection object is in auto-commit mode, which * means that it automatically commits changes after executing each * statement. If auto-commit mode has been disabled, the method commit * must be called explicitly in order to commit changes; otherwise, * database changes will not be saved. * <br /><br /> * The current state of this connection is that it nearly implements the * whole Connection interface.<br /> * Additionally, the static method getEmbeddedInstanceConnection() * provides a Connection for embedded situations, where an embedded * Mserver is started and used. * * @author Fabian Groffen <Fabian.Groffen@cwi.nl> * @version 1.2 */public class MonetConnection implements Connection {	/** The hostname to connect to */	private final String hostname;	/** The port to connect on the host to */	private final int port;	/** The database to use (currently not used) */	private final String database;	/** The username to use when authenticating */	private final String username;	/** The password to use when authenticating */	private final String password;	/** A connection to Mserver using a TCP socket */	private final MonetSocketBlockMode monet;	/** Whether this Connection is closed (and cannot be used anymore) */	private boolean closed;	/** Whether this Connection is in autocommit mode */	private boolean autoCommit = true;	/** The stack of warnings for this Connection object */	private SQLWarning warnings = null;	/** The Connection specific mapping of user defined types to Java	 * types (not used) */	private Map typeMap = new HashMap();	// See javadoc for documentation about WeakHashMap if you don't know what	// it does !!!NOW!!! (only when you deal with it of course)	/** A Map containing all (active) Statements created from this Connection */	private Map statements = new WeakHashMap();	/** The number of results we receive from the server at once */	private int curReplySize = -1;	// the server by default uses -1 (all)	/** A template to apply to each query (like pre and post fixes) */	String[] queryTempl;	/** A template to apply to each command (like pre and post fixes) */	String[] commandTempl;	/** the SQL language */	final static int LANG_SQL = 0;	/** the XQuery language */	final static int LANG_XQUERY = 1;	/** the MIL language (officially *NOT* supported) */	final static int LANG_MIL = 2;	/** an unknown language */	final static int LANG_UNKNOWN = -1;	/** The language which is used */	final int lang;	/** Query types (copied from sql_query.mx) */	final static int Q_PARSE	= '0';	final static int Q_TABLE	= '1';	final static int Q_UPDATE	= '2';	final static int Q_SCHEMA	= '3';	final static int Q_TRANS	= '4';	final static int Q_PREPARE	= '5';	final static int Q_BLOCK	= '6';	/** Embedded instance */	private static MonetEmbeddedInstance embeddedInstance = null;	/** Embedded properties */	private static Properties embeddedProps = null;	/**	 * Constructor of a Connection for MonetDB. At this moment the	 * current implementation limits itself to storing the given host,	 * database, username and password for later use by the	 * createStatement() call.  This constructor is only accessible to	 * classes from the jdbc package.	 *	 * @param props a Property hashtable holding the properties needed for	 *              connecting	 * @throws SQLException if a database error occurs	 * @throws IllegalArgumentException is one of the arguments is null or empty	 */	MonetConnection(		Properties props)		throws SQLException, IllegalArgumentException, MonetRedirectException	{		this.hostname = props.getProperty("host");		int port;		try {			port = Integer.parseInt(props.getProperty("port"));		} catch (NumberFormatException e) {			port = 0;		}		this.port = port;		this.database = props.getProperty("database");		this.username = props.getProperty("user");		this.password = props.getProperty("password");		String language = props.getProperty("language");		boolean debug = Boolean.valueOf(props.getProperty("debug")).booleanValue();		String hash = props.getProperty("hash");		// check input arguments		if (hostname == null || hostname.trim().equals(""))			throw new IllegalArgumentException("hostname should not be null or empty");		if (port == 0)			throw new IllegalArgumentException("port should not be 0");		if (database == null || database.trim().equals(""))			throw new IllegalArgumentException("database should not be null or empty");		if (username == null || username.trim().equals(""))			throw new IllegalArgumentException("user should not be null or empty");		if (password == null || password.trim().equals(""))			throw new IllegalArgumentException("password should not be null or empty");		if (language == null || language.trim().equals("")) {			language = "sql";			addWarning("No language given, defaulting to 'sql'");		}		// initialise query templates (filled later, but needed below)		queryTempl = new String[3]; // pre, post, sep		commandTempl = new String[3]; // pre, post, sep		try {			monet = new MonetSocketBlockMode(hostname, port);			/*			 * There is no need for a lock on the monet object here.			 * Since we just created the object, and the reference to			 * this object has not yet been returned to the caller,			 * noone can (in a legal way) know about the object.			 */			// we're debugging here... uhm, should be off in real life			if (debug) {				try {					String fname = props.getProperty("logfile", "monet_" +						System.currentTimeMillis() + ".log");					File f = new File(fname);					int ext = fname.lastIndexOf(".");					if (ext < 0) ext = fname.length();					String pre = fname.substring(0, ext);					String suf = fname.substring(ext);					for (int i = 1; f.exists(); i++) {						f = new File(pre + "-" + i + suf);					}					monet.debug(f.getAbsolutePath());				} catch (IOException ex) {					throw new SQLException("Opening logfile failed: " + ex.getMessage());				}			}			// read challenge, send response			String[] nulltempl = {null, null, null};			monet.writeLine(nulltempl,					getChallengeResponse(						monet,						monet.readLine(),						username,						password,						language,						database,						hash						)					);			// read monet response till prompt			List redirects = null;			String err = "", tmp;			int lineType = 0;			while (lineType != MonetSocketBlockMode.PROMPT1) {				if ((tmp = monet.readLine()) == null)					throw new IOException("Connection to server lost!");				if ((lineType = monet.getLineType()) == MonetSocketBlockMode.ERROR) {					err += "\n" + tmp.substring(1);				} else if (lineType == MonetSocketBlockMode.INFO) {					addWarning(tmp.substring(1));				} else if (lineType == MonetSocketBlockMode.REDIRECT) {					if (redirects == null)						redirects = new ArrayList();					redirects.add(tmp.substring(1));				}			}			if (err != "") {				monet.disconnect();				throw new SQLException(err.trim());			}			if (redirects != null) {				monet.disconnect();				throw new MonetRedirectException(redirects);			}			// we seem to have managed to log in, let's store the			// language used			if ("sql".equals(language)) {				lang = LANG_SQL;			} else if ("xquery".equals(language)) {				lang = LANG_XQUERY;			} else if ("mil".equals(language)) {				lang = LANG_MIL;			} else {				lang = LANG_UNKNOWN;			}						// we're ready for commands!		} catch (IOException e) {			throw new SQLException("Unable to connect (" + hostname + ":" + port + "): " + e.getMessage());		}		// fill the query templates		if (lang == LANG_SQL) {			queryTempl[0] = "s";		// pre			queryTempl[1] = ";";		// post			queryTempl[2] = ";\n";		// separator			commandTempl[0] = "X";		// pre			commandTempl[1] = null;		// post			commandTempl[2] = "\nX";	// separator		} else if (lang == LANG_XQUERY) {			queryTempl[0] = "s";			queryTempl[1] = null;			queryTempl[2] = ",";			commandTempl[0] = "X";		// pre			commandTempl[1] = null;		// post			commandTempl[2] = "\nX";	// separator		} else if (lang == LANG_MIL) {			queryTempl[0] = null;			queryTempl[1] = ";";			queryTempl[2] = ";\n";			commandTempl[0] = null;		// pre			commandTempl[1] = null;		// post			commandTempl[2] = null;		// separator		}		// the following initialisers are only valid when the language		// is SQL...		if (lang == LANG_SQL) {			// enable auto commit			setAutoCommit(true);			// set our time zone on the server			Calendar cal = Calendar.getInstance();			int offset = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / (60 * 1000);			String tz = offset < 0 ? "-" : "+";			tz += (Math.abs(offset) / 60 < 10 ? "0" : "") + (Math.abs(offset) / 60) + ":";			offset -= (offset / 60) * 60;			tz += (offset < 10 ? "0" : "") + offset;			sendIndependantCommand("SET TIME ZONE INTERVAL '" + tz + "' HOUR TO MINUTE");		}		// the following initialisers are only valid when the language		// is XQUERY...		if (lang == LANG_XQUERY) {			// output format 			sendControlCommand("output seq");		}		// we're absolutely not closed, since we're brand new		closed = false;	}	/**	 * A little helper function that processes a challenge string, and	 * returns a response string for the server.  If the challenge	 * string is null, a challengeless response is returned.	 *	 * @param monet the MonetSocketBlockMode stream to write to	 * @param chalstr the challenge string	 * @param username the username to use	 * @param password the password to use	 * @param language the language to use	 * @param database the database to connect to	 * @param hash the hash method(s) to use, or NULL for all supported	 *             hashes	 */	private String getChallengeResponse(			MonetSocketBlockMode monet,			String chalstr,			String username,			String password,			String language,			String database,			String hash	) throws SQLException, IOException {		int version = 0;		String response;				// hack alert		monet.readLine(); /* prompt */		// parse the challenge string, split it on ':'		String[] chaltok = chalstr.split(":");		if (chaltok.length < 4) throw			new SQLException("Server challenge string unusable!");		// challenge string to use as salt/key		String challenge = chaltok[0];		// chaltok[1]; // server type, not needed yet 		try {			version = Integer.parseInt(chaltok[2].trim());	// protocol version		} catch (NumberFormatException e) {			throw new SQLException("Protocol version unparseable: " + chaltok[3]);		}		// handle the challenge according to the version it is		switch (version) {			default:				throw new SQLException("Unsupported protocol version: " + version);			case 8:				// proto 7 (finally) used the challenge and works with a				// password hash.  The supported implementations come				// from the server challenge.  We chose the best hash				// we can find, in the order SHA1, MD5, plain.  Also,				// the byte-order is reported in the challenge string,				// which makes sense, since only blockmode is supported.				// proto 8 made this obsolete, but retained the				// byteorder report for future "binary" transports.  In				// proto 8, the byteorder of the blocks is always little				// endian because most machines today are.				String hashes = (hash == null ? chaltok[3] : hash);				String pwhash;				if (hashes.indexOf("SHA1") != -1) {					try {						MessageDigest md = MessageDigest.getInstance("SHA-1");						md.update(password.getBytes("UTF-8"));						md.update(challenge.getBytes("UTF-8"));						byte[] digest = md.digest();						pwhash = "{SHA1}" + toHex(digest);					} catch (NoSuchAlgorithmException e) {						throw new AssertionError("internal error: " + e.toString());					} catch (UnsupportedEncodingException e) {						throw new AssertionError("internal error: " + e.toString());					}				} else if (hashes.indexOf("MD5") != -1) {					try {						MessageDigest md = MessageDigest.getInstance("MD5");						md.update(password.getBytes("UTF-8"));						md.update(challenge.getBytes("UTF-8"));						byte[] digest = md.digest();						pwhash = "{MD5}" + toHex(digest);					} catch (NoSuchAlgorithmException e) {						throw new AssertionError("internal error: " + e.toString());					} catch (UnsupportedEncodingException e) {						throw new AssertionError("internal error: " + e.toString());					}				} else if (hashes.indexOf("plain") != -1) {					pwhash = "{plain}" + password + challenge;				} else {					throw new SQLException("no supported password hashes in " + hashes);				}				// TODO: some day when we need this, we should store				// this				if (chaltok[4].equals("BIG")) {					// byte-order of server is big-endian				} else if (chaltok[4].equals("LIT")) {					// byte-order of server is little-endian				} else {					throw new SQLException("Invalid byte-order: " + chaltok[5]);				}				// generate response				response = "BIG:";	// JVM byte-order is big-endian				response += username + ":" + pwhash + ":" + language;				response += ":" + database + ":";				return(response);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -