|
|
(13 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, 2007-12-30'); | + | 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 ($this->mFlags & DBO_PERSISTENT) @$this->mConn = sqlite_popen("$wgSQLiteDataDir/$dbName", 0666, $err);
| |
− | else @$this->mConn = @$this->mConn = sqlite_open("$wgSQLiteDataDir/$dbName", 0666, $err);
| |
− | 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();
| |
− | sqlite_close($this->mConn);
| |
− | }
| |
− | 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; }
| |
− | | |
− | /**
| |
− | * Returns an optional USE INDEX clause to go after the table, and a
| |
− | * string to go at the end of the query
| |
− | *
| |
− | * @private
| |
− | *
| |
− | * @param array $options an associative array of options to be turned into
| |
− | * an SQL query, valid keys are listed in the function.
| |
− | * @return array
| |
− | */
| |
− | function makeSelectOptions($options) {
| |
− | return array($startOpts, $useIndex, $preLimitTail, $postLimitTail);
| |
− | }
| |
− | | |
− | # 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; }
| |
− | | |
− | }
| |