SemanticMediaWiki / SemanticResultFormats

Provides additional visualizations (result formats) for Semantic MediaWiki
https://www.semantic-mediawiki.org/wiki/Extension:Semantic_Result_Formats
Other
45 stars 76 forks source link

[datatables] ($store) must be of type SMW\SQLStore\SQLStore, SMW\SPARQLStore\SPARQLStore given #827

Open simontaurus opened 7 months ago

simontaurus commented 7 months ago

Setup

Issue

(@thomas-topway-it) Sporadically pages with a datatables query throw the mentioned error, probably when a purge is executed but it's hard to reproduce

Exception caught: SMW\SQLStore\QueryEngineFactory::__construct(): Argument #1 ($store) must be of type SMW\SQLStore\SQLStore, SMW\SPARQLStore\SPARQLStore given, called in /var/www/html/w/extensions/SemanticResultFormats/formats/datatables/DataTables.php on line 727

The corresponding line is now in: https://github.com/SemanticMediaWiki/SemanticResultFormats/blob/6dd7e46c1913b6555d8ac2dd0ef8385d0e214709/formats/datatables/SearchPanes.php#L51

Not sure in which cases QueryResult->getStore() returns SMW\SPARQLStore\SPARQLStore in a SPARQLStore setup. https://github.com/SemanticMediaWiki/SemanticResultFormats/blob/6dd7e46c1913b6555d8ac2dd0ef8385d0e214709/formats/datatables/DataTables.php#L510

Workaround is to catch cases where SMW\SPARQLStore\SPARQLStore is given

if ( !( $this->store instanceof \SMW\SQLStore\SQLStore ) ) return [];

Steps to reproduce

  1. Setup with SPARQLStore
  2. Page with datatable ask query
    {{#ask: [[Category:A...]]
    |?Modification date
    |format=datatable
    |datatables-searchPanes=true
    |datatables-searchPanes.initCollapsed=true
    |sort=Modification date
    |order=desc
    }}
  3. Refresh / purge the page

Expected result: No exception

Observed result: exception occurs:

[e288ba64ad67a5461d8397e1] /wiki/Item:OSW1403aaa3e5ab4... TypeError: SMW\SQLStore\QueryEngineFactory::__construct(): Argument #1 ($store) must be of type SMW\SQLStore\SQLStore, SMW\SPARQLStore\SPARQLStore given, called in /var/www/html/w/extensions/SemanticResultFormats/formats/datatables/DataTables.php on line 725

Backtrace:

