sc/inc/queryevaluator.hxx              |    3 +
 sc/qa/unit/ucalc.cxx                   |   56 +++++++++++++++++++++++++++++++++
 sc/source/core/data/dociter.cxx        |    3 +
 sc/source/core/data/queryevaluator.cxx |   27 +++++++--------
 4 files changed, 73 insertions(+), 16 deletions(-)

New commits:
commit 0d1971a8dc1f7ce24f67abcab4d6af9cf2b7b823
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Mon Dec 13 21:35:01 2021 +0100
Commit:     Eike Rathke <er...@redhat.com>
CommitDate: Tue Dec 14 17:04:39 2021 +0100

    make sure text operations are not queried by (numeric) value
    
    E.g. SC_CONTAINS is, according to isPartialTextMatchOp(), a text-only
    operation, so query it as such and not as a numeric value. This
    fixes/allows e.g. substring queries on dates.
    
    Change-Id: I6c612d9934193828b7a7eabed92f2bfeb385e5a0
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126767
    Tested-by: Jenkins
    Reviewed-by: Eike Rathke <er...@redhat.com>

diff --git a/sc/inc/queryevaluator.hxx b/sc/inc/queryevaluator.hxx
index 44bf52ec3685..a1fd20111071 100644
--- a/sc/inc/queryevaluator.hxx
+++ b/sc/inc/queryevaluator.hxx
@@ -79,7 +79,8 @@ class ScQueryEvaluator
 
     bool isRealWildOrRegExp(const ScQueryEntry& rEntry) const;
     bool isTestWildOrRegExp(const ScQueryEntry& rEntry) const;
-    static bool isQueryByValue(const ScQueryEntry::Item& rItem, const 
ScRefCellValue& rCell);
+    static bool isQueryByValue(const ScQueryEntry& rEntry, const 
ScQueryEntry::Item& rItem,
+                               const ScRefCellValue& rCell);
     static bool isQueryByValueForCell(const ScRefCellValue& rCell);
     static bool isQueryByString(const ScQueryEntry& rEntry, const 
ScQueryEntry::Item& rItem,
                                 const ScRefCellValue& rCell);
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 5d32bee3223b..402f3b4388d5 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -176,6 +176,7 @@ public:
     void testTdf137063();
     void testTdf126342();
     void testAdvancedFilter();
+    void testDateFilterContains();
     void testTdf98642();
     void testMergedCells();
     void testUpdateReference();
@@ -301,6 +302,7 @@ public:
     CPPUNIT_TEST(testTdf137063);
     CPPUNIT_TEST(testTdf126342);
     CPPUNIT_TEST(testAdvancedFilter);
+    CPPUNIT_TEST(testDateFilterContains);
     CPPUNIT_TEST(testTdf98642);
     CPPUNIT_TEST(testMergedCells);
     CPPUNIT_TEST(testUpdateReference);
@@ -3902,6 +3904,60 @@ void Test::testAdvancedFilter()
     m_pDoc->DeleteTab(0);
 }
 
