** MySQL 5.5.8 or higher
** PostgreSQL 9.2 or higher
** SQLite 3.8.0 or higher
-** Oracle 9.0.1 or higher
-** Microsoft SQL Server 2005 (9.00.1399)
MediaWiki is developed and tested mainly on Unix/Linux platforms, but should
work on Windows as well.
support.
MySQL/MariaDB is the recommended DBMS. PostgreSQL or SQLite can also be used,
-but support for them is somewhat less mature. There is experimental support for
-Oracle and Microsoft SQL Server.
+but support for them is somewhat less mature.
The supported versions are:
* MySQL 5.5.8 or later
* PostgreSQL 9.2 or later
* SQLite 3.8.0 or later
-* Oracle 9.0.1 or later
-* Microsoft SQL Server 2005 (9.00.1399)
== Online documentation ==
Documentation for both end-users and site administrators is available on
'SearchHighlighter' => __DIR__ . '/includes/search/SearchHighlighter.php',
'SearchIndexField' => __DIR__ . '/includes/search/SearchIndexField.php',
'SearchIndexFieldDefinition' => __DIR__ . '/includes/search/SearchIndexFieldDefinition.php',
- 'SearchMssql' => __DIR__ . '/includes/search/SearchMssql.php',
'SearchMySQL' => __DIR__ . '/includes/search/SearchMySQL.php',
'SearchNearMatchResultSet' => __DIR__ . '/includes/search/SearchNearMatchResultSet.php',
'SearchNearMatcher' => __DIR__ . '/includes/search/SearchNearMatcher.php',
- 'SearchOracle' => __DIR__ . '/includes/search/SearchOracle.php',
'SearchPostgres' => __DIR__ . '/includes/search/SearchPostgres.php',
'SearchResult' => __DIR__ . '/includes/search/SearchResult.php',
'SearchResultSet' => __DIR__ . '/includes/search/SearchResultSet.php',
return SearchMySQL::class;
case 'postgres':
return SearchPostgres::class;
- case 'mssql':
- return SearchMssql::class;
- case 'oracle':
- return SearchOracle::class;
default:
return SearchEngineDummy::class;
}
+++ /dev/null
-<?php
-/**
- * Mssql search engine
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Search
- */
-
-use MediaWiki\MediaWikiServices;
-use Wikimedia\Rdbms\IResultWrapper;
-
-/**
- * Search engine hook base class for Mssql (ConText).
- * @ingroup Search
- */
-class SearchMssql extends SearchDatabase {
- /**
- * Perform a full text search query and return a result set.
- *
- * @param string $term Raw search term
- * @return SqlSearchResultSet|null
- */
- protected function doSearchTextInDB( $term ) {
- $dbr = $this->lb->getConnectionRef( DB_REPLICA );
- $resultSet = $dbr->query( $this->getQuery( $this->filter( $term ), true ) );
-
- return new SqlSearchResultSet( $resultSet, $this->searchTerms );
- }
-
- /**
- * Perform a title-only search query and return a result set.
- *
- * @param string $term Raw search term
- * @return SqlSearchResultSet|null
- */
- protected function doSearchTitleInDB( $term ) {
- $dbr = $this->lb->getConnectionRef( DB_REPLICA );
- $resultSet = $dbr->query( $this->getQuery( $this->filter( $term ), false ) );
-
- return new SqlSearchResultSet( $resultSet, $this->searchTerms );
- }
-
- /**
- * Return a partial WHERE clause to limit the search to the given namespaces
- *
- * @return string
- */
- private function queryNamespaces() {
- $namespaces = implode( ',', $this->namespaces );
- if ( $namespaces == '' ) {
- $namespaces = '0';
- }
- return 'AND page_namespace IN (' . $namespaces . ')';
- }
-
- /**
- * Return a LIMIT clause to limit results on the query.
- *
- * @param string $sql
- *
- * @return string
- */
- private function queryLimit( $sql ) {
- $dbr = $this->lb->getConnectionRef( DB_REPLICA );
-
- return $dbr->limitResult( $sql, $this->limit, $this->offset );
- }
-
- /**
- * Does not do anything for generic search engine
- * subclasses may define this though
- *
- * @param string $filteredTerm
- * @param bool $fulltext
- * @return string
- */
- function queryRanking( $filteredTerm, $fulltext ) {
- return ' ORDER BY ftindex.[RANK] DESC'; // return ' ORDER BY score(1)';
- }
-
- /**
- * Construct the full SQL query to do the search.
- * The guts shoulds be constructed in queryMain()
- *
- * @param string $filteredTerm
- * @param bool $fulltext
- * @return string
- */
- private function getQuery( $filteredTerm, $fulltext ) {
- return $this->queryLimit( $this->queryMain( $filteredTerm, $fulltext ) . ' ' .
- $this->queryNamespaces() . ' ' .
- $this->queryRanking( $filteredTerm, $fulltext ) . ' ' );
- }
-
- /**
- * Picks which field to index on, depending on what type of query.
- *
- * @param bool $fulltext
- * @return string
- */
- function getIndexField( $fulltext ) {
- return $fulltext ? 'si_text' : 'si_title';
- }
-
- /**
- * Get the base part of the search query.
- *
- * @param string $filteredTerm
- * @param bool $fulltext
- * @return string
- */
- private function queryMain( $filteredTerm, $fulltext ) {
- $match = $this->parseQuery( $filteredTerm, $fulltext );
- $dbr = $this->lb->getMaintenanceConnectionRef( DB_REPLICA );
- $page = $dbr->tableName( 'page' );
- $searchindex = $dbr->tableName( 'searchindex' );
-
- return 'SELECT page_id, page_namespace, page_title, ftindex.[RANK]' .
- "FROM $page,FREETEXTTABLE($searchindex , $match, LANGUAGE 'English') as ftindex " .
- 'WHERE page_id=ftindex.[KEY] ';
- }
-
- /** @todo document
- * @param string $filteredText
- * @param bool $fulltext
- * @return string
- */
- private function parseQuery( $filteredText, $fulltext ) {
- $lc = $this->legalSearchChars( self::CHARS_NO_SYNTAX );
- $this->searchTerms = [];
-
- # @todo FIXME: This doesn't handle parenthetical expressions.
- $m = [];
- $q = [];
-
- if ( preg_match_all( '/([-+<>~]?)(([' . $lc . ']+)(\*?)|"[^"]*")/',
- $filteredText, $m, PREG_SET_ORDER ) ) {
- foreach ( $m as $terms ) {
- $q[] = $terms[1] . MediaWikiServices::getInstance()->getContentLanguage()->
- normalizeForSearch( $terms[2] );
-
- if ( !empty( $terms[3] ) ) {
- $regexp = preg_quote( $terms[3], '/' );
- if ( $terms[4] ) {
- $regexp .= "[0-9A-Za-z_]+";
- }
- } else {
- $regexp = preg_quote( str_replace( '"', '', $terms[2] ), '/' );
- }
- $this->searchTerms[] = $regexp;
- }
- }
-
- $dbr = $this->lb->getConnectionRef( DB_REPLICA );
- $searchon = $dbr->addQuotes( implode( ',', $q ) );
- $field = $this->getIndexField( $fulltext );
-
- return "$field, $searchon";
- }
-
- /**
- * Create or update the search index record for the given page.
- * Title and text should be pre-processed.
- *
- * @param int $id
- * @param string $title
- * @param string $text
- * @return bool|IResultWrapper
- */
- function update( $id, $title, $text ) {
- // We store the column data as UTF-8 byte order marked binary stream
- // because we are invoking the plain text IFilter on it so that, and we want it
- // to properly decode the stream as UTF-8. SQL doesn't support UTF8 as a data type
- // but the indexer will correctly handle it by this method. Since all we are doing
- // is passing this data to the indexer and never retrieving it via PHP, this will save space
- $dbr = $this->lb->getMaintenanceConnectionRef( DB_MASTER );
- $table = $dbr->tableName( 'searchindex' );
- $utf8bom = '0xEFBBBF';
- $si_title = $utf8bom . bin2hex( $title );
- $si_text = $utf8bom . bin2hex( $text );
- $sql = "DELETE FROM $table WHERE si_page = $id;";
- $sql .= "INSERT INTO $table (si_page, si_title, si_text) VALUES ($id, $si_title, $si_text)";
- return $dbr->query( $sql, 'SearchMssql::update' );
- }
-
- /**
- * Update a search index record's title only.
- * Title should be pre-processed.
- *
- * @param int $id
- * @param string $title
- * @return bool|IResultWrapper
- */
- function updateTitle( $id, $title ) {
- $dbr = $this->lb->getMaintenanceConnectionRef( DB_MASTER );
- $table = $dbr->tableName( 'searchindex' );
-
- // see update for why we are using the utf8bom
- $utf8bom = '0xEFBBBF';
- $si_title = $utf8bom . bin2hex( $title );
- $sql = "DELETE FROM $table WHERE si_page = $id;";
- $sql .= "INSERT INTO $table (si_page, si_title, si_text) VALUES ($id, $si_title, 0x00)";
- return $dbr->query( $sql, 'SearchMssql::updateTitle' );
- }
-}
+++ /dev/null
-<?php
-/**
- * Oracle search engine
- *
- * Copyright © 2004 Brion Vibber <brion@pobox.com>
- * https://www.mediawiki.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Search
- */
-
-use MediaWiki\MediaWikiServices;
-
-/**
- * Search engine hook base class for Oracle (ConText).
- * @ingroup Search
- */
-class SearchOracle extends SearchDatabase {
- private $reservedWords = [
- 'ABOUT' => 1,
- 'ACCUM' => 1,
- 'AND' => 1,
- 'BT' => 1,
- 'BTG' => 1,
- 'BTI' => 1,
- 'BTP' => 1,
- 'FUZZY' => 1,
- 'HASPATH' => 1,
- 'INPATH' => 1,
- 'MINUS' => 1,
- 'NEAR' => 1,
- 'NOT' => 1,
- 'NT' => 1,
- 'NTG' => 1,
- 'NTI' => 1,
- 'NTP' => 1,
- 'OR' => 1,
- 'PT' => 1,
- 'RT' => 1,
- 'SQE' => 1,
- 'SYN' => 1,
- 'TR' => 1,
- 'TRSYN' => 1,
- 'TT' => 1,
- 'WITHIN' => 1,
- ];
-
- /**
- * Perform a full text search query and return a result set.
- *
- * @param string $term Raw search term
- * @return SqlSearchResultSet|null
- */
- protected function doSearchTextInDB( $term ) {
- if ( $term == '' ) {
- return null;
- }
-
- $dbr = $this->lb->getConnectionRef( DB_REPLICA );
- $resultSet = $dbr->query( $this->getQuery( $this->filter( $term ), true ) );
- return new SqlSearchResultSet( $resultSet, $this->searchTerms );
- }
-
- /**
- * Perform a title-only search query and return a result set.
- *
- * @param string $term Raw search term
- * @return SqlSearchResultSet|null
- */
- protected function doSearchTitleInDB( $term ) {
- if ( $term == '' ) {
- return null;
- }
-
- $dbr = $this->lb->getConnectionRef( DB_REPLICA );
- $resultSet = $dbr->query( $this->getQuery( $this->filter( $term ), false ) );
- return new SqlSearchResultSet( $resultSet, $this->searchTerms );
- }
-
- /**
- * Return a partial WHERE clause to limit the search to the given namespaces
- * @return string
- */
- private function queryNamespaces() {
- if ( is_null( $this->namespaces ) ) {
- return '';
- }
- if ( $this->namespaces === [] ) {
- $namespaces = '0';
- } else {
- $dbr = $this->lb->getConnectionRef( DB_REPLICA );
- $namespaces = $dbr->makeList( $this->namespaces );
- }
- return 'AND page_namespace IN (' . $namespaces . ')';
- }
-
- /**
- * Return a LIMIT clause to limit results on the query.
- *
- * @param string $sql
- *
- * @return string
- */
- private function queryLimit( $sql ) {
- $dbr = $this->lb->getConnectionRef( DB_REPLICA );
-
- return $dbr->limitResult( $sql, $this->limit, $this->offset );
- }
-
- /**
- * Does not do anything for generic search engine
- * subclasses may define this though
- *
- * @param string $filteredTerm
- * @param bool $fulltext
- * @return string
- */
- function queryRanking( $filteredTerm, $fulltext ) {
- return ' ORDER BY score(1)';
- }
-
- /**
- * Construct the full SQL query to do the search.
- * The guts shoulds be constructed in queryMain()
- * @param string $filteredTerm
- * @param bool $fulltext
- * @return string
- */
- private function getQuery( $filteredTerm, $fulltext ) {
- return $this->queryLimit( $this->queryMain( $filteredTerm, $fulltext ) . ' ' .
- $this->queryNamespaces() . ' ' .
- $this->queryRanking( $filteredTerm, $fulltext ) . ' ' );
- }
-
- /**
- * Picks which field to index on, depending on what type of query.
- * @param bool $fulltext
- * @return string
- */
- private function getIndexField( $fulltext ) {
- return $fulltext ? 'si_text' : 'si_title';
- }
-
- /**
- * Get the base part of the search query.
- *
- * @param string $filteredTerm
- * @param bool $fulltext
- * @return string
- */
- function queryMain( $filteredTerm, $fulltext ) {
- $match = $this->parseQuery( $filteredTerm, $fulltext );
-
- $dbr = $this->lb->getMaintenanceConnectionRef( DB_REPLICA );
- $page = $dbr->tableName( 'page' );
- $searchindex = $dbr->tableName( 'searchindex' );
-
- return 'SELECT page_id, page_namespace, page_title ' .
- "FROM $page,$searchindex " .
- 'WHERE page_id=si_page AND ' . $match;
- }
-
- /**
- * Parse a user input search string, and return an SQL fragment to be used
- * as part of a WHERE clause
- * @param string $filteredText
- * @param bool $fulltext
- * @return string
- */
- private function parseQuery( $filteredText, $fulltext ) {
- $lc = $this->legalSearchChars( self::CHARS_NO_SYNTAX );
- $this->searchTerms = [];
-
- # @todo FIXME: This doesn't handle parenthetical expressions.
- $m = [];
- $searchon = '';
- if ( preg_match_all( '/([-+<>~]?)(([' . $lc . ']+)(\*?)|"[^"]*")/',
- $filteredText, $m, PREG_SET_ORDER ) ) {
- foreach ( $m as $terms ) {
- // Search terms in all variant forms, only
- // apply on wiki with LanguageConverter
- $temp_terms = MediaWikiServices::getInstance()->getContentLanguage()->
- autoConvertToAllVariants( $terms[2] );
- if ( is_array( $temp_terms ) ) {
- $temp_terms = array_unique( array_values( $temp_terms ) );
- foreach ( $temp_terms as $t ) {
- $searchon .= ( $terms[1] == '-' ? ' ~' : ' & ' ) . $this->escapeTerm( $t );
- }
- } else {
- $searchon .= ( $terms[1] == '-' ? ' ~' : ' & ' ) . $this->escapeTerm( $terms[2] );
- }
- if ( !empty( $terms[3] ) ) {
- $regexp = preg_quote( $terms[3], '/' );
- if ( $terms[4] ) {
- $regexp .= "[0-9A-Za-z_]+";
- }
- } else {
- $regexp = preg_quote( str_replace( '"', '', $terms[2] ), '/' );
- }
- $this->searchTerms[] = $regexp;
- }
- }
-
- $dbr = $this->lb->getConnectionRef( DB_REPLICA );
- $searchon = $dbr->addQuotes( ltrim( $searchon, ' &' ) );
- $field = $this->getIndexField( $fulltext );
-
- return " CONTAINS($field, $searchon, 1) > 0 ";
- }
-
- private function escapeTerm( $t ) {
- $t = MediaWikiServices::getInstance()->getContentLanguage()->normalizeForSearch( $t );
- $t = isset( $this->reservedWords[strtoupper( $t )] ) ? '{' . $t . '}' : $t;
- $t = preg_replace( '/^"(.*)"$/', '($1)', $t );
- $t = preg_replace( '/([-&|])/', '\\\\$1', $t );
- return $t;
- }
-
- /**
- * Create or update the search index record for the given page.
- * Title and text should be pre-processed.
- *
- * @param int $id
- * @param string $title
- * @param string $text
- */
- function update( $id, $title, $text ) {
- $dbw = $this->lb->getMaintenanceConnectionRef( DB_MASTER );
- $dbw->replace( 'searchindex',
- [ 'si_page' ],
- [
- 'si_page' => $id,
- 'si_title' => $title,
- 'si_text' => $text
- ], 'SearchOracle::update' );
-
- // Sync the index
- // We need to specify the DB name (i.e. user/schema) here so that
- // it can work from the installer, where
- // ALTER SESSION SET CURRENT_SCHEMA = ...
- // was used.
- $dbw->query( "CALL ctx_ddl.sync_index(" .
- $dbw->addQuotes( $dbw->getDBname() . '.' . $dbw->tableName( 'si_text_idx', 'raw' ) ) . ")" );
- $dbw->query( "CALL ctx_ddl.sync_index(" .
- $dbw->addQuotes( $dbw->getDBname() . '.' . $dbw->tableName( 'si_title_idx', 'raw' ) ) . ")" );
- }
-
- /**
- * Update a search index record's title only.
- * Title should be pre-processed.
- *
- * @param int $id
- * @param string $title
- */
- function updateTitle( $id, $title ) {
- $dbw = $this->lb->getConnectionRef( DB_MASTER );
- $dbw->update( 'searchindex',
- [ 'si_title' => $title ],
- [ 'si_page' => $id ],
- 'SearchOracle::updateTitle',
- [] );
- }
-
- public function legalSearchChars( $type = self::CHARS_ALL ) {
- $searchChars = parent::legalSearchChars( $type );
- if ( $type === self::CHARS_ALL ) {
- $searchChars = "\"" . $searchChars;
- }
- return $searchChars;
- }
-}
"version-db-mariadb-url": "https://mariadb.org/",
"version-db-percona-url": "http://www.percona.com/software/percona-server",
"version-db-postgres-url": "http://www.postgresql.org/",
- "version-db-oracle-url": "http://www.oracle.com/database/",
"version-db-sqlite-url": "https://www.sqlite.org/",
- "version-db-mssql-url": "https://www.microsoft.com/sql/",
"version-entrypoints": "Entry point URLs",
"version-entrypoints-header-entrypoint": "Entry point",
"version-entrypoints-header-url": "URL",
"version-db-mariadb-url": "{{ignored}}URL to the website of MariaDB",
"version-db-percona-url": "{{ignored}}URL to the website of Percona",
"version-db-postgres-url": "{{ignored}}URL to the website of PostgreSQL",
- "version-db-oracle-url": "{{ignored}}URL to the website of Oracle",
"version-db-sqlite-url": "{{ignored}}URL to the website of SQLite",
- "version-db-mssql-url": "{{ignored}}URL to the website of Microsoft SQL Server",
"version-entrypoints": "Header on [[Special:Version]] above a table that lists the URLs of various entry points in this MediaWiki installation. Entry points are the \"places\" where the wiki's content and information can be accessed in various ways, for instance the standard index.php which shows normal pages, histories etc.",
"version-entrypoints-header-entrypoint": "Header for the first column in the entry points table on [[Special:Version]].\nSee also {{msg-mw|Version-entrypoints}}",
"version-entrypoints-header-url": "Header for the second column in the entry points table on [[Special:Version]].\n{{Identical|URL}}",
private function assertNotReal() {
global $wgDBprefix;
- if ( $wgDBprefix !== MediaWikiTestCase::DB_PREFIX &&
- $wgDBprefix !== MediaWikiTestCase::ORA_DB_PREFIX
- ) {
+ if ( $wgDBprefix !== MediaWikiTestCase::DB_PREFIX ) {
throw new MWException( "Can't create user on real database" );
}
}