from /var/www/html/w/extensions/SemanticMediaWiki/src/SQLStore/QueryEngineFactory.php(36)
#0 /var/www/html/w/extensions/SemanticResultFormats/formats/datatables/DataTables.php(725): SMW\SQLStore\QueryEngineFactory->__construct()
#1 /var/www/html/w/extensions/SemanticResultFormats/formats/datatables/DataTables.php(522): SRF\DataTables->getSearchPanes()
#2 /var/www/html/w/extensions/SemanticResultFormats/formats/datatables/DataTables.php(395): SRF\DataTables->getResultText()
#3 /var/www/html/w/extensions/SemanticMediaWiki/src/Query/ResultPrinters/ResultPrinter.php(304): SRF\DataTables->buildResult()
#4 /var/www/html/w/extensions/SemanticMediaWiki/includes/query/SMW_QueryProcessor.php(348): SMW\Query\ResultPrinters\ResultPrinter->getResult()
#5 /var/www/html/w/extensions/SemanticMediaWiki/src/ParserFunctions/AskParserFunction.php(370): SMWQueryProcessor::getResultFromQuery()
#6 /var/www/html/w/extensions/SemanticMediaWiki/src/ParserFunctions/AskParserFunction.php(202): SMW\ParserFunctions\AskParserFunction->doFetchResultsFromFunctionParameters()
#7 /var/www/html/w/extensions/SemanticMediaWiki/src/ParserFunctionFactory.php(402): SMW\ParserFunctions\AskParserFunction->parse()
#8 /var/www/html/w/includes/parser/Parser.php(3437): SMW\ParserFunctionFactory->SMW\{closure}()
#9 /var/www/html/w/includes/parser/Parser.php(3122): Parser->callParserFunction()
#10 /var/www/html/w/includes/parser/PPFrame_Hash.php(275): Parser->braceSubstitution()
#11 /var/www/html/w/extensions/Scribunto/includes/engines/LuaCommon/LuaEngine.php(928): PPFrame_Hash->expand()
#12 /var/www/html/w/extensions/Scribunto/includes/engines/LuaCommon/LuaEngine.php(862): Scribunto_LuaEngine->doCachedExpansion()
#13 /var/www/html/w/extensions/Scribunto/includes/engines/LuaStandalone/LuaStandaloneInterpreter.php(399): Scribunto_LuaEngine->preprocess()
#14 /var/www/html/w/extensions/Scribunto/includes/engines/LuaStandalone/LuaStandaloneInterpreter.php(370): MediaWiki\Extension\Scribunto\Engines\LuaStandalone\LuaStandaloneInterpreter->callback()
#15 /var/www/html/w/extensions/Scribunto/includes/engines/LuaStandalone/LuaStandaloneInterpreter.php(446): MediaWiki\Extension\Scribunto\Engines\LuaStandalone\LuaStandaloneInterpreter->handleCall()
#16 /var/www/html/w/extensions/Scribunto/includes/engines/LuaStandalone/LuaStandaloneInterpreter.php(277): MediaWiki\Extension\Scribunto\Engines\LuaStandalone\LuaStandaloneInterpreter->dispatch()
#17 /var/www/html/w/extensions/Scribunto/includes/engines/LuaCommon/LuaEngine.php(302): MediaWiki\Extension\Scribunto\Engines\LuaStandalone\LuaStandaloneInterpreter->callFunction()
#18 /var/www/html/w/extensions/Scribunto/includes/engines/LuaCommon/LuaModule.php(71): Scribunto_LuaEngine->executeFunctionChunk()
#19 /var/www/html/w/extensions/Scribunto/includes/Hooks.php(158): Scribunto_LuaModule->invoke()
#20 /var/www/html/w/includes/parser/Parser.php(3437): MediaWiki\Extension\Scribunto\Hooks::invokeHook()
#21 /var/www/html/w/includes/parser/Parser.php(3122): Parser->callParserFunction()
#22 /var/www/html/w/includes/parser/PPFrame_Hash.php(275): Parser->braceSubstitution()
#23 /var/www/html/w/includes/parser/Parser.php(2951): PPFrame_Hash->expand()
#24 /var/www/html/w/includes/parser/Parser.php(1609): Parser->replaceVariables()
#25 /var/www/html/w/includes/parser/Parser.php(723): Parser->internalParse()
#26 /var/www/html/w/includes/content/WikitextContentHandler.php(301): Parser->parse()
#27 /var/www/html/w/includes/content/ContentHandler.php(1721): WikitextContentHandler->fillParserOutput()
#28 /var/www/html/w/includes/content/Renderer/ContentRenderer.php(47): ContentHandler->getParserOutput()
#29 /var/www/html/w/includes/Revision/RenderedRevision.php(266): MediaWiki\Content\Renderer\ContentRenderer->getParserOutput()
#30 /var/www/html/w/includes/Revision/RenderedRevision.php(237): MediaWiki\Revision\RenderedRevision->getSlotParserOutputUncached()
#31 /var/www/html/w/includes/Revision/RevisionRenderer.php(236): MediaWiki\Revision\RenderedRevision->getSlotParserOutput()
#32 /var/www/html/w/includes/Revision/RevisionRenderer.php(158): MediaWiki\Revision\RevisionRenderer->combineSlotOutput()
#33 [internal function]: MediaWiki\Revision\RevisionRenderer->MediaWiki\Revision\{closure}()
#34 /var/www/html/w/includes/Revision/RenderedRevision.php(199): call_user_func()
#35 /var/www/html/w/includes/poolcounter/PoolWorkArticleView.php(91): MediaWiki\Revision\RenderedRevision->getRevisionParserOutput()
#36 /var/www/html/w/includes/poolcounter/PoolWorkArticleViewCurrent.php(97): PoolWorkArticleView->renderRevision()
#37 /var/www/html/w/includes/poolcounter/PoolCounterWork.php(162): PoolWorkArticleViewCurrent->doWork()
#38 /var/www/html/w/includes/page/ParserOutputAccess.php(299): PoolCounterWork->execute()
#39 /var/www/html/w/includes/page/Article.php(714): MediaWiki\Page\ParserOutputAccess->getParserOutput()
#40 /var/www/html/w/includes/page/Article.php(528): Article->generateContentOutput()
#41 /var/www/html/w/includes/actions/ViewAction.php(78): Article->view()
#42 /var/www/html/w/includes/MediaWiki.php(542): ViewAction->show()
#43 /var/www/html/w/includes/MediaWiki.php(322): MediaWiki->performAction()
#44 /var/www/html/w/includes/MediaWiki.php(904): MediaWiki->performRequest()
#45 /var/www/html/w/includes/MediaWiki.php(562): MediaWiki->main()
#46 /var/www/html/w/index.php(50): MediaWiki->run()
#47 /var/www/html/w/index.php(46): wfIndexMain()
#48 {main}
thomas-topway-it commented 7 months ago

