comparison src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java @ 284:e5b99c929a2d

Improve setSchema(String schema) by checking also on empty name. Improve setSchema(String schema) and getSchema() by checking on null to prevent NPE's Reduce indentation in executeQuery(String[] templ, String query).
author Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
date Thu, 25 Jul 2019 15:35:37 +0200 (2019-07-25)
parents 1d6062d94377
children 637899bda602
comparison
equal deleted inserted replaced
283:92e882feea95 284:e5b99c929a2d
108 /** Whether this Connection is in autocommit mode */ 108 /** Whether this Connection is in autocommit mode */
109 private boolean autoCommit = true; 109 private boolean autoCommit = true;
110 110
111 /** The stack of warnings for this Connection object */ 111 /** The stack of warnings for this Connection object */
112 private SQLWarning warnings = null; 112 private SQLWarning warnings = null;
113 /** The Connection specific mapping of user defined types to Java 113
114 * types */ 114 /** The Connection specific mapping of user defined types to Java types */
115 private Map<String,Class<?>> typeMap = new HashMap<String,Class<?>>() { 115 private Map<String,Class<?>> typeMap = new HashMap<String,Class<?>>() {
116 private static final long serialVersionUID = 1L; 116 private static final long serialVersionUID = 1L;
117 { 117 {
118 put("inet", INET.class); 118 put("inet", INET.class);
119 put("url", URL.class); 119 put("url", URL.class);
1316 if (timeout < 0) 1316 if (timeout < 0)
1317 throw new SQLException("timeout is less than 0", "M1M05"); 1317 throw new SQLException("timeout is less than 0", "M1M05");
1318 if (closed) 1318 if (closed)
1319 return false; 1319 return false;
1320 1320
1321 // ping db using query: select 1; 1321 // ping monetdb server using query: select 1;
1322 Statement stmt = null; 1322 Statement stmt = null;
1323 ResultSet rs = null; 1323 ResultSet rs = null;
1324 boolean isValid = false; 1324 boolean isValid = false;
1325 try { 1325 try {
1326 stmt = createStatement(); 1326 stmt = createStatement();
1519 */ 1519 */
1520 @Override 1520 @Override
1521 public void setSchema(String schema) throws SQLException { 1521 public void setSchema(String schema) throws SQLException {
1522 if (closed) 1522 if (closed)
1523 throw new SQLException("Cannot call on closed Connection", "M1M20"); 1523 throw new SQLException("Cannot call on closed Connection", "M1M20");
1524 if (schema == null) 1524 if (schema == null || schema.isEmpty())
1525 throw new SQLException("Missing schema name", "M1M05"); 1525 throw new SQLException("Missing schema name", "M1M05");
1526 1526
1527 Statement st = createStatement(); 1527 Statement st = null;
1528 try { 1528 try {
1529 st.execute("SET SCHEMA \"" + schema + "\""); 1529 st = createStatement();
1530 if (st != null)
1531 st.execute("SET SCHEMA \"" + schema + "\"");
1532 // do not catch any Exception, just let it propagate
1530 } finally { 1533 } finally {
1531 st.close(); 1534 if (st != null) {
1535 try {
1536 st.close();
1537 } catch (SQLException e) { /* ignore */ }
1538 }
1532 } 1539 }
1533 } 1540 }
1534 1541
1535 /** 1542 /**
1536 * Retrieves this Connection object's current schema name. 1543 * Retrieves this Connection object's current schema name.
1543 @Override 1550 @Override
1544 public String getSchema() throws SQLException { 1551 public String getSchema() throws SQLException {
1545 if (closed) 1552 if (closed)
1546 throw new SQLException("Cannot call on closed Connection", "M1M20"); 1553 throw new SQLException("Cannot call on closed Connection", "M1M20");
1547 1554
1548 String cur_schema; 1555 String cur_schema = null;
1549 Statement st = createStatement(); 1556 Statement st = null;
1550 ResultSet rs = null; 1557 ResultSet rs = null;
1551 try { 1558 try {
1552 rs = st.executeQuery("SELECT CURRENT_SCHEMA"); 1559 st = createStatement();
1553 if (!rs.next()) 1560 if (st != null) {
1554 throw new SQLException("Row expected", "02000"); 1561 rs = st.executeQuery("SELECT CURRENT_SCHEMA");
1555 cur_schema = rs.getString(1); 1562 if (rs != null) {
1563 if (rs.next())
1564 cur_schema = rs.getString(1);
1565 }
1566 }
1567 // do not catch any Exception, just let it propagate
1556 } finally { 1568 } finally {
1557 if (rs != null) 1569 if (rs != null) {
1558 rs.close(); 1570 try {
1559 st.close(); 1571 rs.close();
1560 } 1572 } catch (SQLException e) { /* ignore */ }
1573 }
1574 if (st != null) {
1575 try {
1576 st.close();
1577 } catch (SQLException e) { /* ignore */ }
1578 }
1579 }
1580 if (cur_schema == null)
1581 throw new SQLException("Failed to fetch schema name", "02000");
1561 return cur_schema; 1582 return cur_schema;
1562 } 1583 }
1563 1584
1564 /** 1585 /**
1565 * Terminates an open connection. Calling abort results in: 1586 * Terminates an open connection. Calling abort results in:
2729 // go for new results 2750 // go for new results
2730 String tmpLine = in.readLine(); 2751 String tmpLine = in.readLine();
2731 int linetype = in.getLineType(); 2752 int linetype = in.getLineType();
2732 Response res = null; 2753 Response res = null;
2733 while (linetype != BufferedMCLReader.PROMPT) { 2754 while (linetype != BufferedMCLReader.PROMPT) {
2734 // each response should start with a start of header 2755 // each response should start with a start of header (or error)
2735 // (or error)
2736 switch (linetype) { 2756 switch (linetype) {
2737 case BufferedMCLReader.SOHEADER: 2757 case BufferedMCLReader.SOHEADER:
2738 // make the response object, and fill it 2758 // make the response object, and fill it
2739 try { 2759 try {
2740 switch (sohp.parse(tmpLine)) { 2760 switch (sohp.parse(tmpLine)) {
2741 case StartOfHeaderParser.Q_PARSE: 2761 case StartOfHeaderParser.Q_PARSE:
2742 throw new MCLParseException("Q_PARSE header not allowed here", 1); 2762 throw new MCLParseException("Q_PARSE header not allowed here", 1);
2743 case StartOfHeaderParser.Q_TABLE: 2763 case StartOfHeaderParser.Q_TABLE:
2744 case StartOfHeaderParser.Q_PREPARE: { 2764 case StartOfHeaderParser.Q_PREPARE: {
2745 int id = sohp.getNextAsInt(); 2765 int id = sohp.getNextAsInt();
2746 int tuplecount = sohp.getNextAsInt(); 2766 int tuplecount = sohp.getNextAsInt();
2747 int columncount = sohp.getNextAsInt(); 2767 int columncount = sohp.getNextAsInt();
2748 int rowcount = sohp.getNextAsInt(); 2768 int rowcount = sohp.getNextAsInt();
2749 // enforce the maxrows setting 2769 // enforce the maxrows setting
2750 if (maxrows != 0 && tuplecount > maxrows) 2770 if (maxrows != 0 && tuplecount > maxrows)
2751 tuplecount = maxrows; 2771 tuplecount = maxrows;
2752 res = new ResultSetResponse( 2772 res = new ResultSetResponse(id, tuplecount, columncount, rowcount, this, seqnr);
2753 id, 2773 // only add this resultset to the hashmap if it can possibly have an additional datablock
2754 tuplecount, 2774 if (rowcount < tuplecount) {
2755 columncount, 2775 if (rsresponses == null)
2756 rowcount, 2776 rsresponses = new HashMap<Integer, ResultSetResponse>();
2757 this, 2777 rsresponses.put(Integer.valueOf(id), (ResultSetResponse) res);
2758 seqnr 2778 }
2759 ); 2779 } break;
2760 // only add this resultset to 2780 case StartOfHeaderParser.Q_UPDATE:
2761 // the hashmap if it can possibly 2781 res = new UpdateResponse(sohp.getNextAsInt(), // count
2762 // have an additional datablock 2782 sohp.getNextAsString() // key-id
2763 if (rowcount < tuplecount) {
2764 if (rsresponses == null)
2765 rsresponses = new HashMap<Integer, ResultSetResponse>();
2766 rsresponses.put(
2767 Integer.valueOf(id),
2768 (ResultSetResponse) res
2769 ); 2783 );
2770 } 2784 break;
2771 } break; 2785 case StartOfHeaderParser.Q_SCHEMA:
2772 case StartOfHeaderParser.Q_UPDATE: 2786 res = new SchemaResponse();
2773 res = new UpdateResponse( 2787 break;
2774 sohp.getNextAsInt(), // count 2788 case StartOfHeaderParser.Q_TRANS:
2775 sohp.getNextAsString() // key-id 2789 boolean ac = sohp.getNextAsString().equals("t") ? true : false;
2776 ); 2790 if (autoCommit && ac) {
2791 addWarning("Server enabled auto commit mode " +
2792 "while local state already was auto commit.", "01M11");
2793 }
2794 autoCommit = ac;
2795 res = new AutoCommitResponse(ac);
2796 break;
2797 case StartOfHeaderParser.Q_BLOCK: {
2798 // a new block of results for a response...
2799 int id = sohp.getNextAsInt();
2800 sohp.getNextAsInt(); // columncount
2801 int rowcount = sohp.getNextAsInt();
2802 int offset = sohp.getNextAsInt();
2803 ResultSetResponse t = rsresponses.get(Integer.valueOf(id));
2804 if (t == null) {
2805 error = "M0M12!no ResultSetResponse with id " + id + " found";
2777 break; 2806 break;
2778 case StartOfHeaderParser.Q_SCHEMA:
2779 res = new SchemaResponse();
2780 break;
2781 case StartOfHeaderParser.Q_TRANS:
2782 boolean ac = sohp.getNextAsString().equals("t") ? true : false;
2783 if (autoCommit && ac) {
2784 addWarning("Server enabled auto commit " +
2785 "mode while local state " +
2786 "already was auto commit.", "01M11"
2787 );
2788 }
2789 autoCommit = ac;
2790 res = new AutoCommitResponse(ac);
2791 break;
2792 case StartOfHeaderParser.Q_BLOCK: {
2793 // a new block of results for a
2794 // response...
2795 int id = sohp.getNextAsInt();
2796 sohp.getNextAsInt(); // columncount
2797 int rowcount = sohp.getNextAsInt();
2798 int offset = sohp.getNextAsInt();
2799 ResultSetResponse t =
2800 rsresponses.get(Integer.valueOf(id));
2801 if (t == null) {
2802 error = "M0M12!no ResultSetResponse with id " + id + " found";
2803 break;
2804 }
2805
2806 DataBlockResponse r =
2807 new DataBlockResponse(
2808 rowcount, // rowcount
2809 t.getRSType() == ResultSet.TYPE_FORWARD_ONLY
2810 );
2811
2812 t.addDataBlockResponse(offset, r);
2813 res = r;
2814 } break;
2815 } 2807 }
2816 } catch (MCLParseException e) { 2808 DataBlockResponse r = new DataBlockResponse(rowcount, t.getRSType() == ResultSet.TYPE_FORWARD_ONLY);
2817 error = "M0M10!error while parsing start of header:\n" + 2809 t.addDataBlockResponse(offset, r);
2818 e.getMessage() + 2810 res = r;
2819 " found: '" + tmpLine.charAt(e.getErrorOffset()) + "'" + 2811 } break;
2820 " in: \"" + tmpLine + "\"" + 2812 } // end of switch (sohp.parse(tmpLine))
2821 " at pos: " + e.getErrorOffset(); 2813 } catch (MCLParseException e) {
2822 // flush all the rest 2814 error = "M0M10!error while parsing start of header:\n" +
2815 e.getMessage() +
2816 " found: '" + tmpLine.charAt(e.getErrorOffset()) + "'" +
2817 " in: \"" + tmpLine + "\"" +
2818 " at pos: " + e.getErrorOffset();
2819 // flush all the rest
2820 in.waitForPrompt();
2821 linetype = in.getLineType();
2822 break;
2823 }
2824
2825 // immediately handle errors after parsing the header (res may be null)
2826 if (error != null) {
2827 in.waitForPrompt();
2828 linetype = in.getLineType();
2829 break;
2830 }
2831
2832 // here we have a res object, which we can start filling
2833 while (res.wantsMore()) {
2834 error = res.addLine(in.readLine(), in.getLineType());
2835 if (error != null) {
2836 // right, some protocol violation,
2837 // skip the rest of the result
2838 error = "M0M10!" + error;
2823 in.waitForPrompt(); 2839 in.waitForPrompt();
2824 linetype = in.getLineType(); 2840 linetype = in.getLineType();
2825 break; 2841 break;
2826 } 2842 }
2827 2843 }
2828 // immediately handle errors after parsing 2844 if (error != null)
2829 // the header (res may be null) 2845 break;
2830 if (error != null) { 2846
2831 in.waitForPrompt(); 2847 // it is of no use to store DataBlockReponses, you never want to
2832 linetype = in.getLineType(); 2848 // retrieve them directly anyway
2833 break; 2849 if (!(res instanceof DataBlockResponse))
2834 } 2850 responses.add(res);
2835 2851
2836 // here we have a res object, which 2852 // read the next line (can be prompt, new result, error, etc.)
2837 // we can start filling 2853 // before we start the loop over
2838 while (res.wantsMore()) { 2854 tmpLine = in.readLine();
2839 error = res.addLine( 2855 linetype = in.getLineType();
2840 in.readLine(),
2841 in.getLineType()
2842 );
2843 if (error != null) {
2844 // right, some protocol violation,
2845 // skip the rest of the result
2846 error = "M0M10!" + error;
2847 in.waitForPrompt();
2848 linetype = in.getLineType();
2849 break;
2850 }
2851 }
2852 if (error != null)
2853 break;
2854 // it is of no use to store
2855 // DataBlockReponses, you never want to
2856 // retrieve them directly anyway
2857 if (!(res instanceof DataBlockResponse))
2858 responses.add(res);
2859
2860 // read the next line (can be prompt, new
2861 // result, error, etc.) before we start the
2862 // loop over
2863 tmpLine = in.readLine();
2864 linetype = in.getLineType();
2865 break; 2856 break;
2866 case BufferedMCLReader.INFO: 2857 case BufferedMCLReader.INFO:
2867 addWarning(tmpLine.substring(1), "01000"); 2858 addWarning(tmpLine.substring(1), "01000");
2868 2859 // read the next line (can be prompt, new result, error, etc.)
2869 // read the next line (can be prompt, new 2860 // before we start the loop over
2870 // result, error, etc.) before we start the 2861 tmpLine = in.readLine();
2871 // loop over 2862 linetype = in.getLineType();
2872 tmpLine = in.readLine();
2873 linetype = in.getLineType();
2874 break; 2863 break;
2875 default: // Yeah... in Java this is correct! 2864 default: // Yeah... in Java this is correct!
2876 // we have something we don't 2865 // we have something we don't expect/understand, let's make it an error message
2877 // expect/understand, let's make it an error 2866 tmpLine = "!M0M10!protocol violation, unexpected line: " + tmpLine;
2878 // message 2867 // don't break; fall through...
2879 tmpLine = "!M0M10!protocol violation, unexpected line: " + tmpLine; 2868 case BufferedMCLReader.ERROR:
2880 // don't break; fall through... 2869 // read everything till the prompt (should be
2881 case BufferedMCLReader.ERROR: 2870 // error) we don't know if we ignore some
2882 // read everything till the prompt (should be 2871 // garbage here... but the log should reveal that
2883 // error) we don't know if we ignore some 2872 error = in.waitForPrompt();
2884 // garbage here... but the log should reveal 2873 linetype = in.getLineType();
2885 // that 2874 if (error != null) {
2886 error = in.waitForPrompt(); 2875 error = tmpLine.substring(1) + "\n" + error;
2887 linetype = in.getLineType(); 2876 } else {
2888 if (error != null) { 2877 error = tmpLine.substring(1);
2889 error = tmpLine.substring(1) + "\n" + error; 2878 }
2890 } else {
2891 error = tmpLine.substring(1);
2892 }
2893 break; 2879 break;
2894 } 2880 } // end of switch (linetype)
2895 } 2881 } // end of while (linetype != BufferedMCLReader.PROMPT)
2896 } 2882 } // end of synchronized (server)
2897 2883
2898 // if we used the sendThread, make sure it has finished 2884 // if we used the sendThread, make sure it has finished
2899 if (sendThreadInUse) { 2885 if (sendThreadInUse) {
2900 String tmp = sendThread.getErrors(); 2886 String tmp = sendThread.getErrors();
2901 if (tmp != null) { 2887 if (tmp != null) {