+void Test::testDateFilterContains()
+{
+    m_pDoc->InsertTab(0, "Test");
+
+    constexpr SCCOL nCols = 1;
+    constexpr SCROW nRows = 5;
+    m_pDoc->SetString(0, 0, 0, "Date");
+    m_pDoc->SetString(0, 1, 0, "1/2/2021");
+    m_pDoc->SetString(0, 2, 0, "2/1/1999");
+    m_pDoc->SetString(0, 3, 0, "2/1/1997");
+    m_pDoc->SetString(0, 4, 0, "3/3/2001");
+    m_pDoc->SetString(0, 5, 0, "3/3/1996");
+
+    // Set the fields as dates.
+    SvNumberFormatter* pFormatter = m_pDoc->GetFormatTable();
+    sal_uInt32 nFormat = pFormatter->GetFormatIndex(NF_DATE_DIN_YYMMDD, 
LANGUAGE_ENGLISH_US);
+    ScPatternAttr aNewAttrs(m_pDoc->GetPool());
+    SfxItemSet& rSet = aNewAttrs.GetItemSet();
+    rSet.Put(SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat));
+    m_pDoc->ApplyPatternAreaTab(0, 1, 0, 5, 0, aNewAttrs); // apply it to A1:A6
+
+    ScDBData* pDBData = new ScDBData("NONAME", 0, 0, 0, nCols, nRows);
+    m_pDoc->SetAnonymousDBData(0, std::unique_ptr<ScDBData>(pDBData));
+
+    pDBData->SetAutoFilter(true);
+    ScRange aRange;
+    pDBData->GetArea(aRange);
+    m_pDoc->ApplyFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(),
+                           aRange.aEnd.Col(), aRange.aStart.Row(),
+                           aRange.aStart.Tab(), ScMF::Auto);
+
+    //create the query param
+    ScQueryParam aParam;
+    pDBData->GetQueryParam(aParam);
+    ScQueryEntry& rEntry = aParam.GetEntry(0);
+    rEntry.bDoQuery = true;
+    rEntry.nField = 0;
+    rEntry.eOp = SC_CONTAINS;
+    rEntry.GetQueryItem().maString = m_pDoc->GetSharedStringPool().intern("2");
+    pDBData->SetQueryParam(aParam);
+
+    // perform the query.
+    m_pDoc->Query(0, aParam, true);
+
+    // Dates in rows 2-4 contain '2', row 5 shows 2001 only as 01, and row 6 
doesn't contain it at all.
+    CPPUNIT_ASSERT_MESSAGE("row 2 should be visible", !m_pDoc->RowHidden(1, 
0));
+    CPPUNIT_ASSERT_MESSAGE("row 3 should be visible", !m_pDoc->RowHidden(2, 
0));
+    CPPUNIT_ASSERT_MESSAGE("row 4 should be visible", !m_pDoc->RowHidden(3, 
0));
+    CPPUNIT_ASSERT_MESSAGE("row 5 should be hidden", m_pDoc->RowHidden(4, 0));
+    CPPUNIT_ASSERT_MESSAGE("row 6 should be hidden", m_pDoc->RowHidden(5, 0));
+
+    m_pDoc->DeleteTab(0);
+}
+
 void Test::testTdf98642()
 {
     m_pDoc->InsertTab(0, "Sheet1");
diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx
index cafbbc9c0a1b..a50b6f00550e 100644
--- a/sc/source/core/data/dociter.cxx
+++ b/sc/source/core/data/dociter.cxx
@@ -47,6 +47,7 @@
 #include <svl/sharedstring.hxx>
 #include <unotools/collatorwrapper.hxx>
 #include <osl/diagnose.h>
+#include <sal/log.hxx>
 
 #include <algorithm>
 #include <limits>
@@ -642,6 +643,8 @@ bool 
ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScM
                 break;
             default:
                 // Only the above operators are supported.
+                SAL_WARN("sc.core", "Unsupported operator " << rEntry.eOp
+                    << " in 
ScDBQueryDataIterator::DataAccessMatrix::isValidQuery()");
                 continue;
         }
 
diff --git a/sc/source/core/data/queryevaluator.cxx 
b/sc/source/core/data/queryevaluator.cxx
index 2bc9db3e3a65..dd5d73897e0c 100644
--- a/sc/source/core/data/queryevaluator.cxx
+++ b/sc/source/core/data/queryevaluator.cxx
@@ -128,9 +128,10 @@ bool ScQueryEvaluator::isTestWildOrRegExp(const 
ScQueryEntry& rEntry) const
     return (rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_GREATER_EQUAL);
 }
 
-bool ScQueryEvaluator::isQueryByValue(const ScQueryEntry::Item& rItem, const 
ScRefCellValue& rCell)
+bool ScQueryEvaluator::isQueryByValue(const ScQueryEntry& rEntry, const 
ScQueryEntry::Item& rItem,
+                                      const ScRefCellValue& rCell)
 {
-    if (rItem.meType == ScQueryEntry::ByString)
+    if (rItem.meType == ScQueryEntry::ByString || isPartialTextMatchOp(rEntry))
         return false;
 
     return isQueryByValueForCell(rCell);
@@ -270,9 +271,8 @@ std::pair<bool, bool> 
ScQueryEvaluator::compareByValue(const ScRefCellValue& rCe
             bOk = !::rtl::math::approxEqual(nCellVal, fQueryVal);
             break;
         default:
-        {
-            // added to avoid warnings
-        }
+            assert(false);
+            break;
     }
 
     return std::pair<bool, bool>(bOk, bTestEqual);
@@ -412,9 +412,8 @@ std::pair<bool, bool> 
ScQueryEvaluator::compareByString(const ScQueryEntry& rEnt
                     bOk = !(bMatch && (nEnd == rValue.getLength()));
                     break;
                 default:
-                {
-                    // added to avoid warnings
-                }
+                    assert(false);
+                    break;
             }
         }
         else
@@ -545,9 +544,8 @@ std::pair<bool, bool> 
ScQueryEvaluator::compareByString(const ScQueryEntry& rEnt
                         bOk = (nStrPos < 0);
                         break;
                     default:
-                    {
-                        // added to avoid warnings
-                    }
+                        assert(false);
+                        break;
                 }
             }
         }
@@ -575,9 +573,8 @@ std::pair<bool, bool> 
ScQueryEvaluator::compareByString(const ScQueryEntry& rEnt
                         bTestEqual = (nCompare == 0);
                     break;
                 default:
-                {
-                    // added to avoid warnings
-                }
+                    assert(false);
+                    break;
             }
         }
     }
@@ -845,7 +842,7 @@ std::pair<bool, bool> ScQueryEvaluator::processEntry(SCROW 
nRow, SCCOL nCol, ScR
             aRes.first |= aThisRes.first;
             aRes.second |= aThisRes.second;
         }
-        else if (isQueryByValue(rItem, aCell))
+        else if (isQueryByValue(rEntry, rItem, aCell))
         {
             std::pair<bool, bool> aThisRes = compareByValue(aCell, nCol, nRow, 
rEntry, rItem);
             aRes.first |= aThisRes.first;

Reply via email to