sc/qa/uitest/calc_tests8/dataProvider.py       |   40 ++++++++++++++++++++++++-
 sc/source/ui/dataprovider/csvdataprovider.cxx  |   12 +++++--
 sc/source/ui/dataprovider/htmldataprovider.cxx |    8 +++--
 sc/source/ui/dataprovider/sqldataprovider.cxx  |    7 +++-
 sc/source/ui/dataprovider/xmldataprovider.cxx  |    7 +++-
 5 files changed, 62 insertions(+), 12 deletions(-)

New commits:
commit 655ba73e506d75ca9988a428620f543b213774b7
Author:     Neil Roberts <[email protected]>
AuthorDate: Sat Nov 29 12:42:11 2025 +0100
Commit:     Noel Grandin <[email protected]>
CommitDate: Wed Dec 3 19:23:03 2025 +0100

    tdf#169077: Add a UITest
    
    Co-authored-by: Regina Henschel <[email protected]>
    Change-Id: I7facde3d9aeea7ac3662da060ff821dfa2af7716
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194828
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <[email protected]>

diff --git a/sc/qa/uitest/calc_tests8/dataProvider.py 
b/sc/qa/uitest/calc_tests8/dataProvider.py
index d9052e1bc813..f4ae2917f81b 100644
--- a/sc/qa/uitest/calc_tests8/dataProvider.py
+++ b/sc/qa/uitest/calc_tests8/dataProvider.py
@@ -8,8 +8,11 @@
 #
 
 from uitest.framework import UITestCase
-from uitest.uihelper.common import get_state_as_dict, get_url_for_data_file
+from uitest.uihelper.common import get_state_as_dict, get_url_for_data_file, 
select_by_text
 from libreoffice.uno.propertyvalue import mkPropertyValues
+from libreoffice.calc.document import get_cell_by_position
+
+import os
 
 class DataProvider(UITestCase):
 
@@ -39,4 +42,39 @@ class DataProvider(UITestCase):
                         xApply.executeAction, args=('CLICK', ()), 
close_button="close") as dialog:
                     pass
 
+    def do_import(self, data_format, test_file, identifier, expected_value):
+        with self.ui_test.create_doc_in_start_center("calc") as xDoc:
+
+            # Make a database range on A1:K11 called "TestDB"
+            with 
self.ui_test.execute_dialog_through_command(".uno:DefineDBName") as xDialog:
+                xName = xDialog.getChild("entry")
+                xName.executeAction("SET", mkPropertyValues({"TEXT": 
"TestDB"}))
+
+                xRange = xDialog.getChild("assign")
+                xRange.executeAction("SET", mkPropertyValues({"TEXT": 
"$Sheet1.$A$1:$K$11"}))
+
+            # Set the provider for the range to be the data from the file
+            with 
self.ui_test.execute_dialog_through_command(".uno:DataProvider") as xDialog:
+                xRange = xDialog.getChild("select_db_range")
+                select_by_text(xRange, "TestDB")
+
+                xFormat = xDialog.getChild("provider_lst")
+                select_by_text(xFormat, data_format)
+
+                xURL = xDialog.getChild("ed_url")
+                xURL.executeAction("SET", mkPropertyValues({"TEXT": 
test_file}))
+
+                xId = xDialog.getChild("ed_id")
+                xId.executeAction("SET", mkPropertyValues({"TEXT": 
identifier}))
+
+            # Check that the import updated the A1 cell.
+            self.assertEqual(get_cell_by_position(xDoc, 0, 0, 0).getString(), 
expected_value)
+
+    def test_html_import(self):
+        # tdf#169077: Without the fix the none of the data gets imported
+        test_file = os.path.join(os.getenv("SRCDIR"),
+                                 "sc", "qa", "unit", "data", "dataprovider", 
"html",
+                                 "test1.html")
+        self.do_import("HTML", test_file, "//table", "Col1")
+
 # vim: set shiftwidth=4 softtabstop=4 expandtab:
commit 79b78ab1751f699ac5923cc49cb04eab2ead108c
Author:     Neil Roberts <[email protected]>
AuthorDate: Tue Dec 2 11:18:50 2025 +0100
Commit:     Noel Grandin <[email protected]>
CommitDate: Wed Dec 3 19:22:52 2025 +0100

    dataprovider: Run the import directly on the main thread
    
    When Import is called with mbDeterministic set to true, all of the data
    providers would previously launch the import thread and then immediately
    join the thread thus tying the main thread to the import thread. This is
    equivalent to just doing the work directly on the main thread because in
    either case the main thread is blocked until the work is complete.
    However, normally when the main thread tries to acquire the solar mutex
    it will additionally process any pending yield requests from other
    threads. In this case this yield processing doesn’t happen because the
    import thread returns false for IsMainThread even though in practice
    it’s working as if it’s the main thread because the real main thread is
    waiting on it.
    
    This patch instead makes it just run the import code directly in the
    current thread when mbDeterministic is true instead of launching the
    other thread. This is probably slightly more efficient, but the main
    reason to do this is to fix UI tests that invoke this code. In that case
    UIObjectUnoObj::executeAction will call Scheduler::ProcessEventsToIdle
    after sending the click event but without this patch that function’s
    attempt to cause the main thread to yield will never return when using
    the SVP backend. That happens because that backend doesn’t release the
    solar mutex when waiting for the main thread to yield and the import
    thread doesn’t yield when trying to acquire the mutex because it isn’t
    the main thread. Instead deadlock occurs.
    
    Change-Id: I0c0cf4542f899118e5b6da8bb68b4d645e3fe40e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194916
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <[email protected]>

