[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-6.2' - connectivity/Library_mysqlc.mk connectivity/qa connectivity/source

Tamas Bunth (via logerrit) logerrit at kemper.freedesktop.org
Fri Aug 2 14:50:43 UTC 2019


 connectivity/Library_mysqlc.mk                                   |    1 
 connectivity/qa/connectivity/mysql/mysql.cxx                     |   32 
 connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx |  353 ++++------
 connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx |    5 
 4 files changed, 210 insertions(+), 181 deletions(-)

New commits:
commit e7d3a95d9c87150bcaaf78d5a790ea44e6c1e41b
Author:     Tamas Bunth <tamas.bunth at collabora.co.uk>
AuthorDate: Mon Apr 22 19:09:24 2019 +0200
Commit:     Tamás Bunth <btomi96 at gmail.com>
CommitDate: Fri Aug 2 16:49:55 2019 +0200

    mysqlc: Allow conversions between different types
    
    Change-Id: I54c1f438a755267db0896637c79f915de9113f83
    Reviewed-on: https://gerrit.libreoffice.org/71246
    Reviewed-by: Andras Timar <andras.timar at collabora.com>
    Tested-by: Andras Timar <andras.timar at collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/76731
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Tamás Bunth <btomi96 at gmail.com>

diff --git a/connectivity/Library_mysqlc.mk b/connectivity/Library_mysqlc.mk
index 9dba7769a9a2..455f9b2224df 100644
--- a/connectivity/Library_mysqlc.mk
+++ b/connectivity/Library_mysqlc.mk
@@ -31,6 +31,7 @@ $(eval $(call gb_Library_use_sdk_api,mysqlc))
 
 $(eval $(call gb_Library_use_libraries,mysqlc,\
 	cppu \
+    dbtools \
 	sal \
 	salhelper \
 	comphelper \
diff --git a/connectivity/qa/connectivity/mysql/mysql.cxx b/connectivity/qa/connectivity/mysql/mysql.cxx
index 38683149d432..546e916bd0a7 100644
--- a/connectivity/qa/connectivity/mysql/mysql.cxx
+++ b/connectivity/qa/connectivity/mysql/mysql.cxx
@@ -52,6 +52,7 @@ public:
     void testMultipleResultsets();
     void testDBMetaData();
     void testTimestampField();
+    void testNumericConversionPrepared();
 
     CPPUNIT_TEST_SUITE(MysqlTestDriver);
     CPPUNIT_TEST(testDBConnection);
@@ -60,6 +61,7 @@ public:
     CPPUNIT_TEST(testMultipleResultsets);
     CPPUNIT_TEST(testDBMetaData);
     CPPUNIT_TEST(testTimestampField);
+    CPPUNIT_TEST(testNumericConversionPrepared);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -358,6 +360,36 @@ void MysqlTestDriver::testTimestampField()
     xStatement->executeUpdate("DROP TABLE myTestTable");
 }
 
+/**
+ * Test getting value from a decimal type column from a result set of a
+ * prepared statement, getting as a tinyint, string, short, int, long.
+ */
+void MysqlTestDriver::testNumericConversionPrepared()
+{
+    Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
+    if (!xConnection.is())
+        CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
+    uno::Reference<XStatement> xStatement = xConnection->createStatement();
+    CPPUNIT_ASSERT(xStatement.is());
+    xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
+
+    xStatement->executeUpdate("CREATE TABLE myTestTable (myDecimal DECIMAL(4,2))");
+    xStatement->executeUpdate("INSERT INTO myTestTable VALUES (11.22)");
+    Reference<XPreparedStatement> xPrepared
+        = xConnection->prepareStatement("SELECT * from myTestTable");
+    Reference<XResultSet> xResultSet = xPrepared->executeQuery();
+    xResultSet->next(); // use it
+    Reference<XRow> xRow(xResultSet, UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(OUString("11.22"), xRow->getString(1));
+    // converting to integer types results in rounding down the number
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int8>(11), xRow->getByte(1));
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(11), xRow->getShort(1));
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(11), xRow->getInt(1));
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int64>(11), xRow->getLong(1));
+
+    xStatement->executeUpdate("DROP TABLE myTestTable");
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(MysqlTestDriver);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx
index a3e45937b610..b3630072c143 100644
--- a/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx
+++ b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx
@@ -38,6 +38,7 @@ using namespace rtl;
 #include <cstdlib>
 
 using namespace connectivity::mysqlc;
