comparison src/main/java/nl/cwi/monetdb/jdbc/MonetDatabaseMetaData.java @ 295:003ae6d881db

Add "final" keyword to method arguments and local variables where possible. It discovered some bugs in the MonetStatement constructor (changed the argument instead of object variable) which are fixed now. See also https://en.wikipedia.org/wiki/Final_(Java)
author Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
date Thu, 01 Aug 2019 20:18:43 +0200 (2019-08-01)
parents 894abb249de1
children 6db8f6702ce8
comparison
equal deleted inserted replaced
294:894abb249de1 295:003ae6d881db
15 import java.sql.ResultSet; 15 import java.sql.ResultSet;
16 import java.sql.ResultSetMetaData; 16 import java.sql.ResultSetMetaData;
17 import java.sql.RowIdLifetime; 17 import java.sql.RowIdLifetime;
18 import java.sql.Types; 18 import java.sql.Types;
19 19
20 import java.util.ArrayList;
21
22 /** 20 /**
23 * A DatabaseMetaData object suitable for the MonetDB database. 21 * A DatabaseMetaData object suitable for the MonetDB database.
24 * 22 *
25 * @author Fabian Groffen, Martin van Dinther 23 * @author Fabian Groffen, Martin van Dinther
26 * @version 0.7 24 * @version 0.7
27 */ 25 */
28 public class MonetDatabaseMetaData extends MonetWrapper implements DatabaseMetaData { 26 public class MonetDatabaseMetaData
27 extends MonetWrapper
28 implements DatabaseMetaData
29 {
29 private final Connection con; 30 private final Connection con;
30 31
31 // Internal cache for 3 server environment values 32 // Internal cache for 3 server environment values
32 private String env_current_user; 33 private String env_current_user;
33 private String env_monet_version; 34 private String env_monet_version;
34 private String env_max_clients; 35 private String env_max_clients;
35 36
36 public MonetDatabaseMetaData(Connection parent) { 37 public MonetDatabaseMetaData(final Connection parent) {
37 con = parent; 38 con = parent;
38 } 39 }
39 40
40 /** 41 /**
41 * Utility method to fetch some server environment values combined in one query for efficiency. 42 * Utility method to fetch some server environment values combined in one query for efficiency.
82 // for debug: System.out.println("Read: env_current_user: " + env_current_user + " env_monet_version: " + env_monet_version + " env_max_clients: " + env_max_clients); 83 // for debug: System.out.println("Read: env_current_user: " + env_current_user + " env_monet_version: " + env_monet_version + " env_max_clients: " + env_max_clients);
83 } 84 }
84 85
85 86
86 /** 87 /**
87 * Internal utility method to create a Statement object, execute a query and return the ResulSet object. 88 * Internal utility method to create a Statement object, execute a query and return the ResulSet object which allows scrolling.
88 * As the Statement object is created internally (the caller does not see it and thus can not close it), 89 * As the Statement object is created internally (the caller does not see it and thus can not close it),
89 * we set it to close (and free server resources) when the ResultSet object is closed by the caller. 90 * we set it to close (and free server resources) when the ResultSet object is closed by the caller.
90 */ 91 */
91 private ResultSet executeMetaDataQuery(String query) throws SQLException { 92 private ResultSet executeMetaDataQuery(final String query) throws SQLException {
92 Statement stmt = null; 93 final Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
93 ResultSet rs = null; 94 ResultSet rs = null;
94 stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
95 if (stmt != null) { 95 if (stmt != null) {
96 // for debug: System.out.println("SQL (len " + query.length() + "): " + query); 96 // for debug: System.out.println("SQL (len " + query.length() + "): " + query);
97 rs = stmt.executeQuery(query); 97 rs = stmt.executeQuery(query);
98 if (rs != null) { 98 if (rs != null) {
99 /* we want the statement object to be closed also when the resultset is closed by the caller */ 99 /* we want the statement object to be closed also when the resultset is closed by the caller */
408 * 408 *
409 * @return a comma separated list of MonetDB keywords 409 * @return a comma separated list of MonetDB keywords
410 */ 410 */
411 @Override 411 @Override
412 public String getSQLKeywords() { 412 public String getSQLKeywords() {
413 String keywords = getConcatenatedStringFromQuery("SELECT \"keyword\" FROM \"sys\".\"keywords\" ORDER BY 1"); 413 final String keywords = getConcatenatedStringFromQuery("SELECT \"keyword\" FROM \"sys\".\"keywords\" ORDER BY 1");
414 414
415 /* An old MonetDB server (pre Jul2015 release) will not have a table sys.keywords and return an empty String */ 415 /* An old MonetDB server (pre Jul2015 release) will not have a table sys.keywords and return an empty String */
416 return (keywords.isEmpty()) ? 416 return (keywords.isEmpty()) ?
417 /* for old servers return static list (as returned in clients/odbc/driver/SQLGetInfo.c case SQL_KEYWORDS:) */ 417 /* for old servers return static list (as returned in clients/odbc/driver/SQLGetInfo.c case SQL_KEYWORDS:) */
418 "ADMIN,AFTER,AGGREGATE,ALWAYS,ASYMMETRIC,ATOMIC," + 418 "ADMIN,AFTER,AGGREGATE,ALWAYS,ASYMMETRIC,ATOMIC," +
440 /** 440 /**
441 * Internal utility method getConcatenatedStringFromQuery(String query) 441 * Internal utility method getConcatenatedStringFromQuery(String query)
442 * args: query: SQL SELECT query. Only the output of the first column is concatenated. 442 * args: query: SQL SELECT query. Only the output of the first column is concatenated.
443 * @return a String of query result values concatenated into one string, and values separated by comma's 443 * @return a String of query result values concatenated into one string, and values separated by comma's
444 */ 444 */
445 private String getConcatenatedStringFromQuery(String query) { 445 private String getConcatenatedStringFromQuery(final String query) {
446 StringBuilder sb = new StringBuilder(1024); 446 final StringBuilder sb = new StringBuilder(1024);
447 Statement st = null; 447 Statement st = null;
448 ResultSet rs = null; 448 ResultSet rs = null;
449 try { 449 try {
450 st = con.createStatement(); 450 st = con.createStatement();
451 rs = st.executeQuery(query); 451 rs = st.executeQuery(query);
487 private static final String OrFunctionsMaxMin = " OR \"name\" IN ('sql_max','sql_min','least','greatest')"; 487 private static final String OrFunctionsMaxMin = " OR \"name\" IN ('sql_max','sql_min','least','greatest')";
488 private static final String FunctionsOrderBy1 = " ORDER BY 1"; 488 private static final String FunctionsOrderBy1 = " ORDER BY 1";
489 489
490 @Override 490 @Override
491 public String getNumericFunctions() { 491 public String getNumericFunctions() {
492 String match = 492 final String match =
493 "('tinyint', 'smallint', 'int', 'bigint', 'hugeint', 'decimal', 'double', 'real') )" + 493 "('tinyint', 'smallint', 'int', 'bigint', 'hugeint', 'decimal', 'double', 'real') )" +
494 " AND \"type\" = 1" + // only scalar functions 494 " AND \"type\" = 1" + // only scalar functions
495 // exclude functions which belong to the 'str' module 495 // exclude functions which belong to the 'str' module
496 " AND \"mod\" <> 'str')" + // to filter out string functions: 'code' and 'space' 496 " AND \"mod\" <> 'str')" + // to filter out string functions: 'code' and 'space'
497 " OR \"name\" IN ('degrees','fuse','pi','ms_round','ms_str','ms_trunc','radians')"; 497 " OR \"name\" IN ('degrees','fuse','pi','ms_round','ms_str','ms_trunc','radians')";
498 return getConcatenatedStringFromQuery(FunctionsSelect + FunctionsWhere + match + OrFunctionsMaxMin + FunctionsOrderBy1); 498 return getConcatenatedStringFromQuery(FunctionsSelect + FunctionsWhere + match + OrFunctionsMaxMin + FunctionsOrderBy1);
499 } 499 }
500 500
501 @Override 501 @Override
502 public String getStringFunctions() { 502 public String getStringFunctions() {
503 String match = 503 final String match =
504 "('char', 'varchar', 'clob', 'json') )" + 504 "('char', 'varchar', 'clob', 'json') )" +
505 // include functions which belong to the 'str' module 505 // include functions which belong to the 'str' module
506 " OR \"mod\" = 'str')"; 506 " OR \"mod\" = 'str')";
507 String unionPart = 507 final String unionPart =
508 // add system functions which are not listed in sys.functions but implemented in the SQL parser (see sql/server/sql_parser.y) 508 // add system functions which are not listed in sys.functions but implemented in the SQL parser (see sql/server/sql_parser.y)
509 " UNION SELECT 'position'"; 509 " UNION SELECT 'position'";
510 return getConcatenatedStringFromQuery(FunctionsSelect + FunctionsWhere + match + OrFunctionsMaxMin + unionPart + FunctionsOrderBy1); 510 return getConcatenatedStringFromQuery(FunctionsSelect + FunctionsWhere + match + OrFunctionsMaxMin + unionPart + FunctionsOrderBy1);
511 } 511 }
512 512
513 @Override 513 @Override
514 public String getSystemFunctions() { 514 public String getSystemFunctions() {
515 // Note: As of Apr2019 (11.33.3) release the system table systemfunctions is replaced by a view which queries functions.system 515 // Note: As of Apr2019 (11.33.3) release the system table systemfunctions is replaced by a view which queries functions.system
516 // TODO: Replace join to sys.systemfunctions with " AND \"system\" " but only if the server-version is >= 11.33.3 516 // TODO: Replace join to sys.systemfunctions with " AND \"system\" " but only if the server-version is >= 11.33.3
517 String wherePart = 517 final String wherePart =
518 "\"id\" NOT IN (SELECT \"func_id\" FROM \"sys\".\"args\" WHERE \"number\" = 1)" + // without any args 518 "\"id\" NOT IN (SELECT \"func_id\" FROM \"sys\".\"args\" WHERE \"number\" = 1)" + // without any args
519 " AND \"id\" IN (SELECT \"function_id\" FROM \"sys\".\"systemfunctions\")" + // only functions marked as system 519 " AND \"id\" IN (SELECT \"function_id\" FROM \"sys\".\"systemfunctions\")" + // only functions marked as system
520 " AND \"type\" = 1" + // only scalar functions 520 " AND \"type\" = 1" + // only scalar functions
521 // exclude functions which belong to the 'mtime' module 521 // exclude functions which belong to the 'mtime' module
522 " AND \"mod\" <> 'mtime'" + 522 " AND \"mod\" <> 'mtime'" +
531 return getConcatenatedStringFromQuery(FunctionsSelect + wherePart + FunctionsOrderBy1); 531 return getConcatenatedStringFromQuery(FunctionsSelect + wherePart + FunctionsOrderBy1);
532 } 532 }
533 533
534 @Override 534 @Override
535 public String getTimeDateFunctions() { 535 public String getTimeDateFunctions() {
536 String wherePart = 536 final String wherePart =
537 "\"mod\" IN ('mtime','timestamp') OR \"name\" IN ('localtime','localtimestamp','date_trunc')"; 537 "\"mod\" IN ('mtime','timestamp') OR \"name\" IN ('localtime','localtimestamp','date_trunc')";
538 String unionPart = 538 final String unionPart =
539 // add time date functions which are not listed in sys.functions but implemented in the SQL parser (see sql/server/sql_parser.y) 539 // add time date functions which are not listed in sys.functions but implemented in the SQL parser (see sql/server/sql_parser.y)
540 " UNION SELECT 'extract'" + 540 " UNION SELECT 'extract'" +
541 " UNION SELECT 'now'"; 541 " UNION SELECT 'now'";
542 return getConcatenatedStringFromQuery(FunctionsSelect + wherePart + OrFunctionsMaxMin + unionPart + FunctionsOrderBy1); 542 return getConcatenatedStringFromQuery(FunctionsSelect + wherePart + OrFunctionsMaxMin + unionPart + FunctionsOrderBy1);
543 } 543 }
636 * The JDBC types are the generic SQL data types defined in java.sql.Types. 636 * The JDBC types are the generic SQL data types defined in java.sql.Types.
637 * 637 *
638 * @return true if so; false otherwise 638 * @return true if so; false otherwise
639 */ 639 */
640 @Override 640 @Override
641 public boolean supportsConvert(int fromType, int toType) { 641 public boolean supportsConvert(final int fromType, final int toType) {
642 switch (fromType) { 642 switch (fromType) {
643 case Types.BOOLEAN: 643 case Types.BOOLEAN:
644 switch (toType) { 644 switch (toType) {
645 case Types.BOOLEAN: 645 case Types.BOOLEAN:
646 /* case Types.BIT: is not supported by MonetDB and will fail */ 646 /* case Types.BIT: is not supported by MonetDB and will fail */
1625 * @param level the values are defined in java.sql.Connection 1625 * @param level the values are defined in java.sql.Connection
1626 * @return true if so 1626 * @return true if so
1627 * @see Connection 1627 * @see Connection
1628 */ 1628 */
1629 @Override 1629 @Override
1630 public boolean supportsTransactionIsolationLevel(int level) { 1630 public boolean supportsTransactionIsolationLevel(final int level) {
1631 return level == Connection.TRANSACTION_SERIALIZABLE; 1631 return level == Connection.TRANSACTION_SERIALIZABLE;
1632 } 1632 }
1633 1633
1634 /** 1634 /**
1635 * Are both data definition and data manipulation transactions 1635 * Are both data definition and data manipulation transactions
1724 * @return ResultSet - each row is a procedure description 1724 * @return ResultSet - each row is a procedure description
1725 * @throws SQLException if a database access error occurs 1725 * @throws SQLException if a database access error occurs
1726 */ 1726 */
1727 @Override 1727 @Override
1728 public ResultSet getProcedures( 1728 public ResultSet getProcedures(
1729 String catalog, 1729 final String catalog,
1730 String schemaPattern, 1730 final String schemaPattern,
1731 String procedureNamePattern 1731 final String procedureNamePattern
1732 ) throws SQLException 1732 ) throws SQLException
1733 { 1733 {
1734 boolean useCommentsTable = ((MonetConnection)con).commentsTableExists(); 1734 final boolean useCommentsTable = ((MonetConnection)con).commentsTableExists();
1735 StringBuilder query = new StringBuilder(980); 1735 final StringBuilder query = new StringBuilder(980);
1736 query.append("SELECT cast(null as char(1)) AS \"PROCEDURE_CAT\", " + 1736 query.append("SELECT cast(null as char(1)) AS \"PROCEDURE_CAT\", " +
1737 "\"schemas\".\"name\" AS \"PROCEDURE_SCHEM\", " + 1737 "\"schemas\".\"name\" AS \"PROCEDURE_SCHEM\", " +
1738 "\"functions\".\"name\" AS \"PROCEDURE_NAME\", " + 1738 "\"functions\".\"name\" AS \"PROCEDURE_NAME\", " +
1739 "cast(null as char(1)) AS \"Field4\", " + 1739 "cast(null as char(1)) AS \"Field4\", " +
1740 "cast(null as char(1)) AS \"Field5\", " + 1740 "cast(null as char(1)) AS \"Field5\", " +
1837 * @throws SQLException if a database-access error occurs 1837 * @throws SQLException if a database-access error occurs
1838 * @see #getSearchStringEscape 1838 * @see #getSearchStringEscape
1839 */ 1839 */
1840 @Override 1840 @Override
1841 public ResultSet getProcedureColumns( 1841 public ResultSet getProcedureColumns(
1842 String catalog, 1842 final String catalog,
1843 String schemaPattern, 1843 final String schemaPattern,
1844 String procedureNamePattern, 1844 final String procedureNamePattern,
1845 String columnNamePattern 1845 final String columnNamePattern
1846 ) throws SQLException { 1846 ) throws SQLException {
1847 StringBuilder query = new StringBuilder(2900); 1847 final StringBuilder query = new StringBuilder(2900);
1848 query.append("SELECT cast(null as char(1)) AS \"PROCEDURE_CAT\", " + 1848 query.append("SELECT cast(null as char(1)) AS \"PROCEDURE_CAT\", " +
1849 "\"schemas\".\"name\" AS \"PROCEDURE_SCHEM\", " + 1849 "\"schemas\".\"name\" AS \"PROCEDURE_SCHEM\", " +
1850 "\"functions\".\"name\" AS \"PROCEDURE_NAME\", " + 1850 "\"functions\".\"name\" AS \"PROCEDURE_NAME\", " +
1851 "\"args\".\"name\" AS \"COLUMN_NAME\", " + 1851 "\"args\".\"name\" AS \"COLUMN_NAME\", " +
1852 "cast(CASE \"args\".\"inout\"" + 1852 "cast(CASE \"args\".\"inout\"" +
1905 * compose an exact match (use =) or match with wildcards (use LIKE) or IS NULL 1905 * compose an exact match (use =) or match with wildcards (use LIKE) or IS NULL
1906 * 1906 *
1907 * @param in the string to match 1907 * @param in the string to match
1908 * @return the SQL match part string 1908 * @return the SQL match part string
1909 */ 1909 */
1910 private static final String composeMatchPart(String in) { 1910 private static final String composeMatchPart(final String in) {
1911 if (in == null) 1911 if (in == null)
1912 return "IS NULL"; 1912 return "IS NULL";
1913 1913
1914 String sql = "= '"; 1914 String sql = "= '";
1915 // check if SQL wildcards are used in the input, if so use LIKE 1915 // check if SQL wildcards are used in the input, if so use LIKE
1916 if (in.contains("%") || in.contains("_")) 1916 if (in.contains("%") || in.contains("_"))
1917 sql = "LIKE '"; 1917 sql = "LIKE '";
1918 1918
1919 // all slashes and single quotes in input are escaped with a slash. 1919 // all slashes and single quotes in input are escaped with a slash.
1920 String escaped = in.replaceAll("\\\\", "\\\\\\\\").replaceAll("'", "\\\\'"); 1920 final String escaped = in.replaceAll("\\\\", "\\\\\\\\").replaceAll("'", "\\\\'");
1921 1921
1922 return sql + escaped + "'"; 1922 return sql + escaped + "'";
1923 } 1923 }
1924 1924
1925 /** 1925 /**
1972 * @return ResultSet - each row is a table description 1972 * @return ResultSet - each row is a table description
1973 * @throws SQLException if a database-access error occurs. 1973 * @throws SQLException if a database-access error occurs.
1974 */ 1974 */
1975 @Override 1975 @Override
1976 public ResultSet getTables( 1976 public ResultSet getTables(
1977 String catalog, 1977 final String catalog,
1978 String schemaPattern, 1978 final String schemaPattern,
1979 String tableNamePattern, 1979 final String tableNamePattern,
1980 String types[] 1980 final String types[]
1981 ) throws SQLException 1981 ) throws SQLException
1982 { 1982 {
1983 // as of Jul2015 release the sys.tables.type values (0 through 6) is extended with new values 10, 11, 20, and 30 (for system and temp tables/views). 1983 // as of Jul2015 release the sys.tables.type values (0 through 6) is extended with new values 10, 11, 20, and 30 (for system and temp tables/views).
1984 // as of Jul2015 release we also have a new table: sys.table_types with names for the new table types 1984 // as of Jul2015 release we also have a new table: sys.table_types with names for the new table types
1985 // for correct behavior we need to know if the server is using the old (pre Jul2015) or new sys.tables.type values 1985 // for correct behavior we need to know if the server is using the old (pre Jul2015) or new sys.tables.type values
1986 boolean preJul2015 = ("11.19.15".compareTo(getDatabaseProductVersion()) >= 0); 1986 final boolean preJul2015 = ("11.19.15".compareTo(getDatabaseProductVersion()) >= 0);
1987 /* for debug: System.out.println("getDatabaseProductVersion() is " + getDatabaseProductVersion() + " preJul2015 is " + preJul2015); */ 1987 /* for debug: System.out.println("getDatabaseProductVersion() is " + getDatabaseProductVersion() + " preJul2015 is " + preJul2015); */
1988 1988
1989 boolean useCommentsTable = ((MonetConnection)con).commentsTableExists(); 1989 final boolean useCommentsTable = ((MonetConnection)con).commentsTableExists();
1990 StringBuilder query = new StringBuilder(1600); 1990 final StringBuilder query = new StringBuilder(1600);
1991 if (preJul2015 && types != null && types.length > 0) { 1991 if (preJul2015 && types != null && types.length > 0) {
1992 // we need to filter on the constructed "TABLE_TYPE" expression, this is only possible when we use a subquery in the FROM 1992 // we need to filter on the constructed "TABLE_TYPE" expression, this is only possible when we use a subquery in the FROM
1993 query.append("SELECT * FROM ("); 1993 query.append("SELECT * FROM (");
1994 } 1994 }
1995 query.append("SELECT cast(null as char(1)) AS \"TABLE_CAT\", " + 1995 query.append("SELECT cast(null as char(1)) AS \"TABLE_CAT\", " +
2081 * @return ResultSet each row has a single String column that is a 2081 * @return ResultSet each row has a single String column that is a
2082 * schema name 2082 * schema name
2083 * @throws SQLException if a database error occurs 2083 * @throws SQLException if a database error occurs
2084 */ 2084 */
2085 @Override 2085 @Override
2086 public ResultSet getSchemas(String catalog, String schemaPattern) 2086 public ResultSet getSchemas(final String catalog, final String schemaPattern)
2087 throws SQLException 2087 throws SQLException
2088 { 2088 {
2089 StringBuilder query = new StringBuilder(170); 2089 final StringBuilder query = new StringBuilder(170);
2090 query.append("SELECT \"name\" AS \"TABLE_SCHEM\", " + 2090 query.append("SELECT \"name\" AS \"TABLE_SCHEM\", " +
2091 "cast(null as char(1)) AS \"TABLE_CATALOG\" " + 2091 "cast(null as char(1)) AS \"TABLE_CATALOG\" " +
2092 "FROM \"sys\".\"schemas\""); 2092 "FROM \"sys\".\"schemas\"");
2093 2093
2094 if (catalog != null && !catalog.isEmpty()) { 2094 if (catalog != null && !catalog.isEmpty()) {
2142 * @throws SQLException if a database error occurs 2142 * @throws SQLException if a database error occurs
2143 */ 2143 */
2144 @Override 2144 @Override
2145 public ResultSet getTableTypes() throws SQLException { 2145 public ResultSet getTableTypes() throws SQLException {
2146 // as of Jul2015 release we have a new table: sys.table_types with more table types 2146 // as of Jul2015 release we have a new table: sys.table_types with more table types
2147 String query = "SELECT \"table_type_name\" AS \"TABLE_TYPE\" FROM \"sys\".\"table_types\" ORDER BY 1";
2148 // For old (pre jul2015) servers fall back to old behavior. 2147 // For old (pre jul2015) servers fall back to old behavior.
2149 boolean preJul2015 = ("11.19.15".compareTo(getDatabaseProductVersion()) >= 0); 2148 final boolean preJul2015 = ("11.19.15".compareTo(getDatabaseProductVersion()) >= 0);
2150 if (preJul2015) { 2149 final String query = preJul2015
2151 query = "SELECT 'SESSION TABLE' AS \"TABLE_TYPE\" UNION ALL " + 2150 ? "SELECT 'SESSION TABLE' AS \"TABLE_TYPE\" UNION ALL " +
2152 "SELECT 'SESSION VIEW' UNION ALL " + 2151 "SELECT 'SESSION VIEW' UNION ALL " +
2153 "SELECT 'SYSTEM SESSION TABLE' UNION ALL " + 2152 "SELECT 'SYSTEM SESSION TABLE' UNION ALL " +
2154 "SELECT 'SYSTEM SESSION VIEW' UNION ALL " + 2153 "SELECT 'SYSTEM SESSION VIEW' UNION ALL " +
2155 "SELECT 'SYSTEM TABLE' UNION ALL " + 2154 "SELECT 'SYSTEM TABLE' UNION ALL " +
2156 "SELECT 'SYSTEM VIEW' UNION ALL " + 2155 "SELECT 'SYSTEM VIEW' UNION ALL " +
2157 "SELECT 'TABLE' UNION ALL " + 2156 "SELECT 'TABLE' UNION ALL " +
2158 "SELECT 'VIEW' ORDER BY 1"; 2157 "SELECT 'VIEW' ORDER BY 1"
2159 } 2158 : "SELECT \"table_type_name\" AS \"TABLE_TYPE\" FROM \"sys\".\"table_types\" ORDER BY 1";
2160 2159
2161 return executeMetaDataQuery(query); 2160 return executeMetaDataQuery(query);
2162 } 2161 }
2163 2162
2164 /** 2163 /**
2232 * @throws SQLException if a database error occurs 2231 * @throws SQLException if a database error occurs
2233 * @see #getSearchStringEscape 2232 * @see #getSearchStringEscape
2234 */ 2233 */
2235 @Override 2234 @Override
2236 public ResultSet getColumns( 2235 public ResultSet getColumns(
2237 String catalog, 2236 final String catalog,
2238 String schemaPattern, 2237 final String schemaPattern,
2239 String tableNamePattern, 2238 final String tableNamePattern,
2240 String columnNamePattern 2239 final String columnNamePattern
2241 ) throws SQLException 2240 ) throws SQLException
2242 { 2241 {
2243 boolean useCommentsTable = ((MonetConnection)con).commentsTableExists(); 2242 final boolean useCommentsTable = ((MonetConnection)con).commentsTableExists();
2244 StringBuilder query = new StringBuilder(2450); 2243 final StringBuilder query = new StringBuilder(2450);
2245 query.append("SELECT cast(null as char(1)) AS \"TABLE_CAT\", " + 2244 query.append("SELECT cast(null as char(1)) AS \"TABLE_CAT\", " +
2246 "\"schemas\".\"name\" AS \"TABLE_SCHEM\", " + 2245 "\"schemas\".\"name\" AS \"TABLE_SCHEM\", " +
2247 "\"tables\".\"name\" AS \"TABLE_NAME\", " + 2246 "\"tables\".\"name\" AS \"TABLE_NAME\", " +
2248 "\"columns\".\"name\" AS \"COLUMN_NAME\", " + 2247 "\"columns\".\"name\" AS \"COLUMN_NAME\", " +
2249 "cast(").append(MonetDriver.getSQLTypeMap("\"columns\".\"type\"")).append(" AS int) AS \"DATA_TYPE\", " + 2248 "cast(").append(MonetDriver.getSQLTypeMap("\"columns\".\"type\"")).append(" AS int) AS \"DATA_TYPE\", " +
2330 * @see #getSearchStringEscape 2329 * @see #getSearchStringEscape
2331 * @throws SQLException if a database error occurs 2330 * @throws SQLException if a database error occurs
2332 */ 2331 */
2333 @Override 2332 @Override
2334 public ResultSet getColumnPrivileges( 2333 public ResultSet getColumnPrivileges(
2335 String catalog, 2334 final String catalog,
2336 String schemaPattern, 2335 final String schemaPattern,
2337 String tableNamePattern, 2336 final String tableNamePattern,
2338 String columnNamePattern 2337 final String columnNamePattern
2339 ) throws SQLException 2338 ) throws SQLException
2340 { 2339 {
2341 boolean usePrivilege_codesTable = ((MonetConnection)con).privilege_codesTableExists(); 2340 final boolean usePrivilege_codesTable = ((MonetConnection)con).privilege_codesTableExists();
2342 StringBuilder query = new StringBuilder(1100); 2341 final StringBuilder query = new StringBuilder(1100);
2343 query.append("SELECT cast(null as char(1)) AS \"TABLE_CAT\", " + 2342 query.append("SELECT cast(null as char(1)) AS \"TABLE_CAT\", " +
2344 "\"schemas\".\"name\" AS \"TABLE_SCHEM\", " + 2343 "\"schemas\".\"name\" AS \"TABLE_SCHEM\", " +
2345 "\"tables\".\"name\" AS \"TABLE_NAME\", " + 2344 "\"tables\".\"name\" AS \"TABLE_NAME\", " +
2346 "\"columns\".\"name\" AS \"COLUMN_NAME\", " + 2345 "\"columns\".\"name\" AS \"COLUMN_NAME\", " +
2347 "\"grantors\".\"name\" AS \"GRANTOR\", " + 2346 "\"grantors\".\"name\" AS \"GRANTOR\", " +
2429 * @see #getSearchStringEscape 2428 * @see #getSearchStringEscape
2430 * @throws SQLException if a database error occurs 2429 * @throws SQLException if a database error occurs
2431 */ 2430 */
2432 @Override 2431 @Override
2433 public ResultSet getTablePrivileges( 2432 public ResultSet getTablePrivileges(
2434 String catalog, 2433 final String catalog,
2435 String schemaPattern, 2434 final String schemaPattern,
2436 String tableNamePattern 2435 final String tableNamePattern
2437 ) throws SQLException 2436 ) throws SQLException
2438 { 2437 {
2439 boolean usePrivilege_codesTable = ((MonetConnection)con).privilege_codesTableExists(); 2438 final boolean usePrivilege_codesTable = ((MonetConnection)con).privilege_codesTableExists();
2440 StringBuilder query = new StringBuilder(1000); 2439 final StringBuilder query = new StringBuilder(1000);
2441 query.append("SELECT cast(null as char(1)) AS \"TABLE_CAT\", " + 2440 query.append("SELECT cast(null as char(1)) AS \"TABLE_CAT\", " +
2442 "\"schemas\".\"name\" AS \"TABLE_SCHEM\", " + 2441 "\"schemas\".\"name\" AS \"TABLE_SCHEM\", " +
2443 "\"tables\".\"name\" AS \"TABLE_NAME\", " + 2442 "\"tables\".\"name\" AS \"TABLE_NAME\", " +
2444 "\"grantors\".\"name\" AS \"GRANTOR\", " + 2443 "\"grantors\".\"name\" AS \"GRANTOR\", " +
2445 "\"grantees\".\"name\" AS \"GRANTEE\", ") 2444 "\"grantees\".\"name\" AS \"GRANTEE\", ")
2528 * @return ResultSet each row is a column description 2527 * @return ResultSet each row is a column description
2529 * @throws SQLException if a database error occurs 2528 * @throws SQLException if a database error occurs
2530 */ 2529 */
2531 @Override 2530 @Override
2532 public ResultSet getBestRowIdentifier( 2531 public ResultSet getBestRowIdentifier(
2533 String catalog, 2532 final String catalog,
2534 String schema, 2533 final String schema,
2535 String table, 2534 final String table,
2536 int scope, 2535 final int scope,
2537 boolean nullable 2536 final boolean nullable
2538 ) throws SQLException 2537 ) throws SQLException
2539 { 2538 {
2540 StringBuilder query = new StringBuilder(1500); 2539 final StringBuilder query = new StringBuilder(1500);
2541 query.append("SELECT cast(").append(DatabaseMetaData.bestRowSession).append(" AS smallint) AS \"SCOPE\", " + 2540 query.append("SELECT cast(").append(DatabaseMetaData.bestRowSession).append(" AS smallint) AS \"SCOPE\", " +
2542 "\"columns\".\"name\" AS \"COLUMN_NAME\", " + 2541 "\"columns\".\"name\" AS \"COLUMN_NAME\", " +
2543 "cast(").append(MonetDriver.getSQLTypeMap("\"columns\".\"type\"")).append(" AS int) AS \"DATA_TYPE\", " + 2542 "cast(").append(MonetDriver.getSQLTypeMap("\"columns\".\"type\"")).append(" AS int) AS \"DATA_TYPE\", " +
2544 "\"columns\".\"type\" AS \"TYPE_NAME\", " + 2543 "\"columns\".\"type\" AS \"TYPE_NAME\", " +
2545 "\"columns\".\"type_digits\" AS \"COLUMN_SIZE\", " + 2544 "\"columns\".\"type_digits\" AS \"COLUMN_SIZE\", " +
2613 * @return ResultSet each row is a column description 2612 * @return ResultSet each row is a column description
2614 * @throws SQLException if a database error occurs 2613 * @throws SQLException if a database error occurs
2615 */ 2614 */
2616 @Override 2615 @Override
2617 public ResultSet getVersionColumns( 2616 public ResultSet getVersionColumns(
2618 String catalog, 2617 final String catalog,
2619 String schema, 2618 final String schema,
2620 String table 2619 final String table
2621 ) throws SQLException 2620 ) throws SQLException
2622 { 2621 {
2623 // MonetDB currently does not have columns which update themselves, so return an empty ResultSet 2622 // MonetDB currently does not have columns which update themselves, so return an empty ResultSet
2624 String query = 2623 final String query =
2625 "SELECT cast(0 as smallint) AS \"SCOPE\", " + 2624 "SELECT cast(0 as smallint) AS \"SCOPE\", " +
2626 "cast(null as char(1)) AS \"COLUMN_NAME\", " + 2625 "cast(null as char(1)) AS \"COLUMN_NAME\", " +
2627 "cast(0 as int) AS \"DATA_TYPE\", " + 2626 "cast(0 as int) AS \"DATA_TYPE\", " +
2628 "cast(null as char(1)) AS \"TYPE_NAME\", " + 2627 "cast(null as char(1)) AS \"TYPE_NAME\", " +
2629 "cast(0 as int) AS \"COLUMN_SIZE\", " + 2628 "cast(0 as int) AS \"COLUMN_SIZE\", " +
2656 * @return ResultSet each row is a primary key column description 2655 * @return ResultSet each row is a primary key column description
2657 * @throws SQLException if a database error occurs 2656 * @throws SQLException if a database error occurs
2658 */ 2657 */
2659 @Override 2658 @Override
2660 public ResultSet getPrimaryKeys( 2659 public ResultSet getPrimaryKeys(
2661 String catalog, 2660 final String catalog,
2662 String schema, 2661 final String schema,
2663 String table 2662 final String table
2664 ) throws SQLException 2663 ) throws SQLException
2665 { 2664 {
2666 StringBuilder query = new StringBuilder(600); 2665 final StringBuilder query = new StringBuilder(600);
2667 query.append("SELECT cast(null AS char(1)) AS \"TABLE_CAT\", " + 2666 query.append("SELECT cast(null AS char(1)) AS \"TABLE_CAT\", " +
2668 "\"schemas\".\"name\" AS \"TABLE_SCHEM\", " + 2667 "\"schemas\".\"name\" AS \"TABLE_SCHEM\", " +
2669 "\"tables\".\"name\" AS \"TABLE_NAME\", " + 2668 "\"tables\".\"name\" AS \"TABLE_NAME\", " +
2670 "\"objects\".\"name\" AS \"COLUMN_NAME\", " + 2669 "\"objects\".\"name\" AS \"COLUMN_NAME\", " +
2671 "cast(1 + \"objects\".\"nr\" AS smallint) AS \"KEY_SEQ\", " + 2670 "cast(1 + \"objects\".\"nr\" AS smallint) AS \"KEY_SEQ\", " +
2791 * @return ResultSet each row is a primary key column description 2790 * @return ResultSet each row is a primary key column description
2792 * @see #getExportedKeys 2791 * @see #getExportedKeys
2793 * @throws SQLException if a database error occurs 2792 * @throws SQLException if a database error occurs
2794 */ 2793 */
2795 @Override 2794 @Override
2796 public ResultSet getImportedKeys(String catalog, String schema, String table) 2795 public ResultSet getImportedKeys(
2797 throws SQLException 2796 final String catalog,
2797 final String schema,
2798 final String table
2799 ) throws SQLException
2798 { 2800 {
2799 StringBuilder query = new StringBuilder(keyQuery.length() + 250); 2801 final StringBuilder query = new StringBuilder(keyQuery.length() + 250);
2800 query.append(keyQuery); 2802 query.append(keyQuery);
2801 2803
2802 if (catalog != null && !catalog.isEmpty()) { 2804 if (catalog != null && !catalog.isEmpty()) {
2803 // none empty catalog selection. 2805 // none empty catalog selection.
2804 // as we do not support catalogs this always results in no rows returned 2806 // as we do not support catalogs this always results in no rows returned
2876 * @return ResultSet each row is a foreign key column description 2878 * @return ResultSet each row is a foreign key column description
2877 * @see #getImportedKeys 2879 * @see #getImportedKeys
2878 * @throws SQLException if a database error occurs 2880 * @throws SQLException if a database error occurs
2879 */ 2881 */
2880 @Override 2882 @Override
2881 public ResultSet getExportedKeys(String catalog, String schema, String table) 2883 public ResultSet getExportedKeys(
2882 throws SQLException 2884 final String catalog,
2885 final String schema,
2886 final String table
2887 ) throws SQLException
2883 { 2888 {
2884 StringBuilder query = new StringBuilder(keyQuery.length() + 250); 2889 final StringBuilder query = new StringBuilder(keyQuery.length() + 250);
2885 query.append(keyQuery); 2890 query.append(keyQuery);
2886 2891
2887 if (catalog != null && !catalog.isEmpty()) { 2892 if (catalog != null && !catalog.isEmpty()) {
2888 // none empty catalog selection. 2893 // none empty catalog selection.
2889 // as we do not support catalogs this always results in no rows returned 2894 // as we do not support catalogs this always results in no rows returned
2969 * @throws SQLException if a database error occurs 2974 * @throws SQLException if a database error occurs
2970 * @see #getImportedKeys 2975 * @see #getImportedKeys
2971 */ 2976 */
2972 @Override 2977 @Override
2973 public ResultSet getCrossReference( 2978 public ResultSet getCrossReference(
2974 String pcatalog, 2979 final String pcatalog,
2975 String pschema, 2980 final String pschema,
2976 String ptable, 2981 final String ptable,
2977 String fcatalog, 2982 final String fcatalog,
2978 String fschema, 2983 final String fschema,
2979 String ftable 2984 final String ftable
2980 ) throws SQLException 2985 ) throws SQLException
2981 { 2986 {
2982 StringBuilder query = new StringBuilder(keyQuery.length() + 350); 2987 final StringBuilder query = new StringBuilder(keyQuery.length() + 350);
2983 query.append(keyQuery); 2988 query.append(keyQuery);
2984 2989
2985 if ((pcatalog != null && !pcatalog.isEmpty()) 2990 if ((pcatalog != null && !pcatalog.isEmpty())
2986 || (fcatalog != null && !fcatalog.isEmpty())) { 2991 || (fcatalog != null && !fcatalog.isEmpty())) {
2987 // none empty catalog selection. 2992 // none empty catalog selection.
3059 * @return ResultSet each row is a SQL type description 3064 * @return ResultSet each row is a SQL type description
3060 * @throws SQLException if a database error occurs 3065 * @throws SQLException if a database error occurs
3061 */ 3066 */
3062 @Override 3067 @Override
3063 public ResultSet getTypeInfo() throws SQLException { 3068 public ResultSet getTypeInfo() throws SQLException {
3064 StringBuilder query = new StringBuilder(2300); 3069 final StringBuilder query = new StringBuilder(2300);
3065 query.append("SELECT \"sqlname\" AS \"TYPE_NAME\", " + 3070 query.append("SELECT \"sqlname\" AS \"TYPE_NAME\", " +
3066 "cast(").append(MonetDriver.getSQLTypeMap("\"sqlname\"")).append(" AS int) AS \"DATA_TYPE\", " + 3071 "cast(").append(MonetDriver.getSQLTypeMap("\"sqlname\"")).append(" AS int) AS \"DATA_TYPE\", " +
3067 "\"digits\" AS \"PRECISION\", " + // note that when radix is 2 the precision shows the number of bits 3072 "\"digits\" AS \"PRECISION\", " + // note that when radix is 2 the precision shows the number of bits
3068 "cast(CASE WHEN \"systemname\" IN ('str','inet','json','url','uuid','blob','sqlblob') THEN ''''" + 3073 "cast(CASE WHEN \"systemname\" IN ('str','inet','json','url','uuid','blob','sqlblob') THEN ''''" +
3069 " ELSE NULL END AS varchar(2)) AS \"LITERAL_PREFIX\", " + 3074 " ELSE NULL END AS varchar(2)) AS \"LITERAL_PREFIX\", " +
3146 * @return ResultSet each row is an index column description 3151 * @return ResultSet each row is an index column description
3147 * @throws SQLException if a database occurs 3152 * @throws SQLException if a database occurs
3148 */ 3153 */
3149 @Override 3154 @Override
3150 public ResultSet getIndexInfo( 3155 public ResultSet getIndexInfo(
3151 String catalog, 3156 final String catalog,
3152 String schema, 3157 final String schema,
3153 String table, 3158 final String table,
3154 boolean unique, 3159 final boolean unique,
3155 boolean approximate 3160 final boolean approximate
3156 ) throws SQLException 3161 ) throws SQLException
3157 { 3162 {
3158 String table_row_count = "0"; 3163 String table_row_count = "0";
3159 3164
3160 if (!approximate && schema != null && table != null && !schema.isEmpty() && !table.isEmpty()) { 3165 if (!approximate && schema != null && table != null && !schema.isEmpty() && !table.isEmpty()) {
3176 } catch (SQLException e) { /* ignore */ } 3181 } catch (SQLException e) { /* ignore */ }
3177 } 3182 }
3178 } 3183 }
3179 } 3184 }
3180 3185
3181 StringBuilder query = new StringBuilder(1250); 3186 final StringBuilder query = new StringBuilder(1250);
3182 query.append( 3187 query.append(
3183 "SELECT cast(null AS char(1)) AS \"TABLE_CAT\", " + 3188 "SELECT cast(null AS char(1)) AS \"TABLE_CAT\", " +
3184 "\"schemas\".\"name\" AS \"TABLE_SCHEM\", " + 3189 "\"schemas\".\"name\" AS \"TABLE_SCHEM\", " +
3185 "\"tables\".\"name\" AS \"TABLE_NAME\", " + 3190 "\"tables\".\"name\" AS \"TABLE_NAME\", " +
3186 "CASE WHEN \"keys\".\"name\" IS NULL THEN true ELSE false END AS \"NON_UNIQUE\", " + 3191 "CASE WHEN \"keys\".\"name\" IS NULL THEN true ELSE false END AS \"NON_UNIQUE\", " +
3234 * @param type - defined in java.sql.ResultSet 3239 * @param type - defined in java.sql.ResultSet
3235 * @return true if so; false otherwise 3240 * @return true if so; false otherwise
3236 * @throws SQLException - if a database access error occurs 3241 * @throws SQLException - if a database access error occurs
3237 */ 3242 */
3238 @Override 3243 @Override
3239 public boolean supportsResultSetType(int type) throws SQLException { 3244 public boolean supportsResultSetType(final int type) throws SQLException {
3240 // The only type we don't support 3245 // The only type we don't support
3241 return type != ResultSet.TYPE_SCROLL_SENSITIVE; 3246 return type != ResultSet.TYPE_SCROLL_SENSITIVE;
3242 } 3247 }
3243 3248
3244 3249
3250 * @param concurrency - type defined in java.sql.ResultSet 3255 * @param concurrency - type defined in java.sql.ResultSet
3251 * @return true if so; false otherwise 3256 * @return true if so; false otherwise
3252 * @throws SQLException - if a database access error occurs 3257 * @throws SQLException - if a database access error occurs
3253 */ 3258 */
3254 @Override 3259 @Override
3255 public boolean supportsResultSetConcurrency(int type, int concurrency) 3260 public boolean supportsResultSetConcurrency(final int type, final int concurrency)
3256 throws SQLException 3261 throws SQLException
3257 { 3262 {
3258 // These combinations are not supported! 3263 // These combinations are not supported!
3259 if (type == ResultSet.TYPE_SCROLL_SENSITIVE) 3264 if (type == ResultSet.TYPE_SCROLL_SENSITIVE)
3260 return false; 3265 return false;
3268 } 3273 }
3269 3274
3270 3275
3271 /* lots of unsupported stuff... (no updatable ResultSet!) */ 3276 /* lots of unsupported stuff... (no updatable ResultSet!) */
3272 @Override 3277 @Override
3273 public boolean ownUpdatesAreVisible(int type) { 3278 public boolean ownUpdatesAreVisible(final int type) {
3274 return false; 3279 return false;
3275 } 3280 }
3276 3281
3277 @Override 3282 @Override
3278 public boolean ownDeletesAreVisible(int type) { 3283 public boolean ownDeletesAreVisible(final int type) {
3279 return false; 3284 return false;
3280 } 3285 }
3281 3286
3282 @Override 3287 @Override
3283 public boolean ownInsertsAreVisible(int type) { 3288 public boolean ownInsertsAreVisible(final int type) {
3284 return false; 3289 return false;
3285 } 3290 }
3286 3291
3287 @Override 3292 @Override
3288 public boolean othersUpdatesAreVisible(int type) { 3293 public boolean othersUpdatesAreVisible(final int type) {
3289 return false; 3294 return false;
3290 } 3295 }
3291 3296
3292 @Override 3297 @Override
3293 public boolean othersDeletesAreVisible(int i) { 3298 public boolean othersDeletesAreVisible(final int i) {
3294 return false; 3299 return false;
3295 } 3300 }
3296 3301
3297 @Override 3302 @Override
3298 public boolean othersInsertsAreVisible(int type) { 3303 public boolean othersInsertsAreVisible(final int type) {
3299 return false; 3304 return false;
3300 } 3305 }
3301 3306
3302 @Override 3307 @Override
3303 public boolean updatesAreDetected(int type) { 3308 public boolean updatesAreDetected(final int type) {
3304 return false; 3309 return false;
3305 } 3310 }
3306 3311
3307 @Override 3312 @Override
3308 public boolean deletesAreDetected(int i) { 3313 public boolean deletesAreDetected(final int i) {
3309 return false; 3314 return false;
3310 } 3315 }
3311 3316
3312 @Override 3317 @Override
3313 public boolean insertsAreDetected(int type) { 3318 public boolean insertsAreDetected(final int type) {
3314 return false; 3319 return false;
3315 } 3320 }
3316 3321
3317 /** 3322 /**
3318 * Indicates whether the driver supports batch updates. 3323 * Indicates whether the driver supports batch updates.
3343 * 3348 *
3344 * @throws SQLException - if a database access error occurs 3349 * @throws SQLException - if a database access error occurs
3345 */ 3350 */
3346 @Override 3351 @Override
3347 public ResultSet getUDTs( 3352 public ResultSet getUDTs(
3348 String catalog, 3353 final String catalog,
3349 String schemaPattern, 3354 final String schemaPattern,
3350 String typeNamePattern, 3355 final String typeNamePattern,
3351 int[] types 3356 final int[] types
3352 ) throws SQLException 3357 ) throws SQLException
3353 { 3358 {
3354 StringBuilder query = new StringBuilder(990); 3359 final StringBuilder query = new StringBuilder(990);
3355 if (types != null && types.length > 0) { 3360 if (types != null && types.length > 0) {
3356 query.append("SELECT * FROM ("); 3361 query.append("SELECT * FROM (");
3357 } 3362 }
3358 query.append("SELECT cast(null as char(1)) AS \"TYPE_CAT\", " + 3363 query.append("SELECT cast(null as char(1)) AS \"TYPE_CAT\", " +
3359 "\"schemas\".\"name\" AS \"TYPE_SCHEM\", " + 3364 "\"schemas\".\"name\" AS \"TYPE_SCHEM\", " +
3412 public Connection getConnection() { 3417 public Connection getConnection() {
3413 return con; 3418 return con;
3414 } 3419 }
3415 3420
3416 /* I don't find these in the spec!?! */ 3421 /* I don't find these in the spec!?! */
3417 public boolean rowChangesAreDetected(int type) { 3422 public boolean rowChangesAreDetected(final int type) {
3418 return false; 3423 return false;
3419 } 3424 }
3420 3425
3421 public boolean rowChangesAreVisible(int type) { 3426 public boolean rowChangesAreVisible(final int type) {
3422 return false; 3427 return false;
3423 } 3428 }
3424 3429
3425 //== 1.4 methods (JDBC 3) 3430 //== 1.4 methods (JDBC 3)
3426 3431
3510 * about the designated UDT 3515 * about the designated UDT
3511 * @throws SQLException if a database access error occurs 3516 * @throws SQLException if a database access error occurs
3512 */ 3517 */
3513 @Override 3518 @Override
3514 public ResultSet getSuperTypes( 3519 public ResultSet getSuperTypes(
3515 String catalog, 3520 final String catalog,
3516 String schemaPattern, 3521 final String schemaPattern,
3517 String typeNamePattern 3522 final String typeNamePattern
3518 ) throws SQLException 3523 ) throws SQLException
3519 { 3524 {
3520 String query = 3525 final String query =
3521 "SELECT cast(null as char(1)) AS \"TYPE_CAT\", '' AS \"TYPE_SCHEM\", '' AS \"TYPE_NAME\", " + 3526 "SELECT cast(null as char(1)) AS \"TYPE_CAT\", '' AS \"TYPE_SCHEM\", '' AS \"TYPE_NAME\", " +
3522 "cast(null as char(1)) AS \"SUPERTYPE_CAT\", '' AS \"SUPERTYPE_SCHEM\", '' AS \"SUPERTYPE_NAME\" " + 3527 "cast(null as char(1)) AS \"SUPERTYPE_CAT\", '' AS \"SUPERTYPE_SCHEM\", '' AS \"SUPERTYPE_NAME\" " +
3523 "WHERE 1 = 0"; 3528 "WHERE 1 = 0";
3524 3529
3525 return executeMetaDataQuery(query); 3530 return executeMetaDataQuery(query);
3555 * @return a <code>ResultSet</code> object in which each row is a type description 3560 * @return a <code>ResultSet</code> object in which each row is a type description
3556 * @throws SQLException if a database access error occurs 3561 * @throws SQLException if a database access error occurs
3557 */ 3562 */
3558 @Override 3563 @Override
3559 public ResultSet getSuperTables( 3564 public ResultSet getSuperTables(
3560 String catalog, 3565 final String catalog,
3561 String schemaPattern, 3566 final String schemaPattern,
3562 String tableNamePattern 3567 final String tableNamePattern
3563 ) throws SQLException 3568 ) throws SQLException
3564 { 3569 {
3565 String query = 3570 final String query =
3566 "SELECT cast(null as char(1)) AS \"TABLE_CAT\", " + 3571 "SELECT cast(null as char(1)) AS \"TABLE_CAT\", " +
3567 "'' AS \"TABLE_SCHEM\", '' AS \"TABLE_NAME\", '' AS \"SUPERTABLE_NAME\" " + 3572 "'' AS \"TABLE_SCHEM\", '' AS \"TABLE_NAME\", '' AS \"SUPERTABLE_NAME\" " +
3568 "WHERE 1 = 0"; 3573 "WHERE 1 = 0";
3569 3574
3570 return executeMetaDataQuery(query); 3575 return executeMetaDataQuery(query);
3639 * attribute description 3644 * attribute description
3640 * @throws SQLException if a database access error occurs 3645 * @throws SQLException if a database access error occurs
3641 */ 3646 */
3642 @Override 3647 @Override
3643 public ResultSet getAttributes( 3648 public ResultSet getAttributes(
3644 String catalog, 3649 final String catalog,
3645 String schemaPattern, 3650 final String schemaPattern,
3646 String typeNamePattern, 3651 final String typeNamePattern,
3647 String attributeNamePattern 3652 final String attributeNamePattern
3648 ) throws SQLException 3653 ) throws SQLException
3649 { 3654 {
3650 String query = 3655 final String query =
3651 "SELECT cast(null as char(1)) AS \"TYPE_CAT\", '' AS \"TYPE_SCHEM\", '' AS \"TYPE_NAME\", " + 3656 "SELECT cast(null as char(1)) AS \"TYPE_CAT\", '' AS \"TYPE_SCHEM\", '' AS \"TYPE_NAME\", " +
3652 "'' AS \"ATTR_NAME\", cast(0 as int) AS \"DATA_TYPE\", '' AS \"ATTR_TYPE_NAME\", cast(0 as int) AS \"ATTR_SIZE\", " + 3657 "'' AS \"ATTR_NAME\", cast(0 as int) AS \"DATA_TYPE\", '' AS \"ATTR_TYPE_NAME\", cast(0 as int) AS \"ATTR_SIZE\", " +
3653 "cast(0 as int) AS \"DECIMAL_DIGITS\", cast(0 as int) AS \"NUM_PREC_RADIX\", cast(0 as int) AS \"NULLABLE\", " + 3658 "cast(0 as int) AS \"DECIMAL_DIGITS\", cast(0 as int) AS \"NUM_PREC_RADIX\", cast(0 as int) AS \"NULLABLE\", " +
3654 "'' AS \"REMARKS\", '' AS \"ATTR_DEF\", cast(0 as int) AS \"SQL_DATA_TYPE\", " + 3659 "'' AS \"REMARKS\", '' AS \"ATTR_DEF\", cast(0 as int) AS \"SQL_DATA_TYPE\", " +
3655 "cast(0 as int) AS \"SQL_DATETIME_SUB\", cast(0 as int) AS \"CHAR_OCTET_LENGTH\", " + 3660 "cast(0 as int) AS \"SQL_DATETIME_SUB\", cast(0 as int) AS \"CHAR_OCTET_LENGTH\", " +
3669 * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code> 3674 * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
3670 * @return <code>true</code> if so; <code>false</code> otherwise 3675 * @return <code>true</code> if so; <code>false</code> otherwise
3671 * @see Connection 3676 * @see Connection
3672 */ 3677 */
3673 @Override 3678 @Override
3674 public boolean supportsResultSetHoldability(int holdability) { 3679 public boolean supportsResultSetHoldability(final int holdability) {
3675 // we don't close ResultSets at commit; and we don't do updateable 3680 // we don't close ResultSets at commit; and we don't do updateable
3676 // result sets, so comes closest to hold cursors over commit 3681 // result sets, so comes closest to hold cursors over commit
3677 return holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT; 3682 return holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT;
3678 } 3683 }
3679 3684
3879 * @throws SQLException if a database access error occurs 3884 * @throws SQLException if a database access error occurs
3880 */ 3885 */
3881 @Override 3886 @Override
3882 public ResultSet getClientInfoProperties() throws SQLException { 3887 public ResultSet getClientInfoProperties() throws SQLException {
3883 // for a list of connection properties see also MonetConnection.java constructor MonetConnection(Properties props) 3888 // for a list of connection properties see also MonetConnection.java constructor MonetConnection(Properties props)
3884 String query = 3889 final String query =
3885 "SELECT 'host' AS \"NAME\", cast(1024 as int) AS \"MAX_LEN\", 'localhost' AS \"DEFAULT_VALUE\", 'DSN or IP-address of machine running MonetDB' AS \"DESCRIPTION\" UNION ALL " + 3890 "SELECT 'host' AS \"NAME\", cast(1024 as int) AS \"MAX_LEN\", 'localhost' AS \"DEFAULT_VALUE\", 'DSN or IP-address of machine running MonetDB' AS \"DESCRIPTION\" UNION ALL " +
3886 "SELECT 'port', 5, '50000', 'communication port number of MonetDB server process' UNION ALL " + 3891 "SELECT 'port', 5, '50000', 'communication port number of MonetDB server process' UNION ALL " +
3887 "SELECT 'user', 1024, '', 'user name to login to MonetDB server' UNION ALL " + 3892 "SELECT 'user', 1024, '', 'user name to login to MonetDB server' UNION ALL " +
3888 "SELECT 'password', 128, '', 'password for user name to login to MonetDB server' UNION ALL " + 3893 "SELECT 'password', 128, '', 'password for user name to login to MonetDB server' UNION ALL " +
3889 "SELECT 'language', 16, 'sql', 'language (sql or mal) used to parse commands in MonetDB server' UNION ALL " + 3894 "SELECT 'language', 16, 'sql', 'language (sql or mal) used to parse commands in MonetDB server' UNION ALL " +
3941 * @return ResultSet - each row is a function description 3946 * @return ResultSet - each row is a function description
3942 * @throws SQLException if a database access error occurs 3947 * @throws SQLException if a database access error occurs
3943 */ 3948 */
3944 @Override 3949 @Override
3945 public ResultSet getFunctions( 3950 public ResultSet getFunctions(
3946 String catalog, 3951 final String catalog,
3947 String schemaPattern, 3952 final String schemaPattern,
3948 String functionNamePattern) 3953 final String functionNamePattern
3949 throws SQLException 3954 ) throws SQLException
3950 { 3955 {
3951 boolean useCommentsTable = ((MonetConnection)con).commentsTableExists(); 3956 final boolean useCommentsTable = ((MonetConnection)con).commentsTableExists();
3952 StringBuilder query = new StringBuilder(800); 3957 final StringBuilder query = new StringBuilder(800);
3953 query.append("SELECT cast(null as char(1)) AS \"FUNCTION_CAT\", " + 3958 query.append("SELECT cast(null as char(1)) AS \"FUNCTION_CAT\", " +
3954 "\"schemas\".\"name\" AS \"FUNCTION_SCHEM\", " + 3959 "\"schemas\".\"name\" AS \"FUNCTION_SCHEM\", " +
3955 "\"functions\".\"name\" AS \"FUNCTION_NAME\", ") 3960 "\"functions\".\"name\" AS \"FUNCTION_NAME\", ")
3956 .append(useCommentsTable ? "COALESCE(\"comments\".\"remark\", cast(\"functions\".\"func\" as varchar(9999)))" : "cast(\"functions\".\"func\" as varchar(9999))").append(" AS \"REMARKS\", " + 3961 .append(useCommentsTable ? "COALESCE(\"comments\".\"remark\", cast(\"functions\".\"func\" as varchar(9999)))" : "cast(\"functions\".\"func\" as varchar(9999))").append(" AS \"REMARKS\", " +
3957 "CASE \"functions\".\"type\"" + 3962 "CASE \"functions\".\"type\"" +
4049 * column or return type 4054 * column or return type
4050 * @throws SQLException - if a database access error occurs 4055 * @throws SQLException - if a database access error occurs
4051 */ 4056 */
4052 @Override 4057 @Override
4053 public ResultSet getFunctionColumns( 4058 public ResultSet getFunctionColumns(
4054 String catalog, 4059 final String catalog,
4055 String schemaPattern, 4060 final String schemaPattern,
4056 String functionNamePattern, 4061 final String functionNamePattern,
4057 String columnNamePattern) 4062 final String columnNamePattern
4058 throws SQLException 4063 ) throws SQLException
4059 { 4064 {
4060 StringBuilder query = new StringBuilder(2600); 4065 final StringBuilder query = new StringBuilder(2600);
4061 query.append("SELECT cast(null as char(1)) AS \"FUNCTION_CAT\", " + 4066 query.append("SELECT cast(null as char(1)) AS \"FUNCTION_CAT\", " +
4062 "\"schemas\".\"name\" AS \"FUNCTION_SCHEM\", " + 4067 "\"schemas\".\"name\" AS \"FUNCTION_SCHEM\", " +
4063 "\"functions\".\"name\" AS \"FUNCTION_NAME\", " + 4068 "\"functions\".\"name\" AS \"FUNCTION_NAME\", " +
4064 "\"args\".\"name\" AS \"COLUMN_NAME\", " + 4069 "\"args\".\"name\" AS \"COLUMN_NAME\", " +
4065 "cast(CASE \"args\".\"inout\"" + 4070 "cast(CASE \"args\".\"inout\"" +
4150 * @return ResultSet where each row is a column description 4155 * @return ResultSet where each row is a column description
4151 * @throws SQLException if a database access error occurs 4156 * @throws SQLException if a database access error occurs
4152 */ 4157 */
4153 @Override 4158 @Override
4154 public ResultSet getPseudoColumns( 4159 public ResultSet getPseudoColumns(
4155 String catalog, 4160 final String catalog,
4156 String schemaPattern, 4161 final String schemaPattern,
4157 String tableNamePattern, 4162 final String tableNamePattern,
4158 String columnNamePattern) 4163 final String columnNamePattern
4159 throws SQLException 4164 ) throws SQLException
4160 { 4165 {
4161 // MonetDB currently does not support pseudo or hidden columns, so return an empty ResultSet 4166 // MonetDB currently does not support pseudo or hidden columns, so return an empty ResultSet
4162 String query = 4167 final String query =
4163 "SELECT cast(null as char(1)) AS \"TABLE_CAT\", " + 4168 "SELECT cast(null as char(1)) AS \"TABLE_CAT\", " +
4164 "'' AS \"TABLE_SCHEM\", " + 4169 "'' AS \"TABLE_SCHEM\", " +
4165 "'' AS \"TABLE_NAME\", " + 4170 "'' AS \"TABLE_NAME\", " +
4166 "'' AS \"COLUMN_NAME\", " + 4171 "'' AS \"COLUMN_NAME\", " +
4167 "cast(0 as int) AS \"DATA_TYPE\", " + 4172 "cast(0 as int) AS \"DATA_TYPE\", " +