|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00018 00028 defined('MOODLE_INTERNAL') || die(); 00029 00030 require_once($CFG->libdir.'/dml/moodle_database.php'); 00031 require_once($CFG->libdir.'/dml/pdo_moodle_recordset.php'); 00032 00036 abstract class pdo_moodle_database extends moodle_database { 00037 00038 protected $pdb; 00039 protected $lastError = null; 00040 00046 public function __construct($external=false) { 00047 parent::__construct($external); 00048 } 00049 00061 public function connect($dbhost, $dbuser, $dbpass, $dbname, $prefix, array $dboptions=null) { 00062 $driverstatus = $this->driver_installed(); 00063 00064 if ($driverstatus !== true) { 00065 throw new dml_exception('dbdriverproblem', $driverstatus); 00066 } 00067 00068 $this->store_settings($dbhost, $dbuser, $dbpass, $dbname, $prefix, $dboptions); 00069 00070 try{ 00071 $this->pdb = new PDO($this->get_dsn(), $this->dbuser, $this->dbpass, $this->get_pdooptions()); 00072 // generic PDO settings to match adodb's default; subclasses can change this in configure_dbconnection 00073 $this->pdb->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER); 00074 $this->pdb->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 00075 $this->configure_dbconnection(); 00076 return true; 00077 } catch (PDOException $ex) { 00078 throw new dml_connection_exception($ex->getMessage()); 00079 return false; 00080 } 00081 } 00082 00088 abstract protected function get_dsn(); 00089 00095 protected function get_pdooptions() { 00096 return array(PDO::ATTR_PERSISTENT => !empty($this->dboptions['dbpersist'])); 00097 } 00098 00099 protected function configure_dbconnection() { 00101 } 00102 00108 protected function get_dblibrary() { 00109 return 'pdo'; 00110 } 00111 00117 public function get_name() { 00118 return get_string('pdo'.$this->get_dbtype(), 'install'); 00119 } 00120 00126 public function get_configuration_help() { 00127 return get_string('pdo'.$this->get_dbtype().'help', 'install'); 00128 } 00129 00135 public function get_configuration_hints() { 00136 return get_string('databasesettingssub_' . $this->get_dbtype() . '_pdo', 'install'); 00137 } 00138 00143 public function get_server_info() { 00144 $result = array(); 00145 try { 00146 $result['description'] = $this->pdb->getAttribute(PDO::ATTR_SERVER_INFO); 00147 } catch(PDOException $ex) {} 00148 try { 00149 $result['version'] = $this->pdb->getAttribute(PDO::ATTR_SERVER_VERSION); 00150 } catch(PDOException $ex) {} 00151 return $result; 00152 } 00153 00158 protected function allowed_param_types() { 00159 return SQL_PARAMS_QM | SQL_PARAMS_NAMED; 00160 } 00161 00166 public function get_last_error() { 00167 return $this->lastError; 00168 } 00169 00173 protected function debug_query($sql, $params = null) { 00174 echo '<hr /> (', $this->get_dbtype(), '): ', htmlentities($sql); 00175 if($params) { 00176 echo ' (parameters '; 00177 print_r($params); 00178 echo ')'; 00179 } 00180 echo '<hr />'; 00181 } 00182 00188 public function change_database_structure($sql) { 00189 $result = true; 00190 $this->query_start($sql, null, SQL_QUERY_STRUCTURE); 00191 00192 try { 00193 $this->pdb->exec($sql); 00194 $this->reset_caches(); 00195 } catch (PDOException $ex) { 00196 $this->lastError = $ex->getMessage(); 00197 $result = false; 00198 } 00199 $this->query_end($result); 00200 return $result; 00201 } 00202 00203 public function delete_records_select($table, $select, array $params=null) { 00204 $sql = "DELETE FROM {{$table}}"; 00205 if ($select) { 00206 $sql .= " WHERE $select"; 00207 } 00208 return $this->execute($sql, $params); 00209 } 00210 00218 protected function create_recordset($sth) { 00219 return new pdo_moodle_recordset($sth); 00220 } 00221 00229 public function execute($sql, array $params=null) { 00230 list($sql, $params, $type) = $this->fix_sql_params($sql, $params); 00231 00232 $result = true; 00233 $this->query_start($sql, $params, SQL_QUERY_UPDATE); 00234 00235 try { 00236 $sth = $this->pdb->prepare($sql); 00237 $sth->execute($params); 00238 } catch (PDOException $ex) { 00239 $this->lastError = $ex->getMessage(); 00240 $result = false; 00241 } 00242 00243 $this->query_end($result); 00244 return $result; 00245 } 00246 00261 public function get_recordset_sql($sql, array $params=null, $limitfrom=0, $limitnum=0) { 00262 00263 $result = true; 00264 00265 list($sql, $params, $type) = $this->fix_sql_params($sql, $params); 00266 $sql = $this->get_limit_clauses($sql, $limitfrom, $limitnum); 00267 $this->query_start($sql, $params, SQL_QUERY_SELECT); 00268 00269 try { 00270 $sth = $this->pdb->prepare($sql); 00271 $sth->execute($params); 00272 $result = $this->create_recordset($sth); 00273 } catch (PDOException $ex) { 00274 $this->lastError = $ex->getMessage(); 00275 $result = false; 00276 } 00277 00278 $this->query_end($result); 00279 return $result; 00280 } 00281 00289 public function get_fieldset_sql($sql, array $params=null) { 00290 $rs = $this->get_recordset_sql($sql, $params); 00291 if (!$rs->valid()) { 00292 $rs->close(); // Not going to iterate (but exit), close rs 00293 return false; 00294 } 00295 $result = array(); 00296 foreach($rs as $value) { 00297 $result[] = reset($value); 00298 } 00299 $rs->close(); 00300 return $result; 00301 } 00302 00316 public function get_records_sql($sql, array $params=null, $limitfrom=0, $limitnum=0) { 00317 $rs = $this->get_recordset_sql($sql, $params, $limitfrom, $limitnum); 00318 if (!$rs->valid()) { 00319 $rs->close(); // Not going to iterate (but exit), close rs 00320 return false; 00321 } 00322 $objects = array(); 00323 $debugging = debugging('', DEBUG_DEVELOPER); 00324 foreach($rs as $value) { 00325 $key = reset($value); 00326 if ($debugging && array_key_exists($key, $objects)) { 00327 debugging("Did you remember to make the first column something unique in your call to get_records? Duplicate value '$key' found in column first column of '$sql'.", DEBUG_DEVELOPER); 00328 } 00329 $objects[$key] = (object)$value; 00330 } 00331 $rs->close(); 00332 return $objects; 00333 } 00334 00344 public function insert_record_raw($table, $params, $returnid=true, $bulk=false, $customsequence=false) { 00345 if (!is_array($params)) { 00346 $params = (array)$params; 00347 } 00348 00349 if ($customsequence) { 00350 if (!isset($params['id'])) { 00351 throw new coding_exception('moodle_database::insert_record_raw() id field must be specified if custom sequences used.'); 00352 } 00353 $returnid = false; 00354 } else { 00355 unset($params['id']); 00356 } 00357 00358 if (empty($params)) { 00359 throw new coding_exception('moodle_database::insert_record_raw() no fields found.'); 00360 } 00361 00362 $fields = implode(',', array_keys($params)); 00363 $qms = array_fill(0, count($params), '?'); 00364 $qms = implode(',', $qms); 00365 00366 $sql = "INSERT INTO {{$table}} ($fields) VALUES($qms)"; 00367 if (!$this->execute($sql, $params)) { 00368 return false; 00369 } 00370 if (!$returnid) { 00371 return true; 00372 } 00373 if ($id = $this->pdb->lastInsertId()) { 00374 return (int)$id; 00375 } 00376 return false; 00377 } 00378 00390 public function insert_record($table, $dataobject, $returnid=true, $bulk=false) { 00391 $dataobject = (array)$dataobject; 00392 00393 $columns = $this->get_columns($table); 00394 $cleaned = array(); 00395 00396 foreach ($dataobject as $field=>$value) { 00397 if ($field === 'id') { 00398 continue; 00399 } 00400 if (!isset($columns[$field])) { 00401 continue; 00402 } 00403 $column = $columns[$field]; 00404 if (is_bool($value)) { 00405 $value = (int)$value; // prevent "false" problems 00406 } 00407 if (!empty($column->enums)) { 00408 // workaround for problem with wrong enums 00409 if (is_null($value) and !$column->not_null) { 00410 // ok - nulls allowed 00411 } else { 00412 if (!in_array((string)$value, $column->enums)) { 00413 debugging('Enum value '.s($value).' not allowed in field '.$field.' table '.$table.'.'); 00414 return false; 00415 } 00416 } 00417 } 00418 $cleaned[$field] = $value; 00419 } 00420 00421 if (empty($cleaned)) { 00422 return false; 00423 } 00424 00425 return $this->insert_record_raw($table, $cleaned, $returnid, $bulk); 00426 } 00427 00435 public function update_record_raw($table, $params, $bulk=false) { 00436 $params = (array)$params; 00437 00438 if (!isset($params['id'])) { 00439 throw new coding_exception('moodle_database::update_record_raw() id field must be specified.'); 00440 } 00441 $id = $params['id']; 00442 unset($params['id']); 00443 00444 if (empty($params)) { 00445 throw new coding_exception('moodle_database::update_record_raw() no fields found.'); 00446 } 00447 00448 $sets = array(); 00449 foreach ($params as $field=>$value) { 00450 $sets[] = "$field = ?"; 00451 } 00452 00453 $params[] = $id; // last ? in WHERE condition 00454 00455 $sets = implode(',', $sets); 00456 $sql = "UPDATE {{$table}} SET $sets WHERE id=?"; 00457 return $this->execute($sql, $params); 00458 } 00459 00472 public function update_record($table, $dataobject, $bulk=false) { 00473 $dataobject = (array)$dataobject; 00474 00475 $columns = $this->get_columns($table); 00476 $cleaned = array(); 00477 00478 foreach ($dataobject as $field=>$value) { 00479 if (!isset($columns[$field])) { 00480 continue; 00481 } 00482 if (is_bool($value)) { 00483 $value = (int)$value; // prevent "false" problems 00484 } 00485 $cleaned[$field] = $value; 00486 } 00487 00488 return $this->update_record_raw($table, $cleaned, $bulk); 00489 } 00490 00501 public function set_field_select($table, $newfield, $newvalue, $select, array $params=null) { 00502 if ($select) { 00503 $select = "WHERE $select"; 00504 } 00505 if (is_null($params)) { 00506 $params = array(); 00507 } 00508 list($select, $params, $type) = $this->fix_sql_params($select, $params); 00509 00510 if (is_bool($newvalue)) { 00511 $newvalue = (int)$newvalue; // prevent "false" problems 00512 } 00513 if (is_null($newvalue)) { 00514 $newfield = "$newfield = NULL"; 00515 } else { 00516 // make sure SET and WHERE clauses use the same type of parameters, 00517 // because we don't support different types in the same query 00518 switch($type) { 00519 case SQL_PARAMS_NAMED: 00520 $newfield = "$newfield = :newvalueforupdate"; 00521 $params['newvalueforupdate'] = $newvalue; 00522 break; 00523 case SQL_PARAMS_QM: 00524 $newfield = "$newfield = ?"; 00525 array_unshift($params, $newvalue); 00526 break; 00527 default: 00528 $this->lastError = __FILE__ . ' LINE: ' . __LINE__ . '.'; 00529 print_error(unknowparamtype, 'error', '', $this->lastError); 00530 } 00531 } 00532 $sql = "UPDATE {{$table}} SET $newfield $select"; 00533 return $this->execute($sql, $params); 00534 } 00535 00536 public function sql_concat() { 00537 print_error('TODO'); 00538 } 00539 00540 public function sql_concat_join($separator="' '", $elements=array()) { 00541 print_error('TODO'); 00542 } 00543 00544 protected function begin_transaction() { 00545 $this->query_start('', NULL, SQL_QUERY_AUX); 00546 try { 00547 $this->pdb->beginTransaction(); 00548 } catch(PDOException $ex) { 00549 $this->lastError = $ex->getMessage(); 00550 } 00551 $this->query_end($result); 00552 } 00553 00554 protected function commit_transaction() { 00555 $this->query_start('', NULL, SQL_QUERY_AUX); 00556 00557 try { 00558 $this->pdb->commit(); 00559 } catch(PDOException $ex) { 00560 $this->lastError = $ex->getMessage(); 00561 } 00562 $this->query_end($result); 00563 } 00564 00565 protected function rollback_transaction() { 00566 $this->query_start('', NULL, SQL_QUERY_AUX); 00567 00568 try { 00569 $this->pdb->rollBack(); 00570 } catch(PDOException $ex) { 00571 $this->lastError = $ex->getMessage(); 00572 } 00573 $this->query_end($result); 00574 } 00575 00583 public function import_record($table, $dataobject) { 00584 $dataobject = (object)$dataobject; 00585 00586 $columns = $this->get_columns($table); 00587 $cleaned = array(); 00588 foreach ($dataobject as $field=>$value) { 00589 if (!isset($columns[$field])) { 00590 continue; 00591 } 00592 $cleaned[$field] = $value; 00593 } 00594 00595 return $this->insert_record_raw($table, $cleaned, false, true, true); 00596 } 00597 00609 protected function query_start($sql, array $params=null, $type, $extrainfo=null) { 00610 $this->lastError = null; 00611 parent::query_start($sql, $params, $type, $extrainfo); 00612 } 00613 }