+using namespace connectivity;
 using namespace cppu;
 using namespace com::sun::star;
 using namespace com::sun::star::lang;
@@ -51,6 +52,52 @@ using namespace ::comphelper;
 using ::osl::MutexGuard;
 
 #include <stdio.h>
+#include <typeinfo>
+#include <typeindex>
+
+namespace
+{
+const std::type_index getTypeFromMysqlType(enum_field_types type)
+{
+    switch (type)
+    {
+        case MYSQL_TYPE_TINY:
+            return std::type_index(typeid(sal_Int8));
+        case MYSQL_TYPE_SHORT:
+            return std::type_index(typeid(sal_Int16));
+        case MYSQL_TYPE_LONG:
+            return std::type_index(typeid(sal_Int32));
+        case MYSQL_TYPE_LONGLONG:
+            return std::type_index(typeid(sal_Int64));
+        case MYSQL_TYPE_FLOAT:
+            return std::type_index(typeid(float));
+        case MYSQL_TYPE_DOUBLE:
+            return std::type_index(typeid(double));
+        case MYSQL_TYPE_TIMESTAMP:
+        case MYSQL_TYPE_DATETIME:
+            return std::type_index(typeid(DateTime));
+        case MYSQL_TYPE_DATE:
+            return std::type_index(typeid(Date));
+        case MYSQL_TYPE_TIME:
+            return std::type_index(typeid(Time));
+        case MYSQL_TYPE_STRING:
+        case MYSQL_TYPE_VAR_STRING:
+        case MYSQL_TYPE_DECIMAL:
+        case MYSQL_TYPE_NEWDECIMAL:
+            return std::type_index(typeid(OUString));
+        case MYSQL_TYPE_BLOB:
+        case MYSQL_TYPE_YEAR:
+        case MYSQL_TYPE_BIT:
+        case MYSQL_TYPE_INT24:
+        case MYSQL_TYPE_SET:
+        case MYSQL_TYPE_ENUM:
+        case MYSQL_TYPE_GEOMETRY:
+        case MYSQL_TYPE_NULL:
+        default:
+            return std::type_index(typeid(nullptr));
+    }
+}
+}
 
 OUString SAL_CALL OPreparedResultSet::getImplementationName()
 {
@@ -128,146 +175,169 @@ sal_Int32 SAL_CALL OPreparedResultSet::findColumn(const OUString& columnName)
                        Any());
 }
 
-uno::Reference<XInputStream> SAL_CALL OPreparedResultSet::getBinaryStream(sal_Int32 column)
+template <typename T> T OPreparedResultSet::safelyRetrieveValue(sal_Int32 nColumnIndex)
 {
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
-    checkColumnIndex(column);
+    checkColumnIndex(nColumnIndex);
+    if (*m_aData[nColumnIndex - 1].is_null)
+    {
+        m_bWasNull = true;
+        return T();
+    }
+    m_bWasNull = false;
 
-    mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getBinaryStream",
-                                                            *this);
-    return nullptr;
+    return retrieveValue<T>(nColumnIndex);
 }
 
-uno::Reference<XInputStream> SAL_CALL OPreparedResultSet::getCharacterStream(sal_Int32 column)
+template <typename T> T OPreparedResultSet::retrieveValue(sal_Int32 nColumnIndex)
 {
-    MutexGuard aGuard(m_aMutex);
-    checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
-    checkColumnIndex(column);
+    if (getTypeFromMysqlType(m_aFields[nColumnIndex - 1].type) == std::type_index(typeid(T)))
+        return *static_cast<T*>(m_aData[nColumnIndex - 1].buffer);
+    else
+        return getRowSetValue(nColumnIndex);
+}
 
-    mysqlc_sdbc_driver::throwFeatureNotImplementedException(
-        "OPreparedResultSet::getCharacterStream", *this);
-    return nullptr;
+template <> uno::Sequence<sal_Int8> OPreparedResultSet::retrieveValue(sal_Int32 column)
+{
+    // TODO make conversion possible
+    return uno::Sequence<sal_Int8>(static_cast<sal_Int8 const*>(m_aData[column - 1].buffer),
+                                   *m_aData[column - 1].length);
 }
 
