Date: prev next · Thread: first prev next last
2012 Archives by date, by thread · List index


fdo#44813 is a crasher on 3.4.x, and has been filed as such
separately in fdo#44823.

Since it is a crasher, let's fix it in 3.4.x, too. Attached is a port
to libreoffice-3-4 of the corresponding commits in
libreoffice-3-5, with the later fixup:


commit acc36a60de35cdc07e41d1838738b7603e87cf4d
Author: Lionel Elie Mamane <lionel@mamane.lu>
Date:   Tue Jan 31 21:32:55 2012 +0100

    fdo#45453: use integers rather than booleans

    for always-true and always-false tests.
    Some databases have poor or no support for booleans.

    Signed-off-by: Jan Holesovsky <kendy@suse.cz>


folded in.


-- 
Lionel
From 68101c976558d99a092777da54ba5414bef75e1f Mon Sep 17 00:00:00 2001
From: Lionel Elie Mamane <lionel@mamane.lu>
Date: Mon, 16 Jan 2012 19:38:01 +0100
Subject: [PATCH 1/2] fdo#44813: don't replace NULLs given by the database by
 type-default values

It makes no sense, because non-nullable columns can have NULL value.
E.g. in "foo LEFT JOIN bar ON condition", the non-nullable columns of "bar"
when it has no row matching "condition".

Even when we are about to insert/update a row, we should not put a
hard-coded value (that just happens to be the one constructed by the
C++ default constructor for that type) in non-nullable columns: there
is no guarantee that this value makes sense in that database's context.
The database may or may not have a default value set for that column.
If it has, we should leave it up to the database to set it automatically.
If it has not, an error *is* the right reaction.

Another place where this substitution does damage is when we refresh a
row. We use the values we have read from the primary key to select the
row again. So we should not mangle those, else the select returns no
row and we mistakingly think the row has been deleted.
---
 dbaccess/source/core/api/CacheSet.cxx      |    2 +-
 dbaccess/source/core/api/KeySet.cxx        |   10 +++++-----
 dbaccess/source/core/api/OptimisticSet.cxx |    2 +-
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/dbaccess/source/core/api/CacheSet.cxx b/dbaccess/source/core/api/CacheSet.cxx
index ca3c4d1..7e18fa0 100644
--- a/dbaccess/source/core/api/CacheSet.cxx
+++ b/dbaccess/source/core/api/CacheSet.cxx
@@ -429,7 +429,7 @@ void OCacheSet::fillValueRow(ORowSetRow& _rRow,sal_Int32 _nPosition)
     for(sal_Int32 i=1;aIter != aEnd;++aIter,++i)
     {
         aIter->setSigned(m_aSignedFlags[i-1]);
-        aIter->fill(i,m_aColumnTypes[i-1],m_aNullable[i-1],this);
+        aIter->fill(i, m_aColumnTypes[i-1], this);
     }
 }
 
diff --git a/dbaccess/source/core/api/KeySet.cxx b/dbaccess/source/core/api/KeySet.cxx
index 5ae3385..407b700 100644
--- a/dbaccess/source/core/api/KeySet.cxx
+++ b/dbaccess/source/core/api/KeySet.cxx
@@ -758,7 +758,7 @@ void OKeySet::executeInsert( const ORowSetRow& _rInsertRow,const ::rtl::OUString
 #endif
                         SelectColumnsMetaData::iterator aFind = 
m_pKeyColumnNames->find(*aAutoIter);
                         if ( aFind != m_pKeyColumnNames->end() )
-                            
(_rInsertRow->get())[aFind->second.nPosition].fill(i,aFind->second.nType,aFind->second.bNullable,xRow);
+                            (_rInsertRow->get())[aFind->second.nPosition].fill(i, 
aFind->second.nType, xRow);
                     }
                     bAutoValuesFetched = sal_True;
                 }
@@ -818,7 +818,7 @@ void OKeySet::executeInsert( const ORowSetRow& _rInsertRow,const ::rtl::OUString
                         // we will only fetch values which are keycolumns
                         SelectColumnsMetaData::iterator aFind = 
m_pKeyColumnNames->find(*aAutoIter);
                         if ( aFind != aEnd )
-                            
(_rInsertRow->get())[aFind->second.nPosition].fill(i,aFind->second.nType,aFind->second.bNullable,xRow);
+                            (_rInsertRow->get())[aFind->second.nPosition].fill(i, 
aFind->second.nType, xRow);
                     }
                 }
                 ::comphelper::disposeComponent(xStatement);
