Mercurial > hg > monetdb-java
changeset 67:87ba760038b6 embedded
More cleanup. About to start the tuple conversions.
line wrap: on
line diff
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java @@ -5,7 +5,7 @@ import nl.cwi.monetdb.jdbc.types.URL; import nl.cwi.monetdb.mcl.connection.MCLException; import nl.cwi.monetdb.mcl.connection.Debugger; import nl.cwi.monetdb.mcl.connection.MonetDBLanguage; -import nl.cwi.monetdb.mcl.parser.MCLParseException; +import nl.cwi.monetdb.mcl.protocol.MCLParseException; import nl.cwi.monetdb.mcl.protocol.AbstractProtocol; import nl.cwi.monetdb.mcl.protocol.ServerResponses; import nl.cwi.monetdb.mcl.responses.*; @@ -1398,7 +1398,7 @@ public abstract class MonetConnection ex /** The sequence number of this ResponseList */ private final int seqnr; /** A list of the Responses associated with the query, in the right order */ - private List<IResponse> responses = new ArrayList<>(); + private final List<IResponse> responses = new ArrayList<>(); /** A map of ResultSetResponses, used for additional DataBlockResponse mapping */ private Map<Integer, ResultSetResponse> rsresponses; /** The current header returned by getNextResponse() */ @@ -1414,7 +1414,7 @@ public abstract class MonetConnection ex * @param rstype the type of result sets to produce * @param rsconcur the concurrency of result sets to produce */ - public ResponseList(int cachesize, int maxrows, int rstype, int rsconcur) throws SQLException { + ResponseList(int cachesize, int maxrows, int rstype, int rsconcur) throws SQLException { this.cachesize = cachesize; this.maxrows = maxrows; this.rstype = rstype; @@ -1439,8 +1439,7 @@ public abstract class MonetConnection ex } /** - * Retrieves the next available response, or null if there are - * no more responses. + * Retrieves the next available response, or null if there are no more responses. * * @return the next Response available or null */ @@ -1495,8 +1494,7 @@ public abstract class MonetConnection ex } /** - * Closes this ResponseList by closing all the Responses in this - * ResponseList. + * Closes this ResponseList by closing all the Responses in this ResponseList. */ public void close() { for (int i = 0; i < responses.size(); i++) { @@ -1505,10 +1503,9 @@ public abstract class MonetConnection ex } /** - * Returns whether this ResponseList has still unclosed - * Responses. + * Returns whether this ResponseList has still unclosed Responses. */ - public boolean hasUnclosedResponses() { + boolean hasUnclosedResponses() { for (IResponse r : responses) { if (r != null) return true; @@ -1517,13 +1514,12 @@ public abstract class MonetConnection ex } /** - * Executes the query contained in this ResponseList, and - * stores the Responses resulting from this query in this + * Executes the query contained in this ResponseList, and stores the Responses resulting from this query in this * ResponseList. * * @throws SQLException if a database error occurs */ - public void processQuery(String query) throws SQLException { + void processQuery(String query) throws SQLException { this.executeQuery(language.getQueryTemplates(), query); } @@ -1534,7 +1530,7 @@ public abstract class MonetConnection ex * @param query the query to execute * @throws SQLException if a database error occurs */ - @SuppressWarnings({"fallthrough", "unchecked"}) + @SuppressWarnings("fallthrough") public void executeQuery(byte[][] templ, String query) throws SQLException { String error = null; @@ -1555,7 +1551,8 @@ public abstract class MonetConnection ex int size = cachesize == 0 ? DEF_FETCHSIZE : cachesize; size = maxrows != 0 ? Math.min(maxrows, size) : size; // don't do work if it's not needed - if (language == MonetDBLanguage.LANG_SQL && size != curReplySize && !Arrays.deepEquals(templ, language.getCommandTemplates())) { + if (language == MonetDBLanguage.LANG_SQL && size != curReplySize && + !Arrays.deepEquals(templ, language.getCommandTemplates())) { sendControlCommand("reply_size " + size); // store the reply size after a successful change @@ -1581,7 +1578,8 @@ public abstract class MonetConnection ex } else { // this is a simple call, which is a lot cheaper and will // always succeed for small queries. - protocol.writeNextCommand((templ[0] == null) ? MonetDBLanguage.EmptyString : templ[0], query.getBytes(), (templ[1] == null) ? MonetDBLanguage.EmptyString : templ[1]); + protocol.writeNextCommand((templ[0] == null) ? MonetDBLanguage.EmptyString : templ[0], + query.getBytes(), (templ[1] == null) ? MonetDBLanguage.EmptyString : templ[1]); } // go for new results @@ -1589,8 +1587,7 @@ public abstract class MonetConnection ex ServerResponses nextResponse = protocol.getCurrentServerResponseHeader(); IResponse res = null; while (nextResponse != ServerResponses.PROMPT) { - // each response should start with a start of header - // (or error) + // each response should start with a start of header (or error) switch (nextResponse) { case SOHEADER: // make the response object, and fill it @@ -1600,8 +1597,9 @@ public abstract class MonetConnection ex throw new MCLParseException("Q_PARSE header not allowed here", 1); case Q_TABLE: case Q_PREPARE: { - res = protocol.getNextResultSetResponse(MonetConnection.this, ResponseList.this, seqnr); - ResultSetResponse<?> rsreponse = (ResultSetResponse<?>) res; + res = protocol.getNextResultSetResponse(MonetConnection.this, + ResponseList.this, this.seqnr); + ResultSetResponse rsreponse = (ResultSetResponse) res; // only add this resultset to // the hashmap if it can possibly // have an additional datablock @@ -1628,7 +1626,7 @@ public abstract class MonetConnection ex MonetConnection.this.autoCommit = isAutoCommit; break; case Q_BLOCK: { - DataBlockResponse<?> next = protocol.getNextDatablockResponse(rsresponses); + DataBlockResponse next = protocol.getNextDatablockResponse(rsresponses); if (next == null) { error = "M0M12!No ResultSetResponse for a DataBlock found"; break; @@ -1646,16 +1644,14 @@ public abstract class MonetConnection ex break; } - // immediately handle errors after parsing - // the header (res may be null) + // immediately handle errors after parsing the header (res may be null) if (error != null) { protocol.waitUntilPrompt(); nextResponse = protocol.getCurrentServerResponseHeader(); break; } - // here we have a res object, which - // we can start filling + // here we have a res object, which we can start filling if(res instanceof IIncompleteResponse) { IIncompleteResponse iter = (IIncompleteResponse) res; while (iter.wantsMore()) { @@ -1663,8 +1659,7 @@ public abstract class MonetConnection ex protocol.fetchNextResponseData(); iter.addLine(protocol.getCurrentServerResponseHeader(), protocol.getCurrentData()); } catch (MCLParseException ex) { - // right, some protocol violation, - // skip the rest of the result + // right, some protocol violation, skip the rest of the result error = "M0M10!" + ex.getMessage(); protocol.waitUntilPrompt(); nextResponse = protocol.getCurrentServerResponseHeader(); @@ -1676,33 +1671,25 @@ public abstract class MonetConnection ex if (error != null) { break; } - // it is of no use to store - // DataBlockResponses, you never want to + + // it is of no use to store DataBlockResponses, you never want to // retrieve them directly anyway if (!(res instanceof DataBlockResponse)) { responses.add(res); } - - // read the next line (can be prompt, new - // result, error, etc.) before we start the - // loop over + // read the next line (can be prompt, new result, error, etc.) before we start the loop over protocol.fetchNextResponseData(); nextResponse = protocol.getCurrentServerResponseHeader(); break; case INFO: addWarning(protocol.getRemainingStringLine(1), "01000"); - - // read the next line (can be prompt, new - // result, error, etc.) before we start the - // loop over + // read the next line (can be prompt, new result, error, etc.) before we start the loop over protocol.fetchNextResponseData(); nextResponse = protocol.getCurrentServerResponseHeader(); break; case ERROR: - // read everything till the prompt (should be - // error) we don't know if we ignore some - // garbage here... but the log should reveal - // that + // read everything till the prompt (should be error) we don't know if we ignore some + // garbage here... but the log should reveal that protocol.waitUntilPrompt(); nextResponse = protocol.getCurrentServerResponseHeader(); error = protocol.getRemainingStringLine(1);
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetDriver.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetDriver.java @@ -331,7 +331,7 @@ final public class MonetDriver implement * @return the mathing java.sql.Types constant or java.sql.Types.OTHER if * nothing matched on the given string */ - static int getJavaType(String type) { + public static int getJavaType(String type) { // match the currentColumns type on a java.sql.Types constant Integer tp = typeMap.get(type); if (tp != null) {
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java @@ -428,8 +428,7 @@ public class MonetPreparedStatement exte case Types.BIGINT: String monettype = getColumnTypeName(column); if (monettype != null) { - if ("oid".equals(monettype) - || "ptr".equals(monettype)) + if ("oid".equals(monettype) || "ptr".equals(monettype)) return false; } return true;
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java @@ -10,8 +10,7 @@ package nl.cwi.monetdb.jdbc; import nl.cwi.monetdb.jdbc.types.INET; import nl.cwi.monetdb.jdbc.types.URL; -import nl.cwi.monetdb.mcl.parser.MCLParseException; -import nl.cwi.monetdb.mcl.protocol.AbstractProtocol; +import nl.cwi.monetdb.mcl.protocol.MCLParseException; import nl.cwi.monetdb.mcl.responses.ResultSetResponse; import java.io.ByteArrayInputStream; @@ -72,7 +71,6 @@ public class MonetResultSet extends Mone /** The current position of the cursor for this ResultSet object */ int curRow = 0; - // a blank final is immutable once assigned in the constructor /** A Header to retrieve lines from */ private final ResultSetResponse header; @@ -84,10 +82,8 @@ public class MonetResultSet extends Mone private final int[] JdbcSQLTypes; /** The number of rows in this ResultSet */ final int tupleCount; - /** The parental Statement object */ private final Statement statement; - /** The type of this ResultSet (forward or scrollable) */ private int type = TYPE_FORWARD_ONLY; /** The concurrency of this ResultSet (currently only read-only) */ @@ -98,10 +94,9 @@ public class MonetResultSet extends Mone private boolean lastReadWasNull = true; /** Just a dummy variable to keep store the fetchsize set. */ private int fetchSize; + /** The current row's values */ + Object[] values; - final Object[] values; - - private final AbstractProtocol<?> protocol; /** * Main constructor backed by the given Header. * @@ -123,20 +118,12 @@ public class MonetResultSet extends Mone /* if we have a header object, the fetchSize used for this result set is the header's cacheSize */ this.fetchSize = header.getCacheSize(); - // well there is only one supported concurrency, so we don't have to - // bother about that - - // throws SQLException on getters of Header, so we find out immediately - // if an error occurred for this query + // well there is only one supported concurrency, so we don't have to bother about that + // throws SQLException on getters of Header, so we find out immediately if an error occurred for this query + this.tupleCount = header.getTuplecount(); this.columns = header.getNames(); this.types = header.getTypes(); - this.tupleCount = header.getTuplecount(); - - // create result array - this.protocol = ((MonetConnection)statement.getConnection()).getProtocol(); - this.values = new Object[this.columns.length]; - this.JdbcSQLTypes = new int[types.length]; - populateJdbcSQLtypesArray(); + this.JdbcSQLTypes = header.getJdbcSQLTypes(); } /** @@ -149,7 +136,8 @@ public class MonetResultSet extends Mone * @param results the number of rows in the ResultSet * @throws IllegalArgumentException if communicating with monet failed */ - MonetResultSet(Statement statement, String[] columns, String[] types, int results) throws IllegalArgumentException { + MonetResultSet(Statement statement, String[] columns, String[] types, int[] JdbcSQLTypes, int results) + throws IllegalArgumentException { if (statement == null) { throw new IllegalArgumentException("Statement may not be null!"); } @@ -162,42 +150,13 @@ public class MonetResultSet extends Mone if (results < 0) { throw new IllegalArgumentException("Negative rowcount not allowed!"); } - this.statement = statement; this.header = null; this.fetchSize = 0; - + this.tupleCount = results; this.columns = columns; this.types = types; - this.tupleCount = results; - - try { - this.protocol = ((MonetConnection)statement.getConnection()).getProtocol(); - } catch (SQLException e) { - throw new IllegalArgumentException(e); - } - - this.values = new Object[this.columns.length]; - this.JdbcSQLTypes = new int[types.length]; - populateJdbcSQLtypesArray(); - } - - /** - * Internal utility method to fill the JdbcSQLTypes array with derivable values. - * By doing it once (in the constructor) we can avoid doing this in many getXyz() methods again and again - * thereby improving getXyz() method performance. - */ - private void populateJdbcSQLtypesArray() { - for (int i = 0; i < types.length; i++) { - int javaSQLtype = MonetDriver.getJavaType(types[i]); - JdbcSQLTypes[i] = javaSQLtype; - if (javaSQLtype == Types.BLOB) { - try { - if (((MonetConnection)statement.getConnection()).getBlobAsBinary()) - JdbcSQLTypes[i] = Types.BINARY; - } catch (SQLException se) { /* ignore it */ } - } - } + this.JdbcSQLTypes = JdbcSQLTypes; } //== methods of interface ResultSet @@ -246,19 +205,10 @@ public class MonetResultSet extends Mone if (row < 0) row = 0; // before first else if (row > tupleCount + 1) row = tupleCount + 1; // after last - Object tmpLine = header.getLine(row - 1); - + this.values = header.getLine(row - 1); // store it - curRow = row; - - if (tmpLine == null) return false; - try { - protocol.parseTupleLine(tmpLine, this.values); - } catch (MCLParseException e) { - throw new SQLException(e.getMessage(), "M0M10"); - } - - return true; + this.curRow = row; + return this.values != null; } /** @@ -305,8 +255,9 @@ public class MonetResultSet extends Mone if (header != null && !header.isClosed()) { header.close(); } - if (statement instanceof MonetStatement) + if (statement instanceof MonetStatement) { ((MonetStatement)statement).closeIfCompletion(); + } } // Chapter 14.2.3 from Sun JDBC 3.0 specification @@ -451,8 +402,8 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row - * of this ResultSet object as a java.io.Reader object. + * Retrieves the value of the designated column in the current row of this ResultSet object as a java.io.Reader + * object. * * @param columnIndex the first column is 1, the second is 2, ... * @return a java.io.Reader object that contains the column value; @@ -478,8 +429,8 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row - * of this ResultSet object as a java.io.Reader object. + * Retrieves the value of the designated column in the current row of this ResultSet object as a java.io.Reader + * object. * * @param columnName the name of the column * @return a java.io.Reader object that contains the column value; @@ -531,13 +482,11 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row - * of this ResultSet object as a Blob object in the Java programming - * language. + * Retrieves the value of the designated column in the current row of this ResultSet object as a Blob object in + * the Java programming language. * * @param columnIndex the first column is 1, the second is 2, ... - * @return a Blob object representing the SQL BLOB value in the - * specified column + * @return a Blob object representing the SQL BLOB value in the specified column * @throws SQLException if a database access error occurs */ @Override @@ -1418,8 +1367,7 @@ public class MonetResultSet extends Mone } /** - * Indicates the designated column's normal maximum width in - * characters. + * Indicates the designated column's normal maximum width in characters. * * @param column the first column is 1, the second is 2, ... * @return the normal maximum number of characters allowed as the @@ -1619,9 +1567,8 @@ public class MonetResultSet extends Mone } /** - * Indicates whether the designated column is definitely not - * writable. MonetDB does not support cursor updates, so - * nothing is writable. + * Indicates whether the designated column is definitely not writable. MonetDB does not support + * cursor updates, so nothing is writable. * * @param column the first column is 1, the second is 2, ... * @return true if so; false otherwise @@ -1699,9 +1646,8 @@ public class MonetResultSet extends Mone } /** - * Gets the designated column's suggested title for use in - * printouts and displays. This is currently equal to - * getColumnName(). + * Gets the designated column's suggested title for use in printouts and displays. This is currently equal + * to getColumnName(). * * @param column the first column is 1, the second is 2, ... * @return the suggested column title @@ -1713,7 +1659,7 @@ public class MonetResultSet extends Mone } /** - * Gets the designated column's name + * Gets the designated column's name. * * @param column the first column is 1, the second is 2, ... * @return the column name @@ -2520,7 +2466,7 @@ public class MonetResultSet extends Mone * @return the fractional seconds (nanos) or -1 if the value is NULL * @throws SQLException if a database error occurs */ - private int getJavaDate(Calendar cal, int columnIndex, int type) throws SQLException { + private int getJavaDate(Calendar cal, int columnIndex, int type) throws SQLException { //TODO check this :( if (cal == null) throw new IllegalArgumentException("No Calendar object given!");
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java @@ -60,7 +60,7 @@ public class MonetStatement extends Mone /** Whether this Statement object is closed or not */ protected boolean closed; /** Whether the application wants this Statement object to be pooled */ - protected boolean poolable; + private boolean poolable; /** Whether this Statement should be closed if the last ResultSet closes */ private boolean closeOnCompletion = false; /** The size of the blocks of results to ask for at the server */ @@ -665,16 +665,15 @@ public class MonetStatement extends Mone */ @Override public ResultSet getGeneratedKeys() throws SQLException { - String[] columns, types; + String[] columns = new String[1], types = new String[1]; + int[] jdbcTypes = new int[1]; String[][] results; - columns = new String[1]; - types = new String[1]; - columns[0] = "GENERATED_KEY"; /* the generated key should be an integer, because (wait for it) other * frameworks such as spring expect this. */ types[0] = "BIGINT"; + jdbcTypes[0] = MonetDriver.getJavaType(types[0]); if (header instanceof UpdateResponse) { String lastid = ((UpdateResponse)header).getLastid(); @@ -689,7 +688,7 @@ public class MonetStatement extends Mone } try { - return new MonetVirtualResultSet(this, columns, types, results); + return new MonetVirtualResultSet(this, columns, types, jdbcTypes, results); } catch (IllegalArgumentException e) { throw new SQLException("Internal driver error: " + e.getMessage(), "M0M03"); } @@ -823,7 +822,7 @@ public class MonetStatement extends Mone * @throws SQLException if a database access error occurs */ @Override - public ResultSet getResultSet() throws SQLException{ + public ResultSet getResultSet() throws SQLException { return (header instanceof ResultSetResponse) ? new MonetResultSet(this, (ResultSetResponse)header) : null; } @@ -1115,8 +1114,7 @@ public class MonetStatement extends Mone } /** - * Returns a value indicating whether the Statement is poolable or - * not. + * Returns a value indicating whether the Statement is poolable or not. * * @return true if the Statement is poolable; false otherwise */ @@ -1207,8 +1205,9 @@ final class MonetVirtualResultSet extend private String results[][]; private boolean closed; - MonetVirtualResultSet(Statement statement, String[] columns, String[] types, String[][] results) throws IllegalArgumentException { - super(statement, columns, types, results.length); + MonetVirtualResultSet(Statement statement, String[] columns, String[] types, int[] jdbcTypes, String[][] results) + throws IllegalArgumentException { + super(statement, columns, types, jdbcTypes, results.length); this.results = results; closed = false; } @@ -1250,9 +1249,8 @@ final class MonetVirtualResultSet extend } /** - * Mainly here to prevent errors when the close method is called. There - * is no real need for this object to close it. We simply remove our - * resultset data. + * Mainly here to prevent errors when the close method is called. There is no real need for this object to close it. + * We simply remove our resultset data. */ @Override public void close() {
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/EmbeddedConnection.java +++ b/src/main/java/nl/cwi/monetdb/mcl/connection/EmbeddedConnection.java @@ -4,7 +4,7 @@ import nl.cwi.monetdb.embedded.env.Monet import nl.cwi.monetdb.embedded.env.MonetDBEmbeddedDatabase; import nl.cwi.monetdb.embedded.env.MonetDBEmbeddedException; import nl.cwi.monetdb.jdbc.MonetConnection; -import nl.cwi.monetdb.mcl.parser.MCLParseException; +import nl.cwi.monetdb.mcl.protocol.MCLParseException; import nl.cwi.monetdb.mcl.protocol.embedded.EmbeddedProtocol; import java.io.*;
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/MapiConnection.java +++ b/src/main/java/nl/cwi/monetdb/mcl/connection/MapiConnection.java @@ -4,7 +4,7 @@ import nl.cwi.monetdb.jdbc.MonetConnecti import nl.cwi.monetdb.mcl.io.BufferedMCLReader; import nl.cwi.monetdb.mcl.io.BufferedMCLWriter; import nl.cwi.monetdb.mcl.io.SocketConnection; -import nl.cwi.monetdb.mcl.parser.MCLParseException; +import nl.cwi.monetdb.mcl.protocol.MCLParseException; import nl.cwi.monetdb.mcl.protocol.AbstractProtocol; import nl.cwi.monetdb.mcl.protocol.ServerResponses; import nl.cwi.monetdb.mcl.protocol.oldmapi.OldMapiProtocol; @@ -63,8 +63,6 @@ import java.util.*; * * @author Fabian Groffen * @version 4.1 - * @see BufferedMCLReader - * @see BufferedMCLWriter */ public class MapiConnection extends MonetConnection {
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/MonetDBConnectionFactory.java +++ b/src/main/java/nl/cwi/monetdb/mcl/connection/MonetDBConnectionFactory.java @@ -2,7 +2,7 @@ package nl.cwi.monetdb.mcl.connection; import nl.cwi.monetdb.jdbc.MonetConnection; import nl.cwi.monetdb.jdbc.MonetDriver; -import nl.cwi.monetdb.mcl.parser.MCLParseException; +import nl.cwi.monetdb.mcl.protocol.MCLParseException; import java.io.File; import java.io.IOException;
deleted file mode 100644 --- a/src/main/java/nl/cwi/monetdb/mcl/io/AbstractMCLReader.java +++ /dev/null @@ -1,51 +0,0 @@ -package nl.cwi.monetdb.mcl.io; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; - -/** - * Created by ferreira on 11/24/16. - */ -public abstract class AbstractMCLReader extends BufferedReader { - - /** "there is currently no line", or the the type is unknown is - represented by UNKNOWN */ - public final static int UNKNOWN = 0; - /** a line starting with ! indicates ERROR */ - public final static int ERROR = '!'; - /** a line starting with % indicates HEADER */ - public final static int HEADER = '%'; - /** a line starting with [ indicates RESULT */ - public final static int RESULT = '['; - /** a line which matches the pattern of prompt1 is a PROMPT */ - public final static int PROMPT = '.'; - /** a line which matches the pattern of prompt2 is a MORE */ - public final static int MORE = ','; - /** a line starting with & indicates the start of a header block */ - public final static int SOHEADER = '&'; - /** a line starting with ^ indicates REDIRECT */ - public final static int REDIRECT = '^'; - /** a line starting with # indicates INFO */ - public final static int INFO = '#'; - - /** The type of the last line read */ - protected int lineType; - - public AbstractMCLReader(Reader in) { - super(in); - } - - /** - * getLineType returns the type of the last line read. - * - * @return an integer representing the kind of line this is, one of the - * following constants: UNKNOWN, HEADER, ERROR, PROMPT, - * RESULT, REDIRECT, INFO - */ - public int getLineType() { - return lineType; - } - - public abstract String waitForPrompt() throws IOException; -}
deleted file mode 100644 --- a/src/main/java/nl/cwi/monetdb/mcl/io/AbstractMCLWriter.java +++ /dev/null @@ -1,30 +0,0 @@ -package nl.cwi.monetdb.mcl.io; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.Writer; - -/** - * Created by ferreira on 11/24/16. - */ -public abstract class AbstractMCLWriter extends BufferedWriter { - - protected AbstractMCLReader reader; - - public AbstractMCLWriter(Writer out) { - super(out); - } - - /** - * Registers the given reader in this writer. A registered reader - * receives a linetype reset when a line is written from this - * writer. - * - * @param r an AbstractMCLReader - */ - public void registerReader(AbstractMCLReader r) { - this.reader = r; - } - - public abstract void writeLine(String line) throws IOException; -}
deleted file mode 100644 --- a/src/main/java/nl/cwi/monetdb/mcl/io/BufferedMCLReader.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. - */ - -package nl.cwi.monetdb.mcl.io; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.UnsupportedEncodingException; - -/** - * Read text from a character-input stream, buffering characters so as - * to provide a means for efficient reading of characters, arrays and - * lines. This class is based on the BufferedReader class, and provides - * extra functionality useful for MCL. - * - * The BufferedMCLReader is typically used as layer in between an - * InputStream and a specific interpreter of the data. - * <pre> - * / Response - * BufferedMCLReader ---o <- Tuple - * \ DataBlock - * </pre> - * Because the BufferedMCLReader provides an efficient way to access the - * data from the stream in a line-wise fashion, whereby each line is - * identified as a certain type, consumers can easily decide how to - * parse each retrieved line. The line parsers from - * nl.cwi.monetdb.mcl.parser are well suited to work with the lines - * outputted by the BufferedMCLReader. - * This class is client-oriented, as it doesn't take into account the - * messages as the server receives them. - * - * @author Fabian Groffen <Fabian.Groffen> - * @see BufferedMCLWriter - */ -public class BufferedMCLReader extends AbstractMCLReader { - - /** - * Create a buffering character-input stream that uses a - * default-sized input buffer. - * - * @param in A Reader - */ - public BufferedMCLReader(Reader in) { - super(in); - } - - /** - * Create a buffering character-input stream that uses a - * default-sized input buffer, from an InputStream. - * - * @param in An InputStream - * @param enc Encoding - */ - public BufferedMCLReader(InputStream in, String enc) - throws UnsupportedEncodingException - { - super(new InputStreamReader(in, enc)); - } - - /** - * Sets the linetype to the type of the string given. If the string - * is null, lineType is set to UNKNOWN. - * - * @param line the string to examine - */ - void setLineType(String line) { - lineType = UNKNOWN; - if (line == null || line.length() == 0) - return; - switch (line.charAt(0)) { - case '!': - lineType = ERROR; - break; - case '&': - lineType = SOHEADER; - break; - case '%': - lineType = HEADER; - break; - case '[': - lineType = RESULT; - break; - case '=': - lineType = RESULT; - break; - case '^': - lineType = REDIRECT; - break; - case '#': - lineType = INFO; - break; - case '.': - lineType = PROMPT; - break; - case ',': - lineType = MORE; - break; - } - } - - /** - * Read a line of text. A line is considered to be terminated by - * any one of a line feed ('\n'), a carriage return ('\r'), or a - * carriage return followed immediately by a linefeed. Before this - * method returns, it sets the linetype to any of the in MCL - * recognised line types. - * - * Warning: until the server properly prefixes all of its error - * messages with SQLSTATE codes, this method prefixes all errors it - * sees without sqlstate with the generic data exception code - * (22000). - * - * @return A String containing the contents of the line, not - * including any line-termination characters, or null if the - * end of the stream has been reached - * @throws IOException If an I/O error occurs - */ - @Override - public String readLine() throws IOException { - String r = super.readLine(); - this.setLineType(r); - if (lineType == ERROR && !r.matches("^![0-9A-Z]{5}!.+")) - r = "!22000!" + r.substring(1); - return r; - } - - /** - * Reads up till the MonetDB prompt, indicating the server is ready - * for a new command. All read data is discarded. If the last line - * read by readLine() was a prompt, this method will immediately - * return. - * - * If there are errors present in the lines that are read, then they - * are put in one string and returned <b>after</b> the prompt has - * been found. If no errors are present, null will be returned. - * - * @return a string containing error messages, or null if there aren't any - * @throws IOException if an IO exception occurs while talking to the server - */ - @Override - public synchronized String waitForPrompt() throws IOException { - StringBuilder res = new StringBuilder(); - String tmp; - while (lineType != PROMPT) { - if ((tmp = this.readLine()) == null) - throw new IOException("Connection to server lost!"); - if (lineType == ERROR) - res.append("\n").append(tmp.substring(1)); - } - return res.toString().trim(); - } -}
deleted file mode 100644 --- a/src/main/java/nl/cwi/monetdb/mcl/io/BufferedMCLWriter.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. - */ - -package nl.cwi.monetdb.mcl.io; - -import java.io.*; - -/** - * Write text to a character-output stream, buffering characters so as - * to provide a means for efficient writing of single characters, - * arrays, and strings. - * - * In contrast to the BufferedWriter class, this class' newLine() - * method always writes the newline character '\n', regardless the - * platform's own notion of line separator. Apart from that there are - * no differences in the behaviour of this class, compared to its parent - * class, the BufferedWriter. A small convenience is built into this - * class for cooperation with the BufferedMCLReader, via the - * registerReader() method. It causes the reader to be reset upon each - * write performed though this class. This effectuates the MCL protocol - * flow where a write invalidates the state of the read buffers, since - * each write must be answered by the server. That also makes this - * class client-oriented when a reader is registered. - * - * @author Fabian Groffen <Fabian.Groffen> - * @see BufferedMCLWriter - */ -public class BufferedMCLWriter extends AbstractMCLWriter { - - /** - * Create a buffered character-output stream that uses a - * default-sized output buffer. - * - * @param in A Writer - */ - public BufferedMCLWriter(Writer in) { - super(in); - } - - /** - * Create a buffered character-output stream that uses a - * default-sized output buffer, from an OutputStream. - * - * @param in An OutputStream - * @param enc Encoding - */ - public BufferedMCLWriter(OutputStream in, String enc) - throws UnsupportedEncodingException - { - super(new OutputStreamWriter(in, enc)); - } - - /** - * Write a line separator. The line separator string is in this - * class always the single newline character '\n'. - * - * @throws IOException If an I/O error occurs - */ - @Override - public void newLine() throws IOException { - this.write('\n'); - } - - @Override - public void writeLine(String line) throws IOException { - this.write(line); - this.flush(); - // reset reader state, last line isn't valid any more now - if (reader != null) ((BufferedMCLReader)reader).setLineType(null); - } -}
deleted file mode 100644 --- a/src/main/java/nl/cwi/monetdb/mcl/parser/HeaderLineParser.java +++ /dev/null @@ -1,25 +0,0 @@ -package nl.cwi.monetdb.mcl.parser; - -/** - * Created by ferreira on 11/25/16. - */ -public abstract class HeaderLineParser extends MCLParser { - - public final static int NAME = 1; - public final static int LENGTH = 2; - public final static int TABLE = 3; - public final static int TYPE = 4; - - protected int type; - - /** - * Creates an MCLParser targeted at a given number of field values. - * The lines parsed by an instance of this MCLParser should have - * exactly capacity field values. - * - * @param capacity the number of field values to expect - */ - protected HeaderLineParser(int capacity) { - super(capacity); - } -}
deleted file mode 100644 --- a/src/main/java/nl/cwi/monetdb/mcl/parser/MCLParser.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. - */ - -package nl.cwi.monetdb.mcl.parser; - -/** - * Interface for parsers in MCL. The parser family in MCL is set up as - * a reusable object. This allows the same parser to be used again for - * the same type of work. While this is a very unnatural solution in - * the Java language, it prevents many object creations on a low level - * of the protocol. This favours performance. - * - * A typical parser has a method parse() which takes a String, and the - * methods hasNext() and next() to retrieve the values that were - * extracted by the parser. Parser specific methods may be available to - * perform common tasks. - * - * @author Fabian Groffen - */ -public abstract class MCLParser { - /** The String values found while parsing. Public, you may touch it. */ - public final String values[]; - /** The int values found while parsing. Public, you may touch it. */ - public final int intValues[]; - - protected int colnr; - - /** - * Creates an MCLParser targeted at a given number of field values. - * The lines parsed by an instance of this MCLParser should have - * exactly capacity field values. - * - * @param capacity the number of field values to expect - */ - protected MCLParser(int capacity) { - values = new String[capacity]; - intValues = new int[capacity]; - } - - /** - * Parse the given string, and populate the internal field array - * to allow for next() and hasNext() calls. - * - * @param source the String containing the line to parse - * @return value - * @throws MCLParseException if source cannot be (fully) parsed by - * this parser - * @see #next() - * @see #nextInt() - * @see #hasNext() - */ - public abstract int parse(String source) throws MCLParseException; - - /** - * Repositions the internal field offset to the start, such that the - * next call to next() will return the first field again. - */ - public final void reset() { - colnr = 0; - } - - /** - * Returns whether the next call to next() or nextInt() succeeds. - * - * @return true if the next call to next() or nextInt() is bound to - * succeed - * @see #next() - * @see #nextInt() - */ - public final boolean hasNext() { - return colnr < values.length; - } - - /** - * Returns the current field value, and advances the field counter - * to the next value. This method may fail with a RuntimeError if - * the current field counter is out of bounds. Call hasNext() to - * determine if the call to next() will succeed. - * - * @return the current field value - * @see #nextInt() - * @see #hasNext() - */ - public final String next() { - return values[colnr++]; - } - - /** - * Returns the current field value as integer, and advances the - * field counter to the next value. This method has the same - * characteristics as the next() method, apart from returning the - * field value as an integer. - * - * @return the current field value as integer - * @see #next() - */ - public final int nextInt() { - return intValues[colnr++]; - } -}
deleted file mode 100644 --- a/src/main/java/nl/cwi/monetdb/mcl/parser/TupleLineParser.java +++ /dev/null @@ -1,17 +0,0 @@ -package nl.cwi.monetdb.mcl.parser; - -/** - * Created by ferreira on 11/25/16. - */ -public abstract class TupleLineParser extends MCLParser { - /** - * Creates an MCLParser targeted at a given number of field values. - * The lines parsed by an instance of this MCLParser should have - * exactly capacity field values. - * - * @param capacity the number of field values to expect - */ - protected TupleLineParser(int capacity) { - super(capacity); - } -}
deleted file mode 100644 --- a/src/main/java/nl/cwi/monetdb/mcl/parser/socket/SocketTupleLineParser.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. - */ - -package nl.cwi.monetdb.mcl.parser.socket; - -import nl.cwi.monetdb.mcl.parser.MCLParseException; -import nl.cwi.monetdb.mcl.parser.TupleLineParser; - -/** - * The SocketTupleLineParser extracts the values from a given tuple. The - * number of values that are expected are known upfront to speed up - * allocation and validation. - * - * @author Fabian Groffen <Fabian.Groffen> - */ -public class SocketTupleLineParser extends TupleLineParser { - - /** - * Constructs a SocketTupleLineParser which expects columncount columns. - * - * @param columncount the number of columns in the to be parsed string - */ - public SocketTupleLineParser(int columncount) { - super(columncount); - } - - /** - * Parses the given String source as tuple line. If source cannot - * be parsed, a ParseException is thrown. The columncount argument - * is used for allocation of the returned array. While this seems - * illogical, the caller should know this size, since the - * StartOfHeader contains this information. - * - * @param source a String which should be parsed - * @return 0, as there is no 'type' of TupleLine - * @throws MCLParseException if an error occurs during parsing - */ - @Override - public int parse(String source) throws MCLParseException { - int len = source.length(); - char[] chrLine = new char[len]; - source.getChars(0, len, chrLine, 0); - - // first detect whether this is a single value line (=) or a - // real tuple ([) - if (chrLine[0] == '=') { - if (values.length != 1) - throw new MCLParseException(values.length + - " columns expected, but only single value found"); - - // return the whole string but the leading = - values[0] = source.substring(1); - - // reset colnr - reset(); - - return 0; - } - - // extract separate fields by examining string, char for char - boolean inString = false, escaped = false; - int cursor = 2, column = 0, i = 2; - StringBuilder uesc = new StringBuilder(); - for (; i < len; i++) { - switch(chrLine[i]) { - default: - escaped = false; - break; - case '\\': - escaped = !escaped; - break; - case '"': - /** - * If all strings are wrapped between two quotes, a \" can - * never exist outside a string. Thus if we believe that we - * are not within a string, we can safely assume we're about - * to enter a string if we find a quote. - * If we are in a string we should stop being in a string if - * we find a quote which is not prefixed by a \, for that - * would be an escaped quote. However, a nasty situation can - * occur where the string is like "test \\" as obvious, a - * test for a \ in front of a " doesn't hold here for all - * cases. Because "test \\\"" can exist as well, we need to - * know if a quote is prefixed by an escaping slash or not. - */ - if (!inString) { - inString = true; - } else if (!escaped) { - inString = false; - } - - // reset escaped flag - escaped = false; - break; - case '\t': - if (!inString && - (i > 0 && chrLine[i - 1] == ',') || - (i + 1 == len - 1 && chrLine[++i] == ']')) // dirty - { - // split! - if (chrLine[cursor] == '"' && - chrLine[i - 2] == '"') - { - // reuse the StringBuilder by cleaning it - uesc.delete(0, uesc.length()); - // prevent capacity increasements - uesc.ensureCapacity((i - 2) - (cursor + 1)); - for (int pos = cursor + 1; pos < i - 2; pos++) { - if (chrLine[pos] == '\\' && pos + 1 < i - 2) { - pos++; - // strToStr and strFromStr in gdk_atoms.mx only - // support \t \n \\ \" and \377 - switch (chrLine[pos]) { - case '\\': - uesc.append('\\'); - break; - case 'n': - uesc.append('\n'); - break; - case 't': - uesc.append('\t'); - break; - case '"': - uesc.append('"'); - break; - case '0': case '1': case '2': case '3': - // this could be an octal number, let's check it out - if (pos + 2 < i - 2 && - chrLine[pos + 1] >= '0' && chrLine[pos + 1] <= '7' && - chrLine[pos + 2] >= '0' && chrLine[pos + 2] <= '7' - ) { - // we got the number! - try { - uesc.append((char)(Integer.parseInt("" + chrLine[pos] + chrLine[pos + 1] + chrLine[pos + 2], 8))); - pos += 2; - } catch (NumberFormatException e) { - // hmmm, this point should never be reached actually... - throw new AssertionError("Flow error, should never try to parse non-number"); - } - } else { - // do default action if number seems not to be correct - uesc.append(chrLine[pos]); - } - break; - default: - // this is wrong, just ignore the escape, and print the char - uesc.append(chrLine[pos]); - break; - } - } else { - uesc.append(chrLine[pos]); - } - } - - // put the unescaped string in the right place - values[column++] = uesc.toString(); - } else if ((i - 1) - cursor == 4 && - source.indexOf("NULL", cursor) == cursor) - { - values[column++] = null; - } else { - values[column++] = - source.substring(cursor, i - 1); - } - cursor = i + 1; - } - - // reset escaped flag - escaped = false; - break; - } - } - // check if this result is of the size we expected it to be - if (column != values.length) - throw new MCLParseException("illegal result length: " + column + "\nlast read: " + (column > 0 ? values[column - 1] : "<none>")); - - // reset colnr - reset(); - - return 0; - } -}
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/AbstractProtocol.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/AbstractProtocol.java @@ -1,7 +1,6 @@ package nl.cwi.monetdb.mcl.protocol; import nl.cwi.monetdb.jdbc.MonetConnection; -import nl.cwi.monetdb.mcl.parser.MCLParseException; import nl.cwi.monetdb.mcl.responses.AutoCommitResponse; import nl.cwi.monetdb.mcl.responses.SchemaResponse; import nl.cwi.monetdb.mcl.responses.UpdateResponse; @@ -35,8 +34,7 @@ public abstract class AbstractProtocol<T public abstract StarterHeaders getNextStarterHeader(); - - public abstract ResultSetResponse<T> getNextResultSetResponse(MonetConnection con, MonetConnection.ResponseList list, int seqnr) throws MCLParseException; + public abstract ResultSetResponse getNextResultSetResponse(MonetConnection con, MonetConnection.ResponseList list, int seqnr) throws MCLParseException; public abstract UpdateResponse getNextUpdateResponse() throws MCLParseException; @@ -46,15 +44,13 @@ public abstract class AbstractProtocol<T public abstract AutoCommitResponse getNextAutoCommitResponse() throws MCLParseException; - public abstract DataBlockResponse<T> getNextDatablockResponse(Map<Integer, ResultSetResponse> rsresponses) throws MCLParseException; - + public abstract DataBlockResponse getNextDatablockResponse(Map<Integer, ResultSetResponse> rsresponses) throws MCLParseException; public abstract TableResultHeaders getNextTableHeader(Object line, String[] stringValues, int[] intValues) throws MCLParseException; - public abstract void parseTupleLine(Object line, Object[] values) throws MCLParseException; + public abstract int parseTupleLine(Object line, Object[] values, int[] typesMap) throws MCLParseException; public abstract String getRemainingStringLine(int startIndex); public abstract void writeNextCommand(byte[] prefix, byte[] query, byte[] suffix) throws IOException; - }
rename from src/main/java/nl/cwi/monetdb/mcl/parser/MCLParseException.java rename to src/main/java/nl/cwi/monetdb/mcl/protocol/MCLParseException.java --- a/src/main/java/nl/cwi/monetdb/mcl/parser/MCLParseException.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/MCLParseException.java @@ -6,7 +6,7 @@ * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. */ -package nl.cwi.monetdb.mcl.parser; +package nl.cwi.monetdb.mcl.protocol; import java.text.ParseException; @@ -20,9 +20,7 @@ import java.text.ParseException; * that the error message includes the offending data read. */ public class MCLParseException extends ParseException { - /** - * - */ + private static final long serialVersionUID = 1L; public MCLParseException(String e) {
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/embedded/EmbeddedProtocol.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/embedded/EmbeddedProtocol.java @@ -1,7 +1,8 @@ package nl.cwi.monetdb.mcl.protocol.embedded; import nl.cwi.monetdb.jdbc.MonetConnection; -import nl.cwi.monetdb.mcl.parser.MCLParseException; +import nl.cwi.monetdb.mcl.io.JDBCEmbeddedConnection; +import nl.cwi.monetdb.mcl.protocol.MCLParseException; import nl.cwi.monetdb.mcl.protocol.AbstractProtocol; import nl.cwi.monetdb.mcl.protocol.StarterHeaders; import nl.cwi.monetdb.mcl.protocol.TableResultHeaders; @@ -18,6 +19,16 @@ import java.util.Map; */ public class EmbeddedProtocol extends AbstractProtocol<Object[]> { + private final JDBCEmbeddedConnection connection; + + public EmbeddedProtocol(JDBCEmbeddedConnection con) { + this.connection = con; + } + + public JDBCEmbeddedConnection getEmbeddedConnection() { + return this.connection; + } + @Override public void fetchNextResponseData() { @@ -34,7 +45,7 @@ public class EmbeddedProtocol extends Ab } @Override - public ResultSetResponse<Object[]> getNextResultSetResponse(MonetConnection con, MonetConnection.ResponseList list, int seqnr) throws MCLParseException { + public ResultSetResponse getNextResultSetResponse(MonetConnection con, MonetConnection.ResponseList list, int seqnr) throws MCLParseException { return null; } @@ -49,7 +60,7 @@ public class EmbeddedProtocol extends Ab } @Override - public DataBlockResponse<Object[]> getNextDatablockResponse(Map<Integer, ResultSetResponse> rsresponses) throws MCLParseException { + public DataBlockResponse getNextDatablockResponse(Map<Integer, ResultSetResponse> rsresponses) throws MCLParseException { return null; } @@ -59,8 +70,8 @@ public class EmbeddedProtocol extends Ab } @Override - public void parseTupleLine(Object line, Object[] values) throws MCLParseException { - + public int parseTupleLine(Object line, Object[] values) throws MCLParseException { + return 0; } @Override
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/newmapi/NewMapiProtocol.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/newmapi/NewMapiProtocol.java @@ -1,7 +1,8 @@ package nl.cwi.monetdb.mcl.protocol.newmapi; import nl.cwi.monetdb.jdbc.MonetConnection; -import nl.cwi.monetdb.mcl.parser.MCLParseException; +import nl.cwi.monetdb.mcl.io.SocketConnection; +import nl.cwi.monetdb.mcl.protocol.MCLParseException; import nl.cwi.monetdb.mcl.protocol.AbstractProtocol; import nl.cwi.monetdb.mcl.protocol.StarterHeaders; import nl.cwi.monetdb.mcl.protocol.TableResultHeaders; @@ -18,6 +19,12 @@ import java.util.Map; */ public class NewMapiProtocol extends AbstractProtocol { + private final SocketConnection connection; + + public NewMapiProtocol(SocketConnection con) { + this.connection = con; + } + @Override public void fetchNextResponseData() { @@ -54,8 +61,8 @@ public class NewMapiProtocol extends Abs } @Override - public void parseTupleLine(Object line, Object[] values) throws MCLParseException { - + public int parseTupleLine(Object line, Object[] values) throws MCLParseException { + return 0; } @Override
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiProtocol.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiProtocol.java @@ -2,7 +2,7 @@ package nl.cwi.monetdb.mcl.protocol.oldm import nl.cwi.monetdb.jdbc.MonetConnection; import nl.cwi.monetdb.mcl.io.SocketConnection; -import nl.cwi.monetdb.mcl.parser.MCLParseException; +import nl.cwi.monetdb.mcl.protocol.MCLParseException; import nl.cwi.monetdb.mcl.protocol.AbstractProtocol; import nl.cwi.monetdb.mcl.protocol.ServerResponses; import nl.cwi.monetdb.mcl.protocol.StarterHeaders; @@ -25,13 +25,16 @@ public class OldMapiProtocol extends Abs private final SocketConnection connection; - StringBuilder builder; + final StringBuilder builder; int currentPointer = 0; + final StringBuilder tupleLineBuilder; + public OldMapiProtocol(SocketConnection con) { this.connection = con; this.builder = new StringBuilder(STRING_BUILDER_INITIAL_SIZE); + this.tupleLineBuilder = new StringBuilder(STRING_BUILDER_INITIAL_SIZE); } public SocketConnection getConnection() { @@ -78,17 +81,18 @@ public class OldMapiProtocol extends Abs } @Override - public ResultSetResponse<StringBuilder> getNextResultSetResponse(MonetConnection con, MonetConnection.ResponseList list, int seqnr) throws MCLParseException { + public ResultSetResponse getNextResultSetResponse(MonetConnection con, MonetConnection.ResponseList list, int seqnr) + throws MCLParseException { int id = OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this); int tuplecount = OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this); int columncount = OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this); int rowcount = OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this); - return new ResultSetResponse<>(con, list, seqnr, id, rowcount, tuplecount, columncount); + return new ResultSetResponse(con, list, seqnr, id, rowcount, tuplecount, columncount); } @Override public UpdateResponse getNextUpdateResponse() throws MCLParseException { - int count = OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this); + int count = OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this); //The order cannot be switched!! String lastId = OldMapiStartOfHeaderParser.GetNextResponseDataAsString(this); return new UpdateResponse(lastId, count); } @@ -100,19 +104,17 @@ public class OldMapiProtocol extends Abs } @Override - @SuppressWarnings("unchecked") - public DataBlockResponse<StringBuilder> getNextDatablockResponse(Map<Integer, ResultSetResponse> rsresponses) throws MCLParseException { + public DataBlockResponse getNextDatablockResponse(Map<Integer, ResultSetResponse> rsresponses) throws MCLParseException { int id = OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this); - OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this); // pass the columncount --- Must do this! + int columncount = OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this); int rowcount = OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this); int offset = OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this); - ResultSetResponse<StringBuilder> resultSetResponse = rsresponses.get(id); - if (resultSetResponse == null) { + + ResultSetResponse rs = rsresponses.get(id); + if (rs == null) { return null; } - DataBlockResponse<StringBuilder> res = new DataBlockResponse<>(rowcount, resultSetResponse.getRSType() == ResultSet.TYPE_FORWARD_ONLY, StringBuilder.class); - resultSetResponse.addDataBlockResponse(offset, res); - return res; + return rs.addDataBlockResponse(offset, rowcount, columncount, this); } @Override @@ -121,8 +123,8 @@ public class OldMapiProtocol extends Abs } @Override - public void parseTupleLine(Object line, Object[] values) throws MCLParseException { - + public int parseTupleLine(Object line, Object[] values, int[] typesMap) throws MCLParseException { + return OldMapiTupleLineParser.OldMapiParseTupleLine((StringBuilder) line, values, this.tupleLineBuilder, typesMap); } @Override
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiServerResponseParser.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiServerResponseParser.java @@ -5,7 +5,7 @@ import nl.cwi.monetdb.mcl.protocol.Serve /** * Created by ferreira on 11/30/16. */ -public final class OldMapiServerResponseParser { +final class OldMapiServerResponseParser { static ServerResponses ParseOldMapiServerResponse(OldMapiProtocol protocol) { ServerResponses res;
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiStartOfHeaderParser.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiStartOfHeaderParser.java @@ -1,12 +1,12 @@ package nl.cwi.monetdb.mcl.protocol.oldmapi; -import nl.cwi.monetdb.mcl.parser.MCLParseException; +import nl.cwi.monetdb.mcl.protocol.MCLParseException; import nl.cwi.monetdb.mcl.protocol.StarterHeaders; /** * Created by ferreira on 12/6/16. */ -public class OldMapiStartOfHeaderParser { +final class OldMapiStartOfHeaderParser { static StarterHeaders GetNextStartHeaderOnOldMapi(OldMapiProtocol protocol) { StarterHeaders res;
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTableHeaderParser.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTableHeaderParser.java @@ -1,12 +1,12 @@ package nl.cwi.monetdb.mcl.protocol.oldmapi; -import nl.cwi.monetdb.mcl.parser.MCLParseException; +import nl.cwi.monetdb.mcl.protocol.MCLParseException; import nl.cwi.monetdb.mcl.protocol.TableResultHeaders; /** * Created by ferreira on 12/6/16. */ -public class OldMapiTableHeaderParser { +final class OldMapiTableHeaderParser { static TableResultHeaders GetNextTableHeader(StringBuilder builder, String[] stringValues, int[] intValues) throws MCLParseException { TableResultHeaders res = TableResultHeaders.UNKNOWN;
new file mode 100644 --- /dev/null +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTupleLineParser.java @@ -0,0 +1,131 @@ +package nl.cwi.monetdb.mcl.protocol.oldmapi; + +import nl.cwi.monetdb.mcl.protocol.MCLParseException; + +/** + * Created by ferreira on 12/6/16. + */ +final class OldMapiTupleLineParser { + + static int OldMapiParseTupleLine(StringBuilder line, Object[] values, StringBuilder helper, int[] typesMap) throws MCLParseException { + int len = line.length(); + + // first detect whether this is a single value line (=) or a real tuple ([) + if (line.charAt(0) == '=') { + if (values.length != 1) { + throw new MCLParseException(values.length + " columns expected, but only single value found"); + } + // return the whole string but the leading = + values[0] = line.substring(1); + return 1; + } + + // extract separate fields by examining string, char for char + boolean inString = false, escaped = false; + int cursor = 2, column = 0, i = 2; + for (; i < len; i++) { + switch(line.charAt(i)) { + default: + escaped = false; + break; + case '\\': + escaped = !escaped; + break; + case '"': + /** + * If all strings are wrapped between two quotes, a \" can + * never exist outside a string. Thus if we believe that we + * are not within a string, we can safely assume we're about + * to enter a string if we find a quote. + * If we are in a string we should stop being in a string if + * we find a quote which is not prefixed by a \, for that + * would be an escaped quote. However, a nasty situation can + * occur where the string is like "test \\" as obvious, a + * test for a \ in front of a " doesn't hold here for all + * cases. Because "test \\\"" can exist as well, we need to + * know if a quote is prefixed by an escaping slash or not. + */ + if (!inString) { + inString = true; + } else if (!escaped) { + inString = false; + } + + // reset escaped flag + escaped = false; + break; + case '\t': + if (!inString && (i > 0 && line.charAt(i - 1) == ',') || (i + 1 == len - 1 && line.charAt(++i) == ']')) { // dirty + // split! + if (line.charAt(cursor) == '"' && line.charAt(i - 2) == '"') { + // reuse the StringBuilder by cleaning it + helper.setLength(0); + // prevent capacity increases + helper.ensureCapacity((i - 2) - (cursor + 1)); + for (int pos = cursor + 1; pos < i - 2; pos++) { + if (line.charAt(pos) == '\\' && pos + 1 < i - 2) { + pos++; + // strToStr and strFromStr in gdk_atoms.mx only + // support \t \n \\ \" and \377 + switch (line.charAt(pos)) { + case '\\': + helper.append('\\'); + break; + case 'n': + helper.append('\n'); + break; + case 't': + helper.append('\t'); + break; + case '"': + helper.append('"'); + break; + case '0': case '1': case '2': case '3': + // this could be an octal number, let's check it out + if (pos + 2 < i - 2 && + line.charAt(pos + 1) >= '0' && line.charAt(pos + 1) <= '7' && + line.charAt(pos + 2) >= '0' && line.charAt(pos + 2) <= '7') { + // we got the number! + try { + helper.append((char)(Integer.parseInt("" + line.charAt(pos) + line.charAt(pos + 1) + line.charAt(pos + 2), 8))); + pos += 2; + } catch (NumberFormatException e) { + // hmmm, this point should never be reached actually... + throw new AssertionError("Flow error, should never try to parse non-number"); + } + } else { + // do default action if number seems not to be correct + helper.append(line.charAt(pos)); + } + break; + default: + // this is wrong, just ignore the escape, and print the char + helper.append(line.charAt(pos)); + break; + } + } else { + helper.append(line.charAt(pos)); + } + } + + // put the unescaped string in the right place + values[column++] = helper.toString(); + } else if ((i - 1) - cursor == 4 && line.indexOf("NULL", cursor) == cursor) { + values[column++] = null; + } else { + values[column++] = line.substring(cursor, i - 1); + } + cursor = i + 1; + } + // reset escaped flag + escaped = false; + break; + } + } + // check if this result is of the size we expected it to be + if (column != values.length) + throw new MCLParseException("illegal result length: " + column + "\nlast read: " + (column > 0 ? values[column - 1] : "<none>")); + + return column; + } +}
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/DataBlockResponse.java +++ b/src/main/java/nl/cwi/monetdb/mcl/responses/DataBlockResponse.java @@ -1,9 +1,9 @@ package nl.cwi.monetdb.mcl.responses; -import nl.cwi.monetdb.mcl.parser.MCLParseException; +import nl.cwi.monetdb.mcl.protocol.AbstractProtocol; +import nl.cwi.monetdb.mcl.protocol.MCLParseException; import nl.cwi.monetdb.mcl.protocol.ServerResponses; -import java.lang.reflect.Array; import java.sql.SQLException; /** @@ -23,48 +23,51 @@ import java.sql.SQLException; * rows from it. When multiple threads will retrieve rows from this * object, it is possible for threads to get the same data. */ -public class DataBlockResponse<T> implements IIncompleteResponse { +public class DataBlockResponse implements IIncompleteResponse { - /** The String array to keep the data in */ - private final T[] data; + /** The array to keep the data in */ + private final Object[][] data; /** The counter which keeps the current position in the data array */ private int pos; /** Whether we can discard lines as soon as we have read them */ private boolean forwardOnly; + /** The connection protocol to parse the tuple lines */ + private final AbstractProtocol<?> protocol; + /** The JdbcSQLTypes mapping */ + private final int[] jdbcSQLTypes; /** * Constructs a DataBlockResponse object - * @param size the size of the data array to create + * @param rowcount the number of rows + * @param columncount the number of columns * @param forward whether this is a forward only result */ - @SuppressWarnings("unchecked") - public DataBlockResponse(int size, boolean forward, Class<T> jClass) { + DataBlockResponse(int rowcount, int columncount, boolean forward, AbstractProtocol<?> protocol, int[] JdbcSQLTypes) { this.pos = -1; - this.data = (T[]) Array.newInstance(jClass, size); this.forwardOnly = forward; + this.data = new Object[rowcount][columncount]; + this.protocol = protocol; + this.jdbcSQLTypes = JdbcSQLTypes; } /** - * addLine adds a String of data to this object's data array. - * Note that an IndexOutOfBoundsException can be thrown when an - * attempt is made to add more than the original construction size - * specified. + * addLine adds a String of data to this object's data array. Note that an IndexOutOfBoundsException can be thrown + * when an attempt is made to add more than the original construction size specified. * * @param line the header line as String * @param response the line type according to the MAPI protocol * @throws MCLParseException If the result line is not expected */ - @SuppressWarnings("unchecked") public void addLine(ServerResponses response, Object line) throws MCLParseException { if (response != ServerResponses.RESULT) throw new MCLParseException("protocol violation: unexpected line in data block: " + line.toString()); // add to the backing array - data[++pos] = (T) line; + Object[] next = this.data[++this.pos]; + this.protocol.parseTupleLine(line, next, this.jdbcSQLTypes); } /** - * Returns whether this Response expects more lines to be added - * to it. + * Returns whether this Response expects more lines to be added to it. * * @return true if a next line should be added, false otherwise */ @@ -75,10 +78,8 @@ public class DataBlockResponse<T> implem } /** - * Indicates that no more header lines will be added to this - * Response implementation. In most cases this is a redundant - * operation because the data array is full. However... it can - * happen that this is NOT the case! + * Indicates that no more header lines will be added to this Response implementation. In most cases this is a + * redundant operation because the data array is full. However... it can happen that this is NOT the case! * * @throws SQLException if not all rows are filled */ @@ -90,8 +91,7 @@ public class DataBlockResponse<T> implem } /** - * Instructs the Response implementation to close and do the - * necessary clean up procedures. + * Instructs the Response implementation to close and do the necessary clean up procedures. */ @Override public void close() { @@ -102,16 +102,15 @@ public class DataBlockResponse<T> implem } /** - * Retrieves the required row. Warning: if the requested rows - * is out of bounds, an IndexOutOfBoundsException will be - * thrown. + * Retrieves the required row. Warning: if the requested rows is out of bounds, an IndexOutOfBoundsException will + * be thrown. * * @param line the row to retrieve * @return the requested row as String */ - public T getRow(int line) { + Object[] getRow(int line) { if (forwardOnly) { - T ret = data[line]; + Object[] ret = data[line]; data[line] = null; return ret; } else {
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/IIncompleteResponse.java +++ b/src/main/java/nl/cwi/monetdb/mcl/responses/IIncompleteResponse.java @@ -1,6 +1,6 @@ package nl.cwi.monetdb.mcl.responses; -import nl.cwi.monetdb.mcl.parser.MCLParseException; +import nl.cwi.monetdb.mcl.protocol.MCLParseException; import nl.cwi.monetdb.mcl.protocol.ServerResponses; import java.sql.SQLException;
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/ResultSetResponse.java +++ b/src/main/java/nl/cwi/monetdb/mcl/responses/ResultSetResponse.java @@ -1,13 +1,14 @@ package nl.cwi.monetdb.mcl.responses; import nl.cwi.monetdb.jdbc.MonetConnection; -import nl.cwi.monetdb.mcl.parser.MCLParseException; +import nl.cwi.monetdb.jdbc.MonetDriver; +import nl.cwi.monetdb.mcl.protocol.AbstractProtocol; +import nl.cwi.monetdb.mcl.protocol.MCLParseException; import nl.cwi.monetdb.mcl.protocol.ServerResponses; -import java.lang.reflect.Array; -import java.lang.reflect.ParameterizedType; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Types; /** * The ResultSetResponse represents a tabular result sent by the @@ -21,16 +22,9 @@ import java.sql.SQLException; * there the first line consists out of<br /> * <tt>&"qt" "id" "tc" "cc" "rc"</tt>. */ -public class ResultSetResponse<T> implements IIncompleteResponse { +public class ResultSetResponse implements IIncompleteResponse { - private static boolean CheckBooleanValuesAllTrue(boolean[] array) { - for (boolean anArray : array) { - if (!anArray) { - return false; - } - } - return true; - } + private static final byte IsSetFinalValue = 15; /** The number of columns in this result */ private final int columncount; @@ -46,6 +40,8 @@ public class ResultSetResponse<T> implem private final String[] name; /** The types of the columns in this result */ private final String[] type; + /** The JDBC SQL types of the columns in this ResultSet. The content will be derived from the MonetDB types[] */ + private final int[] JdbcSQLTypes; /** The max string length for each column in this result */ private final int[] columnLengths; /** The table for each column in this result */ @@ -53,7 +49,7 @@ public class ResultSetResponse<T> implem /** The query sequence number */ private final int seqnr; /** A bitmap telling whether the headers are set or not */ - private boolean[] isSet = new boolean[4]; + private byte isSet; /** Whether this Response is closed */ private boolean closed; @@ -68,7 +64,7 @@ public class ResultSetResponse<T> implem /** the offset to be used on Xexport queries */ private int blockOffset = 0; /** A List of result blocks (chunks of size fetchSize/cacheSize) */ - private DataBlockResponse<T>[] resultBlocks; + private final DataBlockResponse[] resultBlocks; /** * Sole constructor, which requires a MonetConnection parent to @@ -82,15 +78,13 @@ public class ResultSetResponse<T> implem * supply new result blocks when necessary * @param seq the query sequence number */ - @SuppressWarnings("unchecked") - public ResultSetResponse(MonetConnection con, MonetConnection.ResponseList parent, int id, int seq, int rowcount, int tuplecount, int columncount) { + public ResultSetResponse(MonetConnection con, MonetConnection.ResponseList parent, int id, int seq, int rowcount, + int tuplecount, int columncount) { this.con = con; this.parent = parent; if (parent.getCachesize() == 0) { - /* Below we have to calculate how many "chunks" we need - * to allocate to store the entire result. However, if - * the user didn't set a cache size, as in this case, we - * need to stick to our defaults. */ + /* Below we have to calculate how many "chunks" we need to allocate to store the entire result. However, if + the user didn't set a cache size, as in this case, we need to stick to our defaults. */ cacheSize = MonetConnection.GetDefFetchsize(); cacheSizeSetExplicitly = false; } else { @@ -98,14 +92,10 @@ public class ResultSetResponse<T> implem cacheSizeSetExplicitly = true; } - /* So far, so good. Now the problem with EXPLAIN, DOT, etc - * queries is, that they don't support any block fetching, - * so we need to always fetch everything at once. For that - * reason, the cache size is here set to the rowcount if - * it's larger, such that we do a full fetch at once. - * (Because we always set a reply_size, we can only get a - * larger rowcount from the server if it doesn't paginate, - * because it's a pseudo SQL result.) */ + /* So far, so good. Now the problem with EXPLAIN, DOT, etc queries is, that they don't support any block + fetching, so we need to always fetch everything at once. For that reason, the cache size is here set to the + rowcount if it's larger, such that we do a full fetch at once. (Because we always set a reply_size, we can + only get a larger rowcount from the server if it doesn't paginate, because it's a pseudo SQL result.) */ if (rowcount > cacheSize) { cacheSize = rowcount; } @@ -122,48 +112,63 @@ public class ResultSetResponse<T> implem this.type = new String[this.columncount]; this.tableNames = new String[this.columncount]; this.columnLengths = new int[this.columncount]; + this.JdbcSQLTypes = new int[this.columncount]; - Class<T> persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; - this.resultBlocks = (DataBlockResponse<T>[]) Array.newInstance(DataBlockResponse.class, (tuplecount / cacheSize) + 1); - this.resultBlocks[0] = new DataBlockResponse<>(rowcount, parent.getRstype() == ResultSet.TYPE_FORWARD_ONLY, persistentClass); + this.resultBlocks = new DataBlockResponse[(tuplecount / cacheSize) + 1]; + this.resultBlocks[0] = new DataBlockResponse(rowcount, columncount, + parent.getRstype() == ResultSet.TYPE_FORWARD_ONLY, con.getProtocol(), this.JdbcSQLTypes); } /** - * Returns whether this ResultSetResponse needs more lines. - * This method returns true if not all headers are set, or the - * first DataBlockResponse reports to want more. + * Internal utility method to fill the JdbcSQLTypes array with derivable values. + * By doing it once (in the constructor) we can avoid doing this in many getXyz() methods again and again + * thereby improving getXyz() method performance. */ - @Override - public boolean wantsMore() { - return !CheckBooleanValuesAllTrue(isSet) || resultBlocks[0].wantsMore(); + private void populateJdbcSQLTypesArray() { + for (int i = 0; i < this.type.length; i++) { + int javaSQLtype = MonetDriver.getJavaType(this.type[i]); + this.JdbcSQLTypes[i] = javaSQLtype; + if (javaSQLtype == Types.BLOB && con.getBlobAsBinary()) { + this.JdbcSQLTypes[i] = Types.BINARY; + } + } } /** - * Adds the given DataBlockResponse to this ResultSetResponse at - * the given block position. - * - * @param offset the offset number of rows for this block - * @param rr the DataBlockResponse to add + * Returns whether this ResultSetResponse needs more lines. This method returns true if not all headers are set, + * or the first DataBlockResponse reports to want more. */ - public void addDataBlockResponse(int offset, DataBlockResponse<T> rr) { - int block = (offset - blockOffset) / cacheSize; - resultBlocks[block] = rr; + @Override + public boolean wantsMore() { + return this.isSet < IsSetFinalValue || resultBlocks[0].wantsMore(); } /** - * Marks this Response as being completed. A complete Response - * needs to be consistent with regard to its internal data. + * Adds the given DataBlockResponse to this ResultSetResponse at the given block position. * - * @throws SQLException if the data currently in this Response is not - * sufficient to be consistent + * @param offset the offset number of rows for this block + */ + public DataBlockResponse addDataBlockResponse(int offset, int rowcount, int columncount, AbstractProtocol proto) { + int block = (offset - blockOffset) / cacheSize; + DataBlockResponse res = new DataBlockResponse(rowcount, columncount, + parent.getRstype() == ResultSet.TYPE_FORWARD_ONLY, proto, JdbcSQLTypes); + resultBlocks[block] = res; + return res; + } + + /** + * Marks this Response as being completed. A complete Response needs to be consistent with regard to its internal + * data. + * + * @throws SQLException if the data currently in this Response is not sufficient to be consistent */ @Override public void complete() throws SQLException { String error = ""; - if (!isSet[0]) error += "name header missing\n"; - if (!isSet[1]) error += "column width header missing\n"; - if (!isSet[2]) error += "table name header missing\n"; - if (!isSet[3]) error += "type header missing\n"; + if ((isSet & 1) == 0) error += "name header missing\n"; + if ((isSet & 2) == 0) error += "column width header missing\n"; + if ((isSet & 4) == 0) error += "table name header missing\n"; + if ((isSet & 8) == 0) error += "type header missing\n"; if (!error.equals("")) throw new SQLException(error, "M0M10"); } @@ -201,6 +206,10 @@ public class ResultSetResponse<T> implem return type; } + public int[] getJdbcSQLTypes() { + return JdbcSQLTypes; + } + /** * Returns the tables of the columns * @@ -256,17 +265,15 @@ public class ResultSetResponse<T> implem } /** - * Parses the given string and changes the value of the matching - * header appropriately, or passes it on to the underlying - * DataResponse. + * Parses the given string and changes the value of the matching header appropriately, or passes it on to the + * underlying DataResponse. * * @param line the string that contains the header * @throws MCLParseException if has a wrong header */ - @SuppressWarnings("unchecked") public void addLine(ServerResponses response, Object line) throws MCLParseException { - if (CheckBooleanValuesAllTrue(isSet)) { - resultBlocks[0].addLine(response, line); + if (this.isSet >= IsSetFinalValue) { + this.resultBlocks[0].addLine(response, line); } if (response != ServerResponses.HEADER) { throw new MCLParseException("header expected, got: " + response.toString()); @@ -275,17 +282,18 @@ public class ResultSetResponse<T> implem switch (con.getProtocol().getNextTableHeader(line, this.tableNames, this.columnLengths)) { case NAME: System.arraycopy(this.tableNames, 0, this.name, 0, this.columncount); - isSet[0] = true; + isSet |= 1; break; case LENGTH: - isSet[1] = true; + isSet |= 2; break; case TYPE: System.arraycopy(this.tableNames, 0, this.type, 0, this.columncount); - isSet[2] = true; + this.populateJdbcSQLTypesArray(); //VERY IMPORTANT! + isSet |= 4; break; case TABLE: - isSet[3] = true; + isSet |= 8; break; } } @@ -302,8 +310,7 @@ public class ResultSetResponse<T> implem * is out of the scope of the result set * @throws SQLException if an database error occurs */ - @SuppressWarnings("unchecked") - public T getLine(int row) throws SQLException { + public Object[] getLine(int row) throws SQLException { if (row >= tuplecount || row < 0) return null; @@ -311,7 +318,7 @@ public class ResultSetResponse<T> implem int blockLine = (row - blockOffset) % cacheSize; // do we have the right block loaded? (optimistic try) - DataBlockResponse<T> rawr; + DataBlockResponse rawr; // load block if appropriate if ((rawr = resultBlocks[block]) == null) { /// TODO: ponder about a maximum number of blocks to keep @@ -355,13 +362,13 @@ public class ResultSetResponse<T> implem } // ok, need to fetch cache block first - parent.executeQuery(con.getLanguage().getCommandTemplates(), "export " + id + " " + ((block * cacheSize) + blockOffset) + " " + cacheSize); + parent.executeQuery(con.getLanguage().getCommandTemplates(), "export " + id + " " + + ((block * cacheSize) + blockOffset) + " " + cacheSize); rawr = resultBlocks[block]; if (rawr == null) { throw new AssertionError("block " + block + " should have been fetched by now :("); } } - return rawr.getRow(blockLine); }
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/SchemaResponse.java +++ b/src/main/java/nl/cwi/monetdb/mcl/responses/SchemaResponse.java @@ -13,10 +13,8 @@ import java.sql.Statement; */ public class SchemaResponse implements IResponse { - private final int state = Statement.SUCCESS_NO_INFO; - public int getState() { - return state; + return Statement.SUCCESS_NO_INFO; } @Override
--- a/src/main/java/nl/cwi/monetdb/merovingian/Control.java +++ b/src/main/java/nl/cwi/monetdb/merovingian/Control.java @@ -8,23 +8,7 @@ package nl.cwi.monetdb.merovingian; -import nl.cwi.monetdb.mcl.io.AbstractMCLReader; -import nl.cwi.monetdb.mcl.io.AbstractMCLWriter; -import nl.cwi.monetdb.mcl.connection.DeleteMe; -import nl.cwi.monetdb.mcl.connection.MCLException; -import nl.cwi.monetdb.mcl.parser.MCLParseException; - -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.net.Socket; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Properties; /** * A Control class to perform operations on a remote merovingian @@ -44,7 +28,7 @@ import java.util.Properties; * @author Fabian Groffen * @version 1.0 */ -public class Control { +public class Control { //TODO make me working again /** The host to connect to */ private final String host; /** The port to connect to */ @@ -54,16 +38,13 @@ public class Control { /** The file we should write MapiSocket debuglog to */ private String debug; - /** * Constructs a new Control object. * * @throws IllegalArgumentException if host, port or passphrase are * null or <= 0 */ - public Control(String host, int port, String passphrase) - throws IllegalArgumentException - { + public Control(String host, int port, String passphrase) throws IllegalArgumentException { this.host = host; this.port = port; this.passphrase = passphrase; @@ -111,10 +92,8 @@ public class Control { final static private String RESPONSE_OK = "OK"; - private List<String> sendCommand( - String database, String command, boolean hasOutput) - throws MerovingianException, IOException - { + /*private List<String> sendCommand(String database, String command, boolean hasOutput) + throws MerovingianException, IOException { AbstractMCLReader min; AbstractMCLWriter mout; DeleteMe ms = new DeleteMe(host, port, "monetdb", "monetdb", false, "sql", "SHA256"); @@ -141,7 +120,7 @@ public class Control { new InputStreamReader(s.getInputStream())); try { /* login ritual, step 1: get challenge from server */ - String response = in.readLine(); + /*String response = in.readLine(); if (response == null) throw new MerovingianException("server closed the connection"); @@ -173,12 +152,12 @@ public class Control { } /* send command, form is simple: "<db> <cmd>\n" */ - out.print(database + " " + command + "\n"); + //out.print(database + " " + command + "\n"); /* Response has the first line either "OK\n" or an error * message. In case of a command with output, the data will * follow the first line */ - response = in.readLine(); + /*response = in.readLine(); if (response == null) { throw new MerovingianException("server closed the connection"); } @@ -226,58 +205,42 @@ public class Control { ms.close(); return l; - } + }*/ - public void start(String database) - throws MerovingianException, IOException - { + /*public void start(String database) throws MerovingianException, IOException { sendCommand(database, "start", false); } - public void stop(String database) - throws MerovingianException, IOException - { + public void stop(String database) throws MerovingianException, IOException { sendCommand(database, "stop", false); } - public void kill(String database) - throws MerovingianException, IOException - { + public void kill(String database) throws MerovingianException, IOException { sendCommand(database, "kill", false); } - public void create(String database) - throws MerovingianException, IOException - { + public void create(String database) throws MerovingianException, IOException { sendCommand(database, "create", false); } - public void destroy(String database) - throws MerovingianException, IOException - { + public void destroy(String database) throws MerovingianException, IOException { sendCommand(database, "destroy", false); } - public void lock(String database) - throws MerovingianException, IOException - { + public void lock(String database) throws MerovingianException, IOException { sendCommand(database, "lock", false); } - public void release(String database) - throws MerovingianException, IOException - { + public void release(String database) throws MerovingianException, IOException { sendCommand(database, "release", false); } - public void rename(String database, String newname) - throws MerovingianException, IOException - { + public void rename(String database, String newname) throws MerovingianException, IOException { if (newname == null) newname = ""; /* force error from merovingian */ - sendCommand(database, "name=" + newname, false); - } + /*sendCommand(database, "name=" + newname, false); + }*/ /** * Sets property for database to value. If value is null, the @@ -291,27 +254,21 @@ public class Control { * @throws IOException if connecting to or communicating with * merovingian failed */ - public void setProperty(String database, String property, String value) - throws MerovingianException, IOException - { + public void setProperty(String database, String property, String value) throws MerovingianException, IOException { /* inherit: set to empty string */ if (value == null) value = ""; - sendCommand(database, property + "=" + value, false); + //sendCommand(database, property + "=" + value, false); } - public void inheritProperty(String database, String property) - throws MerovingianException, IOException - { + public void inheritProperty(String database, String property) throws MerovingianException, IOException { setProperty(database, property, null); } - public Properties getProperties(String database) - throws MerovingianException, IOException - { + /*public Properties getProperties(String database) throws MerovingianException, IOException { Properties ret = new Properties(); - List<String> response = sendCommand(database, "get", true); + //List<String> response = sendCommand(database, "get", true); for (String responseLine : response) { if (responseLine.startsWith("#")) continue; @@ -325,15 +282,11 @@ public class Control { return ret; } - public Properties getDefaultProperties() - throws MerovingianException, IOException - { + public Properties getDefaultProperties() throws MerovingianException, IOException { return(getProperties("#defaults")); } - public SabaothDB getStatus(String database) - throws MerovingianException, IOException - { + public SabaothDB getStatus(String database) throws MerovingianException, IOException { List<String> response = sendCommand(database, "status", true); if (response.isEmpty()) throw new MerovingianException("communication error"); @@ -348,9 +301,7 @@ public class Control { * @throws MerovingianException * @throws IOException */ - public boolean exists(String database) - throws MerovingianException, IOException - { + /*public boolean exists(String database) throws MerovingianException, IOException { List<SabaothDB> all = getAllStatuses(); for (SabaothDB db : all) { if (db.getName().equals(database)) { @@ -360,9 +311,7 @@ public class Control { return false; } - public List<SabaothDB> getAllStatuses() - throws MerovingianException, IOException - { + public List<SabaothDB> getAllStatuses() throws MerovingianException, IOException { List<SabaothDB> l = new ArrayList<>(); List<String> response = sendCommand("#all", "status", true); try { @@ -375,9 +324,7 @@ public class Control { return Collections.unmodifiableList(l); } - public List<URI> getAllNeighbours() - throws MerovingianException, IOException - { + public List<URI> getAllNeighbours() throws MerovingianException, IOException { List<URI> l = new ArrayList<URI>(); List<String> response = sendCommand("anelosimus", "eximius", true); try { @@ -397,5 +344,5 @@ public class Control { throw new MerovingianException(e.getMessage()); } return Collections.unmodifiableList(l); - } + }*/ }
--- a/src/main/java/nl/cwi/monetdb/merovingian/SabaothDB.java +++ b/src/main/java/nl/cwi/monetdb/merovingian/SabaothDB.java @@ -24,15 +24,13 @@ import java.util.*; public class SabaothDB { /** The name of the database */ private String dbname; - /** The URI how to connect to this database, or null if not - * shared */ + /** The URI how to connect to this database, or null if not shared */ private String uri; /** Whether or not the database is under maintenance */ private boolean locked; /** The state of this database, one of SABdbState */ private SABdbState state; - /** A list of Strings representing the available scenarios of this - * database */ + /** A list of Strings representing the available scenarios of this database */ private String[] scenarios; /** The number of times this database was started */ private int startCounter; @@ -58,17 +56,12 @@ public class SabaothDB { private double crashAvg10; /** Average of crashes in the last 30 start attempts */ private double crashAvg30; - /** The serialised format header */ private final String sabdbhdr = "sabdb:"; /** Sabaoth state enumeration */ public enum SABdbState { - SABdbIllegal (0), - SABdbRunning (1), - SABdbCrashed (2), - SABdbInactive(3), - SABdbStarting(4); + SABdbIllegal (0), SABdbRunning (1), SABdbCrashed (2), SABdbInactive(3), SABdbStarting(4); private final int cValue; @@ -88,20 +81,16 @@ public class SabaothDB { return(s); } } - throw new IllegalArgumentException("No such state with value: " - + val); + throw new IllegalArgumentException("No such state with value: " + val); } } - /** * Constructs a new SabaothDB object from a String. * * @param sabdb the serialised sabdb C-struct */ - public SabaothDB(String sabdb) - throws IllegalArgumentException - { + public SabaothDB(String sabdb) throws IllegalArgumentException { if (sabdb == null) throw new IllegalArgumentException("String is null"); if (!sabdb.startsWith(sabdbhdr))
--- a/src/main/java/nl/cwi/monetdb/util/CmdLineOpts.java +++ b/src/main/java/nl/cwi/monetdb/util/CmdLineOpts.java @@ -31,21 +31,9 @@ public class CmdLineOpts { public CmdLineOpts() { } - public void addOption( - String shorta, - String longa, - int type, - String defaulta, - String descriptiona) - throws OptionsException { - OptionContainer oc = - new OptionContainer( - shorta, - longa, - type, - defaulta, - descriptiona - ); + public void addOption(String shorta, String longa, int type, String defaulta, String descriptiona) + throws OptionsException { + OptionContainer oc = new OptionContainer(shorta, longa, type, defaulta, descriptiona); if (shorta != null) opts.put(shorta, oc); if (longa != null) opts.put(longa, oc); } @@ -287,14 +275,8 @@ public class CmdLineOpts { String descriptiona; boolean present; - public OptionContainer( - String shorta, - String longa, - int cardinality, - String defaulta, - String descriptiona) - throws IllegalArgumentException - { + public OptionContainer(String shorta, String longa, int cardinality, String defaulta, String descriptiona) + throws IllegalArgumentException { this.cardinality = cardinality; this.shorta = shorta; this.longa = longa; @@ -302,11 +284,8 @@ public class CmdLineOpts { this.descriptiona = descriptiona; this.present = false; - if (cardinality != CAR_ZERO && - cardinality != CAR_ONE && - cardinality != CAR_ZERO_ONE && - cardinality != CAR_ZERO_MANY && - cardinality != CAR_ONE_MANY) + if (cardinality != CAR_ZERO && cardinality != CAR_ONE && cardinality != CAR_ZERO_ONE + && cardinality != CAR_ZERO_MANY && cardinality != CAR_ONE_MANY) throw new IllegalArgumentException("unknown cardinality"); if (shorta != null && shorta.length() != 1) throw new IllegalArgumentException("short option should consist of exactly one character");
--- a/src/main/java/nl/cwi/monetdb/util/Extract.java +++ b/src/main/java/nl/cwi/monetdb/util/Extract.java @@ -27,8 +27,6 @@ import java.io.InputStreamReader; public class Extract { private static final int DEFAULT_BUFSIZE = 16386; - public Extract() {} - /** * Extracts a file from the Jar package which includes this class to * the given destination @@ -40,17 +38,14 @@ public class Extract { * @throws IOException If any error happens during * creating/reading/writing files. */ - public static void extractFile(String fromFile, String toFile) - throws FileNotFoundException, IOException - { + public static void extractFile(String fromFile, String toFile) throws FileNotFoundException, IOException { char[] cbuf = new char[DEFAULT_BUFSIZE]; int ret; InputStream is = Extract.class.getResourceAsStream(fromFile); if(is == null) { - throw new FileNotFoundException("File " + fromFile + - " does not exist in the JAR package."); + throw new FileNotFoundException("File " + fromFile + " does not exist in the JAR package."); } BufferedReader reader = new BufferedReader(new InputStreamReader(is));
--- a/src/main/java/nl/cwi/monetdb/util/SQLExporter.java +++ b/src/main/java/nl/cwi/monetdb/util/SQLExporter.java @@ -47,14 +47,8 @@ public class SQLExporter extends Exporte * @param name the table to describe in SQL CREATE format (not null) * @throws SQLException if a database related error occurs */ - public void dumpSchema( - DatabaseMetaData dbmd, - String type, - String catalog, - String schema, - String name) - throws SQLException - { + public void dumpSchema(DatabaseMetaData dbmd, String type, String catalog, String schema, String name) + throws SQLException { assert dbmd != null; assert type != null; assert schema != null; @@ -371,9 +365,7 @@ public class SQLExporter extends Exporte * @param rs the ResultSet to convert into INSERT INTO statements * @throws SQLException if a database related error occurs */ - private void resultSetToSQL(ResultSet rs) - throws SQLException - { + private void resultSetToSQL(ResultSet rs) throws SQLException { ResultSetMetaData rsmd = rs.getMetaData(); String statement = "INSERT INTO "; if (!useSchema) {
--- a/src/main/java/nl/cwi/monetdb/util/SQLRestore.java +++ b/src/main/java/nl/cwi/monetdb/util/SQLRestore.java @@ -8,24 +8,14 @@ package nl.cwi.monetdb.util; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; import java.io.IOException; -import java.util.concurrent.atomic.AtomicBoolean; - -import nl.cwi.monetdb.mcl.connection.MCLException; -import nl.cwi.monetdb.mcl.io.AbstractMCLReader; -import nl.cwi.monetdb.mcl.io.AbstractMCLWriter; -import nl.cwi.monetdb.mcl.connection.DeleteMe; -import nl.cwi.monetdb.mcl.parser.MCLParseException; /** * Use this class to restore an SQL dump file. */ public class SQLRestore { - private final String _host; + /*private final String _host; TODO make me working again! private final int _port; private final String _user; private final String _password; @@ -77,25 +67,25 @@ public class SQLRestore { // ignore errors } } - } + }*/ /** * @return whether the server has responded with an error. Any * error is regarded as fatal. */ - public boolean inErrorState() { + /*public boolean inErrorState() { return _errorState.get(); - } + }*/ /** * @return the error message if inErrorState() is true. Behaviour is * not defined if called before inErrorState is true. */ - public String getErrorMessage() { + /*public String getErrorMessage() { return _errorMessage; - } + }*/ - } + //} /** * Restores a given SQL dump to the database. @@ -103,7 +93,7 @@ public class SQLRestore { * @param source File location of the SQL dump * @throws IOException */ - public void restore(File source) throws IOException { + /*public void restore(File source) throws IOException { DeleteMe ms = new DeleteMe(_host, _port, _dbName, _user, false, "sql", "SHA256"); try { ms.connect(_user, _password); @@ -188,5 +178,5 @@ public class SQLRestore { } finally { md.close(); } - } + }*/ }
--- a/src/main/java/nl/cwi/monetdb/util/XMLExporter.java +++ b/src/main/java/nl/cwi/monetdb/util/XMLExporter.java @@ -24,14 +24,8 @@ public class XMLExporter extends Exporte super(out); } - public void dumpSchema( - DatabaseMetaData dbmd, - String type, - String catalog, - String schema, - String name) - throws SQLException - { + public void dumpSchema(DatabaseMetaData dbmd, String type, String catalog, String schema, String name) + throws SQLException { if (type.contains("VIEW")) { String[] types = new String[1]; types[0] = type; @@ -309,10 +303,8 @@ public class XMLExporter extends Exporte out.println("</xsd:schema>"); } - private final static SimpleDateFormat xsd_ts = - new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); - private final static SimpleDateFormat xsd_tstz = - new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); + private final static SimpleDateFormat xsd_ts = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + private final static SimpleDateFormat xsd_tstz = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); /** * Generates an XML representation of the given ResultSet.