Physikerwelt has submitted this change and it was merged. Change subject: Prepare for using DB2 as Database backend. ......................................................................
Prepare for using DB2 as Database backend. This change prepares MathSearch to use rendering engines other than mathWebSearch. UnitTests demonstrate that DB2 can be used as database backend. The integration to the user frontend will be a follow up commit. Change-Id: I4b947d7c7d37eb1409e7f3e57d9b1ff156b4c015 --- A MathEngineDB2.php M MathObject.php M MathQueryObject.php M MathSearch.php M SpecialMathSearch.php M tests/MathDB2ConnectionTest.php A tests/MathEngineTest.php M tests/MathXQueryTest.php 8 files changed, 378 insertions(+), 61 deletions(-) Approvals: Physikerwelt: Verified; Looks good to me, approved diff --git a/MathEngineDB2.php b/MathEngineDB2.php new file mode 100644 index 0000000..ace4d45 --- /dev/null +++ b/MathEngineDB2.php @@ -0,0 +1,118 @@ +<?php + +/** + * MediaWiki MathSearch extension + * + * (c) 2014 Moritz Schubotz + * GPLv2 license; info in main package. + * + * @file + * @ingroup extensions + */ +class MathEngineDB2 { + /** @var MathQueryObject the query to be answered*/ + protected $query; + protected $size = false; + protected $resultSet; + protected $relevanceMap; + + /** + * + * @return MathQueryObject + */ + public function getQuery() { + return $this->query; + } + + function __construct(MathQueryObject $query) { + $this->query = $query; + } + public function getSize() { + return $this->size; + } + + public function getResultSet() { + return $this->resultSet; + } + + public function getRelevanceMap() { + return $this->relevanceMap; + } + + /** + * + * @param MathQueryObject $query + * @return \MathSearchEngine + */ + public function setQuery(MathQueryObject $query) { + $this->query = $query; + return $this; + } + + + /** + * + * @param XQueryGenartorDB2 $query + * @return \DB2 + */ + public function setDBQuery(XQueryGeneratorDB2 $query){ + $this->query = $query; + return $this; + } + + + + + /** + * Posts the query to mwsd and evaluates the result data + * @return boolean + */ + function postQuery() { + + global $wgMathSearchMWSUrl, $wgMathDebug; + global $wgMathSearchDB2ConnStr; + if ( ! MathSearchHooks::isDB2Supported() ) { + throw new error( 'DB2 php client is not installed.' ); + } + $conn = db2_connect($wgMathSearchDB2ConnStr, '', ''); + $stmt = db2_exec($conn, $this->query->getXQuery() ); + + $this->size = db2_num_rows ( $stmt ); + wfDebugLog( "MathSearch", $this->size . " results retrieved from $wgMathSearchMWSUrl." ); + if ($this->size ==-1) { + return true; + } + + $this->relevanceMap = array(); + $this->resultSet = array(); + + $texResults = array(); + $moArray = array(); + while($row = db2_fetch_row( $stmt ) ){ + //FIXME: tex is not a really good key for lookup change to the md5 inputhash + // than use $mo = MathObject::newFromMd5($theMD5) to get the MathObject + $tex = db2_result( $stmt, 0 ); + $tex = str_replace( '<?xml version="1.0" encoding="UTF-8" ?>' , '' , $tex ); + $texResults[] = $tex; + + + $mo = new MathObject($tex); + //$md = MathObject::newFromMd5($tex); + $mo->readFromDatabase(); + + $all = $mo->getAllOccurences(); + + array_push($moArray, $all); + } + //@var $mo MathObject + foreach ($moArray as $mo) { + + $this->relevanceMap[$mo->getPageID()]=true; + //$this->resultSet[(string) $mo->getPageID()][(string) $mo->getAnchorID()][] = array( "xpath" => '/', "mappings" => array() ); // ,"original"=>$page->asXML() + } + + //$this->processMathResults( $xres ); + return true; + + } +} \ No newline at end of file diff --git a/MathObject.php b/MathObject.php index fa504fd..b0b4ef6 100644 --- a/MathObject.php +++ b/MathObject.php @@ -1,6 +1,6 @@ <?php -class MathObject extends MathMathML { +class MathObject extends MathLaTeXML { protected $anchorID = 0; protected $pageID = 0; @@ -199,7 +199,7 @@ * Gets all occurences of the tex. * @return array(MathObject) */ - public function getAllOccurences() { + public function getAllOccurences($printOutput = true) { $out = array( ); $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( @@ -210,7 +210,7 @@ //self::DebugPrint( var_export( $row, true ) ); $var = self::constructformpagerow( $row ); if ( $var ) { - $var->printLink2Page( false ); + if ($printOutput) $var->printLink2Page( false ); array_push( $out, $var ); } } diff --git a/MathQueryObject.php b/MathQueryObject.php index da8d4ac..dc06222 100644 --- a/MathQueryObject.php +++ b/MathQueryObject.php @@ -32,6 +32,10 @@ 'texvc'), ); + /** + * @param string $texquery the TeX-like search input + * @param string $xQueryDialect e.g. db2 or basex + */ public function __construct( $texquery='' , $xQueryDialect = 'db2' ) { $this->texquery = $texquery; $this->xQueryDialect = $xQueryDialect; @@ -214,7 +218,7 @@ * @return XQueryGenerator * @throws Exception */ - public function setXQueryGenerator( $dialect = false ){ + public function setXQueryDialect( $dialect = false ){ if ($dialect === false){ $dialect = $this->xQueryDialect; } @@ -230,10 +234,12 @@ } return $this->xQuery; } - + public function setXQueryGenerator($xQueryGenerator){ + $this->xQuery = $xQueryGenerator; + } public function getXQueryGenerator(){ if ($this->xQuery === false){ - $this->setXQueryGenerator(); + $this->setXQueryDialect(); } return $this->xQuery; } diff --git a/MathSearch.php b/MathSearch.php index 54b491c..662b4a7 100644 --- a/MathSearch.php +++ b/MathSearch.php @@ -44,6 +44,7 @@ $wgAutoloadClasses['SpecialMathDebug'] = $dir . 'SpecialMathDebug.php'; $wgAutoloadClasses['SpecialMathIndex'] = $dir . 'SpecialMathIndex.php'; $wgAutoloadClasses['MathEngineMws'] = $dir . 'MathEngineMws.php'; +$wgAutoloadClasses['MathEngineDB2'] = $dir . 'MathEngineDB2.php'; $wgMessagesDirs['MathSeach'] = __DIR__ . '/i18n'; $wgExtensionMessagesFiles['MathSearch'] = $dir . 'MathSearch.i18n.php'; diff --git a/SpecialMathSearch.php b/SpecialMathSearch.php index ab71290..634f5e9 100644 --- a/SpecialMathSearch.php +++ b/SpecialMathSearch.php @@ -192,10 +192,10 @@ $query = new MathQueryObject( $this->mathpattern ); switch ($this->mathEngine){ case 'db2': - $query->setXQueryGenerator( 'db2' ); + $query->setXQueryDialect( 'db2' ); break; case 'basex': - $query->setXQueryGenerator( 'basex' ); + $query->setXQueryDialect( 'basex' ); } $cQuery = $query->getCQuery(); if ( $cQuery ) { @@ -207,7 +207,12 @@ $this->printSource( $query->getCQuery() ); } } - $this->mathBackend = new MathEngineMws($query); + if( $this->mathEngine == 'db2'){ + $this->mathBackend = new MathEngineDB2($query); + } else { + $this->mathBackend = new MathEngineMws($query); + } + if ( $this->mathBackend->postQuery() ) { $out->addWikiText( "Your mathquery was successfully submitted and " . $this->mathBackend->getSize() . " hits were obtained." ); } else { diff --git a/tests/MathDB2ConnectionTest.php b/tests/MathDB2ConnectionTest.php index 45c17f9..2f0666d 100644 --- a/tests/MathDB2ConnectionTest.php +++ b/tests/MathDB2ConnectionTest.php @@ -7,12 +7,21 @@ * @group Database */ class MathD2ConnectionTest extends MediaWikiTestCase { - public function testConnect() { - global $wgMathSearchDB2ConnStr; + private $phpErrorLevel = -1; + protected function setUp(){ if ( ! MathSearchHooks::isDB2Supported() ) { $this->markTestSkipped( 'DB2 php client is not installed.' ); } + $this->phpErrorLevel = intval( ini_get( 'error_reporting' ) ); + parent::setUp(); + } + protected function tearDown(){ + ini_set( 'error_reporting', $this->phpErrorLevel ); + } + public function testConnect() { + global $wgMathSearchDB2ConnStr; if ( $wgMathSearchDB2ConnStr !== false ) { + $conn = db2_connect( $wgMathSearchDB2ConnStr, '', '' ); $this->assertInternalType( 'resource', $conn, 'Connection failed.' ); db2_close( $conn ); @@ -31,19 +40,35 @@ } } - public function testBasicXQuery() { + public function testBasicSQL(){ global $wgMathSearchDB2ConnStr; - if ( ! MathSearchHooks::isDB2Supported() || true ) { + $conn = db2_connect($wgMathSearchDB2ConnStr, '', ''); + $stmt = db2_exec($conn,'select "math_tex" from "math"'); + $this->assertInternalType( 'resource', $stmt, 'Connection failed.' ); + /*while($row = db2_fetch_object($stmt)){ + printf("$row->math_tex\n"); + }*/ + } + private $testquery = <<<'EOT' +xquery declare default element namespace "http://www.w3.org/1998/Math/MathML"; + for $m in db2-fn:xmlcolumn("math.math_mathml") return +for $x in $m//*:ci +[./text() = 'E'] + where +fn:count($x/*) = 0 + + return +data($m/*[1]/@alttext) +EOT; + public function testBasicXQuery(){ + global $wgMathSearchDB2ConnStr; + if ( ! MathSearchHooks::isDB2Supported() ) { $this->markTestSkipped( 'DB2 php client is not installed.' ); } - $conn = db2_connect( $wgMathSearchDB2ConnStr, '', '' ); - $stmt = db2_exec( $conn, 'xquery declare default element namespace "http://www.w3.org/1998/Math/MathML"; - for $m in db2-fn:xmlcolumn("math.math_mathml") return -for $x in $m//*:\'apply\'[*[1]/name() = \'eq\'] return -data($m/*[1]/@alttext)' ); - while ( $row = db2_fetch_row( $stmt ) ) { - echo db2_result( $stmt, 0 ); + $conn = db2_connect($wgMathSearchDB2ConnStr, '', ''); + $stmt = db2_exec($conn,$this->testquery); + $row = db2_fetch_row($stmt); + $this->assertEquals('<?xml version="1.0" encoding="UTF-8" ?>{\displaystyle E=mc^{2}}', db2_result($stmt,0)); - } } } \ No newline at end of file diff --git a/tests/MathEngineTest.php b/tests/MathEngineTest.php new file mode 100644 index 0000000..a3133cf --- /dev/null +++ b/tests/MathEngineTest.php @@ -0,0 +1,202 @@ +<?php +/** + * MediaWiki MathSearch extension + * + */ + +class MathEngineTest extends MediaWikiTestCase { + + + + private $stmt= <<<'EOT' +xquery declare default element namespace "http://www.w3.org/1998/Math/MathML"; + for $m in db2-fn:xmlcolumn("math.math_mathml") return +for $x in $m//*:apply +[*[1]/name() ='eq' and *[2]/name() ='ci' and *[2][./text() = 'E'] and *[3]/name() ='apply' and *[3][*[1]/name() ='times' and *[2]/name() ='ci' and *[2][./text() = 'm'] and *[3]/name() ='apply' and *[3][*[1]/name() ='csymbol' and *[1][./text() = 'superscript'] and *[2]/name() ='ci' and *[2][./text() = 'c'] and *[3]/name() ='cn' and *[3][./text() = '2']]]] + where +fn:count($x/*[2]/*) = 0 + and fn:count($x/*[3]/*[2]/*) = 0 + and fn:count($x/*[3]/*[3]/*[1]/*) = 0 + and fn:count($x/*[3]/*[3]/*[2]/*) = 0 + and fn:count($x/*[3]/*[3]/*[3]/*) = 0 + and fn:count($x/*[3]/*[3]/*) = 3 + and fn:count($x/*[3]/*) = 3 + and fn:count($x/*) = 3 + + return +data($m/*[1]/@alttext) +EOT; + + private $stmt2= <<<'EOT' +<?xml version="1.0"?> + <mws:query xmlns:mws="http://search.mathweb.org/ns" xmlns:m="http://www.w3.org/1998/Math/MathML" limitmin="0" answsize="30"> + <mws:expr> + <m:apply xml:id="p1.1.m1.1.6.cmml" xref="p1.1.m1.1.6"> + <m:eq xml:id="p1.1.m1.1.2.cmml" xref="p1.1.m1.1.2"/> + <m:ci xml:id="p1.1.m1.1.1.cmml" xref="p1.1.m1.1.1">E</m:ci> + <m:apply xml:id="p1.1.m1.1.6.1.cmml" xref="p1.1.m1.1.6.1"> + <m:times xml:id="p1.1.m1.1.6.1.1.cmml" xref="p1.1.m1.1.6.1.1"/> + <m:ci xml:id="p1.1.m1.1.3.cmml" xref="p1.1.m1.1.3">m</m:ci> + <m:apply xml:id="p1.1.m1.1.6.1.2.cmml" xref="p1.1.m1.1.6.1.2"> + <m:csymbol cd="ambiguous" xml:id="p1.1.m1.1.6.1.2.1.cmml">superscript</m:csymbol> + <m:ci xml:id="p1.1.m1.1.4.cmml" xref="p1.1.m1.1.4">c</m:ci> + <m:cn type="integer" xml:id="p1.1.m1.1.5.1.cmml" xref="p1.1.m1.1.5.1">2</m:cn> + </m:apply> + </m:apply> + </m:apply> + </mws:expr> + </mws:query> +EOT; + + + private $sel = "SELECT + `mathindex`.`mathindex_page_id` AS `mathindex_page_id`, + `mathindex`.`mathindex_anchor` AS `mathindex_anchor`, + `mathindex`.`mathindex_inputhash` AS `mathindex_inputhash`, + `mathindex`.`mathindex_timestamp` AS `mathindex_timestamp`, + `math`.`math_inputhash` AS `math_inputhash`, + `math`.`math_mathml` AS `math_mathml`, + `math`.`math_outputhash` AS `math_outputhash`, + `math`.`math_html_conservativeness` AS `math_html_conservativeness`, + `math`.`math_html` AS `math_html` + FROM (`mathindex` JOIN `math` ON((`mathindex`.`mathindex_page_id` = `mathindex`.`mathindex_anchor`)))"; + + + + + + protected function setUp(){ + if ( ! MathSearchHooks::isDB2Supported() ) { + $this->markTestSkipped( 'DB2 php client is not installed.' ); + } + parent::setUp(); + $this->getTestResultObject()->setTimeoutForLargeTests(60); + } + + /** + * + */ + public function testDirectDB2Query(){ + global $wgMathSearchDB2ConnStr; + $conn = db2_connect($wgMathSearchDB2ConnStr, '', ''); + + $stmt = db2_exec($conn, $this->stmt ); + $this->assertEquals(1, db2_num_fields ( $stmt ) ); + db2_close( $conn ); + } + + public function testHash(){ + $test_tex = 'E=mc^2'; + $test_hash = '826676a6a5ad24552f0d5af1593434cc'; + $renderer = new MathLaTeXML($test_tex); + $realHash = $renderer->getMd5(); + $this->assertEquals($realHash,$test_hash,'wrong hash'); + } + public function testGetAllOcc(){ + global $wgMathSearchDB2ConnStr; + $conn = db2_connect($wgMathSearchDB2ConnStr, '', ''); + $stmt = db2_exec($conn, $this->stmt ); + $hash = '826676a6a5ad24552f0d5af1593434cc'; + + $moArray=array(); + while($row = db2_fetch_row( $stmt ) ){ + $tex = db2_result( $stmt, 0 ); + $tex = str_replace( '<?xml version="1.0" encoding="UTF-8" ?>' , '' , $tex ); + $this->assertEquals($tex, '{\displaystyle E=mc^{2}}'); + + + + $mo = MathObject::newFromMd5($hash); + + $rFD = $mo->readFromDatabase(); + $this->assertTrue( $rFD, 'readFromDatabase() was not successful'); + + + //create the MathObject out of the tex + /* + $mo = new MathObject($tex); + $test= $mo->readFromDatabase(); + $this->assertEquals($test,true,'readFromDatabase() was not successful'); + */ + + + + $all = $mo->getAllOccurences( false ); + $this->assertType( 'array', $all, 'getAllOccurences() return false'); + + array_push($moArray, $all); + + } + //Fixme: Test the content of $moArray + //$this->assertEquals('content', $moArray[0]); + } + + + /** + * Function to test the class MathEngineDB2 + * @Large + */ + public function testMathEngineDB2(){ + $query = new XQueryGeneratorDB2($this->stmt2); + $this->assertEquals($this->stmt, $query->getXQuery() , "XQuery expression did not match"); + $qo = new MathQueryObject(); + $qo->setXQueryGenerator($query); + $eng = new MathEngineDB2($qo); + //$this->assertEquals($query,$eng->getQuery()->getXQuery()); + $this->assertEquals($qo, $eng->getQuery() , "XQuery expression did not match"); + //$eng->postQuery(); + + + /* + * Fixme: If everything is fine until here try this: + * + $map = $eng->getRelevanceMap(); + + $this->assertTrue($map[1]); + $this->asserFalse($map[2]); + */ + + } + + + + /** + * Function to test the join of math and mathindex from MySQL + * @TODO: I think we don't need that test. + * @markTestSkipped + */ + public function testJoin(){ + $this->markTestSkipped('Skipping test'); + + $con = mysqli_connect('localhost','root','vagrant','wiki', 3306); + + // Check connection + if (mysqli_connect_errno()) { + echo "Failed to connect to MySQL:". mysqli_connect_error(); + } + + $result = mysqli_query($con, $this->sel); + + // Check result from query + if($result == false){ + echo "Failed to execute query!"; + } + + while($row = mysqli_fetch_array($result)){ + $this->assertEquals($row['mathindex_page_id'], 1); + //echo $row['mathindex_page_id'] . " " . $row['mathindex_anchor'] . " " . $row['math_html_conservativeness']. "\n"; + } + + mysqli_close($con); + + + } + + + + + + + + +} \ No newline at end of file diff --git a/tests/MathXQueryTest.php b/tests/MathXQueryTest.php index c6635d7..b969c0c 100644 --- a/tests/MathXQueryTest.php +++ b/tests/MathXQueryTest.php @@ -177,44 +177,4 @@ $xQuery = new XQueryGeneratorDB2( $this->qqx2x ); $this->assertEquals( $this->rqx2x, $xQuery->getXQuery() ); } - /*public function testBasicSQL(){ - global $wgMathSearchDB2ConnStr; - $conn = db2_connect($wgMathSearchDB2ConnStr, '', ''); - $stmt = db2_exec($conn,'select "math_tex" from "math"'); - while($row = db2_fetch_object($stmt)){ - printf("$row->math_tex\n"); - } - } - - - - - - - - private function testBasic() { - $cmmlQueryString = <<<'XML' -<?xml version="1.0"?> -<mws:query xmlns:mws="http://search.mathweb.org/ns" xmlns:m="http://www.w3.org/1998/Math/MathML" limitmin="0" answsize="30"> - <mws:expr> - <m:apply xml:id="p1.1.m1.1.6.cmml" xref="p1.1.m1.1.6"> - <m:eq xml:id="p1.1.m1.1.2.cmml" xref="p1.1.m1.1.2"/> - <m:ci xml:id="p1.1.m1.1.1.cmml" xref="p1.1.m1.1.1">E</m:ci> - <m:apply xml:id="p1.1.m1.1.6.1.cmml" xref="p1.1.m1.1.6.1"> - <m:times xml:id="p1.1.m1.1.6.1.1.cmml" xref="p1.1.m1.1.6.1.1"/> - <m:ci xml:id="p1.1.m1.1.3.cmml" xref="p1.1.m1.1.3">m</m:ci> - <m:apply xml:id="p1.1.m1.1.6.1.2.cmml" xref="p1.1.m1.1.6.1.2"> - <m:csymbol cd="ambiguous" xml:id="p1.1.m1.1.6.1.2.1.cmml">superscript</m:csymbol> - <m:ci xml:id="p1.1.m1.1.4.cmml" xref="p1.1.m1.1.4">c</m:ci> - <m:cn type="integer" xml:id="p1.1.m1.1.5.1.cmml" xref="p1.1.m1.1.5.1">2</m:cn> - </m:apply> - </m:apply> - </m:apply> - </mws:expr> -</mws:query> -XML; - //TODO: fix test - $xqueryTest = new XQueryGeneratorDB2($cmmlQueryString); - echo $xqueryTest->getXQuery(); - }*/ } \ No newline at end of file -- To view, visit https://gerrit.wikimedia.org/r/116929 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I4b947d7c7d37eb1409e7f3e57d9b1ff156b4c015 Gerrit-PatchSet: 14 Gerrit-Project: mediawiki/extensions/MathSearch Gerrit-Branch: master Gerrit-Owner: Physikerwelt <w...@physikerwelt.de> Gerrit-Reviewer: Etienne <etienne-m...@web.de> Gerrit-Reviewer: Physikerwelt <w...@physikerwelt.de> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits