Changeset: 940e266eeccd for monetdb-java
URL: https://dev.monetdb.org/hg/monetdb-java/rev/940e266eeccd
Modified Files:
src/main/java/org/monetdb/jdbc/MonetConnection.java
src/main/java/org/monetdb/mcl/io/BufferedMCLReader.java
src/main/java/org/monetdb/mcl/io/BufferedMCLWriter.java
src/main/java/org/monetdb/mcl/net/MapiSocket.java
src/main/java/org/monetdb/merovingian/Control.java
src/main/java/org/monetdb/util/SQLRestore.java
tests/JDBC_API_Tester.java
tests/SQLcopyinto.java
Branch: default
Log Message:
Refactor BufferedMCLReader
It used to inherit from BufferedReader but there is no reason for that.
Also, it used to have a method readLine() which
- returned the line read
- stored the linetype
In the new setup we have a method advance() which reads
a line and stores both it and its type.
This makes the code more regular and makes it possible to
peek ahead without consuming.
diffs (truncated from 485 to 300 lines):
diff --git a/src/main/java/org/monetdb/jdbc/MonetConnection.java
b/src/main/java/org/monetdb/jdbc/MonetConnection.java
--- a/src/main/java/org/monetdb/jdbc/MonetConnection.java
+++ b/src/main/java/org/monetdb/jdbc/MonetConnection.java
@@ -343,7 +343,7 @@ public class MonetConnection
in = server.getReader();
out = server.getWriter();
- final String error = in.waitForPrompt();
+ final String error = in.discardRemainder();
if (error != null)
throw new
SQLNonTransientConnectionException((error.length() > 6) ? error.substring(6) :
error, "08001");
} catch (java.net.UnknownHostException e) {
@@ -2138,7 +2138,7 @@ public class MonetConnection
out.writeLine(queryTempl[0] + command +
queryTempl[1]);
else
out.writeLine(commandTempl[0] + command
+ commandTempl[1]);
- final String error = in.waitForPrompt();
+ final String error = in.discardRemainder();
if (error != null)
throw new
SQLException(error.substring(6), error.substring(0, 5));
} catch (SocketTimeoutException e) {
@@ -3131,7 +3131,7 @@ public class MonetConnection
// have the prompt it is possible (and
most likely) that we
// already have the prompt and do not
have to skip any
// lines. Ignore errors from previous
result sets.
- in.waitForPrompt();
+ in.discardRemainder();
// {{{ set reply size
/**
@@ -3158,16 +3158,15 @@ public class MonetConnection
out.writeLine(templ[0] + query +
templ[1]);
// go for new results
- String tmpLine = in.readLine();
- LineType linetype = in.getLineType();
+ in.advance();
Response res = null;
- while (linetype != LineType.PROMPT) {
+ while (in.getLineType() !=
LineType.PROMPT) {
// each response should start
with a start of header (or error)
- switch (linetype) {
+ switch (in.getLineType()) {
case SOHEADER:
// make the response
object, and fill it
try {
- switch
(sohp.parse(tmpLine)) {
+ switch
(sohp.parse(in.getLine())) {
case
StartOfHeaderParser.Q_PARSE:
throw
new MCLParseException("Q_PARSE header not allowed here", 1);
case
StartOfHeaderParser.Q_TABLE:
@@ -3228,31 +3227,29 @@ public class MonetConnection
final int
offset = e.getErrorOffset();
error =
"M0M10!error while parsing start of header:\n" +
e.getMessage() +
- "
found: '" + tmpLine.charAt(offset) +
- "' in:
\"" + tmpLine +
+ "
found: '" + in.getLine().charAt(offset) +
+ "' in:
\"" + in.getLine() +
"\" at
pos: " + offset;
// flush all
the rest
-
in.waitForPrompt();
- linetype =
in.getLineType();
+
in.discardRemainder();
break;
}
// immediately handle
errors after parsing the header (res may be null)
if (error != null) {
-
in.waitForPrompt();
- linetype =
in.getLineType();
+
in.discardRemainder();
break;
}
// here we have a res
object, which we can start filling
while (res.wantsMore())
{
- error =
res.addLine(in.readLine(), in.getLineType());
+ in.advance();
+ error =
res.addLine(in.getLine(), in.getLineType());
if (error !=
null) {
//
right, some protocol violation,
// skip
the rest of the result
error =
"M0M10!" + error;
-
in.waitForPrompt();
-
linetype = in.getLineType();
+
in.discardRemainder();
break;
}
}
@@ -3266,21 +3263,20 @@ public class MonetConnection
// read the next line
(can be prompt, new result, error, etc.)
// before we start the
loop over
- tmpLine = in.readLine();
- linetype =
in.getLineType();
+ in.advance();
break;
case INFO:
-
addWarning(tmpLine.substring(1), "01000");
+
addWarning(in.getLine().substring(1), "01000");
// read the next line
(can be prompt, new result, error, etc.)
// before we start the
loop over
- tmpLine = in.readLine();
- linetype =
in.getLineType();
+ in.advance();
break;
case FILETRANSFER:
// Consume the command
- final String
transferCommand = in.readLine();
+ in.advance();
+ final String
transferCommand = in.getLine();
// Consume the fake
prompt inserted by MapiSocket.
- in.readLine();
+ in.advance();
// Handle the request
if (transferCommand !=
null)
error =
handleTransfer(transferCommand);
@@ -3289,27 +3285,21 @@ public class MonetConnection
// Then prepare for the
next iteration
if (error != null) {
out.writeLine(error + "\n");
- error =
in.waitForPrompt();
+ error =
in.discardRemainder();
} else {
- tmpLine =
in.readLine();
+ in.advance();
}
- linetype =
in.getLineType();
break;
- default: // Yeah... in
Java this is correct!
+ default:
// we have something we
don't expect/understand, let's make it an error message
- tmpLine =
"!M0M10!protocol violation, unexpected " + linetype + " line: " + tmpLine;
- // don't break; fall
through...
+ String msg =
"M0M10!protocol violation, unexpected " + in.getLineType() + " line: " +
in.getLine();
+ error =
in.discardRemainder(msg);
+ 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
- error =
in.waitForPrompt();
- linetype =
in.getLineType();
- if (error != null) {
- error =
tmpLine.substring(1) + "\n" + error;
- } else {
- error =
tmpLine.substring(1);
- }
+ error =
in.discardRemainder(in.getLine().substring(1));
break;
} // end of switch (linetype)
} // end of while (linetype !=
LineType.PROMPT)
diff --git a/src/main/java/org/monetdb/mcl/io/BufferedMCLReader.java
b/src/main/java/org/monetdb/mcl/io/BufferedMCLReader.java
--- a/src/main/java/org/monetdb/mcl/io/BufferedMCLReader.java
+++ b/src/main/java/org/monetdb/mcl/io/BufferedMCLReader.java
@@ -40,9 +40,10 @@ import java.io.UnsupportedEncodingExcept
* @see org.monetdb.mcl.net.MapiSocket
* @see org.monetdb.mcl.io.BufferedMCLWriter
*/
-public final class BufferedMCLReader extends BufferedReader {
+public final class BufferedMCLReader /* extends BufferedReader */ {
- /** The type of the last line read */
+ private final BufferedReader inner;
+ private String current = null;
private LineType lineType = LineType.UNKNOWN;
/**
@@ -52,7 +53,7 @@ public final class BufferedMCLReader ext
* @param in A Reader
*/
public BufferedMCLReader(final Reader in) {
- super(in);
+ inner = new BufferedReader(in);
}
/**
@@ -66,47 +67,37 @@ public final class BufferedMCLReader ext
public BufferedMCLReader(final InputStream in, final String enc)
throws UnsupportedEncodingException
{
- super(new java.io.InputStreamReader(in, enc));
+ this(new java.io.InputStreamReader(in, enc));
+ }
+
+ public void advance() throws IOException {
+ if (lineType == LineType.PROMPT)
+ return;
+
+ current = inner.readLine();
+ lineType = LineType.classify(current);
+ if (lineType == LineType.ERROR && current != null &&
!current.matches("^![0-9A-Z]{5}!.+")) {
+ current = "!22000!" + current.substring(1);
+ }
}
/**
- * 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
+ * Resets the linetype to UNKNOWN.
*/
- @Override
- public String readLine() throws IOException {
- String r = super.readLine();
- setLineType(r);
- if (lineType == LineType.ERROR && r != null &&
!r.matches("^![0-9A-Z]{5}!.+")) {
- r = "!22000!" + r.substring(1);
- }
- return r;
+ public void resetLineType() {
+ lineType = LineType.UNKNOWN;
}
/**
- * 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
+ * Return the current line, or null if we're at the end or before the
beginning.
+ * @return the current line or null
*/
- public void setLineType(final String line) {
- lineType = LineType.classify(line);
+ public String getLine() {
+ return current;
}
/**
- * getLineType returns the type of the last line read.
+ * getLineType returns the type of the current line.
*
* @return Linetype representing the kind of line this is, one of the
* following enums: UNKNOWN, HEADER, ERROR, RESULT,
@@ -117,35 +108,52 @@ public final class BufferedMCLReader ext
}
/**
- * 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.
+ * Discard the remainder of the response but collect any further error
messages.
*
* @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
*
* TODO(Wouter): should probably not have to be synchronized.
*/
- final public synchronized String waitForPrompt() throws IOException {
- StringBuilder errmsgs = null;
- String tmp;
+
+
+ final public synchronized String discardRemainder() throws IOException {
+ return discard(null);
+ }
+
+ final public synchronized String discardRemainder(String error) throws
IOException {
+ final StringBuilder sb;
+ if (error != null) {
+ sb = makeErrorBuffer();
+ sb.append(error);
+ } else {
+ sb = null;
+ }
+ return discard(sb);
+ }
+
+ final synchronized String discard(StringBuilder errmsgs) throws
IOException {
while (lineType != LineType.PROMPT) {
- tmp = readLine();
- if (tmp == null)
+ advance();
+ if (getLine() == null)
throw new IOException("Connection to server
lost!");
- if (lineType == LineType.ERROR) {
+ if (getLineType() == LineType.ERROR) {
if (errmsgs == null)
errmsgs = new StringBuilder(128);
- errmsgs.append('\n').append(tmp.substring(1));
+
errmsgs.append('\n').append(getLine().substring(1));
}
}
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]