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]

Reply via email to