summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/SemanticMediaWiki/includes/storage/SQLStore/SMW_SQLStore3.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/SemanticMediaWiki/includes/storage/SQLStore/SMW_SQLStore3.php')
-rw-r--r--www/wiki/extensions/SemanticMediaWiki/includes/storage/SQLStore/SMW_SQLStore3.php653
1 files changed, 653 insertions, 0 deletions
diff --git a/www/wiki/extensions/SemanticMediaWiki/includes/storage/SQLStore/SMW_SQLStore3.php b/www/wiki/extensions/SemanticMediaWiki/includes/storage/SQLStore/SMW_SQLStore3.php
new file mode 100644
index 00000000..cfc21271
--- /dev/null
+++ b/www/wiki/extensions/SemanticMediaWiki/includes/storage/SQLStore/SMW_SQLStore3.php
@@ -0,0 +1,653 @@
+<?php
+
+use SMW\DIConcept;
+use SMW\DIProperty;
+use SMW\DIWikiPage;
+use SMW\SemanticData;
+use SMW\SQLStore\PropertyTableInfoFetcher;
+use SMW\SQLStore\RequestOptionsProc;
+use SMW\SQLStore\SQLStoreFactory;
+use SMW\SQLStore\TableBuilder\FieldType;
+use SMW\SQLStore\TableDefinition;
+
+/**
+ * SQL-based implementation of SMW's storage abstraction layer.
+ *
+ * @author Markus Krötzsch
+ * @author Jeroen De Dauw
+ * @author Nischay Nahata
+ *
+ * @since 1.8
+ *
+ * @ingroup SMWStore
+ */
+
+// The use of the following constants is explained in SMWSQLStore3::setup():
+define( 'SMW_SQL3_SMWIW_OUTDATED', ':smw' ); // virtual "interwiki prefix" for old-style special SMW objects (no longer used)
+define( 'SMW_SQL3_SMWREDIIW', ':smw-redi' ); // virtual "interwiki prefix" for SMW objects that are redirected
+define( 'SMW_SQL3_SMWBORDERIW', ':smw-border' ); // virtual "interwiki prefix" separating very important pre-defined properties from the rest
+define( 'SMW_SQL3_SMWINTDEFIW', ':smw-intprop' ); // virtual "interwiki prefix" marking internal (invisible) predefined properties
+define( 'SMW_SQL3_SMWDELETEIW', ':smw-delete' ); // virtual "interwiki prefix" marking a deleted subject, see #1100
+
+/**
+ * Storage access class for using the standard MediaWiki SQL database for
+ * keeping semantic data.
+ *
+ * @note Regarding the use of interwiki links in the store, there is currently
+ * no support for storing semantic data about interwiki objects, and hence
+ * queries that involve interwiki objects really make sense only for them
+ * occurring in object positions. Most methods still use the given input
+ * interwiki text as a simple way to filter out results that may be found if an
+ * interwiki object is given but a local object of the same name exists. It is
+ * currently not planned to support things like interwiki reuse of properties.
+ *
+ * @since 1.8
+ * @ingroup SMWStore
+ */
+class SMWSQLStore3 extends SMWStore {
+
+ /**
+ * Specifies the border limit (upper bound) for pre-defined properties used
+ * in the ID_TABLE
+ *
+ * When changing the upper bound, please make sure to copy the current upper
+ * bound as legcy to the TableIntegrityExaminer::checkPredefinedPropertyUpperbound
+ */
+ const FIXED_PROPERTY_ID_UPPERBOUND = 500;
+
+ /**
+ * Name of the table to store the concept cache in.
+ *
+ * @note This should never change. If it is changed, the concept caches
+ * will appear empty until they are recomputed.
+ */
+ const CONCEPT_CACHE_TABLE = 'smw_concept_cache';
+ const CONCEPT_TABLE = 'smw_fpt_conc';
+
+ /**
+ * Name of the table to store the concept cache in.
+ *
+ * @note This should never change, but if it does then its contents can
+ * simply be rebuilt by running the setup.
+ */
+ const PROPERTY_STATISTICS_TABLE = 'smw_prop_stats';
+
+ /**
+ * Name of the table that manages the query dependency links
+ */
+ const QUERY_LINKS_TABLE = 'smw_query_links';
+
+ /**
+ * Name of the table that manages the fulltext index
+ */
+ const FT_SEARCH_TABLE = 'smw_ft_search';
+
+ /**
+ * Name of the table that manages the Store IDs
+ */
+ const ID_TABLE = 'smw_object_ids';
+
+ /**
+ * @var SQLStoreFactory
+ */
+ private $factory;
+
+ /**
+ * @var PropertyTableInfoFetcher|null
+ */
+ private $propertyTableInfoFetcher = null;
+
+ /**
+ * @var PropertyTableIdReferenceFinder
+ */
+ private $propertyTableIdReferenceFinder;
+
+ /**
+ * @var DataItemHandlerDispatcher
+ */
+ private $dataItemHandlerDispatcher;
+
+ /**
+ * @var EntityLookup
+ */
+ private $entityLookup;
+
+ /**
+ * @var ServicesContainer
+ */
+ protected $servicesContainer;
+
+ /**
+ * Object to access the SMW IDs table.
+ *
+ * @since 1.8
+ * @var SMWSql3SmwIds
+ */
+ public $smwIds;
+
+ /**
+ * The reader object used by this store. Initialized by getReader()
+ * Always access using getReader()
+ *
+ * @since 1.8
+ * @var SMWSQLStore3Readers
+ */
+ protected $reader = false;
+
+ /**
+ * The writer object used by this store. Initialized by getWriter(),
+ * which is the only way in which it should be accessed.
+ *
+ * @since 1.8
+ * @var SMWSQLStore3Writers
+ */
+ protected $writer = false;
+
+ /**
+ * @since 1.8
+ */
+ public function __construct() {
+ $this->factory = new SQLStoreFactory( $this, $this->messageReporter );
+ $this->smwIds = $this->factory->newEntityTable();
+ }
+
+ /**
+ * Get an object of the dataitem handler from the dataitem provided.
+ *
+ * @since 1.8
+ * @param integer $diType
+ *
+ * @return SMWDIHandler
+ * @throws RuntimeException if no handler exists for the given type
+ */
+ public function getDataItemHandlerForDIType( $diType ) {
+
+ if ( $this->dataItemHandlerDispatcher === null ) {
+ $this->dataItemHandlerDispatcher = $this->factory->newDataItemHandlerDispatcher( $this );
+ }
+
+ return $this->dataItemHandlerDispatcher->getHandlerByType( $diType );
+ }
+
+///// Reading methods /////
+
+ public function getReader() {
+ if( $this->reader == false ) {
+ $this->reader = new SMWSQLStore3Readers( $this, $this->factory );//Initialize if not done already
+ }
+
+ return $this->reader;
+ }
+
+ public function getSemanticData( DIWikiPage $subject, $filter = false ) {
+ return $this->getEntityLookup()->getSemanticData( $subject, $filter );
+ }
+
+ /**
+ * @param mixed $subject
+ * @param DIProperty $property
+ * @param null $requestOptions
+ *
+ * @return SMWDataItem[]
+ */
+ public function getPropertyValues( $subject, DIProperty $property, $requestOptions = null ) {
+ return $this->getEntityLookup()->getPropertyValues( $subject, $property, $requestOptions );
+ }
+
+ public function getProperties( DIWikiPage $subject, $requestOptions = null ) {
+ return $this->getEntityLookup()->getProperties( $subject, $requestOptions );
+ }
+
+ public function getPropertySubjects( DIProperty $property, $dataItem, $requestOptions = null ) {
+ return $this->getEntityLookup()->getPropertySubjects( $property, $dataItem, $requestOptions );
+ }
+
+ public function getAllPropertySubjects( DIProperty $property, $requestoptions = null ) {
+ return $this->getEntityLookup()->getAllPropertySubjects( $property, $requestoptions );
+ }
+
+ public function getInProperties( SMWDataItem $value, $requestoptions = null ) {
+ return $this->getEntityLookup()->getInProperties( $value, $requestoptions );
+ }
+
+
+///// Writing methods /////
+
+
+ public function getWriter() {
+ if( $this->writer == false ) {
+ $this->writer = new SMWSQLStore3Writers( $this, $this->factory );
+ }
+
+ return $this->writer;
+ }
+
+ public function deleteSubject( Title $title ) {
+
+ $subject = DIWikiPage::newFromTitle( $title );
+
+ $this->getEntityLookup()->invalidateCache(
+ $subject
+ );
+
+ $this->getWriter()->deleteSubject( $title );
+
+ $this->doDeferredCachedListLookupUpdate(
+ $subject
+ );
+ }
+
+ protected function doDataUpdate( SemanticData $semanticData ) {
+
+ $this->getEntityLookup()->invalidateCache(
+ $semanticData->getSubject()
+ );
+
+ $this->getWriter()->doDataUpdate( $semanticData );
+
+ $this->doDeferredCachedListLookupUpdate(
+ $semanticData->getSubject()
+ );
+ }
+
+ public function changeTitle( Title $oldtitle, Title $newtitle, $pageid, $redirid = 0 ) {
+
+ $this->getEntityLookup()->invalidateCache(
+ DIWikiPage::newFromTitle( $oldtitle )
+ );
+
+ $this->getEntityLookup()->invalidateCache(
+ DIWikiPage::newFromTitle( $newtitle )
+ );
+
+ $this->getWriter()->changeTitle( $oldtitle, $newtitle, $pageid, $redirid );
+
+ $this->doDeferredCachedListLookupUpdate(
+ DIWikiPage::newFromTitle( $oldtitle )
+ );
+ }
+
+ private function doDeferredCachedListLookupUpdate( DIWikiPage $subject ) {
+
+ if ( $subject->getNamespace() !== SMW_NS_PROPERTY ) {
+ return null;
+ }
+
+ $deferredCallableUpdate = $this->factory->newDeferredCallableCachedListLookupUpdate();
+ $deferredCallableUpdate->setOrigin( __METHOD__ );
+ $deferredCallableUpdate->waitOnTransactionIdle();
+ $deferredCallableUpdate->pushUpdate();
+ }
+
+///// Query answering /////
+
+ /**
+ * @note Move hooks to the base class in 3.*
+ *
+ * @see SMWStore::fetchQueryResult
+ *
+ * @since 1.8
+ * @param SMWQuery $query
+ * @return SMWQueryResult|string|integer depends on $query->querymode
+ */
+ public function getQueryResult( SMWQuery $query ) {
+
+ $result = null;
+ $start = microtime( true );
+
+ if ( \Hooks::run( 'SMW::Store::BeforeQueryResultLookupComplete', [ $this, $query, &$result, $this->factory->newSlaveQueryEngine() ] ) ) {
+ $result = $this->fetchQueryResult( $query );
+ }
+
+ \Hooks::run( 'SMW::SQLStore::AfterQueryResultLookupComplete', [ $this, &$result ] );
+ \Hooks::run( 'SMW::Store::AfterQueryResultLookupComplete', [ $this, &$result ] );
+
+ $query->setOption( SMWQuery::PROC_QUERY_TIME, microtime( true ) - $start );
+
+ return $result;
+ }
+
+ protected function fetchQueryResult( SMWQuery $query ) {
+ return $this->factory->newSlaveQueryEngine()->getQueryResult( $query );
+ }
+
+///// Special page functions /////
+
+ /**
+ * @param RequestOptions|null $requestOptions
+ *
+ * @return CachedListLookup
+ */
+ public function getPropertiesSpecial( $requestOptions = null ) {
+ return $this->factory->newPropertyUsageCachedListLookup( $requestOptions );
+ }
+
+ /**
+ * @param RequestOptions|null $requestOptions
+ *
+ * @return CachedListLookup
+ */
+ public function getUnusedPropertiesSpecial( $requestOptions = null ) {
+ return $this->factory->newUnusedPropertyCachedListLookup( $requestOptions );
+ }
+
+ /**
+ * @param RequestOptions|null $requestOptions
+ *
+ * @return CachedListLookup
+ */
+ public function getWantedPropertiesSpecial( $requestOptions = null ) {
+ return $this->factory->newUndeclaredPropertyCachedListLookup( $requestOptions );
+ }
+
+ public function getStatistics() {
+ return $this->factory->newUsageStatisticsCachedListLookup()->fetchList();
+ }
+
+
+///// Setup store /////
+
+ /**
+ * @see Store::service
+ *
+ * {@inheritDoc}
+ */
+ public function service( $service, ...$args ) {
+
+ if ( $this->servicesContainer === null ) {
+ $this->servicesContainer = $this->newServicesContainer();
+ }
+
+ return $this->servicesContainer->get( $service, ...$args );
+ }
+
+ /**
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function setup( $verbose = true ) {
+
+ $installer = $this->factory->newInstaller();
+ $installer->setMessageReporter( $this->messageReporter );
+
+ return $installer->install( $verbose );
+ }
+
+ /**
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function drop( $verbose = true ) {
+
+ $installer = $this->factory->newInstaller();
+ $installer->setMessageReporter( $this->messageReporter );
+
+ return $installer->uninstall( $verbose );
+ }
+
+ public function refreshData( &$id, $count, $namespaces = false, $usejobs = true ) {
+
+ $entityRebuildDispatcher = $this->factory->newEntityRebuildDispatcher();
+
+ $entityRebuildDispatcher->setDispatchRangeLimit( $count );
+ $entityRebuildDispatcher->setRestrictionToNamespaces( $namespaces );
+
+ $entityRebuildDispatcher->setOptions(
+ [
+ 'use-job' => $usejobs
+ ]
+ );
+
+ return $entityRebuildDispatcher;
+ }
+
+
+///// Concept caching /////
+
+ /**
+ * Refresh the concept cache for the given concept.
+ *
+ * @since 1.8
+ * @param Title $concept
+ * @return array of error strings (empty if no errors occurred)
+ */
+ public function refreshConceptCache( Title $concept ) {
+ return $this->factory->newMasterConceptCache()->refreshConceptCache( $concept );
+ }
+
+ /**
+ * Delete the concept cache for the given concept.
+ *
+ * @since 1.8
+ * @param Title $concept
+ */
+ public function deleteConceptCache( $concept ) {
+ $this->factory->newMasterConceptCache()->deleteConceptCache( $concept );
+ }
+
+ /**
+ * Return status of the concept cache for the given concept as an array
+ * with key 'status' ('empty': not cached, 'full': cached, 'no': not
+ * cacheable). If status is not 'no', the array also contains keys 'size'
+ * (query size), 'depth' (query depth), 'features' (query features). If
+ * status is 'full', the array also contains keys 'date' (timestamp of
+ * cache), 'count' (number of results in cache).
+ *
+ * @since 1.8
+ * @param Title|SMWWikiPageValue $concept
+ *
+ * @return DIConcept|null
+ */
+ public function getConceptCacheStatus( $concept ) {
+ return $this->factory->newSlaveConceptCache()->getStatus( $concept );
+ }
+
+
+///// Helper methods, mostly protected /////
+
+ /**
+ * @see RequestOptionsProc::getSQLOptions
+ *
+ * @since 1.8
+ *
+ * @param SMWRequestOptions|null $requestOptions
+ * @param string $valuecol
+ *
+ * @return array
+ */
+ public function getSQLOptions( SMWRequestOptions $requestOptions = null, $valueCol = '' ) {
+ return RequestOptionsProc::getSQLOptions( $requestOptions, $valueCol );
+ }
+
+ /**
+ * @see RequestOptionsProc::getSQLConditions
+ *
+ * @since 1.8
+ *
+ * @param SMWRequestOptions|null $requestOptions
+ * @param string $valueCol name of SQL column to which conditions apply
+ * @param string $labelCol name of SQL column to which string conditions apply, if any
+ * @param boolean $addAnd indicate whether the string should begin with " AND " if non-empty
+ *
+ * @return string
+ */
+ public function getSQLConditions( SMWRequestOptions $requestOptions = null, $valueCol = '', $labelCol = '', $addAnd = true ) {
+ return RequestOptionsProc::getSQLConditions( $this, $requestOptions, $valueCol, $labelCol, $addAnd );
+ }
+
+ /**
+ * @see RequestOptionsProc::applyRequestOptions
+ *
+ * @since 1.8
+ *
+ * @param array $data array of SMWDataItem objects
+ * @param SMWRequestOptions|null $requestOptions
+ *
+ * @return SMWDataItem[]
+ */
+ public function applyRequestOptions( array $data, SMWRequestOptions $requestOptions = null ) {
+ return RequestOptionsProc::applyRequestOptions( $this, $data, $requestOptions );
+ }
+
+ /**
+ * PropertyTableInfoFetcher::findTableIdForDataTypeTypeId
+ *
+ * @param string $typeid
+ *
+ * @return string
+ */
+ public function findTypeTableId( $typeid ) {
+ return $this->getPropertyTableInfoFetcher()->findTableIdForDataTypeTypeId( $typeid );
+ }
+
+ /**
+ * PropertyTableInfoFetcher::findTableIdForDataItemTypeId
+ *
+ * @param integer $dataItemId
+ *
+ * @return string
+ */
+ public function findDiTypeTableId( $dataItemId ) {
+ return $this->getPropertyTableInfoFetcher()->findTableIdForDataItemTypeId( $dataItemId );
+ }
+
+ /**
+ * PropertyTableInfoFetcher::findTableIdForProperty
+ *
+ * @param DIProperty $property
+ *
+ * @return string
+ */
+ public function findPropertyTableID( DIProperty $property ) {
+ return $this->getPropertyTableInfoFetcher()->findTableIdForProperty( $property );
+ }
+
+ /**
+ * PropertyTableInfoFetcher::getPropertyTableDefinitions
+ *
+ * @return TableDefinition[]
+ */
+ public function getPropertyTables() {
+ return $this->getPropertyTableInfoFetcher()->getPropertyTableDefinitions();
+ }
+
+ /**
+ * Returns SMW Id object
+ *
+ * @since 1.9
+ *
+ * @return SMWSql3SmwIds
+ */
+ public function getObjectIds() {
+ return $this->smwIds;
+ }
+
+ /**
+ * Returns the statics table
+ *
+ * @since 1.9
+ *
+ * @return string
+ */
+ public function getStatisticsTable() {
+ return self::PROPERTY_STATISTICS_TABLE;
+ }
+
+ /**
+ * Resets internal objects
+ *
+ * @since 1.9.1.1
+ */
+ public function clear() {
+ parent::clear();
+ $this->factory->newSemanticDataLookup()->clear();
+ $this->propertyTableInfoFetcher = null;
+ $this->servicesContainer = null;
+ $this->getObjectIds()->initCache();
+ }
+
+ /**
+ * @since 3.0
+ *
+ * @param string|null $type
+ *
+ * @return array
+ */
+ public function getInfo( $type = null ) {
+
+ if ( $type === 'store' ) {
+ return 'SMWSQLStore';
+ }
+
+ $connection = $this->getConnection( 'mw.db' );
+
+ if ( $type === 'db' ) {
+ return $connection->getInfo();
+ }
+
+ return [
+ 'SMWSQLStore' => $connection->getInfo()
+ ];
+ }
+
+ /**
+ * @since 2.1
+ *
+ * @param string $type
+ *
+ * @return Database
+ */
+ public function getConnection( $type = 'mw.db' ) {
+ return parent::getConnection( $type );
+ }
+
+ /**
+ * @since 2.2
+ *
+ * @return PropertyTableInfoFetcher
+ */
+ public function getPropertyTableInfoFetcher() {
+
+ if ( $this->propertyTableInfoFetcher === null ) {
+ $this->propertyTableInfoFetcher = $this->factory->newPropertyTableInfoFetcher();
+ }
+
+ return $this->propertyTableInfoFetcher;
+ }
+
+ /**
+ * @since 2.4
+ *
+ * @return PropertyTableIdReferenceFinder
+ */
+ public function getPropertyTableIdReferenceFinder() {
+
+ if ( $this->propertyTableIdReferenceFinder === null ) {
+ $this->propertyTableIdReferenceFinder = $this->factory->newPropertyTableIdReferenceFinder();
+ }
+
+ return $this->propertyTableIdReferenceFinder;
+ }
+
+ /**
+ * @return ServicesContainer
+ */
+ protected function newServicesContainer() {
+ return $this->factory->newServicesContainer();
+ }
+
+ /**
+ * @return EntityLookup
+ */
+ private function getEntityLookup() {
+
+ if ( $this->entityLookup === null ) {
+ $this->entityLookup = $this->factory->newEntityLookup();
+ }
+
+ return $this->entityLookup;
+ }
+
+}