-sal_Bool SAL_CALL OPreparedResultSet::getBoolean(sal_Int32 column)
+template <> Date OPreparedResultSet::retrieveValue(sal_Int32 column)
 {
-    MutexGuard aGuard(m_aMutex);
-    checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
-    checkColumnIndex(column);
+    if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(Date)))
+        return getRowSetValue(column);
+    const MYSQL_TIME* pTime = static_cast<MYSQL_TIME*>(m_aData[column - 1].buffer);
 
-    if (*m_aData[column - 1].is_null)
-    {
-        m_bWasNull = true;
-        return false;
-    }
-    m_bWasNull = false;
-    return *static_cast<bool*>(m_aData[column - 1].buffer);
+    Date d;
+    d.Year = pTime->year;
+    d.Month = pTime->month;
+    d.Day = pTime->day;
+    return d;
 }
 
-sal_Int8 SAL_CALL OPreparedResultSet::getByte(sal_Int32 column)
+template <> Time OPreparedResultSet::retrieveValue(sal_Int32 column)
 {
-    MutexGuard aGuard(m_aMutex);
-    checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
-    checkColumnIndex(column);
+    if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(Time)))
+        return getRowSetValue(column);
+    const MYSQL_TIME* pTime = static_cast<MYSQL_TIME*>(m_aData[column - 1].buffer);
 
-    if (*m_aData[column - 1].is_null)
-    {
-        m_bWasNull = true;
-        return 0;
-    }
-    m_bWasNull = false;
-    return *static_cast<sal_Int8*>(m_aData[column - 1].buffer);
+    Time t;
+    t.Hours = pTime->hour;
+    t.Minutes = pTime->minute;
+    t.Seconds = pTime->second;
+    return t;
 }
 
-uno::Sequence<sal_Int8> SAL_CALL OPreparedResultSet::getBytes(sal_Int32 column)
+template <> DateTime OPreparedResultSet::retrieveValue(sal_Int32 column)
 {
-    checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
-    MutexGuard aGuard(m_aMutex);
-
-    if (*m_aData[column - 1].is_null)
-    {
-        m_bWasNull = true;
-        return uno::Sequence<sal_Int8>();
-    }
-    m_bWasNull = false;
+    if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(DateTime)))
+        return getRowSetValue(column);
+    const MYSQL_TIME* pTime = static_cast<MYSQL_TIME*>(m_aData[column - 1].buffer);
 
-    return uno::Sequence<sal_Int8>(static_cast<sal_Int8 const*>(m_aData[column - 1].buffer),
-                                   *m_aData[column - 1].length);
+    DateTime t;
+    t.Year = pTime->year;
+    t.Month = pTime->month;
+    t.Day = pTime->day;
+    t.Hours = pTime->hour;
+    t.Minutes = pTime->minute;
+    t.Seconds = pTime->second;
+    return t;
 }
 
-Date SAL_CALL OPreparedResultSet::getDate(sal_Int32 column)
+template <> OUString OPreparedResultSet::retrieveValue(sal_Int32 column)
 {
-    MutexGuard aGuard(m_aMutex);
-    checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
-    checkColumnIndex(column);
+    if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(OUString)))
+        return getRowSetValue(column);
+    const char* sStr = static_cast<const char*>(m_aData[column - 1].buffer);
 
-    if (*m_aData[column - 1].is_null)
+    OUString sReturn = OUString(sStr, *m_aData[column - 1].length, m_encoding);
+    return sReturn;
+}
+
+ORowSetValue OPreparedResultSet::getRowSetValue(sal_Int32 nColumnIndex)
+{
+    switch (m_aFields[nColumnIndex - 1].type)
     {
-        m_bWasNull = true;
-        return Date{}; // TODO init
+        case MYSQL_TYPE_TINY:
+            return getByte(nColumnIndex);
+        case MYSQL_TYPE_SHORT:
+            return getShort(nColumnIndex);
+        case MYSQL_TYPE_LONG:
+            return getInt(nColumnIndex);
+        case MYSQL_TYPE_LONGLONG:
+            return getLong(nColumnIndex);
+        case MYSQL_TYPE_FLOAT:
+        case MYSQL_TYPE_DOUBLE:
+            return getDouble(nColumnIndex);
+        case MYSQL_TYPE_TIMESTAMP:
+        case MYSQL_TYPE_DATETIME:
+            return getTimestamp(nColumnIndex);
+        case MYSQL_TYPE_DATE:
+            return getDate(nColumnIndex);
+        case MYSQL_TYPE_TIME:
+            return getTime(nColumnIndex);
+        case MYSQL_TYPE_STRING:
+        case MYSQL_TYPE_VAR_STRING:
+        case MYSQL_TYPE_DECIMAL:
+        case MYSQL_TYPE_NEWDECIMAL:
+            return getString(nColumnIndex);
+        default:
+            mysqlc_sdbc_driver::throwFeatureNotImplementedException(
+                "OPreparedResultSet::getRowSetValue", *this);
+            return ORowSetValue();
     }
-    m_bWasNull = false;
+}
 