@@ -1335,13 +1335,13 @@ sal_Bool OKeySet::fetchRow()
     {
         ORowSetRow aKeyRow = new connectivity::ORowVector< ORowSetValue 
((*m_pKeyColumnNames).size() + m_pForeignColumnNames->size());
         connectivity::ORowVector< ORowSetValue >::Vector::iterator aIter = aKeyRow->get().begin();
-        // first fetch the values needed for the key column
+        // first fetch the values needed for the key columns
         SelectColumnsMetaData::const_iterator aPosIter = (*m_pKeyColumnNames).begin();
         SelectColumnsMetaData::const_iterator aPosEnd = (*m_pKeyColumnNames).end();
         for(;aPosIter != aPosEnd;++aPosIter,++aIter)
         {
             const SelectColumnDescription& rColDesc = aPosIter->second;
-            aIter->fill(rColDesc.nPosition,rColDesc.nType,rColDesc.bNullable,m_xDriverRow);
+            aIter->fill(rColDesc.nPosition, rColDesc.nType, m_xDriverRow);
         }
         // now fetch the values from the missing columns from other tables
         aPosIter = (*m_pForeignColumnNames).begin();
@@ -1349,7 +1349,7 @@ sal_Bool OKeySet::fetchRow()
         for(;aPosIter != aPosEnd;++aPosIter,++aIter)
         {
             const SelectColumnDescription& rColDesc = aPosIter->second;
-            aIter->fill(rColDesc.nPosition,rColDesc.nType,rColDesc.bNullable,m_xDriverRow);
+            aIter->fill(rColDesc.nPosition, rColDesc.nType, m_xDriverRow);
         }
         m_aKeyIter = 
m_aKeyMap.insert(OKeySetMatrix::value_type(m_aKeyMap.rbegin()->first+1,OKeySetValue(aKeyRow,::std::pair<sal_Int32,Reference<XRow>
(0,NULL)))).first;
     }
diff --git a/dbaccess/source/core/api/OptimisticSet.cxx b/dbaccess/source/core/api/OptimisticSet.cxx
index 38dba0e..a84eb9c 100644
--- a/dbaccess/source/core/api/OptimisticSet.cxx
+++ b/dbaccess/source/core/api/OptimisticSet.cxx
@@ -722,7 +722,7 @@ void OptimisticSet::fillMissingValues(ORowSetValueVector::Vector& io_aRow) const
                         {
                             if ( aColIter->second.sTableName == aSqlIter->first )
                             {
-                                
io_aRow[aColIter->second.nPosition].fill(i++,aColIter->second.nType,aColIter->second.bNullable,xRow);
+                                io_aRow[aColIter->second.nPosition].fill(i++, 
aColIter->second.nType, xRow);
                                 io_aRow[aColIter->second.nPosition].setModified();
                             }
                         }
-- 
1.7.7.3

From a6c3a95501b63e77e67e5fe6f1b57e5f579e84e3 Mon Sep 17 00:00:00 2001
From: Lionel Elie Mamane <lionel@mamane.lu>
Date: Wed, 18 Jan 2012 12:30:36 +0100
Subject: [PATCH 2/2] fdo#44813: make the refresh query filter NULL-safe

---
 dbaccess/source/core/api/KeySet.cxx |   77 ++++++++++++++++++++++++----------
 dbaccess/source/core/api/KeySet.hxx |    5 ++
 2 files changed, 59 insertions(+), 23 deletions(-)

diff --git a/dbaccess/source/core/api/KeySet.cxx b/dbaccess/source/core/api/KeySet.cxx
index 407b700..8c7f83a 100644
--- a/dbaccess/source/core/api/KeySet.cxx
+++ b/dbaccess/source/core/api/KeySet.cxx
@@ -219,22 +219,56 @@ void OKeySet::findTableColumnsMatching_throw(   const Any& i_aTable,
             m_aAutoColumns.push_back( keyColumn->first );
     }
 }