diff --git a/sc/source/ui/dataprovider/csvdataprovider.cxx 
b/sc/source/ui/dataprovider/csvdataprovider.cxx
index 30874102d446..9cac06a48f2a 100644
--- a/sc/source/ui/dataprovider/csvdataprovider.cxx
+++ b/sc/source/ui/dataprovider/csvdataprovider.cxx
@@ -154,21 +154,25 @@ void CSVDataProvider::Import()
     mpDoc->ResetClip(mpDocument, SCTAB(0));
     mxCSVFetchThread = new CSVFetchThread(*mpDoc, mrDataSource.getURL(),
         [this]() { this->ImportFinished(); }, 
std::vector(mrDataSource.getDataTransformation()));
-    mxCSVFetchThread->launch();
 
     if (mbDeterministic)
     {
         SolarMutexReleaser aReleaser;
-        mxCSVFetchThread->join();
+        mxCSVFetchThread->execute();
 
         // tdf#165658 An exception may have happened during the parsing of the 
file.
-        // Since parsing happens in a separate thread, here we need to check if
-        // something wrong happened and then rethrow the exception
+        // CSVFetchThread::execute catches the exception and stores it in case 
it is running in a
+        // separate thread. Here we need to check if something wrong happened 
and then rethrow the
+        // exception
         if (mxCSVFetchThread->IsParseError())
         {
             std::rethrow_exception(mxCSVFetchThread->GetLastException());
         }
     }
+    else
+    {
+        mxCSVFetchThread->launch();
+    }
 }
 
 void CSVDataProvider::ImportFinished()
diff --git a/sc/source/ui/dataprovider/htmldataprovider.cxx 
b/sc/source/ui/dataprovider/htmldataprovider.cxx
index 29810a54384f..d4195d41b9f7 100644
--- a/sc/source/ui/dataprovider/htmldataprovider.cxx
+++ b/sc/source/ui/dataprovider/htmldataprovider.cxx
@@ -256,12 +256,14 @@ void HTMLDataProvider::Import()
     mpDoc->ResetClip(mpDocument, SCTAB(0));
     mxHTMLFetchThread = new HTMLFetchThread(*mpDoc, mrDataSource.getURL(), 
mrDataSource.getID(),
             [this]() { this->ImportFinished(); }, 
std::vector(mrDataSource.getDataTransformation()));
-    mxHTMLFetchThread->launch();
-
     if (mbDeterministic)
     {
         SolarMutexReleaser aReleaser;
-        mxHTMLFetchThread->join();
+        mxHTMLFetchThread->execute();
+    }
+    else
+    {
+        mxHTMLFetchThread->launch();
     }
 }
 
diff --git a/sc/source/ui/dataprovider/sqldataprovider.cxx 
b/sc/source/ui/dataprovider/sqldataprovider.cxx
index 05401075bf86..d015db233d33 100644
--- a/sc/source/ui/dataprovider/sqldataprovider.cxx
+++ b/sc/source/ui/dataprovider/sqldataprovider.cxx
@@ -147,12 +147,15 @@ void SQLDataProvider::Import()
     mxSQLFetchThread = new SQLFetchThread(*mpDoc, mrDataSource.getID(),
                                           
std::bind(&SQLDataProvider::ImportFinished, this),
                                           
std::vector(mrDataSource.getDataTransformation()));
-    mxSQLFetchThread->launch();
 
     if (mbDeterministic)
     {
         SolarMutexReleaser aReleaser;
-        mxSQLFetchThread->join();
+        mxSQLFetchThread->execute();
+    }
+    else
+    {
+        mxSQLFetchThread->launch();
     }
 }
 
diff --git a/sc/source/ui/dataprovider/xmldataprovider.cxx 
b/sc/source/ui/dataprovider/xmldataprovider.cxx
index 7572c3f358ec..3fe8ca016546 100644
--- a/sc/source/ui/dataprovider/xmldataprovider.cxx
+++ b/sc/source/ui/dataprovider/xmldataprovider.cxx
@@ -106,12 +106,15 @@ void XMLDataProvider::Import()
     mxXMLFetchThread = new XMLFetchThread(
         *mpDoc, mrDataSource.getURL(), mrDataSource.getXMLImportParam(), 
mrDataSource.getID(),
         [this]() { this->ImportFinished(); }, 
std::vector(mrDataSource.getDataTransformation()));
-    mxXMLFetchThread->launch();
 
     if (mbDeterministic)
     {
         SolarMutexReleaser aReleaser;
-        mxXMLFetchThread->join();
+        mxXMLFetchThread->execute();
+    }
+    else
+    {
+        mxXMLFetchThread->launch();
     }
 }
 

Reply via email to