-    const MYSQL_TIME* pTime = static_cast<MYSQL_TIME*>(m_aData[column - 1].buffer);
+uno::Reference<XInputStream> SAL_CALL OPreparedResultSet::getBinaryStream(sal_Int32 /*column*/)
+{
+    mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getBinaryStream",
+                                                            *this);
+    return nullptr;
+}
 
-    assert(pTime != nullptr);
+uno::Reference<XInputStream> SAL_CALL OPreparedResultSet::getCharacterStream(sal_Int32 /*column*/)
+{
+    mysqlc_sdbc_driver::throwFeatureNotImplementedException(
+        "OPreparedResultSet::getCharacterStream", *this);
+    return nullptr;
+}
 
-    Date d;
-    d.Year = pTime->year;
-    d.Month = pTime->month;
-    d.Day = pTime->day;
-    return d;
+sal_Bool SAL_CALL OPreparedResultSet::getBoolean(sal_Int32 column)
+{
+    return safelyRetrieveValue<bool>(column);
 }
 
-double SAL_CALL OPreparedResultSet::getDouble(sal_Int32 column)
+sal_Int8 SAL_CALL OPreparedResultSet::getByte(sal_Int32 column)
 {
-    MutexGuard aGuard(m_aMutex);
-    checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
-    checkColumnIndex(column);
+    return safelyRetrieveValue<sal_Int8>(column);
+}
 
-    if (*m_aData[column - 1].is_null)
-    {
-        m_bWasNull = true;
-        return 0;
-    }
-    m_bWasNull = false;
+uno::Sequence<sal_Int8> SAL_CALL OPreparedResultSet::getBytes(sal_Int32 column)
+{
+    return safelyRetrieveValue<uno::Sequence<sal_Int8>>(column);
+}
 
-    if (m_aFields[column - 1].type == MYSQL_TYPE_FLOAT)
-        return *static_cast<float*>(m_aData[column - 1].buffer);
+Date SAL_CALL OPreparedResultSet::getDate(sal_Int32 column)
+{
+    return safelyRetrieveValue<Date>(column);
+}
 
-    return *static_cast<double*>(m_aData[column - 1].buffer);
+double SAL_CALL OPreparedResultSet::getDouble(sal_Int32 column)
+{
+    return safelyRetrieveValue<double>(column);
 }
 
 float SAL_CALL OPreparedResultSet::getFloat(sal_Int32 column)
 {
-    MutexGuard aGuard(m_aMutex);
-    checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
-    checkColumnIndex(column);
-
-    if (*m_aData[column - 1].is_null)
-    {
-        m_bWasNull = true;
-        return 0;
-    }
-    m_bWasNull = false;
-
-    return *static_cast<float*>(m_aData[column - 1].buffer);
+    return safelyRetrieveValue<float>(column);
 }
 
 sal_Int32 SAL_CALL OPreparedResultSet::getInt(sal_Int32 column)
 {
-    MutexGuard aGuard(m_aMutex);
-    checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
-    checkColumnIndex(column);
-    if (*m_aData[column - 1].is_null)
-    {
-        m_bWasNull = true;
-        return 0;
-    }
-    m_bWasNull = false;
-
-    return *static_cast<sal_Int32*>(m_aData[column - 1].buffer);
+    return safelyRetrieveValue<sal_Int32>(column);
 }
 
 sal_Int32 SAL_CALL OPreparedResultSet::getRow()
@@ -280,14 +350,7 @@ sal_Int32 SAL_CALL OPreparedResultSet::getRow()
 
 sal_Int64 SAL_CALL OPreparedResultSet::getLong(sal_Int32 column)
 {
-    MutexGuard aGuard(m_aMutex);
-    checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
-    checkColumnIndex(column);
-
-    if (*m_aData[column - 1].is_null)
-        return 0;
-
-    return *static_cast<sal_Int64*>(m_aData[column - 1].buffer);
+    return safelyRetrieveValue<sal_Int64>(column);
 }
 
 uno::Reference<XResultSetMetaData> SAL_CALL OPreparedResultSet::getMetaData()
