📄 monetstatement.java
字号:
/* * 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.*;/** * A Statement suitable for the MonetDB database. * <br /><br /> * The object used for executing a static SQL statement and returning * the results it produces.<br /> * <br /><br /> * By default, only one ResultSet object per Statement object can be * open at the same time. Therefore, if the reading of one ResultSet * object is interleaved with the reading of another, each must have * been generated by different Statement objects. All execution methods * in the Statement interface implicitly close a Statement's current * ResultSet object if an open one exists. * <br /><br /> * The current state of this Statement is that it only implements the * executeQuery() which returns a ResultSet where from results can be * read and executeUpdate() which doesn't return the affected rows. * Commit and rollback are implemented, as is the autoCommit mechanism * which relies on server side auto commit.<br /> * Multi-result queries are supported using the getMoreResults() method. * * @author Fabian Groffen <Fabian.Groffen@cwi.nl> * @version 0.7 */public class MonetStatement implements Statement { /** the default value of maxRows, 0 indicates unlimited */ static final int DEF_MAXROWS = 0; /** The parental Connection object */ private MonetConnection connection; /** The last ResponseList object this Statement produced */ private MonetConnection.ResponseList lastResponseList; /** The last Response that this object uses */ MonetConnection.Response header; /** The warnings this Statement object generated */ private SQLWarning warnings; /** Whether this Statement object is closed or not */ private boolean closed; /** The size of the blocks of results to ask for at the server */ private int fetchSize = 0; /** The maximum number of rows to return in a ResultSet */ private int maxRows = DEF_MAXROWS; /** The suggested direction of fetching data (implemented but not used) */ private int fetchDirection = ResultSet.FETCH_FORWARD; /** The type of ResultSet to produce; i.e. forward only, random access */ private int resultSetType = ResultSet.TYPE_FORWARD_ONLY; /** The concurrency of the ResultSet to produce */ private int resultSetConcurrency = ResultSet.CONCUR_READ_ONLY; /** A List to hold all queries of a batch */ private List batch; /** * MonetStatement constructor which checks the arguments for validity, tries * to set up a socket to MonetDB and attempts to login. * This constructor is only accessible to classes from the jdbc package. * * @param connection the connection that created this Statement * @param resultSetType type of ResultSet to produce * @param resultSetConcurrency concurrency of ResultSet to produce * @throws SQLException if an error occurs during login * @throws IllegalArgumentException is one of the arguments is null or empty */ MonetStatement( MonetConnection connection, int resultSetType, int resultSetConcurrency) throws SQLException, IllegalArgumentException { if (connection == null) throw new IllegalArgumentException("No Connection given!"); this.connection = connection; this.resultSetType = resultSetType; this.resultSetConcurrency = resultSetConcurrency; // check our limits, and generate warnings as appropriate if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) { addWarning("No concurrency mode other then read only is supported, continuing with concurrency level READ_ONLY"); resultSetConcurrency = ResultSet.CONCUR_READ_ONLY; } // check type for supported mode if (resultSetType == ResultSet.TYPE_SCROLL_SENSITIVE) { addWarning("Change sensitive scrolling ResultSet objects are not supported, continuing with a change non-sensitive scrollable cursor."); resultSetType = ResultSet.TYPE_SCROLL_INSENSITIVE; } closed = false; } //== methods of interface Statement /** * Adds the given SQL command to the current list of commmands for this * Statement object. The commands in this list can be executed as a * batch by calling the method executeBatch. * * @param sql typically this is a static SQL INSERT or UPDATE statement * @throws SQLException so the PreparedStatement can throw this exception */ public void addBatch(String sql) throws SQLException { // we assume a batch is big; average q = 1000 if (batch == null) batch = new ArrayList(1000); batch.add(sql); } /** * Empties this Statement object's current list of SQL commands. */ public void clearBatch() { // we simply feed the `old' List to the garbage collector batch = null; } /** * Submits a batch of commands to the database for execution and if * all commands execute successfully, returns an array of update * counts. The int elements of the array that is returned are * ordered to correspond to the commands in the batch, which are * ordered according to the order in which they were added to the * batch. The elements in the array returned by the method * executeBatch may be one of the following: * <br /> * <ol> * <li>A number greater than or equal to zero -- indicates that the * command was processed successfully and is an update count giving * the number of rows in the database that were affected by the * command's execution</li> * <li>A value of SUCCESS_NO_INFO -- indicates that the command was * processed successfully but that the number of rows affected is * unknown</li> * </ol> * If one of the commands in a batch update fails to execute * properly, this method throws a BatchUpdateException, and a JDBC * driver may or may not continue to process the remaining commands * in the batch. However, the driver's behavior must be consistent * with a particular DBMS, either always continuing to process * commands or never continuing to process commands. * <br /><br /> * MonetDB does continues after an error has occurred in the batch. * If one of the commands attempts to return a result set, an * SQLException is added to the SQLException list and thrown * afterwards execution. Failing queries result in SQLExceptions * too and may cause subparts of the batch to fail as well.<br /> * * @return an array of update counts containing one element for each * command in the batch. The elements of the array are ordered * according to the order in which commands were added to the * batch. * @throws SQLException if a database access error occurs. Throws * BatchUpdateException (a subclass of SQLException) if one of the * commands sent to the database fails to execute properly */ public synchronized int[] executeBatch() throws SQLException { // this method is synchronized to make sure noone gets inbetween the // operations we execute below // don't think long if there isn't much to do if (batch == null) return(new int[0]); // go into special Xcopy mode with XQuery if (((MonetConnection)connection).lang == MonetConnection.LANG_XQUERY) { // concatenate all strings into one, and send them over StringBuffer buf = new StringBuffer(8192); for (int i = 0; i < batch.size(); i++) { buf.append(batch.get(i)).append('\n'); } ((MonetConnection)connection).copyToServer(buf.toString(), null); // ignore the resonse for now, it's empty return(new int[0]); } int[] counts = new int[batch.size()]; int offset = 0; boolean first = true; boolean error = false; BatchUpdateException e = new BatchUpdateException("Error(s) occurred while executing the batch, see next SQLExceptions for details", counts); StringBuffer tmpBatch = new StringBuffer(MonetSocketBlockMode.BLOCK); String sep = connection.queryTempl[2]; for (int i = 0; i < batch.size(); i++) { String tmp = batch.get(i).toString(); if (sep.length() + tmp.length() > MonetSocketBlockMode.BLOCK) { // The thing is too big. Way too big. Since it won't // be optimal anyway, just add it to whatever we have // and continue. if (!first) tmpBatch.append(sep); tmpBatch.append(tmp); // send and receive error |= internalBatch(tmpBatch.toString(), counts, offset, i, e); offset = i; tmpBatch.delete(0, tmpBatch.length()); first = true; continue; } if (tmpBatch.length() + sep.length() + tmp.length() >= MonetSocketBlockMode.BLOCK) { // send and receive error |= internalBatch(tmpBatch.toString(), counts, offset, i, e); offset = i; tmpBatch.delete(0, tmpBatch.length()); first = true; } if (!first) tmpBatch.append(sep); first = false; tmpBatch.append(tmp); } // send and receive error |= internalBatch(tmpBatch.toString(), counts, offset, counts.length, e); // throw BatchUpdateException if it contains something if (error) throw e; // otherwise just return the counts return(counts); } private boolean internalBatch( String batch, int[] counts, int offset, int max, BatchUpdateException e) throws BatchUpdateException { try { boolean type = internalExecute(batch); int count = -1; if (!type) count = getUpdateCount(); do { if (offset >= max) throw new SQLException("Overflow: don't use multi statements when batching (" + max + ")"); if (type) { e.setNextException( new SQLException("Batch query produced a ResultSet! " + "Ignoring and setting update count to " + "value " + EXECUTE_FAILED)); counts[offset] = EXECUTE_FAILED; } else if (count >= 0) { counts[offset] = count; } offset++; } while ((type = getMoreResults()) || (count = getUpdateCount()) != -1); } catch (SQLException ex) { e.setNextException(ex); for (; offset < max; offset++) { counts[offset] = EXECUTE_FAILED; } return(true); } return(false); } /** * Cancels this Statement object if both the DBMS and driver support * aborting an SQL statement. This method can be used by one thread to * cancel a statement that is being executed by another thread. * * @throws SQLException if a database access error occurs or the cancel * operation is not supported */ public void cancel() throws SQLException { throw new SQLException("Query cancelling is currently not supported by the DBMS."); } /** * Clears all warnings reported for this Statement object. After a call to * this method, the method getWarnings returns null until a new warning is * reported for this Statement object. */ public void clearWarnings() { warnings = null; } /** * Releases this Statement object's database and JDBC resources immediately * instead of waiting for this to happen when it is automatically closed. It * is generally good practice to release resources as soon as you are * finished with them to avoid tying up database resources. * <br /><br /> * Calling the method close on a Statement object that is already closed has * no effect. * <br /><br /> * A Statement object is automatically closed when it is garbage collected. * When a Statement object is closed, its current ResultSet object, if one * exists, is also closed. */ public void close() { // close previous ResultSet, if not closed already if (lastResponseList != null) lastResponseList.close(); closed = true; } // Chapter 13.1.2.3 of Sun's JDBC 3.0 Specification /** * Executes the given SQL statement, which may return multiple results. In * some (uncommon) situations, a single SQL statement may return multiple * result sets and/or update counts. Normally you can ignore this unless * you are (1) executing a stored procedure that you know may return * multiple results or (2) you are dynamically executing an unknown SQL * string. * <br /><br /> * The execute method executes an SQL statement and indicates the form of * the first result. You must then use the methods getResultSet or * getUpdateCount to retrieve the result, and getMoreResults to move to any * subsequent result(s). * * @param sql any SQL statement * @return true if the first result is a ResultSet object; false if it is an * update count or there are no results * @throws SQLException if a database access error occurs */ public boolean execute(String sql) throws SQLException { return(internalExecute(sql)); } /** * Performs the steps to execute a given SQL statement. This method * exists to allow the functionality of this function to be called * from within this class only. The PreparedStatement for example * overrides the execute() method to throw an SQLException, but it * needs its functionality when the executeBatch method (which is * inherited) is called. * * @param sql any SQL statement * @return true if the first result is a ResultSet object; false if * it is an update count or there are no results * @throws SQLException if a database access error occurs */ private boolean internalExecute(String sql) throws SQLException { // close previous query, if not closed already if (lastResponseList != null) { lastResponseList.close(); lastResponseList = null; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -