Mercurial > hg > monetdb-java
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) { |