@@ -356,94 +419,22 @@ Any SAL_CALL OPreparedResultSet::getObject(sal_Int32 column,
 
 sal_Int16 SAL_CALL OPreparedResultSet::getShort(sal_Int32 column)
 {
-    MutexGuard aGuard(m_aMutex);
-    checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
-    checkColumnIndex(column);
-
-    if (*m_aData[column - 1].is_null)
-    {
-        m_bWasNull = true;
-        return 0;
-    }
-    m_bWasNull = false;
-
-    return *static_cast<sal_Int16*>(m_aData[column - 1].buffer);
+    return safelyRetrieveValue<sal_Int16>(column);
 }
 
 OUString SAL_CALL OPreparedResultSet::getString(sal_Int32 column)
 {
-    MutexGuard aGuard(m_aMutex);
-    checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
-    checkColumnIndex(column);
-    if (*m_aData[column - 1].is_null)
-    {
-        m_bWasNull = true;
-        return OUString{};
-    }
-    m_bWasNull = false;
-
-    if (m_aFields[column - 1].type == MYSQL_TYPE_BIT)
-    {
-        if (*static_cast<sal_Int8*>(m_aData[column - 1].buffer) != 0)
-            return OUString{ "YES" };
-        return OUString{ "NO" };
-    }
-
-    const char* sStr = static_cast<const char*>(m_aData[column - 1].buffer);
-
-    OUString sReturn = OUString(sStr, *m_aData[column - 1].length, m_encoding);
-    return sReturn;
+    return safelyRetrieveValue<OUString>(column);
 }
 
 Time SAL_CALL OPreparedResultSet::getTime(sal_Int32 column)
 {
-    checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
-    MutexGuard aGuard(m_aMutex);
-    checkColumnIndex(column);
-
-    if (*m_aData[column - 1].is_null)
-    {
-        m_bWasNull = true;
-        return Time{}; // TODO init
-    }
-    m_bWasNull = false;
-
-    const MYSQL_TIME* pTime = static_cast<MYSQL_TIME*>(m_aData[column - 1].buffer);
-
-    assert(pTime != nullptr);
-
-    Time t;
-    t.Hours = pTime->hour;
-    t.Minutes = pTime->minute;
-    t.Seconds = pTime->second;
-    return t;
+    return safelyRetrieveValue<Time>(column);
 }
 
 DateTime SAL_CALL OPreparedResultSet::getTimestamp(sal_Int32 column)
 {
-    checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
-    MutexGuard aGuard(m_aMutex);
-    checkColumnIndex(column);
-
-    if (*m_aData[column - 1].is_null)
-    {
-        m_bWasNull = true;
-        return DateTime{};
-    }
-    m_bWasNull = false;
-
-    const MYSQL_TIME* pTime = static_cast<MYSQL_TIME*>(m_aData[column - 1].buffer);
-
-    assert(pTime != nullptr);
-
-    DateTime t;
-    t.Year = pTime->year;
-    t.Month = pTime->month;
-    t.Day = pTime->day;
-    t.Hours = pTime->hour;
-    t.Minutes = pTime->minute;
-    t.Seconds = pTime->second;
-    return t;
+    return safelyRetrieveValue<DateTime>(column);
 }
 
 sal_Bool SAL_CALL OPreparedResultSet::isBeforeFirst()
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx
index 647d872c50d8..b43935039efe 100644
--- a/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx
+++ b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx
@@ -36,6 +36,7 @@
 #include <com/sun/star/sdbcx/XDeleteRows.hpp>
 #include <com/sun/star/sdbcx/XRowLocate.hpp>
 #include <com/sun/star/util/XCancellable.hpp>
+#include <connectivity/FValue.hxx>
 
 #include <cppuhelper/compbase12.hxx>
 
@@ -91,6 +92,10 @@ class OPreparedResultSet final : public OBase_Mutex,
 
     void SAL_CALL getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const override;
 
+    template <typename T> T safelyRetrieveValue(const sal_Int32 nColumnIndex);
+    template <typename T> T retrieveValue(const sal_Int32 nColumnIndex);
+    connectivity::ORowSetValue getRowSetValue(sal_Int32 nColumnIndex);
+
     // you can't delete objects of this type
     virtual ~OPreparedResultSet() override = default;
 


More information about the Libreoffice-commits mailing list