+namespace
+{
+    void appendOneKeyColumnClause( const ::rtl::OUString &tblName, const ::rtl::OUString &colName, 
::rtl::OUStringBuffer &o_buf )
+    {
+        static ::rtl::OUString s_sDot(RTL_CONSTASCII_USTRINGPARAM("."));
+        static ::rtl::OUString s_sParam0(RTL_CONSTASCII_USTRINGPARAM(" ( 1 = ? AND "));
+        static ::rtl::OUString s_sParam1(RTL_CONSTASCII_USTRINGPARAM(" = ? OR 1 = ? AND "));
+        static ::rtl::OUString s_sParam2(RTL_CONSTASCII_USTRINGPARAM(" IS NULL ) "));
+        o_buf.append(s_sParam0);
+        o_buf.append(tblName);
+        o_buf.append(s_sDot);
+        o_buf.append(colName);
+        o_buf.append(s_sParam1);
+        o_buf.append(tblName);
+        o_buf.append(s_sDot);
+        o_buf.append(colName);
+        o_buf.append(s_sParam2);
+    }
+}
+
+void OKeySet::setOneKeyColumnParameter( sal_Int32 &nPos, const Reference< XParameters > 
&_xParameter, const connectivity::ORowSetValue &_rValue, sal_Int32 _nType, sal_Int32 _nScale ) const
+{
+    if ( _rValue.isNull() )
+    {
+        _xParameter->setByte( nPos++, 0 );
+        // We do the full call so that the right sqlType is passed to setNull
+        setParameter( nPos++, _xParameter, _rValue, _nType, _nScale );
+        _xParameter->setByte( nPos++, 1 );
+    }
+    else
+    {
+        _xParameter->setByte( nPos++, 1 );
+        setParameter( nPos++, _xParameter, _rValue, _nType, _nScale );
+        _xParameter->setByte( nPos++, 0 );
+    }
+}
+
 ::rtl::OUStringBuffer OKeySet::createKeyFilter()
 {
     static ::rtl::OUString aAnd(RTL_CONSTASCII_USTRINGPARAM(" AND "));
-    const ::rtl::OUString aQuote       = getIdentifierQuoteString();
+    const ::rtl::OUString aQuote    = getIdentifierQuoteString();
     ::rtl::OUStringBuffer aFilter;
-    static ::rtl::OUString s_sDot(RTL_CONSTASCII_USTRINGPARAM("."));
-    static ::rtl::OUString s_sParam(RTL_CONSTASCII_USTRINGPARAM(" = ?"));
     // create the where clause
     Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
     SelectColumnsMetaData::iterator aPosEnd = m_pKeyColumnNames->end();
     for(SelectColumnsMetaData::iterator aPosIter = m_pKeyColumnNames->begin();aPosIter != aPosEnd;)
     {
-        aFilter.append(::dbtools::quoteTableName( 
xMeta,aPosIter->second.sTableName,::dbtools::eInDataManipulation));
-        aFilter.append(s_sDot);
-        aFilter.append(::dbtools::quoteName( aQuote,aPosIter->second.sRealName));
-        aFilter.append(s_sParam);
+        appendOneKeyColumnClause(::dbtools::quoteTableName( 
xMeta,aPosIter->second.sTableName,::dbtools::eInDataManipulation),
+                                 ::dbtools::quoteName( aQuote,aPosIter->second.sRealName),
+                                 aFilter);
         ++aPosIter;
         if(aPosIter != aPosEnd)
             aFilter.append(aAnd);
@@ -272,8 +306,6 @@ void OKeySet::construct(const Reference< XResultSet>& _xDriverSet,const ::rtl::O
     {
         static ::rtl::OUString aAnd(RTL_CONSTASCII_USTRINGPARAM(" AND "));
         const ::rtl::OUString aQuote   = getIdentifierQuoteString();
-        static ::rtl::OUString s_sDot(RTL_CONSTASCII_USTRINGPARAM("."));
-        static ::rtl::OUString s_sParam(RTL_CONSTASCII_USTRINGPARAM(" = ?"));
         const ::rtl::OUString* pIter = aSeq.getConstArray();
         const ::rtl::OUString* pEnd      = pIter + aSeq.getLength();
         for(;pIter != pEnd;++pIter)
@@ -290,12 +322,11 @@ void OKeySet::construct(const Reference< XResultSet>& _xDriverSet,const 
::rtl::O
                 for(SelectColumnsMetaData::iterator aPosIter = 
(*m_pForeignColumnNames).begin();aPosIter != aPosEnd;++aPosIter)
                 {
                     // look for columns not in the source columns to use them as filter as well
-                        if ( aFilter.getLength() )
-                            aFilter.append(aAnd);
-                        aFilter.append(::dbtools::quoteName( aQuote,sSelectTableName));
-                        aFilter.append(s_sDot);
-                        aFilter.append(::dbtools::quoteName( aQuote,aPosIter->second.sRealName));
-                        aFilter.append(s_sParam);
+                    if ( aFilter.getLength() )
+                        aFilter.append(aAnd);
+                    appendOneKeyColumnClause(::dbtools::quoteName( aQuote,sSelectTableName),
+                                             ::dbtools::quoteName( 
aQuote,aPosIter->second.sRealName),
+                                             aFilter);
                 }
                 break;
             }
@@ -875,12 +906,12 @@ void OKeySet::tryRefetch(const ORowSetRow& _rInsertRow,bool bRefetch)
             connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aIter2 = 
m_aKeyIter->second.first->get().begin();
             SelectColumnsMetaData::const_iterator aPosIter = (*m_pKeyColumnNames).begin();
             SelectColumnsMetaData::const_iterator aPosEnd = (*m_pKeyColumnNames).end();
-            for(;aPosIter != aPosEnd;++aPosIter,++aIter2,++nPos)
-                
setParameter(nPos,xParameter,*aIter2,aPosIter->second.nType,aPosIter->second.nScale);
+            for(;aPosIter != aPosEnd;++aPosIter,++aIter2)
+                
setOneKeyColumnParameter(nPos,xParameter,*aIter2,aPosIter->second.nType,aPosIter->second.nScale);
             aPosIter = (*m_pForeignColumnNames).begin();
             aPosEnd = (*m_pForeignColumnNames).end();
-            for(;aPosIter != aPosEnd;++aPosIter,++aIter2,++nPos)
-                
setParameter(nPos,xParameter,*aIter2,aPosIter->second.nType,aPosIter->second.nScale);
+            for(;aPosIter != aPosEnd;++aPosIter,++aIter2)
+                
setOneKeyColumnParameter(nPos,xParameter,*aIter2,aPosIter->second.nType,aPosIter->second.nScale);
 
             m_xSet = m_xStatement->executeQuery();
             OSL_ENSURE(m_xSet.is(),"No resultset form statement!");
@@ -1308,12 +1339,12 @@ void SAL_CALL OKeySet::refreshRow() throw(SQLException, RuntimeException)
     connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aIter = 
m_aKeyIter->second.first->get().begin();
     SelectColumnsMetaData::const_iterator aPosIter = (*m_pKeyColumnNames).begin();
     SelectColumnsMetaData::const_iterator aPosEnd = (*m_pKeyColumnNames).end();
-    for(;aPosIter != aPosEnd;++aPosIter,++aIter,++nPos)
-        setParameter(nPos,xParameter,*aIter,aPosIter->second.nType,aPosIter->second.nScale);
+    for(;aPosIter != aPosEnd;++aPosIter,++aIter)
+        
setOneKeyColumnParameter(nPos,xParameter,*aIter,aPosIter->second.nType,aPosIter->second.nScale);
     aPosIter = (*m_pForeignColumnNames).begin();
     aPosEnd = (*m_pForeignColumnNames).end();
-    for(;aPosIter != aPosEnd;++aPosIter,++aIter,++nPos)
-        setParameter(nPos,xParameter,*aIter,aPosIter->second.nType,aPosIter->second.nScale);
+    for(;aPosIter != aPosEnd;++aPosIter,++aIter)
+        
setOneKeyColumnParameter(nPos,xParameter,*aIter,aPosIter->second.nType,aPosIter->second.nScale);
 
     m_xSet = m_xStatement->executeQuery();
     OSL_ENSURE(m_xSet.is(),"No resultset form statement!");
diff --git a/dbaccess/source/core/api/KeySet.hxx b/dbaccess/source/core/api/KeySet.hxx
index 826ec1a..84781d4 100644
--- a/dbaccess/source/core/api/KeySet.hxx
+++ b/dbaccess/source/core/api/KeySet.hxx
@@ -138,6 +138,11 @@ namespace dbaccess
                                              const ::com::sun::star::uno::Reference< 
::com::sun::star::sdbc::XDatabaseMetaData>& i_xMeta,
                                              const ::com::sun::star::uno::Reference< 
::com::sun::star::container::XNameAccess>& i_xQueryColumns,
                                              ::std::auto_ptr<SelectColumnsMetaData>& 
o_pKeyColumnNames);
+        void setOneKeyColumnParameter( sal_Int32 &nPos,
+                                       const ::com::sun::star::uno::Reference<  
::com::sun::star::sdbc::XParameters > &_xParameter,
+                                       const connectivity::ORowSetValue &_rValue,
+                                       sal_Int32 _nType,
+                                       sal_Int32 _nScale ) const;
         ::rtl::OUStringBuffer createKeyFilter();
         void tryRefetch(const ORowSetRow& _rInsertRow,bool bRefetch);
         void executeUpdate(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOrginalRow,const 
::rtl::OUString& i_sSQL,const ::rtl::OUString& i_sTableName,const ::std::vector<sal_Int32>& 
_aIndexColumnPositions = ::std::vector<sal_Int32>());
-- 
1.7.7.3


Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.