Mercurial > hg > monetdb-java
changeset 255:96057ee68017 embedded
Merge with default.
author | Pedro Ferreira <pedro.ferreira@monetdbsolutions.com> |
---|---|
date | Fri, 09 Nov 2018 12:18:51 +0100 (2018-11-09) |
parents | 14e6f812b43c (current diff) 27b7166860c8 (diff) |
children | 4face9f42efc |
files | example/SQLcopyinto.java src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java src/main/java/nl/cwi/monetdb/jdbc/MonetDatabaseMetaData.java src/main/java/nl/cwi/monetdb/jdbc/MonetDriver.java.in src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java tests/SQLcopyinto.java tests/build.xml |
diffstat | 9 files changed, 242 insertions(+), 213 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,39 +1,12 @@ # ChangeLog file for monetdb-java # This file is updated with Maddlog -* Wed May 23 2018 Sjoerd Mullender <sjoerd@acm.org> -- Compiled and released new jars: monetdb-jdbc-2.28.jar, monetdb-mcl-1.17.jar - and updated jdbcclient.jar - -* Thu Apr 26 2018 Martin van Dinther <martin.van.dinther@monetdbsolutions.com> -- Corrected and extended output of DatabaseMetaData methods - getTimeDateFunctions() and getSystemFunctions(). The Date/Time functions - (curdate, current_date, current_time, current_timestamp, curtime, - local_timezone, localtime, localtimestamp) were returned by - getSystemFunctions() but are now returned by getTimeDateFunctions(). - getTimeDateFunctions() now also lists functions: date_to_str, extract, now, - str_to_date, str_to_time, str_to_timestamp, time_to_str and timestamp_to_str. -- Improved DatabaseMetaData methods getTablePrivileges() and - getColumnPrivileges() by returning also any combination of privileges - for the table or column in the PRIVILEGE result column. Previously only - single privileges (SELECT or UPDATE or INSERT or DELETE or EXECUTE or - GRANT) would be returned. +* Thu Sep 20 2018 Martin van Dinther <martin.van.dinther@monetdbsolutions.com> +- Improved example program SQLcopyinto.java and moved it to tests directory + for automatic testing. -* Thu Apr 19 2018 Martin van Dinther <martin.van.dinther@monetdbsolutions.com> -- Corrected method DatabaseMetaData.getFunctions() for result column - FUNCTION_TYPE. It used to return DatabaseMetaData.functionResultUnknown - value for Analytic (functions.type 6) and Loader function (functions type 7). - It now returns DatabaseMetaData.functionNoTable for Analytic functions and - DatabaseMetaData.functionReturnsTable for Loader functions. -- DatabaseMetaData methods getTables(), getColumns(), getProcedures() and - getFunctions() now return the comment in the REMARKS result column when a - comment has been set for the table / view / column / procedure / function - via the SQL command COMMENT ON <db-object type> <qname> IS 'comment-text'. +* Thu Jun 28 2018 Martin van Dinther <martin.van.dinther@monetdbsolutions.com> +- Corrected return values of DatabaseMetaData methods + allTablesAreSelectable() and allProceduresAreCallable(). + They used to return true but now return false. -* Thu Dec 14 2017 Martin van Dinther <martin.van.dinther@monetdbsolutions.com> -- Fixed a problem with retrieving Dates and Timestamps which contained a - year value less than 1000. It would throw an SQLDataException with message: - Could not convert value to a Date. Expected JDBC date escape format - yyyy-[m]m-[d]d. - See also: https://www.monetdb.org/bugzilla/show_bug.cgi?id=6468 -
deleted file mode 100644 --- a/example/SQLcopyinto.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright 1997 - July 2008 CWI, August 2008 - 2018 MonetDB B.V. - */ - -import java.sql.*; -import java.io.*; -import java.util.*; - -import nl.cwi.monetdb.mcl.connection.mapi.MapiConnection; -import nl.cwi.monetdb.mcl.protocol.AbstractProtocol; - -/** - * This example demonstrates how the MonetDB JDBC driver can facilitate - * in performing COPY INTO sequences. This is mainly meant to show how - * a quick load can be performed from Java. - * - * @author Fabian Groffen - */ - -public class SQLcopyinto { - public static void main(String[] args) throws Exception { - // request a connection suitable for Monet from the driver manager - // note that the database specifier is currently not implemented, for - // Monet itself can't access multiple databases. - // turn on debugging - Connection con = DriverManager.getConnection("jdbc:monetdb://localhost/database", "monetdb", "monetdb"); - - // get a statement to execute on - Statement stmt = con.createStatement(); - - String query = "CREATE TABLE example (id int, val varchar(24))"; - try { - stmt.execute(query); - } catch (SQLException e) { - System.out.println(query + ": " + e.getMessage()); - System.exit(1); - } - - // now create a connection manually to perform a load, this can - // of course also be done simultaneously with the JDBC - // connection being kept connected - - MapiConnection server = new MapiConnection(null, null, "sql", false, true,"localhost", 50000, "database"); - - try { - List warning = server.connect("monetdb", "monetdb"); - if (warning != null) { - for (Object aWarning : warning) { - System.out.println(aWarning.toString()); - } - } - AbstractProtocol oldmMapiProtocol = server.getProtocol(); - - oldmMapiProtocol.waitUntilPrompt(); - String error = oldmMapiProtocol.getRemainingStringLine(0); - if (error != null) - throw new Exception(error); - - query = "COPY INTO example FROM STDIN USING DELIMITERS ',','\\n';"; - // the leading 's' is essential, since it is a protocol - // marker that should not be omitted, likewise the - // trailing semicolon - oldmMapiProtocol.writeNextQuery("s", query, "\n"); - - for (int i = 0; i < 100; i++) { - oldmMapiProtocol.writeNextQuery(null, "" + i + ",val_" + i, "\n"); - } - oldmMapiProtocol.waitUntilPrompt(); - error = oldmMapiProtocol.getRemainingStringLine(0); - if (error != null) - throw new Exception(error); - // disconnect from server - server.close(); - } catch (IOException e) { - System.err.println("unable to connect: " + e.getMessage()); - System.exit(-1); - } catch (Exception e) { - System.err.println(e.getMessage()); - System.exit(-1); - } - - query = "SELECT COUNT(*) FROM example"; - ResultSet rs = null; - try { - rs = stmt.executeQuery(query); - } catch (SQLException e) { - System.out.println(query + ": " + e.getMessage()); - System.exit(1); - } - if (rs != null && rs.next()) - System.out.println(rs.getString(1)); - - // free resources, close the statement - stmt.close(); - // close the connection with the database - con.close(); - - } -}
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java @@ -178,6 +178,8 @@ public abstract class MonetConnection ex private boolean queriedCommentsTable = false; private boolean hasCommentsTable = false; + /** The last set query timeout on the server as used by Statement and PreparedStatement (and CallableStatement in future) */ + protected int lastSetQueryTimeout = 0; // 0 means no timeout, which is the default on the server /** * Gets the initial value for the StringBuilder size. @@ -1026,7 +1028,8 @@ public abstract class MonetConnection ex */ @Override public String toString() { - return "MonetDB Connection (" + this.getJDBCURL() + ") " + (closed ? "disconnected" : "connected"); + return "MonetDB Connection (" + getJDBCURL() + ") " + + (closed ? "disconnected" : "connected"); } /**
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetDatabaseMetaData.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetDatabaseMetaData.java @@ -107,25 +107,27 @@ public class MonetDatabaseMetaData exten } /** - * Can all the procedures returned by getProcedures be called - * by the current user? + * Retrieves whether the current user can call all the procedures + * returned by the method getProcedures. * - * @return true if so + * @return false because we currently return all procedures from sys.functions + * and do not filter on EXECUTE privilege or procedure ownership. */ @Override public boolean allProceduresAreCallable() { - return true; + return false; } /** - * Can all the tables returned by getTable be SELECTed by - * the current user? + * Retrieves whether the current user can use all the tables + * returned by the method getTables in a SELECT statement. * - * @return true because we only have one user a.t.m. + * @return false because we currently return all tables from sys.tables + * and do not filter on SELECT privilege or table ownership. */ @Override public boolean allTablesAreSelectable() { - return true; + return false; } /** @@ -1698,6 +1700,7 @@ public class MonetDatabaseMetaData exten * "" retrieves those without a schema; * null means that the schema name should not be used to narrow the search * @param procedureNamePattern - a procedure name pattern; must match the procedure name as it is stored in the database + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @return ResultSet - each row is a procedure description * @throws SQLException if a database access error occurs */ @@ -1807,7 +1810,9 @@ public class MonetDatabaseMetaData exten * "" retrieves those without a schema; * null means that the schema name should not be used to narrow the search * @param procedureNamePattern - a procedure name pattern; must match the procedure name as it is stored in the database + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @param columnNamePattern - a column name pattern; must match the column name as it is stored in the database + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @return ResultSet - each row describes a stored procedure parameter or column * @throws SQLException if a database-access error occurs * @see #getSearchStringEscape @@ -1877,7 +1882,7 @@ public class MonetDatabaseMetaData exten /** * Returns a SQL match part string where depending on the input value we - * compose an exact match (use =) or match with wildcards (use LIKE) + * compose an exact match (use =) or match with wildcards (use LIKE) or IS NULL * * @param in the string to match * @return the SQL match part string @@ -1941,6 +1946,7 @@ public class MonetDatabaseMetaData exten * null means that the schema name should not be used to narrow the search * @param tableNamePattern - a table name pattern; must match the table name as it is stored in the database * For all tables this should be "%" + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @param types - a list of table types, which must be from the list of table types returned * from getTableTypes(),to include; null returns all types * @return ResultSet - each row is a table description @@ -2199,7 +2205,9 @@ public class MonetDatabaseMetaData exten * null means that the schema name should not be used to narrow the search * @param tableNamePattern - a table name pattern; must match the table name as it is stored in the database * For all tables this should be "%" + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @param columnNamePattern - a column name pattern; must match the column name as it is stored in the database + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @return ResultSet - each row is a column description * @throws SQLException if a database error occurs * @see #getSearchStringEscape @@ -2295,7 +2303,9 @@ public class MonetDatabaseMetaData exten * @param catalog a catalog name; "" retrieves those without a catalog * @param schemaPattern a schema name; "" retrieves those without a schema * @param tableNamePattern a table name + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @param columnNamePattern a column name pattern + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @return ResultSet each row is a column privilege description * @see #getSearchStringEscape * @throws SQLException if a database error occurs @@ -2394,6 +2404,7 @@ public class MonetDatabaseMetaData exten * @param catalog a catalog name; "" retrieves those without a catalog * @param schemaPattern a schema name pattern; "" retrieves those without a schema * @param tableNamePattern a table name pattern + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @return ResultSet each row is a table privilege description * @see #getSearchStringEscape * @throws SQLException if a database error occurs @@ -2491,6 +2502,7 @@ public class MonetDatabaseMetaData exten * @param catalog a catalog name; "" retrieves those without a catalog * @param schema a schema name; "" retrieves those without a schema * @param table a table name + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @param scope the scope of interest; use same values as SCOPE * @param nullable include columns that are nullable? * @return ResultSet each row is a column description @@ -2577,6 +2589,7 @@ public class MonetDatabaseMetaData exten * @param catalog a catalog name; "" retrieves those without a catalog * @param schema a schema name; "" retrieves those without a schema * @param table a table name + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @return ResultSet each row is a column description * @throws SQLException if a database error occurs */ @@ -2617,9 +2630,9 @@ public class MonetDatabaseMetaData exten * </OL> * * @param catalog a catalog name; "" retrieves those without a catalog - * @param schema a schema name pattern; "" retrieves those - * without a schema + * @param schema a schema name pattern; "" retrieves those without a schema * @param table a table name + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @return ResultSet each row is a primary key column description * @throws SQLException if a database error occurs */ @@ -2754,6 +2767,7 @@ public class MonetDatabaseMetaData exten * @param catalog a catalog name; "" retrieves those without a catalog * @param schema a schema name pattern; "" retrieves those without a schema * @param table a table name + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @return ResultSet each row is a primary key column description * @see #getExportedKeys * @throws SQLException if a database error occurs @@ -2838,6 +2852,7 @@ public class MonetDatabaseMetaData exten * @param catalog a catalog name; "" retrieves those without a catalog * @param schema a schema name pattern; "" retrieves those without a schema * @param table a table name + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @return ResultSet each row is a foreign key column description * @see #getImportedKeys * @throws SQLException if a database error occurs @@ -2925,9 +2940,11 @@ public class MonetDatabaseMetaData exten * @param pcatalog primary key catalog name; "" retrieves those without a catalog * @param pschema primary key schema name pattern; "" retrieves those without a schema * @param ptable primary key table name + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @param fcatalog foreign key catalog name; "" retrieves those without a catalog * @param fschema foreign key schema name pattern; "" retrieves those without a schema * @param ftable koreign key table name + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @return ResultSet each row is a foreign key column description * @throws SQLException if a database error occurs * @see #getImportedKeys @@ -3102,6 +3119,7 @@ public class MonetDatabaseMetaData exten * @param catalog a catalog name; "" retrieves those without a catalog * @param schema a schema name pattern; "" retrieves those without a schema * @param table a table name + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @param unique when true, return only indices for unique values; * when false, return indices regardless of whether unique or not * @param approximate when true, result is allowed to reflect approximate @@ -3468,10 +3486,8 @@ public class MonetDatabaseMetaData exten * * @param catalog a catalog name; "" retrieves those without a catalog; * <code>null</code> means drop catalog name from the selection criteria - * @param schemaPattern a schema name pattern; "" retrieves those - * without a schema - * @param typeNamePattern a UDT name pattern; may be a fully-qualified - * name + * @param schemaPattern a schema name pattern; "" retrieves those without a schema + * @param typeNamePattern a UDT name pattern; may be a fully-qualified name * @return a <code>ResultSet</code> object in which a row gives information * about the designated UDT * @throws SQLException if a database access error occurs @@ -3516,10 +3532,8 @@ public class MonetDatabaseMetaData exten * * @param catalog a catalog name; "" retrieves those without a catalog; * <code>null</code> means drop catalog name from the selection criteria - * @param schemaPattern a schema name pattern; "" retrieves those - * without a schema - * @param tableNamePattern a table name pattern; may be a fully-qualified - * name + * @param schemaPattern a schema name pattern; "" retrieves those without a schema + * @param tableNamePattern a table name pattern; may be a fully-qualified name * @return a <code>ResultSet</code> object in which each row is a type description * @throws SQLException if a database access error occurs */ @@ -3905,6 +3919,7 @@ public class MonetDatabaseMetaData exten * not be used to narrow the search * @param functionNamePattern a function name pattern; must match * the function name as it is stored in the database + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @return ResultSet - each row is a function description * @throws SQLException if a database access error occurs */ @@ -4008,8 +4023,10 @@ public class MonetDatabaseMetaData exten * not be used to narrow the search * @param functionNamePattern a procedure name pattern; must match the * function name as it is stored in the database + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @param columnNamePattern a parameter name pattern; must match the * parameter or column name as it is stored in the database + * Note that our implementation allows this param to be null also (for efficiency as no extra LIKE "%" condition is added to be evaluated). * @return ResultSet - each row describes a user function parameter, * column or return type * @throws SQLException - if a database access error occurs
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetDriver.java.in +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetDriver.java.in @@ -386,7 +386,7 @@ public final class MonetDriver implement Properties props = new Properties(); if (!acceptsURL(url)) - throw new SQLException("Invalid URL: it does not start with: " + MONETURL, "08M26"); + return null; if(!url.startsWith("jdbc:monetdb:embedded:")) { // url should be of style jdbc:monetdb://<host>/<database> @@ -404,12 +404,12 @@ public final class MonetDriver implement try { uri = new URI(url.substring(5)); } catch (URISyntaxException e) { - throw new SQLNonTransientConnectionException(e.toString(), "08M26"); + return null; } String uri_host = uri.getHost(); if (uri_host == null) - throw new SQLNonTransientConnectionException("Invalid URL: no hostname given or unparsable in '" + url + "'", "08M26"); + return null; info.put("host", uri_host); int uri_port = uri.getPort();
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java @@ -59,9 +59,11 @@ public class MonetStatement extends Mone /** Whether this Statement object is closed or not */ protected boolean closed; /** Whether the application wants this Statement object to be pooled */ - boolean poolable; + protected boolean poolable; /** Whether this Statement should be closed if the last ResultSet closes */ private boolean closeOnCompletion = false; + /** The timeout (in sec) for the query to return, 0 means no timeout */ + private int queryTimeout = 0; /** The size of the blocks of results to ask for at the server */ private int fetchSize = 0; /** The maximum number of rows to return in a ResultSet, 0 indicates unlimited */ @@ -93,6 +95,7 @@ public class MonetStatement extends Mone this.connection = connection; this.resultSetType = resultSetType; this.resultSetConcurrency = resultSetConcurrency; + this.queryTimeout = connection.lastSetQueryTimeout; // check our limits, and generate warnings as appropriate if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) { @@ -216,7 +219,8 @@ public class MonetStatement extends Mone try { boolean type = internalExecute(batch); int count = -1; - if (!type) count = getUpdateCount(); + if (!type) + count = getUpdateCount(); do { if (offset >= max) throw new SQLException("Overflow: don't use multi statements when batching (" + max + ")", "M1M16"); @@ -451,6 +455,25 @@ public class MonetStatement extends Mone lastResponseList = null; } + if (queryTimeout != connection.lastSetQueryTimeout) { + // set requested/changed queryTimeout on the server side first + Statement st = null; + try { + st = connection.createStatement(); + String callstmt = "CALL \"sys\".\"settimeout\"(" + queryTimeout + ")"; + // for debug: System.out.println("Before: " + callstmt); + st.execute(callstmt); + // for debug: System.out.println("After : " + callstmt); + connection.lastSetQueryTimeout = queryTimeout; + } + /* do not catch SQLException here, as we want to know it when it fails */ + finally { + if (st != null) { + st.close(); + } + } + } + // create a container for the result lastResponseList = connection.new ResponseList(fetchSize, maxRows, resultSetType, resultSetConcurrency); // fill the header list by processing the query @@ -681,7 +704,7 @@ public class MonetStatement extends Mone * @see #setMaxFieldSize(int max) */ @Override - public int getMaxFieldSize() throws SQLException { + public int getMaxFieldSize() { return 2*1024*1024*1024 - 2; // MonetDB supports null terminated strings of max 2GB, see function: int UTF8_strlen() } @@ -696,7 +719,7 @@ public class MonetStatement extends Mone * @see #setMaxRows(int max) */ @Override - public int getMaxRows() throws SQLException { + public int getMaxRows() { return maxRows; } @@ -762,27 +785,8 @@ public class MonetStatement extends Mone * @see #setQueryTimeout(int) */ @Override - public int getQueryTimeout() throws SQLException { - Statement st = null; - ResultSet rs = null; - try { - st = connection.createStatement(); - rs = st.executeQuery("SELECT \"querytimeout\" FROM \"sys\".\"sessions\"() WHERE \"active\""); - if (rs != null && rs.next()) { - // MonetDB stores querytimeout in a bigint, so correctly deal with big int values - long timeout = rs.getLong(1); - return (timeout > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) timeout; - } - /* do not catch SQLException here, as we want to know it when it fails */ - } finally { - if (rs != null) { - rs.close(); - } - if (st != null) { - st.close(); - } - } - return 0; // in case the query didn't return a result (which should normally never happen) + public int getQueryTimeout() { + return queryTimeout; } /** @@ -815,7 +819,7 @@ public class MonetStatement extends Mone * @throws SQLException if a database access error occurs */ @Override - public int getResultSetHoldability() throws SQLException { + public int getResultSetHoldability() { return ResultSet.HOLD_CURSORS_OVER_COMMIT; } @@ -1027,20 +1031,9 @@ public class MonetStatement extends Mone */ @Override public void setQueryTimeout(int seconds) throws SQLException { - if (seconds < 0) { + if (seconds < 0) throw new SQLException("Illegal timeout value: " + seconds, "M1M05"); - } - Statement st = null; - try { - st = connection.createStatement(); - // CALL "sys"."settimeout"(int_value) - st.execute("CALL \"sys\".\"settimeout\"(" + seconds + ")"); - /* do not catch SQLException here, as we want to know it when it fails */ - } finally { - if (st != null) { - st.close(); - } - } + queryTimeout = seconds; } //== 1.6 methods (JDBC 4.0) @@ -1202,14 +1195,19 @@ final class MonetVirtualResultSet extend row = tupleCount + row + 1; } // now place the row not farther than just before or after the result - if (row < 0) row = 0; // before first - else if (row > tupleCount + 1) row = tupleCount + 1; // after last + if (row < 0) + row = 0; // before first + else if (row > tupleCount + 1) + row = tupleCount + 1; // after last // store it this.curRow = row; // see if we have the row - return !(row < 1 || row > tupleCount); + if (row < 1 || row > tupleCount) + return false; + + return true; } @Override
--- a/tests/BugSetQueryTimeout_Bug_3357.java +++ b/tests/BugSetQueryTimeout_Bug_3357.java @@ -16,17 +16,12 @@ public class BugSetQueryTimeout_Bug_3357 try { System.out.println("QueryTimeout = " + st.getQueryTimeout()); - st.setQueryTimeout(123); - System.out.println("QueryTimeout = " + st.getQueryTimeout()); - - st.setQueryTimeout(2134567890); - System.out.println("QueryTimeout = " + st.getQueryTimeout()); - - st.setQueryTimeout(0); - System.out.println("QueryTimeout = " + st.getQueryTimeout()); - - st.setQueryTimeout(-1); // to generate an SQLException as negative timeouts are invalid - System.out.println("QueryTimeout = " + st.getQueryTimeout()); + testTimeout(st, 123); + testTimeout(st, 123); + testTimeout(st, 2134567890); + testTimeout(st, 0); + testTimeout(st, 0); + testTimeout(st, -1); // to generate an SQLException as negative timeouts are invalid } catch (SQLException se) { System.out.println("setQueryTimeout(timeout_value) throws: " + se); } finally { @@ -34,4 +29,13 @@ public class BugSetQueryTimeout_Bug_3357 } con.close(); } + + private static void testTimeout(Statement st, int secs) throws SQLException { + st.setQueryTimeout(secs); + // as the call to set the timeout is delayed till a statement is executed, issue a select statment + ResultSet rs = st.executeQuery("SELECT " + secs); + if (rs != null) + rs.close(); + System.out.println("QueryTimeout = " + st.getQueryTimeout()); + } }
new file mode 100644 --- /dev/null +++ b/tests/SQLcopyinto.java @@ -0,0 +1,130 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2018 MonetDB B.V. + */ + +import java.sql.*; +import java.io.*; +import java.util.*; +import nl.cwi.monetdb.mcl.connection.mapi.MapiConnection; +import nl.cwi.monetdb.mcl.protocol.AbstractProtocol; + +/** + * This program demonstrates how the MonetDB JDBC driver can facilitate + * in performing COPY INTO ... FROM STDIN sequences. + * It shows how a data stream via MapiSocket to STDIN can be performed. + * + * @author Fabian Groffen, Martin van Dinther + */ + +public class SQLcopyinto { + final private static String tablenm = "exampleSQLCopyInto"; + + public static void main(String[] args) throws Exception { + System.out.println("SQLcopyinto started"); + if (args.length == 0) { + System.err.println("Error: missing startup argument: the jdbc connection url !"); + System.err.println("Usage: java -cp monetdb-jdbc-2.28.jar:. SQLcopyinto \"jdbc:monetdb://localhost:50000/demo?user=monetdb&password=monetdb\""); + System.exit(-1); + } + String jdbc_url = args[0]; + + // request a connection to MonetDB server via the driver manager + Connection conn = DriverManager.getConnection(jdbc_url); + System.out.println("Connected to MonetDB server"); + + Statement stmt = null; + ResultSet rs = null; + try { + stmt = conn.createStatement(); + stmt.execute("CREATE TABLE IF NOT EXISTS " + tablenm + " (id int, val varchar(24))"); + + fillTableUsingCopyIntoSTDIN(conn); + + // check content of the table populated via COPY INTO ... FROM STDIN + System.out.println("Listing uploaded data:"); + rs = stmt.executeQuery("SELECT * FROM " + tablenm); + if (rs != null) { + while (rs.next()) { + System.out.println("Row data: " + rs.getString(1) + ", " + rs.getString(2)); + } + rs.close(); + rs = null; + } + + stmt.execute("DROP TABLE " + tablenm); + + System.out.println("SQLcopyinto completed"); + } catch (SQLException e) { + System.err.println("SQLException: " + e.getMessage()); + } catch (Exception e) { + System.err.println("Exception: " + e.getMessage()); + } finally { + // free resources + if (rs != null) + rs.close(); + if (stmt != null) + stmt.close(); + // close the JDBC connection to MonetDB server + if (conn != null) + conn.close(); + } + } + + public static void fillTableUsingCopyIntoSTDIN(Connection mcon) throws Exception { + System.out.println(); + System.out.println("CopyInto STDIN begin"); + + MapiConnection server = new MapiConnection(null, null, "sql", false, true,"localhost", 50000, "database"); + try { + server.setSoTimeout(60); + + // extract from MonetConnection object the used connection properties + String host = mcon.getClientInfo("host"); + int port = Integer.parseInt(mcon.getClientInfo("port")); + String login = mcon.getClientInfo("user"); + String passw = mcon.getClientInfo("password"); + // System.out.println("host: " + host + " port: " + port + " login: " + login + " passwd: " + passw); + + System.out.println("Before connecting to MonetDB server via MapiSocket"); + List warning = server.connect("monetdb", "monetdb"); + if (warning != null) { + for (Iterator it = warning.iterator(); it.hasNext(); ) { + System.out.println("Warning: " + it.next().toString()); + } + } + System.out.println("Connected to MonetDB server via MapiSocket"); + AbstractProtocol oldmMapiProtocol = server.getProtocol(); + + String error = oldmMapiProtocol.getRemainingStringLine(0); + if (error != null) + System.err.println("Received start error: " + error); + + System.out.println("Before sending data to STDIN"); + + // the leading 's' is essential, since it is a protocol marker + // that should not be omitted, likewise the trailing semicolon + oldmMapiProtocol.writeNextQuery("s", "COPY INTO " + tablenm + " FROM STDIN USING DELIMITERS ',','\\n';", "\n"); + // now write the row data values as csv data lines to the STDIN stream + for (int i = 0; i < 40; i++) { + oldmMapiProtocol.writeNextQuery(null, "" + i + ",val_" + i, "\n"); + } + oldmMapiProtocol.waitUntilPrompt(); + error = oldmMapiProtocol.getRemainingStringLine(0); + if (error != null) + System.err.println("Received error: " + error); + System.out.println("Completed sending data via STDIN"); + } catch (Exception e) { + System.err.println("Mapi Exception: " + e.getMessage()); + } finally { + // close connection to MonetDB server + server.close(); + } + + System.out.println("CopyInto STDIN end"); + System.out.println(); + } +}
--- a/tests/build.xml +++ b/tests/build.xml @@ -95,6 +95,7 @@ Copyright 1997 - July 2008 CWI, August 2 <!-- Run tests --> <target name="test"> + <antcall target="SQLcopyinto" /> <antcall target="Test_Cautocommit" /> <!-- <antcall target="Test_Cforkbomb" /> --> <antcall target="Test_CisValid" /> @@ -152,6 +153,12 @@ Copyright 1997 - July 2008 CWI, August 2 <!-- convenience targets for the outside caller to specify which test(s) should be run --> + <target name="SQLcopyinto"> + <antcall target="test_class"> + <param name="test.class" value="SQLcopyinto" /> + </antcall> + </target> + <target name="Test_Cautocommit"> <antcall target="test_class"> <param name="test.class" value="Test_Cautocommit" />