📄 adodb.php
字号:
<?php // -*-php-*-rcs_id('$Id: ADODB.php,v 1.74 2005/02/10 19:04:22 rurban Exp $');/* Copyright 2002,2004 $ThePhpWikiProgrammingTeam This file is part of PhpWiki. PhpWiki 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. PhpWiki 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 PhpWiki; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ /** * Based on PearDB.php. * @author: Lawrence Akka, Reini Urban * * Now (phpwiki-1.3.10) with adodb-4.22, by Reini Urban: * 1) Extended to use all available database backends, not only mysql. * 2) It uses the ultra-fast binary adodb extension if loaded. * 3) We use FETCH_NUM instead of FETCH_ASSOC (faster and more generic) * 4) To support generic iterators which return ASSOC fields, and to support queries with * variable columns, some trickery was needed to use recordset specific fetchMode. * The first Execute uses the global fetchMode (ASSOC), then it's resetted back to NUM * and the recordset fetchmode is set to ASSOC. * 5) Transaction support, and locking as fallback. * 6) 2004-12-10 added extra page.cached_html * * phpwiki-1.3.11, by Philippe Vanhaesendonck * - pass column list to iterators so we can FETCH_NUM in all cases * * ADODB basic differences to PearDB: It pre-fetches the first row into fields, * is dirtier in style, layout and more low-level ("worse is better"). * It has less needed basic features (modifyQuery, locks, ...), but some more * unneeded features included: paging, monitoring and sessions, and much more drivers. * No locking (which PearDB supports in some backends), and sequences are very * bad compared to PearDB. * Old Comments, by Lawrence Akka: * 1) ADODB's GetRow() is slightly different from that in PEAR. It does not * accept a fetchmode parameter * That doesn't matter too much here, since we only ever use FETCHMODE_ASSOC * 2) No need for ''s around strings in sprintf arguments - qstr puts them * there automatically * 3) ADODB has a version of GetOne, but it is difficult to use it when * FETCH_ASSOC is in effect. * Instead, use $rs = Execute($query); $value = $rs->fields["$colname"] * 4) No error handling yet - could use ADOConnection->raiseErrorFn * 5) It used to be faster then PEAR/DB at the beginning of 2002. * Now at August 2002 PEAR/DB with our own page cache added, * performance is comparable. */require_once('lib/WikiDB/backend.php');// Error handling - calls trigger_error. NB - does not close the connection. Does it need to?include_once('lib/WikiDB/adodb/adodb-errorhandler.inc.php');// include the main adodb filerequire_once('lib/WikiDB/adodb/adodb.inc.php');class WikiDB_backend_ADODBextends WikiDB_backend{ function WikiDB_backend_ADODB ($dbparams) { $parsed = parseDSN($dbparams['dsn']); $this->_dbparams = $dbparams; $this->_parsedDSN =& $parsed; $this->_dbh = &ADONewConnection($parsed['phptype']); if (DEBUG & _DEBUG_SQL) { $this->_dbh->debug = true; $GLOBALS['ADODB_OUTP'] = '_sql_debuglog'; } $this->_dsn = $parsed; // persistent is defined as DSN option, or with a config value. // phptype://username:password@hostspec/database?persistent=false if (!empty($parsed['persistent']) or DATABASE_PERSISTENT) $conn = $this->_dbh->PConnect($parsed['hostspec'],$parsed['username'], $parsed['password'], $parsed['database']); else $conn = $this->_dbh->Connect($parsed['hostspec'],$parsed['username'], $parsed['password'], $parsed['database']); // Since 1.3.10 we use the faster ADODB_FETCH_NUM, // with some ASSOC based recordsets. $GLOBALS['ADODB_FETCH_MODE'] = ADODB_FETCH_NUM; $this->_dbh->SetFetchMode(ADODB_FETCH_NUM); $GLOBALS['ADODB_COUNTRECS'] = false; $prefix = isset($dbparams['prefix']) ? $dbparams['prefix'] : ''; $this->_table_names = array('page_tbl' => $prefix . 'page', 'version_tbl' => $prefix . 'version', 'link_tbl' => $prefix . 'link', 'recent_tbl' => $prefix . 'recent', 'nonempty_tbl' => $prefix . 'nonempty'); $page_tbl = $this->_table_names['page_tbl']; $version_tbl = $this->_table_names['version_tbl']; $this->page_tbl_fields = "$page_tbl.id AS id, $page_tbl.pagename AS pagename, " . "$page_tbl.hits hits"; $this->page_tbl_field_list = array('id', 'pagename', 'hits'); $this->version_tbl_fields = "$version_tbl.version AS version, " . "$version_tbl.mtime AS mtime, " . "$version_tbl.minor_edit AS minor_edit, $version_tbl.content AS content, " . "$version_tbl.versiondata AS versiondata"; $this->version_tbl_field_list = array('version', 'mtime', 'minor_edit', 'content', 'versiondata'); $this->_expressions = array('maxmajor' => "MAX(CASE WHEN minor_edit=0 THEN version END)", 'maxminor' => "MAX(CASE WHEN minor_edit<>0 THEN version END)", 'maxversion' => "MAX(version)", 'notempty' => "<>''", 'iscontent' => "$version_tbl.content<>''"); $this->_lock_count = 0; } /** * Close database connection. */ function close () { if (!$this->_dbh) return; if ($this->_lock_count) { trigger_error("WARNING: database still locked " . '(lock_count = $this->_lock_count)' . "\n<br />", E_USER_WARNING); }// $this->_dbh->setErrorHandling(PEAR_ERROR_PRINT); // prevent recursive loops. $this->unlock(false,'force'); $this->_dbh->close(); $this->_dbh = false; } /* * Fast test for wikipage. */ function is_wiki_page($pagename) { $dbh = &$this->_dbh; extract($this->_table_names); $row = $dbh->GetRow(sprintf("SELECT $page_tbl.id AS id" . " FROM $nonempty_tbl, $page_tbl" . " WHERE $nonempty_tbl.id=$page_tbl.id" . " AND pagename=%s", $dbh->qstr($pagename))); return $row ? $row[0] : false; } function get_all_pagenames() { $dbh = &$this->_dbh; extract($this->_table_names); $result = $dbh->Execute("SELECT pagename" . " FROM $nonempty_tbl, $page_tbl" . " WHERE $nonempty_tbl.id=$page_tbl.id"); return $result->GetArray(); } function numPages($filter=false, $exclude='') { $dbh = &$this->_dbh; extract($this->_table_names); $result = $dbh->getRow("SELECT count(*)" . " FROM $nonempty_tbl, $page_tbl" . " WHERE $nonempty_tbl.id=$page_tbl.id"); return $result[0]; } function increaseHitCount($pagename) { $dbh = &$this->_dbh; // Hits is the only thing we can update in a fast manner. // Note that this will fail silently if the page does not // have a record in the page table. Since it's just the // hit count, who cares? $dbh->Execute(sprintf("UPDATE %s SET hits=hits+1 WHERE pagename=%s LIMIT 1", $this->_table_names['page_tbl'], $dbh->qstr($pagename))); return; } /** * Read page information from database. */ function get_pagedata($pagename) { $dbh = &$this->_dbh; $row = $dbh->GetRow(sprintf("SELECT id,pagename,hits,pagedata FROM %s WHERE pagename=%s", $this->_table_names['page_tbl'], $dbh->qstr($pagename))); return $row ? $this->_extract_page_data($row[3], $row[2]) : false; } function _extract_page_data($data, $hits) { if (empty($data)) return array('hits' => $hits); else return array_merge(array('hits' => $hits), $this->_unserialize($data)); } function update_pagedata($pagename, $newdata) { $dbh = &$this->_dbh; $page_tbl = $this->_table_names['page_tbl']; // Hits is the only thing we can update in a fast manner. if (count($newdata) == 1 && isset($newdata['hits'])) { // Note that this will fail silently if the page does not // have a record in the page table. Since it's just the // hit count, who cares? $dbh->Execute(sprintf("UPDATE $page_tbl SET hits=%d WHERE pagename=%s", $newdata['hits'], $dbh->qstr($pagename))); return; } $where = sprintf("pagename=%s", $dbh->qstr($pagename)); $dbh->BeginTrans( ); $dbh->RowLock($page_tbl,$where); $data = $this->get_pagedata($pagename); if (!$data) { $data = array(); $this->_get_pageid($pagename, true); // Creates page record } $hits = (empty($data['hits'])) ? 0 : (int)$data['hits']; unset($data['hits']); foreach ($newdata as $key => $val) { if ($key == 'hits') $hits = (int)$val; else if (empty($val)) unset($data[$key]); else $data[$key] = $val; } if ($dbh->Execute("UPDATE $page_tbl" . " SET hits=?, pagedata=?" . " WHERE pagename=?", array($hits, $this->_serialize($data),$pagename))) { $dbh->CommitTrans( ); return true; } else { $dbh->RollbackTrans( ); return false; } } function get_cached_html($pagename) { $dbh = &$this->_dbh; $page_tbl = $this->_table_names['page_tbl']; $row = $dbh->GetRow(sprintf("SELECT cached_html FROM $page_tbl WHERE pagename=%s", $dbh->qstr($pagename))); return $row ? $row[0] : false; } function set_cached_html($pagename, $data) { $dbh = &$this->_dbh; $page_tbl = $this->_table_names['page_tbl']; if (empty($data)) $data = ''; $rs = $dbh->Execute("UPDATE $page_tbl" . " SET cached_html=?" . " WHERE pagename=?", array($data, $pagename)); } function _get_pageid($pagename, $create_if_missing = false) { // check id_cache global $request; $cache =& $request->_dbi->_cache->_id_cache; if (isset($cache[$pagename])) { if ($cache[$pagename] or !$create_if_missing) { return $cache[$pagename]; } } $dbh = &$this->_dbh; $page_tbl = $this->_table_names['page_tbl']; $query = sprintf("SELECT id FROM $page_tbl WHERE pagename=%s", $dbh->qstr($pagename)); if (! $create_if_missing ) { $row = $dbh->GetRow($query); return $row ? $row[0] : false; } $row = $dbh->GetRow($query); if (! $row ) { //mysql, mysqli or mysqlt if (substr($dbh->databaseType,0,5) == 'mysql') { // have auto-incrementing, atomic version $rs = $dbh->Execute(sprintf("INSERT INTO $page_tbl" . " (id,pagename)" . " VALUES(NULL,%s)", $dbh->qstr($pagename))); $id = $dbh->_insertid(); } else { //$id = $dbh->GenID($page_tbl . 'seq'); // Better generic version than with adodob::genID //TODO: Does the DBM has subselects? Then we can do it with select max(id)+1 $this->lock(array('page')); $dbh->BeginTrans( ); $dbh->CommitLock($page_tbl); $row = $dbh->GetRow("SELECT MAX(id) FROM $page_tbl"); $id = $row[0] + 1; $rs = $dbh->Execute(sprintf("INSERT INTO $page_tbl" . " (id,pagename,hits)" . " VALUES (%d,%s,0)", $id, $dbh->qstr($pagename))); if ($rs) $dbh->CommitTrans( ); else $dbh->RollbackTrans( ); $this->unlock(array('page')); } } else { $id = $row[0]; } assert($id); return $id; } function get_latest_version($pagename) { $dbh = &$this->_dbh; extract($this->_table_names); $row = $dbh->GetRow(sprintf("SELECT latestversion" . " FROM $page_tbl, $recent_tbl" . " WHERE $page_tbl.id=$recent_tbl.id" . " AND pagename=%s", $dbh->qstr($pagename))); return $row ? (int)$row[0] : false; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -