comparison src/main/java/org/monetdb/jdbc/MonetConnection.java @ 700:940e266eeccd

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.
author Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com>
date Thu, 08 Dec 2022 15:59:17 +0100 (2022-12-08)
parents 68422d7f3961
children f89882b07614
comparison
equal deleted inserted replaced
699:0ff364f569a1 700:940e266eeccd
341 server.setSoTimeout(sockTimeout); 341 server.setSoTimeout(sockTimeout);
342 342
343 in = server.getReader(); 343 in = server.getReader();
344 out = server.getWriter(); 344 out = server.getWriter();
345 345
346 final String error = in.waitForPrompt(); 346 final String error = in.discardRemainder();
347 if (error != null) 347 if (error != null)
348 throw new SQLNonTransientConnectionException((error.length() > 6) ? error.substring(6) : error, "08001"); 348 throw new SQLNonTransientConnectionException((error.length() > 6) ? error.substring(6) : error, "08001");
349 } catch (java.net.UnknownHostException e) { 349 } catch (java.net.UnknownHostException e) {
350 throw new SQLNonTransientConnectionException("Unknown Host (" + hostname + "): " + e.getMessage(), "08006"); 350 throw new SQLNonTransientConnectionException("Unknown Host (" + hostname + "): " + e.getMessage(), "08006");
351 } catch (IOException e) { 351 } catch (IOException e) {
2136 try { 2136 try {
2137 if (usequeryTempl) 2137 if (usequeryTempl)
2138 out.writeLine(queryTempl[0] + command + queryTempl[1]); 2138 out.writeLine(queryTempl[0] + command + queryTempl[1]);
2139 else 2139 else
2140 out.writeLine(commandTempl[0] + command + commandTempl[1]); 2140 out.writeLine(commandTempl[0] + command + commandTempl[1]);
2141 final String error = in.waitForPrompt(); 2141 final String error = in.discardRemainder();
2142 if (error != null) 2142 if (error != null)
2143 throw new SQLException(error.substring(6), error.substring(0, 5)); 2143 throw new SQLException(error.substring(6), error.substring(0, 5));
2144 } catch (SocketTimeoutException e) { 2144 } catch (SocketTimeoutException e) {
2145 close(); // JDBC 4.1 semantics, abort() 2145 close(); // JDBC 4.1 semantics, abort()
2146 throw new SQLNonTransientConnectionException("connection timed out", "08M33"); 2146 throw new SQLNonTransientConnectionException("connection timed out", "08M33");
3129 synchronized (server) { 3129 synchronized (server) {
3130 // make sure we're ready to send query; read data till we 3130 // make sure we're ready to send query; read data till we
3131 // have the prompt it is possible (and most likely) that we 3131 // have the prompt it is possible (and most likely) that we
3132 // already have the prompt and do not have to skip any 3132 // already have the prompt and do not have to skip any
3133 // lines. Ignore errors from previous result sets. 3133 // lines. Ignore errors from previous result sets.
3134 in.waitForPrompt(); 3134 in.discardRemainder();
3135 3135
3136 // {{{ set reply size 3136 // {{{ set reply size
3137 /** 3137 /**
3138 * Change the reply size of the server. If the given 3138 * Change the reply size of the server. If the given
3139 * value is the same as the current value known to use, 3139 * value is the same as the current value known to use,
3156 3156
3157 // send query to the server 3157 // send query to the server
3158 out.writeLine(templ[0] + query + templ[1]); 3158 out.writeLine(templ[0] + query + templ[1]);
3159 3159
3160 // go for new results 3160 // go for new results
3161 String tmpLine = in.readLine(); 3161 in.advance();
3162 LineType linetype = in.getLineType();
3163 Response res = null; 3162 Response res = null;
3164 while (linetype != LineType.PROMPT) { 3163 while (in.getLineType() != LineType.PROMPT) {
3165 // each response should start with a start of header (or error) 3164 // each response should start with a start of header (or error)
3166 switch (linetype) { 3165 switch (in.getLineType()) {
3167 case SOHEADER: 3166 case SOHEADER:
3168 // make the response object, and fill it 3167 // make the response object, and fill it
3169 try { 3168 try {
3170 switch (sohp.parse(tmpLine)) { 3169 switch (sohp.parse(in.getLine())) {
3171 case StartOfHeaderParser.Q_PARSE: 3170 case StartOfHeaderParser.Q_PARSE:
3172 throw new MCLParseException("Q_PARSE header not allowed here", 1); 3171 throw new MCLParseException("Q_PARSE header not allowed here", 1);
3173 case StartOfHeaderParser.Q_TABLE: 3172 case StartOfHeaderParser.Q_TABLE:
3174 case StartOfHeaderParser.Q_PREPARE: { 3173 case StartOfHeaderParser.Q_PREPARE: {
3175 final int id = sohp.getNextAsInt(); 3174 final int id = sohp.getNextAsInt();
3226 } // end of switch (sohp.parse(tmpLine)) 3225 } // end of switch (sohp.parse(tmpLine))
3227 } catch (MCLParseException e) { 3226 } catch (MCLParseException e) {
3228 final int offset = e.getErrorOffset(); 3227 final int offset = e.getErrorOffset();
3229 error = "M0M10!error while parsing start of header:\n" + 3228 error = "M0M10!error while parsing start of header:\n" +
3230 e.getMessage() + 3229 e.getMessage() +
3231 " found: '" + tmpLine.charAt(offset) + 3230 " found: '" + in.getLine().charAt(offset) +
3232 "' in: \"" + tmpLine + 3231 "' in: \"" + in.getLine() +
3233 "\" at pos: " + offset; 3232 "\" at pos: " + offset;
3234 // flush all the rest 3233 // flush all the rest
3235 in.waitForPrompt(); 3234 in.discardRemainder();
3236 linetype = in.getLineType();
3237 break; 3235 break;
3238 } 3236 }
3239 3237
3240 // immediately handle errors after parsing the header (res may be null) 3238 // immediately handle errors after parsing the header (res may be null)
3241 if (error != null) { 3239 if (error != null) {
3242 in.waitForPrompt(); 3240 in.discardRemainder();
3243 linetype = in.getLineType();
3244 break; 3241 break;
3245 } 3242 }
3246 3243
3247 // here we have a res object, which we can start filling 3244 // here we have a res object, which we can start filling
3248 while (res.wantsMore()) { 3245 while (res.wantsMore()) {
3249 error = res.addLine(in.readLine(), in.getLineType()); 3246 in.advance();
3247 error = res.addLine(in.getLine(), in.getLineType());
3250 if (error != null) { 3248 if (error != null) {
3251 // right, some protocol violation, 3249 // right, some protocol violation,
3252 // skip the rest of the result 3250 // skip the rest of the result
3253 error = "M0M10!" + error; 3251 error = "M0M10!" + error;
3254 in.waitForPrompt(); 3252 in.discardRemainder();
3255 linetype = in.getLineType();
3256 break; 3253 break;
3257 } 3254 }
3258 } 3255 }
3259 if (error != null) 3256 if (error != null)
3260 break; 3257 break;
3264 if (!(res instanceof DataBlockResponse)) 3261 if (!(res instanceof DataBlockResponse))
3265 responses.add(res); 3262 responses.add(res);
3266 3263
3267 // read the next line (can be prompt, new result, error, etc.) 3264 // read the next line (can be prompt, new result, error, etc.)
3268 // before we start the loop over 3265 // before we start the loop over
3269 tmpLine = in.readLine(); 3266 in.advance();
3270 linetype = in.getLineType();
3271 break; 3267 break;
3272 case INFO: 3268 case INFO:
3273 addWarning(tmpLine.substring(1), "01000"); 3269 addWarning(in.getLine().substring(1), "01000");
3274 // read the next line (can be prompt, new result, error, etc.) 3270 // read the next line (can be prompt, new result, error, etc.)
3275 // before we start the loop over 3271 // before we start the loop over
3276 tmpLine = in.readLine(); 3272 in.advance();
3277 linetype = in.getLineType();
3278 break; 3273 break;
3279 case FILETRANSFER: 3274 case FILETRANSFER:
3280 // Consume the command 3275 // Consume the command
3281 final String transferCommand = in.readLine(); 3276 in.advance();
3277 final String transferCommand = in.getLine();
3282 // Consume the fake prompt inserted by MapiSocket. 3278 // Consume the fake prompt inserted by MapiSocket.
3283 in.readLine(); 3279 in.advance();
3284 // Handle the request 3280 // Handle the request
3285 if (transferCommand != null) 3281 if (transferCommand != null)
3286 error = handleTransfer(transferCommand); 3282 error = handleTransfer(transferCommand);
3287 else 3283 else
3288 error = "Protocol violation, expected transfer command, got nothing"; 3284 error = "Protocol violation, expected transfer command, got nothing";
3289 // Then prepare for the next iteration 3285 // Then prepare for the next iteration
3290 if (error != null) { 3286 if (error != null) {
3291 out.writeLine(error + "\n"); 3287 out.writeLine(error + "\n");
3292 error = in.waitForPrompt(); 3288 error = in.discardRemainder();
3293 } else { 3289 } else {
3294 tmpLine = in.readLine(); 3290 in.advance();
3295 } 3291 }
3296 linetype = in.getLineType();
3297 break; 3292 break;
3298 default: // Yeah... in Java this is correct! 3293 default:
3299 // we have something we don't expect/understand, let's make it an error message 3294 // we have something we don't expect/understand, let's make it an error message
3300 tmpLine = "!M0M10!protocol violation, unexpected " + linetype + " line: " + tmpLine; 3295 String msg = "M0M10!protocol violation, unexpected " + in.getLineType() + " line: " + in.getLine();
3301 // don't break; fall through... 3296 error = in.discardRemainder(msg);
3297 break;
3302 case ERROR: 3298 case ERROR:
3303 // read everything till the prompt (should be 3299 // read everything till the prompt (should be
3304 // error) we don't know if we ignore some 3300 // error) we don't know if we ignore some
3305 // garbage here... but the log should reveal that 3301 // garbage here... but the log should reveal that
3306 error = in.waitForPrompt(); 3302 error = in.discardRemainder(in.getLine().substring(1));
3307 linetype = in.getLineType();
3308 if (error != null) {
3309 error = tmpLine.substring(1) + "\n" + error;
3310 } else {
3311 error = tmpLine.substring(1);
3312 }
3313 break; 3303 break;
3314 } // end of switch (linetype) 3304 } // end of switch (linetype)
3315 } // end of while (linetype != LineType.PROMPT) 3305 } // end of while (linetype != LineType.PROMPT)
3316 } // end of synchronized (server) 3306 } // end of synchronized (server)
3317 3307