Hello @simontaurus as far as I understand you are using as SPARQLStore, is that correct ? I haven't tested it directly, however I think that QueryEngineFactory (for it to work) should be a subclass of SMW\SPARQLStore, not SMW\SQLStore. On the other side, a class SMW\SPARQLStore\QueryEngineFactory does not exist. So first I would need to know whether search panes queries are applicable to the SPARQLStore and they should be implemented for it. If so, we have to look at the class SMW\SPARQLStore\SPARQLStoreFactory (function newMasterQueryEngine), where there is some hint. Otherwise we could just use your workaround to provide an empty result.

simontaurus commented 7 months ago

Thank you for your response. Correct, I'm using a SPARQLStore. The missing SMW\SPARQLStore\QueryEngineFactory was also comming up while I was browsing the SMW sources. Apparently the issue only occurs with |sort=SomePropertyOfTypeDateTime while saving the page edits or purging the page, in all other cases (also normal reloads) everything including the search panels looks fine. Since |sort=SomePropertyOfTypeDateTime works in principle with other result formats I hope there's a solution.

thomas-topway-it commented 6 months ago

hello @simontaurus I've checked but I need to test with a SPARQLStore and I don't have it installed right now. Is there any docker container that I can use for this purpose ?

simontaurus commented 6 months ago

One option would be our docker image / compose-stack

simontaurus commented 5 months ago

After doing some research on that I still do not understand in which cases SMW passes an SPARQLStore as store and in which cases a SQLStore - it seems random. Maybe @JeroenDeDauw / @kghbln can elaborate on that.

While ElasticStore subclasses SQLStore https://github.com/SemanticMediaWiki/SemanticMediaWiki/blob/c8f778a85aca38d4d78173c4014f9dc40d067473/src/Elastic/ElasticStore.php#L39

SPARQLStore has a private member that is a SQLStore https://github.com/SemanticMediaWiki/SemanticMediaWiki/blob/c8f778a85aca38d4d78173c4014f9dc40d067473/src/SPARQLStore/SPARQLStore.php#L49-L66

So theoretically using this basestore should work, but any try to provide a SQLStore as fallback fails, see below.

public function getSearchPanes( $printRequests, $searchPanesOptions ) {
        if ( !( $this->datatables->store instanceof \SMW\SQLStore\SQLStore ) ) { // we got a SPARQLStore
                // $this->datatables->store = new SQLStore(); // fails, see exception
                // $this->datatables->store = \SMW\Services\ServicesFactory::getInstance()->getStore(); // fails, see exception
                // $this->datatables->store = \SMW\StoreFactory::getStore( "\SMW\SQLStore\SQLStore" ); // fails, see exception
                // $this->datatables->store = $this->datatables->store->baseStore; // fails, private property 'baseStore'
                $closure = \Closure::bind(function &(\SMW\SPARQLStore\SPARQLStore $class) { // dirty hack to access private member
                        return $class->baseStore;
                }, null, \SMW\SPARQLStore\SPARQLStore::class);
                $this->datatables->store = &$closure($this->datatables->store); // fails, see exception
        }
}

Exception (may indicate a dirty state on the DB due to a previous exception while playing around with some dirty hacks) Edit: unrelated, see #https://github.com/SemanticMediaWiki/SemanticMediaWiki/issues/5714

Error 1050: Table 't3' already exists
Function: SMW\SQLStore\TableBuilder\TemporaryTableBuilder::create
Query: CREATE TEMPORARY TABLE `t3`( id INT UNSIGNED KEY ) ENGINE=MEMORY

Backtrace:

