|
|
| (10 intermediate revisions by 2 users not shown) |
| Line 1: |
Line 1: |
| − | <?php
| + | {{legacy|this is now done using the built in [[SQLite]] database layer}} |
| − | # Extension:SQLite{{Category:Extensions|SQLite}}{{php}}{{Category:Extensions in progress|SQLite}}
| + | <php><?php |
| | + | # Extension:MediaWikiLite |
| | # - Licenced under LGPL (http://www.gnu.org/copyleft/lesser.html) | | # - Licenced under LGPL (http://www.gnu.org/copyleft/lesser.html) |
| − | # - Author: [http://www.organicdesign.co.nz/nad User:Nad]{{Category:Extensions created with Template:Extension}} | + | # - Author: [http://www.organicdesign.co.nz/nad User:Nad] |
| | + | # - Started: 2007-12-17 |
| | | | |
| | if (!defined('MEDIAWIKI')) die('Not an entry point.'); | | if (!defined('MEDIAWIKI')) die('Not an entry point.'); |
| − | if (!defined('SQLITE_OK')) die('SQLite is not installed!'); | + | if (!defined('PDO::ATTR_SERVER_VERSION')) die('PDO::SQLite3 is not installed!'); |
| | | | |
| − | define('MWLITE_VERSION','0.0.0, 2008-01-08'); | + | define('MWLITE_VERSION','0.1.0, 2008-01-16'); |
| | | | |
| − | $wgDBtype = 'sqlite'; | + | $wgDBtype = 'sqlite'; |
| | + | |
| | + | # Currently all the data for each wiki is in its own file in $wgSQLiteDataDir |
| | $wgSQLiteDataDir = dirname(__FILE__); | | $wgSQLiteDataDir = dirname(__FILE__); |
| | + | |
| | + | # For debugging |
| | $wgShowSQLErrors = true; | | $wgShowSQLErrors = true; |
| | + | $wgShowExceptionDetails = true; |
| | + | |
| | + | # Ensure the LoadBalancer knows how to load our DB class when the time comes |
| | + | $wgAutoloadClasses['DatabaseSqlite'] = dirname(__FILE__)."/DatabaseSqlite.php"; |
| | | | |
| | $wgExtensionCredits['other'][] = array( | | $wgExtensionCredits['other'][] = array( |
| Line 20: |
Line 30: |
| | 'version' => MWLITE_VERSION | | 'version' => MWLITE_VERSION |
| | ); | | ); |
| − | | + | </php> |
| − | class DatabaseSqlite extends Database {
| + | [[Category:Legacy Extensions|MediaWikiLite]] |
| − | | |
| − | var $mAffectedRows;
| |
| − | | |
| − | function DatabaseSqlite($server = false, $user = false, $password = false, $dbName = false, $failFunction = false, $flags = 0) {
| |
| − | global $wgOut;
| |
| − | # Can't get a reference if it hasn't been set yet
| |
| − | if (!isset($wgOut)) $wgOut = NULL;
| |
| − | $this->mOut =& $wgOut;
| |
| − | $this->mFailFunction = $failFunction;
| |
| − | $this->mFlags = $flags;
| |
| − | $this->open($server, $user, $password, $dbName);
| |
| − | }
| |
| − | | |
| − | function cascadingDeletes() { return true; }
| |
| − | function cleanupTriggers() { return true; }
| |
| − | function strictIPs() { return true; }
| |
| − | function realTimestamps() { return true; }
| |
| − | function implicitGroupby() { return false; }
| |
| − | function implicitOrderby() { return false; }
| |
| − | function searchableIPs() { return true; }
| |
| − | function functionalIndexes() { return true; }
| |
| − | | |
| − | static function newFromParams($server, $user, $password, $dbName, $failFunction = false, $flags = 0) {
| |
| − | return new DatabaseSqlite($server, $user, $password, $dbName, $failFunction, $flags);
| |
| − | }
| |
| − | | |
| − | # Open an SQLite database and return a resource handle to it
| |
| − | # NOTE: only $dbName is used, the other parameters are irrelevant for SQLite databases
| |
| − | function open($server,$user,$password,$dbName) {
| |
| − | global $wgSQLiteDataDir;
| |
| − | $this->mConn = false;
| |
| − | if ($dbName) {
| |
| − | if ($this->mFlags & DBO_PERSISTENT) @$this->mConn = new PDO("sqlite:$wgSQLiteDataDir/$dbName",$user,$pass,array(PDO::ATTR_PERSISTENT => true));
| |
| − | else @$this->mConn = @$this->mConn = new PDO("sqlite:$wgSQLiteDataDir/$dbName",$user,$pass);
| |
| − | if ($this->mConn === false) wfDebug("DB connection error: $err\n");;
| |
| − | $this->mOpened = $this->mConn;
| |
| − | }
| |
| − | return $this->mConn;
| |
| − | }
| |
| − | | |
| − | # Close an SQLite database
| |
| − | function close() {
| |
| − | $this->mOpened = false;
| |
| − | if ($this->mConn) {
| |
| − | if ($this->trxLevel()) $this->immediateCommit();
| |
| − | $this->mConn = null;
| |
| − | }
| |
| − | return true;
| |
| − | }
| |
| − | | |
| − | function doQuery($sql) {
| |
| − | if ($this->bufferResults()) @$ret = sqlite_query($this->mConn, $sql, SQLITE_BOTH, $err);
| |
| − | else @$ret = sqlite_unbuffered_query($this->mConn, $sql, SQLITE_BOTH, $err);
| |
| − | if ($err) $this->reportQueryError($err, 0, $sql, __FUNCTION__);
| |
| − | return $ret;
| |
| − | }
| |
| − | | |
| − | function queryIgnore($sql, $fname = '') {
| |
| − | return $this->query($sql, $fname, true);
| |
| − | }
| |
| − | | |
| − | function freeResult($res) {
| |
| − | return;
| |
| − | }
| |
| − | | |
| − | function fetchObject($res) {
| |
| − | if ($res instanceof ResultWrapper) $res = $res->result;
| |
| − | @$row = sqlite_fetch_object($res);
| |
| − | if ($this->lastErrno()) throw new DBUnexpectedError($this,'Error in fetchObject(): '.htmlspecialchars($this->lastError()));
| |
| − | return $row;
| |
| − | }
| |
| − | | |
| − | function fetchRow($res) {
| |
| − | if ($res instanceof ResultWrapper) $res = $res->result;
| |
| − | @$row = sqlite_fetch_array($res);
| |
| − | if ($this->lastErrno()) throw new DBUnexpectedError($this,'Error in fetchRow(): '.htmlspecialchars($this->lastError()));
| |
| − | return $row;
| |
| − | }
| |
| − | | |
| − | function numRows($res) {
| |
| − | if ($res instanceof ResultWrapper) $res = $res->result;
| |
| − | @$n = sqlite_num_rows($res);
| |
| − | if ($this->lastErrno()) throw new DBUnexpectedError($this,'Error in numRows(): '.htmlspecialchars($this->lastError()));
| |
| − | return $n;
| |
| − | }
| |
| − | | |
| − | function numFields($res) {
| |
| − | if ($res instanceof ResultWrapper) $res = $res->result;
| |
| − | @$n = sqlite_num_fields($res);
| |
| − | if ($this->lastErrno()) throw new DBUnexpectedError($this,'Error in numFields(): '.htmlspecialchars($this->lastError()));
| |
| − | return $n;
| |
| − | }
| |
| − | | |
| − | function fieldName($res,$n) {
| |
| − | return sqlite_field_name($res,$n);
| |
| − | }
| |
| − | | |
| − | # SQLite doesn't like the back-tick for strings
| |
| − | function tableName($name) {
| |
| − | return ereg_replace('`','"',parent::tableName($name));
| |
| − | }
| |
| − | | |
| − | # This must be called after nextSequenceVal
| |
| − | function insertId() {
| |
| − | # todo: return $this->mInsertId; ?
| |
| − | }
| |
| − | | |
| − | function dataSeek($res, $row) {
| |
| − | $res->seek($row);
| |
| − | }
| |
| − | | |
| − | function lastError() {
| |
| − | if ($this->mConn === false) return "Cannot return last error, no db connection";
| |
| − | return sqlite_error_string(sqlite_last_error($this->mConn));
| |
| − | }
| |
| − | | |
| − | function lastErrno() {
| |
| − | if ($this->mConn === false) return "Cannot return last error, no db connection";
| |
| − | return sqlite_last_error($this->mConn);
| |
| − | }
| |
| − | | |
| − | function affectedRows() {
| |
| − | return $this->mAffectedRows;
| |
| − | }
| |
| − | | |
| − | # Returns information about an index
| |
| − | # - if errors are explicitly ignored, returns NULL on failure
| |
| − | function indexInfo($table, $index, $fname = 'Database::indexExists') {
| |
| − | # todo
| |
| − | }
| |
| − | | |
| − | function indexUnique($table, $index, $fname = 'Database::indexUnique') {
| |
| − | # todo
| |
| − | }
| |
| − | | |
| − | function insert($table, $a, $fname = 'Database::insert', $options = array()) {
| |
| − | # todo
| |
| − | }
| |
| − | | |
| − | function insertOneRow($table, $row, $fname) {
| |
| − | # todo
| |
| − | }
| |
| − |
| |
| − | # SQLite does not have a "USE INDEX" clause, so return an empty string
| |
| − | function useIndexClause($index) {
| |
| − | return '';
| |
| − | }
| |
| − | | |
| − | # REPLACE query wrapper
| |
| − | function replace($table, $uniqueIndexes, $rows, $fname = 'Database::replace') {
| |
| − | # todo
| |
| − | }
| |
| − | | |
| − | # DELETE where the condition is a join
| |
| − | function deleteJoin($delTable, $joinTable, $delVar, $joinVar, $conds, $fname = "Database::deleteJoin") {
| |
| − | # todo
| |
| − | }
| |
| − | | |
| − | # Returns the size of a text field, or -1 for "unlimited"
| |
| − | function textFieldSize($table, $field) {
| |
| − | # todo
| |
| − | }
| |
| − | | |
| − | # No low priority option in SQLite
| |
| − | function lowPriorityOption() {
| |
| − | return '';
| |
| − | }
| |
| − | | |
| − | # Returns an SQL expression for a simple conditional.
| |
| − | # - uses CASE on SQLite
| |
| − | function conditional($cond, $trueVal, $falseVal) {
| |
| − | return " (CASE WHEN $cond THEN $trueVal ELSE $falseVal END) ";
| |
| − | }
| |
| − | | |
| − | function wasDeadlock() {
| |
| − | return $this->lastErrno() == SQLITE_BUSY;
| |
| − | }
| |
| − | | |
| − | # @return string wikitext of a link to the server software's web site
| |
| − | function getSoftwareLink() {
| |
| − | return "[http://sqlite.org/ SQLite]";
| |
| − | }
| |
| − | | |
| − | # @return string Version information from the database
| |
| − | function getServerVersion() {
| |
| − | return sqlite_libversion();
| |
| − | }
| |
| − | | |
| − | # Query whether a given column exists in the mediawiki schema
| |
| − | function fieldExists($table, $field) { return true; }
| |
| − | | |
| − | function fieldInfo($table, $field) { return false; }
| |
| − | | |
| − | function begin($fname = 'DatabasePostgres::begin') {
| |
| − | $this->query('BEGIN', $fname);
| |
| − | $this->mTrxLevel = 1;
| |
| − | }
| |
| − | | |
| − | function immediateCommit($fname = 'DatabaseSqlite::immediateCommit') {
| |
| − | return true;
| |
| − | }
| |
| − | | |
| − | function commit($fname = 'DatabaseSqlite::commit') {
| |
| − | $this->query('COMMIT', $fname);
| |
| − | $this->mTrxLevel = 0;
| |
| − | }
| |
| − | | |
| − | function limitResultForUpdate($sql, $num) {
| |
| − | return $sql;
| |
| − | }
| |
| − | | |
| − | function strencode($s) {
| |
| − | return sqlite_escape_string($s);
| |
| − | }
| |
| − | | |
| − | function encodeBlob($b) {
| |
| − | return new SQLiteBlob($b);
| |
| − | }
| |
| − | | |
| − | function decodeBlob($b) {
| |
| − | return $b; //return $b->load();
| |
| − | }
| |
| − | | |
| − | function addQuotes($s) {
| |
| − | global $wgLang;
| |
| − | $s = $wgLang->checkTitleEncoding($s);
| |
| − | return $this->strencode($s);
| |
| − | }
| |
| − | | |
| − | function quote_ident($s) { return $s; }
| |
| − | | |
| − | # For now, does nothing
| |
| − | function selectDB($db) { return true; }
| |
| − | | |
| − | # not done
| |
| − | public function setTimeout($timeout) { return; }
| |
| − | | |
| − | function ping() {
| |
| − | wfDebug("Function ping() not written for SQLite yet");
| |
| − | return true;
| |
| − | }
| |
| − | | |
| − | # How lagged is this slave?
| |
| − | public function getLag() { return 0; }
| |
| − | | |
| − | # Called by the installer script (when modified according to the MediaWikiLite installation instructions)
| |
| − | # - this is the same way PostgreSQL works, MySQL reads in tables.sql and interwiki.sql using dbsource (which calls db->sourceFile)
| |
| − | public function setup_database() {
| |
| − | global $IP,$wgSQLiteDataDir;
| |
| − | $mysql_tmpl = "$IP/maintenance/tables.sql";
| |
| − | $sqlite_tmpl = "$wgSQLiteDataDir/tables.sql";
| |
| − | | |
| − | # Make an SQLite template file if it doesn't exist (based on the same one MySQL uses to create a new wiki db)
| |
| − | if (!file_exists($sqlite_tmpl)) {
| |
| − | $sql = file_get_contents($mysql_tmpl);
| |
| − | # todo: do a regexp to make the SQL compatible with SQLite3
| |
| − | file_put_contents($sqlite_tmpl,$sql);
| |
| − | }
| |
| − | | |
| − | # Parse the SQL template replacing inline variables such as /*$wgDBprefix*/
| |
| − | $this->sourceFile($sqlite_tmpl);
| |
| − | }
| |
| − | | |
| − | }
| |