/** * Generate textual debug output that shows an arbitrary list of informative * fields. Used for formatting query debug output. * * @note All strings given must be usable and safe in wiki and HTML * contexts. * * @param $storeName string name of the storage backend for which this is generated * @param $entries array of name => value of informative entries to display * @param $query SMWQuery or null, if given add basic data about this query as well * * @return string */ public static function formatOutputFor($storeName, array $entries, Query $query = null) { if ($query instanceof Query) { $preEntries = array(); $preEntries['Ask query'] = '<div class="smwpre">' . str_replace('[', '[', $query->getDescription()->getQueryString()) . '</div>'; $entries = array_merge($preEntries, $entries); $entries['Query Metrics'] = 'Query-Size:' . $query->getDescription()->getSize() . '<br />' . 'Query-Depth:' . $query->getDescription()->getDepth(); $errors = ''; foreach ($query->getErrors() as $error) { $errors .= $error . '<br />'; } if ($errors === '') { $errors = 'None'; } $entries['Errors and Warnings'] = $errors; } $result = '<div style="border: 5px dotted #A1FB00; background: #FFF0BD; padding: 20px; ">' . "<h3>Debug Output by {$storeName}</h3>"; foreach ($entries as $header => $information) { $result .= "<h4>{$header}</h4>"; if ($information !== '') { $result .= "{$information}"; } } $result .= '</div>'; return $result; }
/** * Generate textual debug output that shows an arbitrary list of informative * fields. Used for formatting query debug output. * * @note All strings given must be usable and safe in wiki and HTML * contexts. * * @param $storeName string name of the storage backend for which this is generated * @param $entries array of name => value of informative entries to display * @param $query SMWQuery or null, if given add basic data about this query as well * * @return string */ public static function getStringFrom($storeName, array $entries, Query $query = null) { if ($query instanceof Query) { $preEntries = array(); $preEntries['ASK Query'] = '<div class="smwpre">' . str_replace('[', '[', $query->getDescription()->getQueryString()) . '</div>'; $entries = array_merge($preEntries, $entries); $entries['Query Metrics'] = 'Query-Size:' . $query->getDescription()->getSize() . '<br />' . 'Query-Depth:' . $query->getDescription()->getDepth(); $errors = ''; $queryErrors = ProcessingErrorMsgHandler::normalizeMessages($query->getErrors()); foreach ($queryErrors as $error) { $errors .= $error . '<br />'; } if ($errors === '') { $errors = 'None'; } $entries['Errors and Warnings'] = $errors; } $result = '<div style="border: 5px dotted #ffcc00; background: #FFF0BD; padding: 20px; ">' . "<div class='smw-column-header'><big>{$storeName} debug output</big></div>"; foreach ($entries as $header => $information) { $result .= "<div class='smw-column-header'>{$header}</div>"; if ($information !== '') { $result .= "{$information}"; } } $result .= '</div>'; return $result; }
/** * Add data about the query and its parameters to the semantic data of * the given parser. The $queryKey is a string key that uniquely * identifies the query; this is difficult to create in a stable way * from the processed query object and parameters, but easy to get from * the raw user input. * * @param string $queryKey * @param SMWQuery $query * @param array $params * @param Parser $parser * * @since 1.8 */ public static function addQueryData($queryKey, SMWQuery $query, array $params, Parser $parser) { $mainSemanticData = SMWParseData::getSMWData($parser); $subject = $mainSemanticData->getSubject(); $diSubWikiPage = new SMWDIWikiPage($subject->getDBkey(), $subject->getNamespace(), $subject->getInterwiki(), "_QUERY" . $queryKey); $semanticData = new SMWContainerSemanticData($diSubWikiPage); $description = $query->getDescription(); // Add query string $propertyDi = new SMWDIProperty('_ASKST'); $valueDi = new SMWDIBlob($description->getQueryString()); $semanticData->addPropertyObjectValue($propertyDi, $valueDi); // Add query size $propertyDi = new SMWDIProperty('_ASKSI'); $valueDi = new SMWDINumber($description->getSize()); $semanticData->addPropertyObjectValue($propertyDi, $valueDi); // Add query depth $propertyDi = new SMWDIProperty('_ASKDE'); $valueDi = new SMWDINumber($description->getDepth()); $semanticData->addPropertyObjectValue($propertyDi, $valueDi); // Add query format $propertyDi = new SMWDIProperty('_ASKFO'); $valueDi = new SMWDIString($params['format']->getValue()); $semanticData->addPropertyObjectValue($propertyDi, $valueDi); $propertyDi = new SMWDIProperty('_ASK'); $subObjectDi = new SMWDIContainer($semanticData); SMWParseData::getSMWData($parser)->addPropertyObjectValue($propertyDi, $subObjectDi); }
/** * @since 2.1 * * @param Title $title * @param Query $query * @param string $format * @param integer|null $duration * * @return ProfileAnnotator */ public function newJointProfileAnnotator(Title $title, Query $query, $format, $duration = null) { $profiler = new NullProfile(new Subobject($title), $query->getHash()); $profiler = new DescriptionProfile($profiler, $query->getDescription()); $profiler = new FormatProfile($profiler, $format); $profiler = new DurationProfile($profiler, $duration); return $profiler; }
/** * @since 2.1 * * @param Query $query * @param string $format * @param integer|null $duration * * @return ProfileAnnotator */ public function newJointProfileAnnotator(Query $query, $format, $duration = null) { $nullProfileAnnotator = new NullProfileAnnotator(new Subobject($query->getSubject()->getTitle()), $query->getQueryId()); $descriptionProfileAnnotator = new DescriptionProfileAnnotator($nullProfileAnnotator, $query->getDescription()); $formatProfileAnnotator = new FormatProfileAnnotator($descriptionProfileAnnotator, $format); $durationProfileAnnotator = new DurationProfileAnnotator($formatProfileAnnotator, $duration); return $durationProfileAnnotator; }
public function testNullQueryResult() { $term = '[[Some_string_to_query]]'; $description = new ValueDescription(new DIWikiPage($term, NS_MAIN), null); $query = new Query($description, false, false); $query->querymode = Query::MODE_INSTANCES; $description = $query->getDescription(); $namespacesDisjunction = new Disjunction(array_map(function ($ns) { return new NamespaceDescription($ns); }, array(NS_MAIN))); $description = new Conjunction(array($description, $namespacesDisjunction)); $query->setDescription($description); $this->assertInstanceOf('\\SMWQueryResult', ApplicationFactory::getInstance()->getStore()->getQueryResult($query)); }
/** * @since 2.0 * @param Query $query * * @return QueryResult|string */ public function getQueryResult(Query $query) { if ((!$this->engineOptions->get('smwgIgnoreQueryErrors') || $query->getDescription() instanceof ThingDescription) && $query->querymode != Query::MODE_DEBUG && count($query->getErrors()) > 0) { return $this->queryResultFactory->newEmptyQueryResult($query, false); } // don't query, but return something to the printer if ($query->querymode == Query::MODE_NONE || $query->getLimit() < 1) { return $this->queryResultFactory->newEmptyQueryResult($query, true); } $this->compoundConditionBuilder->setSortKeys($query->sortkeys); $compoundCondition = $this->compoundConditionBuilder->buildCondition($query->getDescription()); $query->addErrors($this->compoundConditionBuilder->getErrors()); if ($query->querymode == Query::MODE_DEBUG) { return $this->getDebugQueryResult($query, $compoundCondition); } elseif ($query->querymode == Query::MODE_COUNT) { return $this->getCountQueryResult($query, $compoundCondition); } return $this->getInstanceQueryResult($query, $compoundCondition); }
/** * Using a preprocessed internal query description referenced by $rootid, * compute the proper result instance output for the given query. * @todo The SQL standard requires us to select all fields by which we sort, leading * to wrong results regarding the given limit: the user expects limit to be applied to * the number of distinct pages, but we can use DISTINCT only to whole rows. Thus, if * rows contain sortfields, then pages with multiple values for that field are distinct * and appear multiple times in the result. Filtering duplicates in post processing * would still allow such duplicates to push aside wanted values, leading to less than * "limit" results although there would have been "limit" really distinct results. For * this reason, we select sortfields only for POSTGRES. MySQL is able to perform what * we want here. It would be nice if we could eliminate the bug in POSTGRES as well. * * @param Query $query * @param integer $rootid * * @return QueryResult */ private function getInstanceQueryResult(Query $query, $rootid) { global $wgDBtype; $db = $this->store->getConnection(); $qobj = $this->querySegments[$rootid]; if ($qobj->joinfield === '') { // empty result, no query needed $result = new QueryResult($query->getDescription()->getPrintrequests(), $query, array(), $this->store, false); return $result; } $sql_options = $this->getSQLOptions($query, $rootid); // Selecting those is required in standard SQL (but MySQL does not require it). $sortfields = implode($qobj->sortfields, ','); $res = $db->select($db->tableName($qobj->joinTable) . " AS {$qobj->alias}" . $qobj->from, "DISTINCT {$qobj->alias}.smw_id AS id,{$qobj->alias}.smw_title AS t,{$qobj->alias}.smw_namespace AS ns,{$qobj->alias}.smw_iw AS iw,{$qobj->alias}.smw_subobject AS so,{$qobj->alias}.smw_sortkey AS sortkey" . ($wgDBtype == 'postgres' ? ($sortfields ? ',' : '') . $sortfields : ''), $qobj->where, __METHOD__, $sql_options); $qr = array(); $count = 0; // the number of fetched results ( != number of valid results in array $qr) $missedCount = 0; $dataItemCache = array(); $logToTable = array(); $hasFurtherResults = false; $prs = $query->getDescription()->getPrintrequests(); $diHandler = $this->store->getDataItemHandlerForDIType(DataItem::TYPE_WIKIPAGE); while ($count < $query->getLimit() && ($row = $db->fetchObject($res))) { if ($row->iw === '' || $row->iw[0] != ':') { // Catch exception for non-existing predefined properties that // still registered within non-updated pages (@see bug 48711) try { $dataItem = $diHandler->dataItemFromDBKeys(array($row->t, intval($row->ns), $row->iw, '', $row->so)); } catch (InvalidPredefinedPropertyException $e) { $logToTable[$row->t] = "issue creating a {$row->t} dataitem from a database row"; wfDebugLog('smw', __METHOD__ . ' ' . $e->getMessage() . "\n"); $dataItem = ''; } if ($dataItem instanceof DIWikiPage && !isset($dataItemCache[$dataItem->getHash()])) { $count++; $dataItemCache[$dataItem->getHash()] = true; $qr[] = $dataItem; // These IDs are usually needed for displaying the page (esp. if more property values are displayed): $this->store->smwIds->setCache($row->t, $row->ns, $row->iw, $row->so, $row->id, $row->sortkey); } else { $missedCount++; $logToTable[$row->t] = "skip result for {$row->t} existing cache entry / query " . $query->getHash(); } } else { $missedCount++; $logToTable[$row->t] = "skip result for {$row->t} due to an internal `{$row->iw}` pointer / query " . $query->getHash(); } } if ($db->fetchObject($res)) { $count++; } if ($logToTable !== array()) { wfDebugLog('smw', __METHOD__ . ' ' . implode(',', $logToTable) . "\n"); } if ($count > $query->getLimit() || $count + $missedCount > $query->getLimit()) { $hasFurtherResults = true; } $db->freeResult($res); $result = new QueryResult($prs, $query, $qr, $this->store, $hasFurtherResults); return $result; }
/** * @see SMWStore::getQueryResult() * @since 1.6 */ public function getQueryResult(SMWQuery $query) { global $smwgIgnoreQueryErrors; if ((!$smwgIgnoreQueryErrors || $query->getDescription() instanceof SMWThingDescription) && $query->querymode != SMWQuery::MODE_DEBUG && count($query->getErrors()) > 0) { return new SMWQueryResult($query->getDescription()->getPrintrequests(), $query, array(), $this, false); } if ($query->querymode == SMWQuery::MODE_NONE) { // don't query, but return something to printer return new SMWQueryResult($query->getDescription()->getPrintrequests(), $query, array(), $this, true); } elseif ($query->querymode == SMWQuery::MODE_DEBUG) { $queryEngine = new SMWSparqlStoreQueryEngine($this); return $queryEngine->getDebugQueryResult($query); } elseif ($query->querymode == SMWQuery::MODE_COUNT) { $queryEngine = new SMWSparqlStoreQueryEngine($this); return $queryEngine->getCountQueryResult($query); } else { $queryEngine = new SMWSparqlStoreQueryEngine($this); return $queryEngine->getInstanceQueryResult($query); } }
private function makeQueryResultForInstance(FederateResultSet $federateResultSet, Query $query) { $resultDataItems = array(); foreach ($federateResultSet as $resultRow) { if (count($resultRow) > 0) { $dataItem = Exporter::findDataItemForExpElement($resultRow[0]); if (!is_null($dataItem)) { $resultDataItems[] = $dataItem; } } } if ($federateResultSet->numRows() > $query->getLimit()) { array_pop($resultDataItems); $hasFurtherResults = true; } else { $hasFurtherResults = false; } $result = new QueryResult($query->getDescription()->getPrintrequests(), $query, $resultDataItems, $this->store, $hasFurtherResults); switch ($federateResultSet->getErrorCode()) { case FederateResultSet::ERROR_NOERROR: break; case FederateResultSet::ERROR_INCOMPLETE: $result->addErrors(array(wfMessage('smw_db_sparqlqueryincomplete')->inContentLanguage()->text())); break; default: $result->addErrors(array(wfMessage('smw_db_sparqlqueryproblem')->inContentLanguage()->text())); break; } return $result; }
public function getQueryResult( SMWQuery $query ) { global $smwgIgnoreQueryErrors; if ( !$smwgIgnoreQueryErrors && ( $query->querymode != SMWQuery::MODE_DEBUG ) && ( count( $query->getErrors() ) > 0 ) ) { return new SMWQueryResult( $query->getDescription()->getPrintrequests(), $query, array(), $this, false ); // NOTE: we check this here to prevent unnecessary work, but we may need to check it after query processing below again in case more errors occurred } if ( $query->querymode == SMWQuery::MODE_NONE ) { // don't query, but return something to printer return new SMWQueryResult( $query->getDescription()->getPrintrequests(), $query, array(), $this, true ); } elseif ( $query->querymode == SMWQuery::MODE_DEBUG ) { $queryEngine = new SMWSparqlStoreQueryEngine( $this ); return $queryEngine->getDebugQueryResult( $query ); } elseif ( $query->querymode == SMWQuery::MODE_COUNT ) { $queryEngine = new SMWSparqlStoreQueryEngine( $this ); return $queryEngine->getCountQueryResult( $query ); } else { $queryEngine = new SMWSparqlStoreQueryEngine( $this ); return $queryEngine->getInstanceQueryResult( $query ); } }
/** * The new SQL store's implementation of query answering. */ public function getQueryResult(SMWQuery $query) { if ($query->querymode == SMWQuery::MODE_NONE) { // don't query, but return something to printer $result = new SMWQueryResult($query->getDescription()->getPrintrequests(), $query, true); return $result; } $this->m_qmode = $query->querymode; $this->m_queries = array(); $this->m_hierarchies = array(); $this->m_querylog = array(); $this->m_errors = array(); SMWSQLStore2Query::$qnum = 0; $this->m_sortkeys = $query->sortkeys; // manually make final root query (to retrieve namespace,title): $rootid = SMWSQLStore2Query::$qnum; $qobj = new SMWSQLStore2Query(); $qobj->jointable = 'smw_ids'; $qobj->joinfield = "{$qobj->alias}.smw_id"; // build query dependency tree: wfProfileIn('SMWSQLStore2Queries::compileMainQuery (SMW)'); $qid = $this->compileQueries($query->getDescription()); // compile query, build query "plan" wfProfileOut('SMWSQLStore2Queries::compileMainQuery (SMW)'); if ($qid < 0) { // no valid/supported condition; ensure that at least only proper pages are delivered $qid = SMWSQLStore2Query::$qnum; $q = new SMWSQLStore2Query(); $q->jointable = 'smw_ids'; $q->joinfield = "{$q->alias}.smw_id"; $q->where = "{$q->alias}.smw_iw!=" . $this->m_dbs->addQuotes(SMW_SQL2_SMWIW) . " AND {$q->alias}.smw_iw!=" . $this->m_dbs->addQuotes(SMW_SQL2_SMWREDIIW) . " AND {$q->alias}.smw_iw!=" . $this->m_dbs->addQuotes(SMW_SQL2_SMWBORDERIW) . " AND {$q->alias}.smw_iw!=" . $this->m_dbs->addQuotes(SMW_SQL2_SMWINTDEFIW); $this->m_queries[$qid] = $q; } // append query to root: $qobj->components = array($qid => "{$qobj->alias}.smw_id"); $qobj->sortfields = $this->m_queries[$qid]->sortfields; $this->m_queries[$rootid] = $qobj; $this->applyOrderConditions($query, $rootid); // may extend query if needed for sorting wfProfileIn('SMWSQLStore2Queries::executeMainQuery (SMW)'); $this->executeQueries($this->m_queries[$rootid]); // execute query tree, resolve all dependencies wfProfileOut('SMWSQLStore2Queries::executeMainQuery (SMW)'); $result = $this->getNMQueryResult($query, $rootid); $this->cleanUp(); $query->addErrors($this->m_errors); return $result; }
private function createConceptFor(DIWikiPage $concept, Description $description, $documentation = '') { $semanticData = $this->semanticDataFactory->setSubject($concept)->newEmptySemanticData(); $query = new Query($description, false, true); $semanticData->addPropertyObjectValue(new DIProperty('_CONC'), new DIConcept($query->getDescription()->getQueryString(), $documentation, $query->getDescription()->getQueryFeatures(), $query->getDescription()->getSize(), $query->getDescription()->getDepth())); $this->getStore()->updateData($semanticData); }
/** * Get the output string for a query in debugging mode. * * @param Query $query * * @return string */ public function getDebugQueryResult(Query $query) { $this->sortkeys = $query->sortkeys; $this->compoundConditionBuilder->setSortKeys($this->sortkeys); $sparqlCondition = $this->compoundConditionBuilder->buildCondition($query->getDescription()); $query->addErrors($this->compoundConditionBuilder->getErrors()); $entries = array(); if ($sparqlCondition instanceof SingletonCondition) { if ($sparqlCondition->condition === '') { // all URIs exist, no querying $sparql = 'None (no conditions).'; } else { $condition = $this->compoundConditionBuilder->convertConditionToString($sparqlCondition); $namespaces = $sparqlCondition->namespaces; $sparql = $this->connection->getSparqlForAsk($condition, $namespaces); } } elseif ($sparqlCondition instanceof FalseCondition) { $sparql = 'None (conditions can not be satisfied by anything).'; } else { $condition = $this->compoundConditionBuilder->convertConditionToString($sparqlCondition); $namespaces = $sparqlCondition->namespaces; $options = $this->getOptions($query, $sparqlCondition); $options['DISTINCT'] = true; $sparql = $this->connection->getSparqlForSelect('?' . self::RESULT_VARIABLE, $condition, $options, $namespaces); } $sparql = str_replace(array('[', ':', ' '), array('[', ':', ' '), $sparql); $entries['SPARQL Query'] = '<div class="smwpre">' . $sparql . '</div>'; return DebugOutputFormatter::formatOutputFor('SPARQLStore', $entries, $query); }
/** * Parses a SPARQL XML-Result and returns an SMWHaloQueryResult. * * @param SMWQuery $query * @param xml string $sparqlXMLResult * @return SMWHaloQueryResult */ protected function parseSPARQLXMLResult(&$query, &$sparqlXMLResult) { // parse xml results $dom = simplexml_load_string($sparqlXMLResult); if ($dom === FALSE) { return new SMWHaloQueryResult(array(), $query, array(), $this); } $variables = $dom->xpath('//variable'); $results = $dom->xpath('//result'); // if no results return empty result object if (count($results) == 0) { return new SMWHaloQueryResult(array(), $query, array(), $this); } $variableSet = array(); foreach ($variables as $var) { $variableSet[] = (string) $var->attributes()->name; } // PrinterRequests to use $prs = array(); // Use PrintRequests to determine which variable denotes what type of entity. If no PrintRequest is given use first result row // (which exist!) to determine which variable denotes what type of entity. // maps print requests (variable name) to result columns ( var_name => index ) $mapPRTOColumns = array(); // use user-given PrintRequests if possible $print_requests = $query->getDescription()->getPrintRequests(); // _X_ is used for the main variable. $hasMainColumn = false; $index = 0; if ($query->fromASK) { // SPARQL query which was transformed from ASK // x variable is handeled specially as main variable foreach ($print_requests as $pr) { $data = $pr->getData(); if ($data == NULL) { // main column $hasMainColumn = true; if (in_array('_X_', $variableSet)) { // x is missing for INSTANCE queries $mapPRTOColumns['_X_'] = $index; $prs[] = $pr; $index++; } } else { $label = $data instanceof Title ? $data->getDBkey() : array_shift($data->getDBkeys()); $mapPRTOColumns[$label] = $index; $rewritten_pr = $this->rewritePrintrequest($pr); $prs[] = $rewritten_pr; $index++; } } } else { // native SPARQL query, no main variable foreach ($print_requests as $pr) { $data = $pr->getData(); if ($data != NULL) { $label = $data instanceof Title ? $data->getDBkey() : array_shift($data->getDBkeys()); $mapPRTOColumns[$label] = $index; $rewritten_pr = $this->rewritePrintrequest($pr); $prs[] = $rewritten_pr; $index++; } } } // generate PrintRequests for all bindings (if they do not exist already) $var_index = 0; $bindings = $results[0]->children()->binding; foreach ($bindings as $b) { $var_name = ucfirst((string) $variables[$var_index]->attributes()->name); $var_index++; // if no mainlabel, do not create a printrequest for _X_ (instance variable for ASK-converted queries) if ($query->mainLabelMissing && $var_name == "_X_") { continue; } // do not generate new printRequest if already given if ($this->containsPrintRequest($var_name, $print_requests, $query)) { continue; } // otherwise create one $var_path = explode(".", $var_name); $sel_var = ucfirst($var_path[count($var_path) - 1]); $data = SMWPropertyValue::makeUserProperty($sel_var); $prs[] = new SMWPrintRequest(SMWPrintRequest::PRINT_THIS, str_replace("_", " ", $sel_var), $data); $mapPRTOColumns[$var_name] = $index; $index++; } // get resultpage, ie. the pages which "define" a result row. if ($query->fromASK) { // ASK queries usually always have a result column, // except if a single instance is requested // result column is available if first variable is "_X_" $var_name = ucfirst((string) $variables[0]->attributes()->name); // not available, so set dummys foreach ($results as $r) { // SPARQL queries do not, so just set a dummy $resultPages[] = SMWDataValueFactory::newTypeIDValue('_wpg'); } } else { foreach ($results as $r) { // SPARQL queries do not, so just set a dummy $resultPages[] = SMWDataValueFactory::newTypeIDValue('_wpg'); } } // create and add result rows // iterate result rows and add an SMWResultArray object for each field $qresults = array(); $rowIndex = 0; foreach ($results as $r) { $row = array(); $columnIndex = 0; // column = n-th XML binding node $children = $r->children(); // $chilren->binding denote all binding nodes foreach ($children->binding as $b) { $var_name = ucfirst((string) $children[$columnIndex]->attributes()->name); // ignore main variable if not displayed if (!$hasMainColumn && $var_name == '_X_') { $columnIndex++; continue; } $resultColumn = $mapPRTOColumns[$var_name]; $allValues = array(); $this->parseBindungs($b, $var_name, $prs[$resultColumn], $allValues); // note: ignore bnodes $columnIndex++; $row[$resultColumn] = new SMWHaloResultArray($resultPages[$rowIndex], $prs[$resultColumn], $this, $allValues); } $rowIndex++; ksort($row); $qresults[] = $row; } // Query result object $queryResult = new SMWHaloQueryResult($prs, $query, $qresults, $this, count($results) > $query->getLimit()); return $queryResult; }
/** * Using a preprocessed internal query description referenced by $rootid, * compute the proper result instance output for the given query. * @todo The SQL standard requires us to select all fields by which we sort, leading * to wrong results regarding the given limit: the user expects limit to be applied to * the number of distinct pages, but we can use DISTINCT only to whole rows. Thus, if * rows contain sortfields, then pages with multiple values for that field are distinct * and appear multiple times in the result. Filtering duplicates in post processing * would still allow such duplicates to push aside wanted values, leading to less than * "limit" results although there would have been "limit" really distinct results. For * this reason, we select sortfields only for POSTGRES. MySQL is able to perform what * we want here. It would be nice if we could eliminate the bug in POSTGRES as well. * * @param SMWQuery $query * @param integer $rootid * * @return SMWQueryResult */ protected function getInstanceQueryResult(SMWQuery $query, $rootid) { global $wgDBtype; wfProfileIn('SMWSQLStore3Queries::getInstanceQueryResult (SMW)'); $qobj = $this->m_queries[$rootid]; if ($qobj->joinfield === '') { // empty result, no query needed $result = new SMWQueryResult($query->getDescription()->getPrintrequests(), $query, array(), $this->m_store, false); wfProfileOut('SMWSQLStore3Queries::getInstanceQueryResult (SMW)'); return $result; } $sql_options = $this->getSQLOptions($query, $rootid); // Selecting those is required in standard SQL (but MySQL does not require it). $sortfields = implode($qobj->sortfields, ','); $res = $this->m_dbs->select($this->m_dbs->tableName($qobj->jointable) . " AS {$qobj->alias}" . $qobj->from, "DISTINCT {$qobj->alias}.smw_id AS id,{$qobj->alias}.smw_title AS t,{$qobj->alias}.smw_namespace AS ns,{$qobj->alias}.smw_iw AS iw,{$qobj->alias}.smw_subobject AS so,{$qobj->alias}.smw_sortkey AS sortkey" . ($wgDBtype == 'postgres' ? ($sortfields ? ',' : '') . $sortfields : ''), $qobj->where, 'SMW::getQueryResult', $sql_options); $qr = array(); $count = 0; // the number of fetched results ( != number of valid results in array $qr) $prs = $query->getDescription()->getPrintrequests(); $diHandler = $this->m_store->getDataItemHandlerForDIType(SMWDataItem::TYPE_WIKIPAGE); while ($count < $query->getLimit() && ($row = $this->m_dbs->fetchObject($res))) { $count++; if ($row->iw === '' || $row->iw[0] != ':') { $qr[] = $diHandler->dataItemFromDBKeys(array($row->t, intval($row->ns), $row->iw, '', $row->so)); // These IDs are usually needed for displaying the page (esp. if more property values are displayed): $this->m_store->smwIds->setCache($row->t, $row->ns, $row->iw, $row->so, $row->id, $row->sortkey); } } if ($this->m_dbs->fetchObject($res)) { $count++; } $this->m_dbs->freeResult($res); $result = new SMWQueryResult($prs, $query, $qr, $this->m_store, $count > $query->getLimit()); wfProfileOut('SMWSQLStore3Queries::getInstanceQueryResult (SMW)'); return $result; }
/** * Build an SMWQueryResult object from a SMWSparqlResultWrapper. This * function is used to generate instance query results, and the given * result wrapper must have an according format (one result column that * contains URIs of wiki pages). * * @param $sparqlResultWrapper SMWSparqlResultWrapper * @param $query SMWQuery, SMWQueryResults hold a reference to original query * @return SMWQueryResult */ protected function getQueryResultFromSparqlResult(SMWSparqlResultWrapper $sparqlResultWrapper, SMWQuery $query) { $resultDataItems = array(); foreach ($sparqlResultWrapper as $resultRow) { if (count($resultRow) > 0) { $dataItem = SMWExporter::findDataItemForExpElement($resultRow[0]); if (!is_null($dataItem)) { $resultDataItems[] = $dataItem; } } } if ($sparqlResultWrapper->numRows() > $query->getLimit()) { array_pop($resultDataItems); $hasFurtherResults = true; } else { $hasFurtherResults = false; } $result = new SMWQueryResult($query->getDescription()->getPrintrequests(), $query, $resultDataItems, $this->m_store, $hasFurtherResults); switch ($sparqlResultWrapper->getErrorCode()) { case SMWSparqlResultWrapper::ERROR_NOERROR: break; case SMWSparqlResultWrapper::ERROR_INCOMPLETE: $result->addErrors(array(wfMessage('smw_db_sparqlqueryincomplete')->inContentLanguage()->text())); break; default: $result->addErrors(array(wfMessage('smw_db_sparqlqueryproblem')->inContentLanguage()->text())); break; } return $result; }
/** * Using a preprocessed internal query description referenced by $rootid, * compute the proper result instance output for the given query. * @todo The SQL standard requires us to select all fields by which we sort, leading * to wrong results regarding the given limit: the user expects limit to be applied to * the number of distinct pages, but we can use DISTINCT only to whole rows. Thus, if * rows contain sortfields, then pages with multiple values for that field are distinct * and appear multiple times in the result. Filtering duplicates in post processing * would still allow such duplicates to push aside wanted values, leading to less than * "limit" results although there would have been "limit" really distinct results. For * this reason, we select sortfields only for POSTGRES. MySQL is able to perform what * we want here. It would be nice if we could eliminate the bug in POSTGRES as well. * * @param SMWQuery $query * @param integer $rootid * * @return SMWQueryResult */ protected function getInstanceQueryResult(SMWQuery $query, $rootid) { global $wgDBtype; wfProfileIn('SMWSQLStore2Queries::getInstanceQueryResult (SMW)'); $qobj = $this->m_queries[$rootid]; if ($qobj->joinfield === '') { // empty result, no query needed $result = new SMWQueryResult($query->getDescription()->getPrintrequests(), $query, array(), $this->m_store, false); wfProfileOut('SMWSQLStore2Queries::getInstanceQueryResult (SMW)'); return $result; } $sql_options = $this->getSQLOptions($query, $rootid); // Selecting those is required in standard SQL (but MySQL does not require it). $sortfields = implode($qobj->sortfields, ','); $res = $this->m_dbs->select($this->m_dbs->tableName($qobj->jointable) . " AS {$qobj->alias}" . $qobj->from, "DISTINCT {$qobj->alias}.smw_id AS id,{$qobj->alias}.smw_title AS t,{$qobj->alias}.smw_namespace AS ns,{$qobj->alias}.smw_iw AS iw,{$qobj->alias}.smw_subobject AS so,{$qobj->alias}.smw_sortkey AS sortkey" . ($wgDBtype == 'postgres' ? ($sortfields ? ',' : '') . $sortfields : ''), $qobj->where, 'SMW::getQueryResult', $sql_options); $qr = array(); $count = 0; // the number of fetched results ( != number of valid results in array $qr) $prs = $query->getDescription()->getPrintrequests(); while ($count < $query->getLimit() && ($row = $this->m_dbs->fetchObject($res))) { $count++; if ($row->iw === '' || $row->iw[0] != ':') { $v = new SMWDIWikiPage($row->t, intval($row->ns), $row->iw, $row->so); $qr[] = $v; $this->m_store->cacheSMWPageID($row->id, $row->t, $row->ns, $row->iw, $row->so); } } if ($this->m_dbs->fetchObject($res)) { $count++; } $this->m_dbs->freeResult($res); // TODO: for some reason this line makes PHPunit complain "This test printed output: ". $result = new SMWQueryResult($prs, $query, $qr, $this->m_store, $count > $query->getLimit()); wfProfileOut('SMWSQLStore2Queries::getInstanceQueryResult (SMW)'); return $result; }
/** * @since 2.5 * * @param Store $store * @param Query $query * @param DIWikiPage[]|[] $results = array() * @param boolean $continue * * @return QueryResult */ public function newQueryResult(Store $store, Query $query, $results = array(), $continue = false) { $queryResult = new QueryResult($query->getDescription()->getPrintrequests(), $query, $results, $store, $continue); return $queryResult; }
/** * The new SQL store's implementation of query answering. This function * works in two stages: First, the nested conditions of the given query * object are preprocessed to compute an abstract representation of the * SQL query that is to be executed. Since query conditions correspond to * joins with property tables in most cases, this abstract representation * is essentially graph-like description of how property tables are joined. * Moreover, this graph is tree-shaped, since all query conditions are * tree-shaped. Each part of this abstract query structure is represented * by an SMWSQLStore2Query object in the array m_queries. * * As a second stage of processing, the thus prepared SQL query is actually * executed. Typically, this means that the joins are collapsed into one * SQL query to retrieve results. In some cases, such as in dbug mode, the * execution might be restricted and not actually perform the whole query. * * The two-stage process helps to separate tasks, and it also allows for * better optimisations: it is left to the execution engine how exactly the * query result is to be obtained. For example, one could pre-compute * partial suib-results in temporary tables (or even cache them somewhere), * instead of passing one large join query to the DB (of course, it might * be large only if the configuration of SMW allows it). For some DBMS, a * step-wise execution of the query might lead to better performance, since * it exploits the tree-structure of the joins, which is important for fast * processing -- not all DBMS might be able in seeing this by themselves. * * @param SMWQuery $query */ public function getQueryResult(SMWQuery $query) { global $smwgIgnoreQueryErrors, $smwgQSortingSupport; if (!$smwgIgnoreQueryErrors && $query->querymode != SMWQuery::MODE_DEBUG && count($query->getErrors()) > 0) { return new SMWQueryResult($query->getDescription()->getPrintrequests(), $query, array(), $this->m_store, false); // NOTE: we check this here to prevent unnecessary work, but we check it after query processing below again in case more errors occurred } elseif ($query->querymode == SMWQuery::MODE_NONE) { // don't query, but return something to printer return new SMWQueryResult($query->getDescription()->getPrintrequests(), $query, array(), $this->m_store, true); } $this->m_qmode = $query->querymode; $this->m_queries = array(); $this->m_hierarchies = array(); $this->m_querylog = array(); $this->m_errors = array(); SMWSQLStore2Query::$qnum = 0; $this->m_sortkeys = $query->sortkeys; // *** First compute abstract representation of the query (compilation) ***// wfProfileIn('SMWSQLStore2Queries::compileMainQuery (SMW)'); $qid = $this->compileQueries($query->getDescription()); // compile query, build query "plan" wfProfileOut('SMWSQLStore2Queries::compileMainQuery (SMW)'); if ($qid < 0) { // no valid/supported condition; ensure that at least only proper pages are delivered $qid = SMWSQLStore2Query::$qnum; $q = new SMWSQLStore2Query(); $q->jointable = 'smw_ids'; $q->joinfield = "{$q->alias}.smw_id"; $q->where = "{$q->alias}.smw_iw!=" . $this->m_dbs->addQuotes(SMW_SQL2_SMWIW) . " AND {$q->alias}.smw_iw!=" . $this->m_dbs->addQuotes(SMW_SQL2_SMWREDIIW) . " AND {$q->alias}.smw_iw!=" . $this->m_dbs->addQuotes(SMW_SQL2_SMWBORDERIW) . " AND {$q->alias}.smw_iw!=" . $this->m_dbs->addQuotes(SMW_SQL2_SMWINTDEFIW); $this->m_queries[$qid] = $q; } if ($this->m_queries[$qid]->jointable != 'smw_ids') { // manually make final root query (to retrieve namespace,title): $rootid = SMWSQLStore2Query::$qnum; $qobj = new SMWSQLStore2Query(); $qobj->jointable = 'smw_ids'; $qobj->joinfield = "{$qobj->alias}.smw_id"; $qobj->components = array($qid => "{$qobj->alias}.smw_id"); $qobj->sortfields = $this->m_queries[$qid]->sortfields; $this->m_queries[$rootid] = $qobj; } else { // not such a common case, but worth avoiding the additional inner join: $rootid = $qid; } // commented by ning, no need to sort // // Include order conditions (may extend query if needed for sorting): // if ( $smwgQSortingSupport ) { // $this->applyOrderConditions( $rootid ); // } if (!$smwgIgnoreQueryErrors && $query->querymode != SMWQuery::MODE_DEBUG && count($this->m_errors) > 0) { // stop here if new errors happened $query->addErrors($this->m_errors); return new SMWQueryResult($query->getDescription()->getPrintrequests(), $query, array(), $this->m_store, false); } // *** Now execute the computed query ***// wfProfileIn('SMWSQLStore2Queries::executeMainQuery (SMW)'); $this->executeQueries($this->m_queries[$rootid]); // execute query tree, resolve all dependencies wfProfileOut('SMWSQLStore2Queries::executeMainQuery (SMW)'); $result = $this->getNMQueryResult($query, $rootid); $this->cleanUp(); $query->addErrors($this->m_errors); return $result; }