Changeset: 3661d21cc19b for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=3661d21cc19b
Added Files:
        sql/test/BugTracker-2016/Tests/data3987.csv
        sql/test/BugTracker-2016/Tests/malformed-copy-int.Bug-3987.sql.in
        sql/test/BugTracker-2016/Tests/malformed-copy-int.Bug-3987.stable.err
        sql/test/BugTracker-2016/Tests/malformed-copy-int.Bug-3987.stable.out
Modified Files:
        common/stream/stream.c
        java/ChangeLog.Jun2016
        java/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java
        java/tests/Test_Rmetadata.java
        monetdb5/modules/mal/tablet.c
        sql/backends/monet5/sql.c
        sql/jdbc/tests/Tests/Test_Rmetadata.stable.out
        sql/storage/bat/bat_storage.c
        tools/embedded/build-on-windows.bat
        tools/embedded/build-rpkg.sh
        tools/embedded/inlined_scripts.c
        tools/embedded/inlined_scripts.sh
        tools/embedded/rpackage/DESCRIPTION
        tools/embedded/rpackage/configure.win
        tools/embedded/windows/sedscript.tpl
Branch: default
Log Message:

Merge with Jun2016 branch.


diffs (truncated from 3233 to 300 lines):

diff --git a/common/stream/stream.c b/common/stream/stream.c
--- a/common/stream/stream.c
+++ b/common/stream/stream.c
@@ -128,7 +128,7 @@
 #define UTF8BOM                "\xEF\xBB\xBF" /* UTF-8 encoding of Unicode BOM 
*/
 #define UTF8BOMLENGTH  3              /* length of above */
 
-#ifdef WIN32
+#ifdef _MSC_VER
 /* use intrinsic functions on Windows */
 #define short_int_SWAP(s)      ((short) _byteswap_ushort((unsigned short) (s)))
 /* on Windows, long is the same size as int */
diff --git a/java/ChangeLog.Jun2016 b/java/ChangeLog.Jun2016
--- a/java/ChangeLog.Jun2016
+++ b/java/ChangeLog.Jun2016
@@ -1,6 +1,10 @@
 # ChangeLog file for java
 # This file is updated with Maddlog
 
+* Thu Apr 21 2016 Martin van Dinther <martin.van.dint...@monetdbsolutions.com>
+- Fixed resource leak in ResultSetMetaData. It created and cached a ResultSet
+  object for each column but never closed the ResultSet objects.
+
 * Thu Mar 31 2016 Martin van Dinther <martin.van.dint...@monetdbsolutions.com>
 - Corrected DatabaseMetaData methods which accept a catalog filter argument.
   Those methods will now filter the results on the specified catalog name,
diff --git a/java/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java 
b/java/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java
--- a/java/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java
+++ b/java/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java
@@ -21,6 +21,7 @@ import java.net.URL;
 import java.sql.Array;
 import java.sql.Blob;
 import java.sql.Clob;
+import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.NClob;
 import java.sql.Ref;
@@ -683,44 +684,43 @@ public class MonetResultSet extends Mone
         * @throws SQLException if there is no such column
         */
        @Override