from /var/www/html/w/includes/libs/rdbms/database/Database.php(1618)
#0 /var/www/html/w/includes/libs/rdbms/database/Database.php(1602): Wikimedia\Rdbms\Database->getQueryException()
#1 /var/www/html/w/includes/libs/rdbms/database/Database.php(1576): Wikimedia\Rdbms\Database->getQueryExceptionAndLog()
#2 /var/www/html/w/includes/libs/rdbms/database/Database.php(952): Wikimedia\Rdbms\Database->reportQueryError()
#3 /var/www/html/w/includes/libs/rdbms/database/DBConnRef.php(103): Wikimedia\Rdbms\Database->query()
#4 /var/www/html/w/includes/libs/rdbms/database/DBConnRef.php(293): Wikimedia\Rdbms\DBConnRef->__call()
#5 /var/www/html/w/extensions/SemanticMediaWiki/src/MediaWiki/Connection/Database.php(380): Wikimedia\Rdbms\DBConnRef->query()
#6 /var/www/html/w/extensions/SemanticMediaWiki/src/MediaWiki/Connection/Database.php(292): SMW\MediaWiki\Connection\Database->executeQuery()
#7 /var/www/html/w/extensions/SemanticMediaWiki/src/SQLStore/TableBuilder/TemporaryTableBuilder.php(59): SMW\MediaWiki\Connection\Database->query()
#8 /var/www/html/w/extensions/SemanticMediaWiki/src/SQLStore/QueryEngine/HierarchyTempTableBuilder.php(111): SMW\SQLStore\TableBuilder\TemporaryTableBuilder->create()
#9 /var/www/html/w/extensions/SemanticMediaWiki/src/SQLStore/QueryEngine/QuerySegmentListProcessor.php(355): SMW\SQLStore\QueryEngine\HierarchyTempTableBuilder->fillTempTable()
#10 /var/www/html/w/extensions/SemanticMediaWiki/src/SQLStore/QueryEngine/QuerySegmentListProcessor.php(132): SMW\SQLStore\QueryEngine\QuerySegmentListProcessor->hierarchy()
#11 /var/www/html/w/extensions/SemanticMediaWiki/src/SQLStore/QueryEngine/QuerySegmentListProcessor.php(146): SMW\SQLStore\QueryEngine\QuerySegmentListProcessor->segment()
#12 /var/www/html/w/extensions/SemanticMediaWiki/src/SQLStore/QueryEngine/QuerySegmentListProcessor.php(122): SMW\SQLStore\QueryEngine\QuerySegmentListProcessor->table()
#13 /var/www/html/w/extensions/SemanticMediaWiki/src/SQLStore/QueryEngine/QuerySegmentListProcessor.php(220): SMW\SQLStore\QueryEngine\QuerySegmentListProcessor->segment()
#14 /var/www/html/w/extensions/SemanticMediaWiki/src/SQLStore/QueryEngine/QuerySegmentListProcessor.php(125): SMW\SQLStore\QueryEngine\QuerySegmentListProcessor->conjunction()
#15 /var/www/html/w/extensions/SemanticMediaWiki/src/SQLStore/QueryEngine/QuerySegmentListProcessor.php(146): SMW\SQLStore\QueryEngine\QuerySegmentListProcessor->segment()
#16 /var/www/html/w/extensions/SemanticMediaWiki/src/SQLStore/QueryEngine/QuerySegmentListProcessor.php(122): SMW\SQLStore\QueryEngine\QuerySegmentListProcessor->table()
#17 /var/www/html/w/extensions/SemanticMediaWiki/src/SQLStore/QueryEngine/QuerySegmentListProcessor.php(115): SMW\SQLStore\QueryEngine\QuerySegmentListProcessor->segment()
#18 /var/www/html/w/extensions/SemanticResultFormats/formats/datatables/SearchPanes.php(153): SMW\SQLStore\QueryEngine\QuerySegmentListProcessor->process()
#19 /var/www/html/w/extensions/SemanticResultFormats/formats/datatables/SearchPanes.php(85): SRF\DataTables\SearchPanes->getPanesOptions()
#20 /var/www/html/w/extensions/SemanticResultFormats/formats/datatables/DataTables.php(586): SRF\DataTables\SearchPanes->getSearchPanes()
#21 /var/www/html/w/extensions/SemanticResultFormats/formats/datatables/DataTables.php(440): SRF\DataTables->getResultText()
#22 /var/www/html/w/extensions/SemanticMediaWiki/src/Query/ResultPrinters/ResultPrinter.php(304): SRF\DataTables->buildResult()
#23 /var/www/html/w/extensions/SemanticMediaWiki/includes/query/SMW_QueryProcessor.php(348): SMW\Query\ResultPrinters\ResultPrinter->getResult()
#24 /var/www/html/w/extensions/SemanticMediaWiki/src/ParserFunctions/AskParserFunction.php(370): SMWQueryProcessor::getResultFromQuery()
#25 /var/www/html/w/extensions/SemanticMediaWiki/src/ParserFunctions/AskParserFunction.php(202): SMW\ParserFunctions\AskParserFunction->doFetchResultsFromFunctionParameters()
#26 /var/www/html/w/extensions/SemanticMediaWiki/src/ParserFunctionFactory.php(402): SMW\ParserFunctions\AskParserFunction->parse()
#27 /var/www/html/w/includes/parser/Parser.php(3437): SMW\ParserFunctionFactory->SMW\{closure}()
#28 /var/www/html/w/includes/parser/Parser.php(3122): Parser->callParserFunction()
#29 /var/www/html/w/includes/parser/PPFrame_Hash.php(275): Parser->braceSubstitution()
#30 /var/www/html/w/includes/parser/Parser.php(2951): PPFrame_Hash->expand()
#31 /var/www/html/w/includes/parser/Parser.php(1609): Parser->replaceVariables()
#32 /var/www/html/w/includes/parser/Parser.php(723): Parser->internalParse()
#33 /var/www/html/w/includes/content/WikitextContentHandler.php(301): Parser->parse()
#34 /var/www/html/w/includes/content/ContentHandler.php(1721): WikitextContentHandler->fillParserOutput()
#35 /var/www/html/w/includes/content/Renderer/ContentRenderer.php(47): ContentHandler->getParserOutput()
#36 /var/www/html/w/includes/Revision/RenderedRevision.php(266): MediaWiki\Content\Renderer\ContentRenderer->getParserOutput()
#37 /var/www/html/w/includes/Revision/RenderedRevision.php(237): MediaWiki\Revision\RenderedRevision->getSlotParserOutputUncached()
#38 /var/www/html/w/includes/Revision/RevisionRenderer.php(221): MediaWiki\Revision\RenderedRevision->getSlotParserOutput()
#39 /var/www/html/w/includes/Revision/RevisionRenderer.php(158): MediaWiki\Revision\RevisionRenderer->combineSlotOutput()
#40 [internal function]: MediaWiki\Revision\RevisionRenderer->MediaWiki\Revision\{closure}()
#41 /var/www/html/w/includes/Revision/RenderedRevision.php(199): call_user_func()
#42 /var/www/html/w/includes/poolcounter/PoolWorkArticleView.php(91): MediaWiki\Revision\RenderedRevision->getRevisionParserOutput()
#43 /var/www/html/w/includes/poolcounter/PoolWorkArticleViewCurrent.php(97): PoolWorkArticleView->renderRevision()
#44 /var/www/html/w/includes/poolcounter/PoolCounterWork.php(162): PoolWorkArticleViewCurrent->doWork()
#45 /var/www/html/w/includes/page/ParserOutputAccess.php(299): PoolCounterWork->execute()
#46 /var/www/html/w/includes/page/Article.php(714): MediaWiki\Page\ParserOutputAccess->getParserOutput()
#47 /var/www/html/w/includes/page/Article.php(528): Article->generateContentOutput()
#48 /var/www/html/w/includes/actions/ViewAction.php(78): Article->view()
#49 /var/www/html/w/includes/MediaWiki.php(542): ViewAction->show()
#50 /var/www/html/w/includes/MediaWiki.php(322): MediaWiki->performAction()
#51 /var/www/html/w/includes/MediaWiki.php(904): MediaWiki->performRequest()
#52 /var/www/html/w/includes/MediaWiki.php(562): MediaWiki->main()
#53 /var/www/html/w/index.php(50): MediaWiki->run()
#54 /var/www/html/w/index.php(46): wfIndexMain()
#55 {main}
simontaurus commented 1 day ago

@thomas-topway-it, @JeroenDeDauw Since the error above was unrelated, this is actually a solution:

public function getSearchPanes( $printRequests, $searchPanesOptions ) {
        if ( this->datatables->store instanceof \SMW\SPARQLStore\SPARQLStore ) ) { // we got a SPARQLStore
                $closure = \Closure::bind(function &(\SMW\SPARQLStore\SPARQLStore $class) { // dirty hack to access private member
                        return $class->baseStore;
                }, null, \SMW\SPARQLStore\SPARQLStore::class);
                $this->datatables->store = &$closure($this->datatables->store); // works
        }
}

We can get rid of the closure if we make SPARQLStore->baseStore public see https://github.com/SemanticMediaWiki/SemanticMediaWiki/issues/5748