-       public boolean getBoolean(int columnIndex) throws SQLException{
-               int dataType = getJavaType(types[columnIndex - 1]);
-               if (dataType == Types.TINYINT ||
-                       dataType == Types.SMALLINT ||
-                       dataType == Types.INTEGER ||
-                       dataType == Types.BIGINT)
-               {
-                       if (getLong(columnIndex) == 0L) {
-                               return false;
-                       } else {
+       public boolean getBoolean(int columnIndex) throws SQLException {
+               switch (getJavaType(types[columnIndex - 1])) {
+                       case Types.TINYINT:
+                       case Types.SMALLINT:
+                       case Types.INTEGER:
+                               if (getInt(columnIndex) == 0) {
+                                       return false;
+                               }
                                return true;
-                       }
-               } else if (dataType == Types.REAL ||
-                       dataType == Types.FLOAT ||
-                       dataType == Types.DOUBLE)
-               {
-                       if (getDouble(columnIndex) == 0.0) {
-                               return false;
-                       } else {
+                       case Types.BIGINT:
+                               if (getLong(columnIndex) == 0L) {
+                                       return false;
+                               }
                                return true;
-                       }
-               } else if (dataType == Types.DECIMAL ||
-                       dataType == Types.NUMERIC)
-               {
-                       if (getBigDecimal(columnIndex).compareTo(new 
BigDecimal(0.0)) == 0) {
-                               return false;
-                       } else {
+                       case Types.DOUBLE:
+                       case Types.FLOAT:
+                       case Types.REAL:
+                               if (getDouble(columnIndex) == 0.0) {
+                                       return false;
+                               }
                                return true;
-                       }
-               } else if (dataType == Types.BIT ||
-                       dataType == Types.BOOLEAN ||
-                       dataType == Types.CHAR ||
-                       dataType == Types.VARCHAR ||
-                       dataType == Types.LONGVARCHAR)
-               {
-                       return 
(Boolean.valueOf(getString(columnIndex))).booleanValue();
-               } else {
-                       throw new SQLException("Conversion from " + 
types[columnIndex - 1] + " to boolean type not supported", "M1M05");
+                       case Types.DECIMAL:
+                       case Types.NUMERIC:
+                               if 
(getBigDecimal(columnIndex).compareTo(BigDecimal.ZERO) == 0) {
+                                       return false;
+                               }
+                               return true;
+                       case Types.BOOLEAN:
+                       case Types.BIT: // MonetDB doesn't use type BIT, it's 
here for completeness
+                       case Types.CHAR:
+                       case Types.VARCHAR:
+                       case Types.LONGVARCHAR: // MonetDB doesn't use type 
LONGVARCHAR, it's here for completeness
+                       case Types.CLOB:
+                               // check if string value equals "true" (case 
insensitive) or not
+                               return 
(Boolean.valueOf(getString(columnIndex))).booleanValue();
+                       default:
+                               throw new SQLException("Conversion from " + 
types[columnIndex - 1] + " to boolean type not supported", "M1M05");
                }
        }
 
@@ -1082,11 +1082,63 @@ public class MonetResultSet extends Mone
        public ResultSetMetaData getMetaData() {
                // return inner class which implements the ResultSetMetaData 
interface
                return new rsmdw() {
-                       // for the more expensive methods, we provide a simple 
cache
-                       // for the most expensive part; getting the ResultSet 
which
-                       // contains the data
+                       // for the more expensive methods (getPrecision(), 
getScale(), isNullable()), we provide a simple cache
+                       // caches to store precision, scale and isNullable 
values from getColumns()
+                       private boolean[] _is_fetched   = new 
boolean[columns.length +1];
+                       private int[] _precision        = new 
int[columns.length +1];
+                       private int[] _scale            = new 
int[columns.length +1];
+                       private int[] _isNullable       = new 
int[columns.length +1];
+                       private Connection conn = null;
                        private DatabaseMetaData dbmd = null;
-                       private ResultSet[] colrs = new 
ResultSet[columns.length];
+
+                       /**
+                        * A private method to fetch the precision, scale and 
isNuallble value for a fully qualified column.
+                        * As md.getColumns() is an expensive method we call it 
only once per column
+                        * and cache the precision, scale and isNullable values 
in the above array chaches.
+                        * Also we only call md.getColumns() when we have a non 
empty schema name and table name and column name.
+                        */
+                       private void fetchColumnInfo(int column) throws 
SQLException
+                       {
+                               if (column <= 0 || column > columns.length)
+                                       throw new SQLException("No such column 
" + column, "M1M05");
+
+                               _is_fetched[column] = true;
+                               _precision[column] = 0;
+                               _scale[column] = 0;
+                               _isNullable[column] = columnNullableUnknown;
+
+                               // we can only call dbmd.getColumns() when we 
have a specific schema name and table name and column name
+                               String schName = getSchemaName(column);
+                               if (schName != null && !"".equals(schName)) {
+                                       String tblName = getTableName(column);
+                                       if (tblName != null && 
!"".equals(tblName)) {
+                                               String colName = 
getColumnName(column);
+                                               if (colName != null && 
!"".equals(colName)) {
+                                                       if (conn == null) {
+                                                               // first time, 
get a Connection object and cache it for all next columns
+                                                               conn = 
getStatement().getConnection();
+                                                       }
+                                                       if (conn != null && 
dbmd == null) {
+                                                               // first time, 
get a MetaData object and cache it for all next columns
+                                                               dbmd = 
conn.getMetaData();
+                                                       }
+                                                       if (dbmd != null) {
+                                                               // for 
precision, scale and isNullable we query the information from data dictionary
+                                                               ResultSet 
colInfo = dbmd.getColumns(null, schName, tblName, colName);
+                                                               if (colInfo != 
null) {
+                                                                       // we 
expect exactly one row in the resultset
+                                                                       if 
(colInfo.next()) {
+                                                                               
_precision[column] = colInfo.getInt(7);  // col 7 is "COLUMN_SIZE"
+                                                                               
_scale[column] = colInfo.getInt(9);  // col 9 is "DECIMAL_DIGITS"
+                                                                               
_isNullable[column] = colInfo.getInt(11);  // col 11 is "NULLABLE"
+                                                                       }
+                                                                       
colInfo.close();  // close the resultset to release resources
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
 
                        /**
                         * Returns the number of columns in this ResultSet 
object.
@@ -1099,8 +1151,7 @@ public class MonetResultSet extends Mone
                        }
 
                        /**
-                        * Indicates whether the designated column is 
automatically
-                        * numbered, thus read-only.
+                        * Indicates whether the designated column is 
automatically numbered.
                         * 
                         * @param column the first column is 1, the second is 
2, ...
                         * @return true if so; false otherwise
@@ -1119,15 +1170,21 @@ public class MonetResultSet extends Mone
                        }
 
                        /**
-                        * Indicates whether a column's case matters. This 
holds for all
-                        * columns in MonetDB resultsets since the mapping is 
done case
-                        * insensitive, therefore this method will always 
return false.
+                        * Indicates whether a column's case matters.
                         *
                         * @param column the first column is 1, the second is 
2, ...
-                        * @returns false
+                        * @returns true for all character string columns else 
false
                         */
                        @Override
-                       public boolean isCaseSensitive(int column) {
+                       public boolean isCaseSensitive(int column) throws 
SQLException {
+                               switch (getColumnType(column)) {
+                                       case Types.CHAR:
+                                       case Types.VARCHAR:
+                                       case Types.LONGVARCHAR: // MonetDB 
doesn't use type LONGVARCHAR, it's here for completeness
+                                       case Types.CLOB:
+                                               return true;
+                               }
+
                                return false;
                        }
 
@@ -1291,19 +1348,62 @@ public class MonetResultSet extends Mone
                         */
                        @Override
                        public int getPrecision(int column) throws SQLException 
{
-                               int precision = 0;
-                               try {
-                                       ResultSet col = 
getColumnResultSet(column);
-
-                                       // the result has either zero or one 
results, as the
-                                       // schema, table and column should be 
unique...
-                                       if (col.next())
-                                               precision = 
col.getInt("COLUMN_SIZE");
-                               } catch (NullPointerException npe) {
-                                       /* do nothing */
+                               if (_is_fetched[column] != true) {
+                                       fetchColumnInfo(column);
                                }
-
-                               return precision;
+                               if (_precision[column] == 0) {
+                                       // apparently no precision could be 
fetched
+                                       // use columnDisplaySize() value for 
variable length data types
+                                       switch (getColumnType(column)) {
+                                               case Types.CHAR:
+                                               case Types.VARCHAR:
+                                               case Types.LONGVARCHAR: // 
MonetDB doesn't use type LONGVARCHAR, it's here for completeness
+                                               case Types.CLOB:
+                                               case Types.BLOB:
+                                               case Types.NUMERIC:
+                                               case Types.DECIMAL:
+                                                       _precision[column] = 
getColumnDisplaySize(column);
+                                                       break;
+                                               case Types.TINYINT:
+                                                       _precision[column] = 3;
+                                                       break;
+                                               case Types.SMALLINT:
+                                                       _precision[column] = 5;
+                                                       break;
+                                               case Types.INTEGER:
+                                                       _precision[column] = 10;
+                                                       break;
+                                               case Types.BIGINT:
+                                                       _precision[column] = 19;
+                                                       break;
+                                               case Types.REAL:
+                                                       _precision[column] = 7;
+                                                       break;
+                                               case Types.FLOAT:
+                                               case Types.DOUBLE:
+                                                       _precision[column] = 15;
+                                                       break;
+                                               case Types.BIT: // MonetDB 
doesn't use type BIT, it's here for completeness
+                                                       _precision[column] = 1;
+                                                       break;
+                                               case Types.BOOLEAN:
+                                                       _precision[column] = 5;
+                                                       break;
+                                               case Types.DATE:
+                                                       _precision[column] = 10;
+                                                       break;
+                                               case Types.TIME:
+                                                       _precision[column] = 8;
+                                                       break;
+                                               case Types.TIMESTAMP:
+                                                       _precision[column] = 19;
+                                                       break;
+                                               default:
+                                                       _precision[column] = 30;
+                                                       break;
+                                       }
+                               }
+                               return _precision[column];
                        }
 
                        /**
@@ -1318,19 +1418,10 @@ public class MonetResultSet extends Mone
                         */
                        @Override
                        public int getScale(int column) throws SQLException {
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to