2009-06-12 08:14:29 +00:00
< ? php
// This file is part of Moodle - http://moodle.org/
//
// Moodle 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 3 of the License, or
// (at your option) any later version.
//
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Abstract database driver class .
*
2012-01-19 10:15:11 +08:00
* @ package core
* @ category dml
2012-01-20 14:39:49 +08:00
* @ subpackage dml
2012-01-19 10:15:11 +08:00
* @ copyright 2008 Petr Skoda ( http :// skodak . org )
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2009-06-12 08:14:29 +00:00
*/
2008-05-15 21:40:00 +00:00
2010-07-25 12:57:24 +00:00
defined ( 'MOODLE_INTERNAL' ) || die ();
2008-05-25 22:21:01 +00:00
require_once ( $CFG -> libdir . '/dml/database_column_info.php' );
2008-09-02 20:32:03 +00:00
require_once ( $CFG -> libdir . '/dml/moodle_recordset.php' );
2009-11-07 08:52:56 +00:00
require_once ( $CFG -> libdir . '/dml/moodle_transaction.php' );
2008-05-25 22:21:01 +00:00
2008-06-15 11:35:25 +00:00
/// GLOBAL CONSTANTS /////////////////////////////////////////////////////////
2012-01-19 10:15:11 +08:00
/** SQL_PARAMS_NAMED - Bitmask, indicates :name type parameters are supported by db backend. */
2008-06-15 11:35:25 +00:00
define ( 'SQL_PARAMS_NAMED' , 1 );
2012-01-19 10:15:11 +08:00
/** SQL_PARAMS_QM - Bitmask, indicates ? type parameters are supported by db backend. */
2008-06-15 11:35:25 +00:00
define ( 'SQL_PARAMS_QM' , 2 );
2012-01-19 10:15:11 +08:00
/** SQL_PARAMS_DOLLAR - Bitmask, indicates $1, $2, ... type parameters are supported by db backend. */
2008-06-15 11:35:25 +00:00
define ( 'SQL_PARAMS_DOLLAR' , 4 );
2012-01-19 10:15:11 +08:00
/** SQL_QUERY_SELECT - Normal select query, reading only. */
2008-10-28 22:31:26 +00:00
define ( 'SQL_QUERY_SELECT' , 1 );
2012-01-19 10:15:11 +08:00
/** SQL_QUERY_INSERT - Insert select query, writing. */
2008-10-28 22:31:26 +00:00
define ( 'SQL_QUERY_INSERT' , 2 );
2012-01-19 10:15:11 +08:00
/** SQL_QUERY_UPDATE - Update select query, writing. */
2008-10-28 22:31:26 +00:00
define ( 'SQL_QUERY_UPDATE' , 3 );
2012-01-19 10:15:11 +08:00
/** SQL_QUERY_STRUCTURE - Query changing db structure, writing. */
2008-10-28 22:31:26 +00:00
define ( 'SQL_QUERY_STRUCTURE' , 4 );
2012-01-19 10:15:11 +08:00
/** SQL_QUERY_AUX - Auxiliary query done by driver, setting connection config, getting table info, etc. */
2008-10-28 22:31:26 +00:00
define ( 'SQL_QUERY_AUX' , 5 );
2008-05-15 21:40:00 +00:00
/**
* Abstract class representing moodle database interface .
2012-02-16 10:29:45 +08:00
* @ link http :// docs . moodle . org / dev / DML_functions
2012-01-19 10:15:11 +08:00
*
* @ package core
* @ category dml
* @ copyright 2008 Petr Skoda ( http :// skodak . org )
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2008-05-15 21:40:00 +00:00
*/
abstract class moodle_database {
2012-01-19 10:15:11 +08:00
/** @var database_manager db manager which allows db structure modifications. */
2008-05-15 21:40:00 +00:00
protected $database_manager ;
2012-01-19 10:15:11 +08:00
/** @var moodle_temptables temptables manager to provide cross-db support for temp tables. */
2010-04-21 16:12:27 +00:00
protected $temptables ;
2012-01-19 10:15:11 +08:00
/** @var array Cache of column info. */
2008-05-25 09:31:38 +00:00
protected $columns = array (); // I wish we had a shared memory cache for this :-(
2012-01-19 10:15:11 +08:00
/** @var array Cache of table info. */
2009-01-12 18:10:50 +00:00
protected $tables = null ;
2008-05-25 09:31:38 +00:00
2008-05-15 21:40:00 +00:00
// db connection options
2012-01-19 10:15:11 +08:00
/** @var string db host name. */
2008-05-15 21:40:00 +00:00
protected $dbhost ;
2012-01-19 10:15:11 +08:00
/** @var string db host user. */
2008-05-15 21:40:00 +00:00
protected $dbuser ;
2012-01-19 10:15:11 +08:00
/** @var string db host password. */
2008-05-15 21:40:00 +00:00
protected $dbpass ;
2012-01-19 10:15:11 +08:00
/** @var string db name. */
2008-05-15 21:40:00 +00:00
protected $dbname ;
2012-01-19 10:15:11 +08:00
/** @var string Prefix added to table names. */
2008-05-15 21:40:00 +00:00
protected $prefix ;
2012-01-19 10:15:11 +08:00
/** @var array Database or driver specific options, such as sockets or TCPIP db connections. */
2009-02-07 10:20:33 +00:00
protected $dboptions ;
2008-05-15 21:40:00 +00:00
2012-01-19 10:15:11 +08:00
/** @var bool True means non-moodle external database used.*/
2009-02-07 10:20:33 +00:00
protected $external ;
2008-05-19 18:02:33 +00:00
2009-06-12 08:27:19 +00:00
/** @var int The database reads (performance counter).*/
2008-06-16 21:01:54 +00:00
protected $reads = 0 ;
2009-06-12 08:27:19 +00:00
/** @var int The database writes (performance counter).*/
2008-06-16 21:01:54 +00:00
protected $writes = 0 ;
2012-01-19 10:15:11 +08:00
/** @var int Debug level. */
2008-11-21 20:09:13 +00:00
protected $debug = 0 ;
2012-01-19 10:15:11 +08:00
/** @var string Last used query sql. */
2008-11-04 23:07:14 +00:00
protected $last_sql ;
2012-01-19 10:15:11 +08:00
/** @var array Last query parameters. */
2008-11-04 23:07:14 +00:00
protected $last_params ;
2012-01-19 10:15:11 +08:00
/** @var int Last query type. */
2008-11-04 23:07:14 +00:00
protected $last_type ;
2012-01-19 10:15:11 +08:00
/** @var string Last extra info. */
2008-11-04 23:07:14 +00:00
protected $last_extrainfo ;
2012-01-19 10:15:11 +08:00
/** @var float Last time in seconds with millisecond precision. */
2009-06-13 10:16:29 +00:00
protected $last_time ;
2012-01-19 10:15:11 +08:00
/** @var bool Flag indicating logging of query in progress. This helps prevent infinite loops. */
2009-06-13 10:16:29 +00:00
private $loggingquery = false ;
2008-05-15 21:40:00 +00:00
2012-01-19 10:15:11 +08:00
/** @var bool True if the db is used for db sessions. */
2009-01-17 14:31:29 +00:00
protected $used_for_db_sessions = false ;
2009-01-16 17:27:36 +00:00
2012-01-19 10:15:11 +08:00
/** @var array Array containing open transactions. */
2009-11-07 08:52:56 +00:00
private $transactions = array ();
2012-01-19 10:15:11 +08:00
/** @var bool Flag used to force rollback of all current transactions. */
2009-11-07 08:52:56 +00:00
private $force_rollback = false ;
2009-06-12 07:55:44 +00:00
2012-02-07 10:58:55 +08:00
/**
2012-02-16 10:29:45 +08:00
* @ var int internal temporary variable used to fix params . Its used by { @ link _fix_sql_params_dollar_callback ()} .
2012-02-07 10:58:55 +08:00
*/
2008-11-06 18:36:50 +00:00
private $fix_sql_params_i ;
2012-02-07 10:58:55 +08:00
/**
2012-02-16 10:29:45 +08:00
* @ var int internal temporary variable used to guarantee unique parameters in each request . Its used by { @ link get_in_or_equal ()} .
2012-02-07 10:58:55 +08:00
*/
2012-01-19 10:15:11 +08:00
private $inorequaluniqueindex = 1 ;
2008-11-06 18:36:50 +00:00
2008-05-15 21:40:00 +00:00
/**
2012-01-19 10:15:11 +08:00
* Constructor - Instantiates the database , specifying if it ' s external ( connect to other systems ) or not ( Moodle DB ) .
* Note that this affects the decision of whether prefix checks must be performed or not .
* @ param bool $external True means that an external database is used .
2008-05-15 21:40:00 +00:00
*/
2008-05-19 18:02:33 +00:00
public function __construct ( $external = false ) {
$this -> external = $external ;
}
2008-05-15 21:40:00 +00:00
2008-10-28 12:02:13 +00:00
/**
* Destructor - cleans up and flushes everything needed .
*/
2009-05-26 14:46:01 +00:00
public function __destruct () {
2008-10-28 12:02:13 +00:00
$this -> dispose ();
}
2008-05-15 21:40:00 +00:00
/**
2012-01-19 10:15:11 +08:00
* Detects if all needed PHP stuff are installed for DB connectivity .
2008-05-19 18:02:33 +00:00
* Note : can be used before connect ()
2012-01-19 10:15:11 +08:00
* @ return mixed True if requirements are met , otherwise a string if something isn ' t installed .
2008-05-15 21:40:00 +00:00
*/
2008-05-19 18:02:33 +00:00
public abstract function driver_installed ();
2008-05-15 21:40:00 +00:00
/**
* Returns database table prefix
2008-05-19 18:02:33 +00:00
* Note : can be used before connect ()
2012-01-19 10:15:11 +08:00
* @ return string The prefix used in the database .
2008-05-15 21:40:00 +00:00
*/
public function get_prefix () {
return $this -> prefix ;
}
2008-07-24 12:21:19 +00:00
/**
2008-09-02 20:32:03 +00:00
* Loads and returns a database instance with the specified type and library .
2012-01-19 10:15:11 +08:00
*
* The loaded class is within lib / dml directory and of the form : $type . '_' . $library . '_moodle_database'
*
* @ param string $type Database driver ' s type . ( eg : mysqli , pgsql , mssql , sqldrv , oci , etc . )
* @ param string $library Database driver ' s library ( native , pdo , etc . )
* @ param bool $external True if this is an external database .
2012-02-16 10:29:45 +08:00
* @ return moodle_database driver object or null if error , for example of driver object see { @ link mysqli_native_moodle_database }
2008-07-24 12:21:19 +00:00
*/
2011-07-05 11:58:14 +01:00
public static function get_driver_instance ( $type , $library , $external = false ) {
2008-07-24 12:21:19 +00:00
global $CFG ;
2008-09-02 20:32:03 +00:00
$classname = $type . '_' . $library . '_moodle_database' ;
$libfile = " $CFG->libdir /dml/ $classname .php " ;
if ( ! file_exists ( $libfile )) {
return null ;
}
require_once ( $libfile );
2011-07-05 11:58:14 +01:00
return new $classname ( $external );
2008-07-24 12:21:19 +00:00
}
2008-05-15 21:40:00 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns the database family type . ( This sort of describes the SQL 'dialect' )
2008-05-19 18:02:33 +00:00
* Note : can be used before connect ()
2012-01-19 10:15:11 +08:00
* @ return string The db family name ( mysql , postgres , mssql , oracle , etc . )
2008-05-19 18:02:33 +00:00
*/
public abstract function get_dbfamily ();
/**
2012-01-19 10:15:11 +08:00
* Returns a more specific database driver type
2008-05-19 18:02:33 +00:00
* Note : can be used before connect ()
2012-01-19 10:15:11 +08:00
* @ return string The db type mysqli , pgsql , oci , mssql , sqlsrv
2008-05-15 21:40:00 +00:00
*/
protected abstract function get_dbtype ();
2008-06-22 22:53:40 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns the general database library name
2008-06-22 22:53:40 +00:00
* Note : can be used before connect ()
2012-01-19 10:15:11 +08:00
* @ return string The db library type - pdo , native etc .
2008-06-22 22:53:40 +00:00
*/
protected abstract function get_dblibrary ();
2008-05-15 21:40:00 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns the localised database type name
2008-05-19 18:02:33 +00:00
* Note : can be used before connect ()
* @ return string
2008-05-15 21:40:00 +00:00
*/
2008-05-19 18:02:33 +00:00
public abstract function get_name ();
/**
2012-01-19 10:15:11 +08:00
* Returns the localised database configuration help .
2008-05-19 18:02:33 +00:00
* Note : can be used before connect ()
* @ return string
*/
2009-02-07 10:20:33 +00:00
public abstract function get_configuration_help ();
2008-05-15 21:40:00 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns the localised database description
2008-05-19 18:02:33 +00:00
* Note : can be used before connect ()
* @ return string
*/
2009-02-07 10:20:33 +00:00
public abstract function get_configuration_hints ();
2008-06-22 22:53:40 +00:00
2009-02-07 10:20:33 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns the db related part of config . php
* @ return stdClass
2009-02-07 10:20:33 +00:00
*/
public function export_dbconfig () {
2008-06-22 22:53:40 +00:00
$cfg = new stdClass ();
$cfg -> dbtype = $this -> get_dbtype ();
$cfg -> dblibrary = $this -> get_dblibrary ();
$cfg -> dbhost = $this -> dbhost ;
$cfg -> dbname = $this -> dbname ;
$cfg -> dbuser = $this -> dbuser ;
$cfg -> dbpass = $this -> dbpass ;
$cfg -> prefix = $this -> prefix ;
if ( $this -> dboptions ) {
$cfg -> dboptions = $this -> dboptions ;
}
return $cfg ;
}
2008-05-19 18:02:33 +00:00
2010-08-18 16:47:00 +00:00
/**
* Diagnose database and tables , this function is used
* to verify database and driver settings , db engine types , etc .
*
* @ return string null means everything ok , string means problem found .
*/
public function diagnose () {
return null ;
}
2008-05-19 18:02:33 +00:00
/**
2012-01-19 10:15:11 +08:00
* Connects to the database .
2008-05-19 18:02:33 +00:00
* Must be called before other methods .
2012-01-19 10:15:11 +08:00
* @ param string $dbhost The database host .
* @ param string $dbuser The database user to connect as .
* @ param string $dbpass The password to use when connecting to the database .
* @ param string $dbname The name of the database being connected to .
2008-05-19 18:02:33 +00:00
* @ param mixed $prefix string means moodle db prefix , false used for external databases where prefix not used
* @ param array $dboptions driver specific options
2008-11-22 01:16:52 +00:00
* @ return bool true
* @ throws dml_connection_exception if error
2008-05-15 21:40:00 +00:00
*/
2008-10-27 22:21:34 +00:00
public abstract function connect ( $dbhost , $dbuser , $dbpass , $dbname , $prefix , array $dboptions = null );
2008-05-19 18:02:33 +00:00
2008-06-22 22:53:40 +00:00
/**
* Store various database settings
2012-01-19 10:15:11 +08:00
* @ param string $dbhost The database host .
* @ param string $dbuser The database user to connect as .
* @ param string $dbpass The password to use when connecting to the database .
* @ param string $dbname The name of the database being connected to .
2008-06-22 22:53:40 +00:00
* @ param mixed $prefix string means moodle db prefix , false used for external databases where prefix not used
* @ param array $dboptions driver specific options
* @ return void
*/
2008-10-27 22:21:34 +00:00
protected function store_settings ( $dbhost , $dbuser , $dbpass , $dbname , $prefix , array $dboptions = null ) {
2008-06-22 22:53:40 +00:00
$this -> dbhost = $dbhost ;
$this -> dbuser = $dbuser ;
$this -> dbpass = $dbpass ;
$this -> dbname = $dbname ;
$this -> prefix = $prefix ;
$this -> dboptions = ( array ) $dboptions ;
}
2008-06-09 20:22:11 +00:00
/**
* Attempt to create the database
2012-01-19 10:15:11 +08:00
* @ param string $dbhost The database host .
* @ param string $dbuser The database user to connect as .
* @ param string $dbpass The password to use when connecting to the database .
* @ param string $dbname The name of the database being connected to .
2012-02-07 10:58:55 +08:00
* @ param array $dboptions An array of optional database options ( eg : dbport )
2008-06-09 20:22:11 +00:00
*
2012-01-19 10:15:11 +08:00
* @ return bool success True for successful connection . False otherwise .
2008-06-09 20:22:11 +00:00
*/
2009-02-07 10:20:33 +00:00
public function create_database ( $dbhost , $dbuser , $dbpass , $dbname , array $dboptions = null ) {
2008-06-09 20:22:11 +00:00
return false ;
}
2008-05-25 19:56:34 +00:00
/**
2012-01-19 10:15:11 +08:00
* Closes the database connection and releases all resources
2008-05-25 19:56:34 +00:00
* and memory ( especially circular memory references ) .
* Do NOT use connect () again , create a new instance if needed .
2010-08-22 19:06:06 +00:00
* @ return void
2008-05-25 19:56:34 +00:00
*/
public function dispose () {
2009-11-07 08:52:56 +00:00
if ( $this -> transactions ) {
2010-05-21 18:18:42 +00:00
// this should not happen, it usually indicates wrong catching of exceptions,
// because all transactions should be finished manually or in default exception handler.
2009-11-07 08:52:56 +00:00
// unfortunately we can not access global $CFG any more and can not print debug,
// the diagnostic info should be printed in footer instead
2009-11-08 21:19:11 +00:00
$lowesttransaction = end ( $this -> transactions );
$backtrace = $lowesttransaction -> get_backtrace ();
error_log ( 'Potential coding error - active database transaction detected when disposing database:' . " \n " . format_backtrace ( $backtrace , true ));
2009-11-07 08:52:56 +00:00
$this -> force_transaction_rollback ();
2009-06-12 07:55:44 +00:00
}
2009-01-16 17:27:36 +00:00
if ( $this -> used_for_db_sessions ) {
// this is needed because we need to save session to db before closing it
2009-01-17 15:25:08 +00:00
session_get_instance () -> write_close ();
2009-01-17 14:31:29 +00:00
$this -> used_for_db_sessions = false ;
2009-01-16 17:27:36 +00:00
}
2010-04-21 16:12:27 +00:00
if ( $this -> temptables ) {
$this -> temptables -> dispose ();
$this -> temptables = null ;
}
2008-05-25 19:56:34 +00:00
if ( $this -> database_manager ) {
$this -> database_manager -> dispose ();
$this -> database_manager = null ;
}
2008-10-28 12:02:13 +00:00
$this -> columns = array ();
2009-01-12 18:10:50 +00:00
$this -> tables = null ;
2008-05-25 19:56:34 +00:00
}
2008-10-28 22:31:26 +00:00
/**
2012-01-19 10:15:11 +08:00
* This should be called before each db query .
* @ param string $sql The query string .
* @ param array $params An array of parameters .
* @ param int $type The type of query . ( SQL_QUERY_SELECT | SQL_QUERY_AUX | SQL_QUERY_INSERT | SQL_QUERY_UPDATE | SQL_QUERY_STRUCTURE )
* @ param mixed $extrainfo This is here for any driver specific extra information .
2008-10-28 22:31:26 +00:00
* @ return void
*/
2008-10-29 23:55:16 +00:00
protected function query_start ( $sql , array $params = null , $type , $extrainfo = null ) {
2009-06-13 10:16:29 +00:00
if ( $this -> loggingquery ) {
return ;
}
2008-11-04 23:07:14 +00:00
$this -> last_sql = $sql ;
$this -> last_params = $params ;
$this -> last_type = $type ;
$this -> last_extrainfo = $extrainfo ;
2009-06-13 10:16:29 +00:00
$this -> last_time = microtime ( true );
2008-11-04 23:07:14 +00:00
2008-10-29 23:55:16 +00:00
switch ( $type ) {
case SQL_QUERY_SELECT :
case SQL_QUERY_AUX :
$this -> reads ++ ;
break ;
case SQL_QUERY_INSERT :
case SQL_QUERY_UPDATE :
case SQL_QUERY_STRUCTURE :
$this -> writes ++ ;
}
2008-11-04 23:07:14 +00:00
$this -> print_debug ( $sql , $params );
2008-10-28 22:31:26 +00:00
}
/**
2012-01-19 10:15:11 +08:00
* This should be called immediately after each db query . It does a clean up of resources .
* It also throws exceptions if the sql that ran produced errors .
2012-02-07 10:58:55 +08:00
* @ param mixed $result The db specific result obtained from running a query .
2012-01-19 10:15:11 +08:00
* @ throws dml_read_exception | dml_write_exception | ddl_change_structure_exception
2008-10-28 22:31:26 +00:00
* @ return void
*/
2008-10-29 23:55:16 +00:00
protected function query_end ( $result ) {
2009-06-13 10:16:29 +00:00
if ( $this -> loggingquery ) {
return ;
}
2009-06-13 15:59:55 +00:00
if ( $result !== false ) {
$this -> query_log ();
// free memory
$this -> last_sql = null ;
$this -> last_params = null ;
return ;
}
// remember current info, log queries may alter it
2009-06-13 10:16:29 +00:00
$type = $this -> last_type ;
$sql = $this -> last_sql ;
$params = $this -> last_params ;
$time = microtime ( true ) - $this -> last_time ;
2009-06-13 15:59:55 +00:00
$error = $this -> get_last_error ();
2009-06-13 10:16:29 +00:00
2009-06-13 15:59:55 +00:00
$this -> query_log ( $error );
2009-06-13 10:16:29 +00:00
2009-06-13 15:59:55 +00:00
switch ( $type ) {
2008-11-04 23:07:14 +00:00
case SQL_QUERY_SELECT :
case SQL_QUERY_AUX :
2009-06-13 10:16:29 +00:00
throw new dml_read_exception ( $error , $sql , $params );
2008-11-04 23:07:14 +00:00
case SQL_QUERY_INSERT :
case SQL_QUERY_UPDATE :
2009-06-13 10:16:29 +00:00
throw new dml_write_exception ( $error , $sql , $params );
2008-11-05 10:45:45 +00:00
case SQL_QUERY_STRUCTURE :
$this -> get_manager (); // includes ddl exceptions classes ;-)
2009-06-13 10:16:29 +00:00
throw new ddl_change_structure_exception ( $error , $sql );
}
}
/**
2012-01-19 10:15:11 +08:00
* This logs the last query based on 'logall' , 'logslow' and 'logerrors' options configured via $CFG -> dboptions .
2009-06-13 10:16:29 +00:00
* @ param mixed string error or false if not error
* @ return void
*/
2009-06-13 15:59:55 +00:00
public function query_log ( $error = false ) {
2009-06-13 10:16:29 +00:00
$logall = ! empty ( $this -> dboptions [ 'logall' ]);
$logslow = ! empty ( $this -> dboptions [ 'logslow' ]) ? $this -> dboptions [ 'logslow' ] : false ;
$logerrors = ! empty ( $this -> dboptions [ 'logerrors' ]);
$iserror = ( $error !== false );
2009-06-13 15:59:55 +00:00
$time = microtime ( true ) - $this -> last_time ;
2009-06-13 10:16:29 +00:00
if ( $logall or ( $logslow and ( $logslow < ( $time + 0.00001 ))) or ( $iserror and $logerrors )) {
$this -> loggingquery = true ;
try {
2009-06-13 15:59:55 +00:00
$backtrace = debug_backtrace ();
if ( $backtrace ) {
//remove query_log()
array_shift ( $backtrace );
}
if ( $backtrace ) {
//remove query_end()
array_shift ( $backtrace );
}
2010-09-21 07:57:42 +00:00
$log = new stdClass ();
2009-06-13 15:59:55 +00:00
$log -> qtype = $this -> last_type ;
$log -> sqltext = $this -> last_sql ;
$log -> sqlparams = var_export (( array ) $this -> last_params , true );
$log -> error = ( int ) $iserror ;
$log -> info = $iserror ? $error : null ;
2009-06-26 09:06:16 +00:00
$log -> backtrace = format_backtrace ( $backtrace , true );
2009-06-13 15:59:55 +00:00
$log -> exectime = $time ;
$log -> timelogged = time ();
$this -> insert_record ( 'log_queries' , $log );
2009-06-13 10:16:29 +00:00
} catch ( Exception $ignored ) {
}
$this -> loggingquery = false ;
2008-11-04 23:07:14 +00:00
}
2008-10-28 22:31:26 +00:00
}
2008-05-19 18:02:33 +00:00
/**
* Returns database server info array
2012-01-19 10:15:11 +08:00
* @ return array Array containing 'description' and 'version' atleast .
2008-05-19 18:02:33 +00:00
*/
public abstract function get_server_info ();
/**
* Returns supported query parameter types
2012-01-19 10:15:11 +08:00
* @ return int bitmask of accepted SQL_PARAMS_ *
2008-05-19 18:02:33 +00:00
*/
protected abstract function allowed_param_types ();
2008-05-15 21:40:00 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns the last error reported by the database engine .
* @ return string The error message .
2008-05-15 21:40:00 +00:00
*/
public abstract function get_last_error ();
2008-10-18 22:35:42 +00:00
/**
2012-01-19 10:15:11 +08:00
* Prints sql debug info
* @ param string $sql The query which is being debugged .
* @ param array $params The query parameters . ( optional )
* @ param mixed $obj The library specific object . ( optional )
2010-08-22 19:26:48 +00:00
* @ return void
2008-10-18 22:35:42 +00:00
*/
protected function print_debug ( $sql , array $params = null , $obj = null ) {
if ( ! $this -> get_debug ()) {
return ;
}
2009-06-13 09:16:30 +00:00
if ( CLI_SCRIPT ) {
echo " -------------------------------- \n " ;
echo $sql . " \n " ;
if ( ! is_null ( $params )) {
echo " [ " . var_export ( $params , true ) . " ] \n " ;
}
echo " -------------------------------- \n " ;
} else {
echo " <hr /> \n " ;
echo s ( $sql ) . " \n " ;
if ( ! is_null ( $params )) {
echo " [ " . s ( var_export ( $params , true )) . " ] \n " ;
}
echo " <hr /> \n " ;
2008-10-18 22:35:42 +00:00
}
2008-05-15 21:40:00 +00:00
}
2008-11-22 19:32:16 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns the SQL WHERE conditions .
* @ param string $table The table name that these conditions will be validated against .
* @ param array $conditions The conditions to build the where clause . ( must not contain numeric indexes )
* @ throws dml_exception
* @ return array An array list containing sql 'where' part and 'params' .
2008-11-22 19:32:16 +00:00
*/
2010-11-18 06:00:51 +00:00
protected function where_clause ( $table , array $conditions = null ) {
2011-11-12 22:27:24 +01:00
// We accept nulls in conditions
$conditions = is_null ( $conditions ) ? array () : $conditions ;
// Some checks performed under debugging only
2011-08-05 21:33:16 +02:00
if ( debugging ()) {
$columns = $this -> get_columns ( $table );
2011-11-12 22:27:24 +01:00
if ( empty ( $columns )) {
// no supported columns means most probably table does not exist
throw new dml_exception ( 'ddltablenotexist' , $table );
}
2011-08-05 21:33:16 +02:00
foreach ( $conditions as $key => $value ) {
if ( ! isset ( $columns [ $key ])) {
2011-11-12 22:27:24 +01:00
$a = new stdClass ();
$a -> fieldname = $key ;
$a -> tablename = $table ;
throw new dml_exception ( 'ddlfieldnotexist' , $a );
2011-08-05 21:33:16 +02:00
}
$column = $columns [ $key ];
if ( $column -> meta_type == 'X' ) {
//ok so the column is a text column. sorry no text columns in the where clause conditions
throw new dml_exception ( 'textconditionsnotallowed' , $conditions );
}
2010-11-18 06:00:51 +00:00
}
2011-08-05 21:33:16 +02:00
}
2011-11-12 22:27:24 +01:00
$allowed_types = $this -> allowed_param_types ();
if ( empty ( $conditions )) {
return array ( '' , array ());
}
$where = array ();
$params = array ();
2011-08-05 21:33:16 +02:00
foreach ( $conditions as $key => $value ) {
2008-11-22 19:32:16 +00:00
if ( is_int ( $key )) {
throw new dml_exception ( 'invalidnumkey' );
}
if ( is_null ( $value )) {
$where [] = " $key IS NULL " ;
} else {
if ( $allowed_types & SQL_PARAMS_NAMED ) {
2010-08-24 21:50:53 +00:00
// Need to verify key names because they can contain, originally,
// spaces and other forbidden chars when using sql_xxx() functions and friends.
2011-03-16 14:58:41 +01:00
$normkey = trim ( preg_replace ( '/[^a-zA-Z0-9_-]/' , '_' , $key ), '-_' );
2010-08-24 21:50:53 +00:00
if ( $normkey !== $key ) {
debugging ( 'Invalid key found in the conditions array.' );
}
2010-08-25 11:18:37 +00:00
$where [] = " $key = : $normkey " ;
2010-08-24 21:50:53 +00:00
$params [ $normkey ] = $value ;
} else {
2010-08-25 11:18:37 +00:00
$where [] = " $key = ? " ;
2008-11-22 19:32:16 +00:00
$params [] = $value ;
}
}
}
$where = implode ( " AND " , $where );
return array ( $where , $params );
}
2008-12-15 02:13:11 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns SQL WHERE conditions for the ... _list group of methods .
2008-12-15 02:13:11 +00:00
*
* @ param string $field the name of a field .
* @ param array $values the values field might take .
2012-01-19 10:15:11 +08:00
* @ return array An array containing sql 'where' part and 'params'
2008-12-15 02:13:11 +00:00
*/
protected function where_clause_list ( $field , array $values ) {
$params = array ();
$select = array ();
$values = ( array ) $values ;
foreach ( $values as $value ) {
if ( is_bool ( $value )) {
$value = ( int ) $value ;
}
if ( is_null ( $value )) {
$select [] = " $field IS NULL " ;
} else {
$select [] = " $field = ? " ;
$params [] = $value ;
}
}
$select = implode ( " OR " , $select );
return array ( $select , $params );
}
2008-05-15 21:40:00 +00:00
/**
2012-01-19 10:15:11 +08:00
* Constructs 'IN()' or '=' sql fragment
* @ param mixed $items A single value or array of values for the expression .
* @ param int $type Parameter bounding type : SQL_PARAMS_QM or SQL_PARAMS_NAMED .
* @ param string $prefix Named parameter placeholder prefix ( a unique counter value is appended to each parameter name ) .
* @ param bool $equal True means we want to equate to the constructed expression , false means we don ' t want to equate to it .
* @ param mixed $onemptyitems This defines the behavior when the array of items provided is empty . Defaults to false ,
2011-03-07 16:58:51 +01:00
* meaning throw exceptions . Other values will become part of the returned SQL fragment .
2012-01-19 10:15:11 +08:00
* @ throws coding_exception | dml_exception
* @ return array A list containing the constructed sql fragment and an array of parameters .
2008-05-15 21:40:00 +00:00
*/
2011-04-14 14:50:35 +02:00
public function get_in_or_equal ( $items , $type = SQL_PARAMS_QM , $prefix = 'param' , $equal = true , $onemptyitems = false ) {
2011-03-07 16:58:51 +01:00
// default behavior, throw exception on empty array
if ( is_array ( $items ) and empty ( $items ) and $onemptyitems === false ) {
2009-09-22 21:03:38 +00:00
throw new coding_exception ( 'moodle_database::get_in_or_equal() does not accept empty arrays' );
}
2011-03-07 16:58:51 +01:00
// handle $onemptyitems on empty array of items
if ( is_array ( $items ) and empty ( $items )) {
if ( is_null ( $onemptyitems )) { // Special case, NULL value
$sql = $equal ? ' IS NULL' : ' IS NOT NULL' ;
return ( array ( $sql , array ()));
} else {
$items = array ( $onemptyitems ); // Rest of cases, prepare $items for std processing
}
}
2008-05-15 21:40:00 +00:00
if ( $type == SQL_PARAMS_QM ) {
if ( ! is_array ( $items ) or count ( $items ) == 1 ) {
2008-05-24 20:42:40 +00:00
$sql = $equal ? '= ?' : '<> ?' ;
2008-05-24 13:05:34 +00:00
$items = ( array ) $items ;
$params = array_values ( $items );
2008-05-15 21:40:00 +00:00
} else {
2008-05-24 20:42:40 +00:00
if ( $equal ) {
$sql = 'IN (' . implode ( ',' , array_fill ( 0 , count ( $items ), '?' )) . ')' ;
} else {
$sql = 'NOT IN (' . implode ( ',' , array_fill ( 0 , count ( $items ), '?' )) . ')' ;
}
2008-05-15 21:40:00 +00:00
$params = array_values ( $items );
}
} else if ( $type == SQL_PARAMS_NAMED ) {
2011-04-14 14:50:35 +02:00
if ( empty ( $prefix )) {
$prefix = 'param' ;
}
2008-05-24 13:05:34 +00:00
if ( ! is_array ( $items )){
2011-06-17 11:25:44 +01:00
$param = $prefix . $this -> inorequaluniqueindex ++ ;
2011-04-14 14:50:35 +02:00
$sql = $equal ? " = : $param " : " <> : $param " ;
$params = array ( $param => $items );
2008-05-24 13:05:34 +00:00
} else if ( count ( $items ) == 1 ) {
2011-06-17 11:25:44 +01:00
$param = $prefix . $this -> inorequaluniqueindex ++ ;
2011-04-14 14:50:35 +02:00
$sql = $equal ? " = : $param " : " <> : $param " ;
2008-05-24 13:05:34 +00:00
$item = reset ( $items );
2011-04-14 14:50:35 +02:00
$params = array ( $param => $item );
2008-05-15 21:40:00 +00:00
} else {
$params = array ();
$sql = array ();
foreach ( $items as $item ) {
2011-06-17 11:25:44 +01:00
$param = $prefix . $this -> inorequaluniqueindex ++ ;
2011-04-14 14:50:35 +02:00
$params [ $param ] = $item ;
$sql [] = ':' . $param ;
2008-05-24 20:42:40 +00:00
}
if ( $equal ) {
$sql = 'IN (' . implode ( ',' , $sql ) . ')' ;
} else {
$sql = 'NOT IN (' . implode ( ',' , $sql ) . ')' ;
2008-05-15 21:40:00 +00:00
}
}
} else {
2008-10-25 17:43:45 +00:00
throw new dml_exception ( 'typenotimplement' );
2008-05-15 21:40:00 +00:00
}
return array ( $sql , $params );
}
2008-06-07 14:41:01 +00:00
/**
2012-01-19 10:15:11 +08:00
* Converts short table name { tablename } to the real prefixed table name in given sql .
* @ param string $sql The sql to be operated on .
* @ return string The sql with tablenames being prefixed with $CFG -> prefix
2008-06-07 14:41:01 +00:00
*/
protected function fix_table_names ( $sql ) {
return preg_replace ( '/\{([a-z][a-z0-9_]*)\}/' , $this -> prefix . '$1' , $sql );
}
2012-01-19 10:15:11 +08:00
/**
* Internal private utitlity function used to fix parameters .
2012-02-16 10:29:45 +08:00
* Used with { @ link preg_replace_callback ()}
2012-02-07 10:58:55 +08:00
* @ param array $match Refer to preg_replace_callback usage for description .
2012-01-19 10:15:11 +08:00
*/
2008-11-06 18:36:50 +00:00
private function _fix_sql_params_dollar_callback ( $match ) {
$this -> fix_sql_params_i ++ ;
return " \$ " . $this -> fix_sql_params_i ;
}
2008-05-15 21:40:00 +00:00
/**
* Normalizes sql query parameters and verifies parameters .
2012-01-19 10:15:11 +08:00
* @ param string $sql The query or part of it .
* @ param array $params The query parameters .
2010-08-22 19:26:48 +00:00
* @ return array ( sql , params , type of params )
2008-05-15 21:40:00 +00:00
*/
public function fix_sql_params ( $sql , array $params = null ) {
$params = ( array ) $params ; // mke null array if needed
$allowed_types = $this -> allowed_param_types ();
// convert table names
2008-06-07 14:41:01 +00:00
$sql = $this -> fix_table_names ( $sql );
2008-05-15 21:40:00 +00:00
2010-09-03 15:44:11 +00:00
// cast booleans to 1/0 int
foreach ( $params as $key => $value ) {
$params [ $key ] = is_bool ( $value ) ? ( int ) $value : $value ;
}
2008-05-21 14:59:33 +00:00
// NICOLAS C: Fixed regexp for negative backwards lookahead of double colons. Thanks for Sam Marshall's help
$named_count = preg_match_all ( '/(?<!:):[a-z][a-z0-9_]*/' , $sql , $named_matches ); // :: used in pgsql casts
$dollar_count = preg_match_all ( '/\$[1-9][0-9]*/' , $sql , $dollar_matches );
2008-05-15 21:40:00 +00:00
$q_count = substr_count ( $sql , '?' );
$count = 0 ;
if ( $named_count ) {
$type = SQL_PARAMS_NAMED ;
$count = $named_count ;
}
2008-05-21 14:59:33 +00:00
if ( $dollar_count ) {
2008-05-15 21:40:00 +00:00
if ( $count ) {
2008-10-25 17:43:45 +00:00
throw new dml_exception ( 'mixedtypesqlparam' );
2008-05-15 21:40:00 +00:00
}
2008-05-21 14:59:33 +00:00
$type = SQL_PARAMS_DOLLAR ;
$count = $dollar_count ;
2008-05-15 21:40:00 +00:00
}
if ( $q_count ) {
if ( $count ) {
2008-10-25 17:43:45 +00:00
throw new dml_exception ( 'mixedtypesqlparam' );
2008-05-15 21:40:00 +00:00
}
$type = SQL_PARAMS_QM ;
$count = $q_count ;
}
if ( ! $count ) {
// ignore params
if ( $allowed_types & SQL_PARAMS_NAMED ) {
return array ( $sql , array (), SQL_PARAMS_NAMED );
} else if ( $allowed_types & SQL_PARAMS_QM ) {
return array ( $sql , array (), SQL_PARAMS_QM );
} else {
2008-05-21 14:59:33 +00:00
return array ( $sql , array (), SQL_PARAMS_DOLLAR );
2008-05-15 21:40:00 +00:00
}
}
if ( $count > count ( $params )) {
2008-10-29 06:54:32 +00:00
$a = new stdClass ;
$a -> expected = $count ;
$a -> actual = count ( $params );
throw new dml_exception ( 'invalidqueryparam' , $a );
2008-05-15 21:40:00 +00:00
}
2008-11-19 23:20:46 +00:00
$target_type = $allowed_types ;
2008-05-15 21:40:00 +00:00
if ( $type & $allowed_types ) { // bitwise AND
if ( $count == count ( $params )) {
if ( $type == SQL_PARAMS_QM ) {
return array ( $sql , array_values ( $params ), SQL_PARAMS_QM ); // 0-based array required
} else {
2008-05-21 14:59:33 +00:00
//better do the validation of names below
2008-05-15 21:40:00 +00:00
}
}
// needs some fixing or validation - there might be more params than needed
$target_type = $type ;
}
if ( $type == SQL_PARAMS_NAMED ) {
$finalparams = array ();
foreach ( $named_matches [ 0 ] as $key ) {
$key = trim ( $key , ':' );
if ( ! array_key_exists ( $key , $params )) {
2008-11-18 04:22:57 +00:00
throw new dml_exception ( 'missingkeyinsql' , $key , '' );
2008-05-15 21:40:00 +00:00
}
2011-07-22 14:22:35 +01:00
if ( strlen ( $key ) > 30 ) {
throw new coding_exception (
" Placeholder names must be 30 characters or shorter. ' " .
$key . " ' is too long. " , $sql );
}
2008-05-15 21:40:00 +00:00
$finalparams [ $key ] = $params [ $key ];
}
if ( $count != count ( $finalparams )) {
2008-10-25 17:43:45 +00:00
throw new dml_exception ( 'duplicateparaminsql' );
2008-05-15 21:40:00 +00:00
}
if ( $target_type & SQL_PARAMS_QM ) {
2008-05-21 14:59:33 +00:00
$sql = preg_replace ( '/(?<!:):[a-z][a-z0-9_]*/' , '?' , $sql );
2008-05-15 21:40:00 +00:00
return array ( $sql , array_values ( $finalparams ), SQL_PARAMS_QM ); // 0-based required
} else if ( $target_type & SQL_PARAMS_NAMED ) {
return array ( $sql , $finalparams , SQL_PARAMS_NAMED );
2008-05-21 14:59:33 +00:00
} else { // $type & SQL_PARAMS_DOLLAR
2008-11-06 18:36:50 +00:00
//lambda-style functions eat memory - we use globals instead :-(
$this -> fix_sql_params_i = 0 ;
$sql = preg_replace_callback ( '/(?<!:):[a-z][a-z0-9_]*/' , array ( $this , '_fix_sql_params_dollar_callback' ), $sql );
2008-10-26 12:45:05 +00:00
return array ( $sql , array_values ( $finalparams ), SQL_PARAMS_DOLLAR ); // 0-based required
2008-05-15 21:40:00 +00:00
}
2008-05-21 14:59:33 +00:00
} else if ( $type == SQL_PARAMS_DOLLAR ) {
2008-10-26 12:45:05 +00:00
if ( $target_type & SQL_PARAMS_DOLLAR ) {
return array ( $sql , array_values ( $params ), SQL_PARAMS_DOLLAR ); // 0-based required
2008-10-27 12:00:04 +00:00
} else if ( $target_type & SQL_PARAMS_QM ) {
$sql = preg_replace ( '/\$[0-9]+/' , '?' , $sql );
return array ( $sql , array_values ( $params ), SQL_PARAMS_QM ); // 0-based required
} else { //$target_type & SQL_PARAMS_NAMED
$sql = preg_replace ( '/\$([0-9]+)/' , ':param\\1' , $sql );
$finalparams = array ();
foreach ( $params as $key => $param ) {
$key ++ ;
$finalparams [ 'param' . $key ] = $param ;
}
return array ( $sql , $finalparams , SQL_PARAMS_NAMED );
2008-10-26 12:45:05 +00:00
}
2008-05-15 21:40:00 +00:00
} else { // $type == SQL_PARAMS_QM
if ( count ( $params ) != $count ) {
$params = array_slice ( $params , 0 , $count );
}
if ( $target_type & SQL_PARAMS_QM ) {
return array ( $sql , array_values ( $params ), SQL_PARAMS_QM ); // 0-based required
} else if ( $target_type & SQL_PARAMS_NAMED ) {
$finalparams = array ();
2008-12-04 11:52:53 +00:00
$pname = 'param0' ;
2008-05-15 21:40:00 +00:00
$parts = explode ( '?' , $sql );
$sql = array_shift ( $parts );
foreach ( $parts as $part ) {
$param = array_shift ( $params );
$pname ++ ;
$sql .= ':' . $pname . $part ;
$finalparams [ $pname ] = $param ;
}
return array ( $sql , $finalparams , SQL_PARAMS_NAMED );
2008-05-21 14:59:33 +00:00
} else { // $type & SQL_PARAMS_DOLLAR
2008-11-06 18:36:50 +00:00
//lambda-style functions eat memory - we use globals instead :-(
$this -> fix_sql_params_i = 0 ;
$sql = preg_replace_callback ( '/\?/' , array ( $this , '_fix_sql_params_dollar_callback' ), $sql );
2008-10-26 12:45:05 +00:00
return array ( $sql , array_values ( $params ), SQL_PARAMS_DOLLAR ); // 0-based required
2008-05-15 21:40:00 +00:00
}
}
}
/**
2012-01-19 10:15:11 +08:00
* Return tables in database WITHOUT current prefix .
* @ param bool $usecache if true , returns list of cached tables .
2008-05-25 22:22:57 +00:00
* @ return array of table names in lowercase and without prefix
2008-05-15 21:40:00 +00:00
*/
2009-01-12 18:10:50 +00:00
public abstract function get_tables ( $usecache = true );
2008-05-15 21:40:00 +00:00
/**
2012-01-19 10:15:11 +08:00
* Return table indexes - everything lowercased .
* @ param string $table The table we want to get indexes from .
* @ return array An associative array of indexes containing 'unique' flag and 'columns' being indexed
2008-05-15 21:40:00 +00:00
*/
public abstract function get_indexes ( $table );
/**
2010-09-06 14:11:38 +00:00
* Returns detailed information about columns in table . This information is cached internally .
2012-01-19 10:15:11 +08:00
* @ param string $table The table ' s name .
* @ param bool $usecache Flag to use internal cacheing . The default is true .
2010-09-06 14:11:38 +00:00
* @ return array of database_column_info objects indexed with column names
2008-05-15 21:40:00 +00:00
*/
2008-05-25 09:31:38 +00:00
public abstract function get_columns ( $table , $usecache = true );
2008-05-15 21:40:00 +00:00
2009-11-04 13:19:11 +00:00
/**
2012-01-19 10:15:11 +08:00
* Normalise values based on varying RDBMS ' s dependencies ( booleans , LOBs ... )
2009-11-04 13:19:11 +00:00
*
* @ param database_column_info $column column metadata corresponding with the value we are going to normalise
* @ param mixed $value value we are going to normalise
* @ return mixed the normalised value
*/
protected abstract function normalise_value ( $column , $value );
2008-05-15 21:40:00 +00:00
/**
2012-01-19 10:15:11 +08:00
* Resets the internal column details cache
2008-05-15 21:40:00 +00:00
* @ return void
*/
2009-01-12 18:10:50 +00:00
public function reset_caches () {
2008-06-12 15:18:11 +00:00
$this -> columns = array ();
2009-01-12 18:10:50 +00:00
$this -> tables = null ;
2008-05-25 09:31:38 +00:00
}
2008-05-15 21:40:00 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns the sql generator used for db manipulation .
2008-05-15 21:40:00 +00:00
* Used mostly in upgrade . php scripts .
2012-02-16 10:29:45 +08:00
* @ return database_manager The instance used to perform ddl operations .
* @ see lib / ddl / database_manager . php
2008-05-15 21:40:00 +00:00
*/
public function get_manager () {
global $CFG ;
if ( ! $this -> database_manager ) {
2008-08-30 18:48:39 +00:00
require_once ( $CFG -> libdir . '/ddllib.php' );
2008-05-15 21:40:00 +00:00
$classname = $this -> get_dbfamily () . '_sql_generator' ;
require_once ( " $CFG->libdir /ddl/ $classname .php " );
2010-04-21 16:12:27 +00:00
$generator = new $classname ( $this , $this -> temptables );
2008-05-15 21:40:00 +00:00
$this -> database_manager = new database_manager ( $this , $generator );
}
return $this -> database_manager ;
}
/**
2012-01-19 10:15:11 +08:00
* Attempts to change db encoding to UTF - 8 encoding if possible .
* @ return bool True is successful .
2008-05-15 21:40:00 +00:00
*/
public function change_db_encoding () {
return false ;
}
/**
2012-01-19 10:15:11 +08:00
* Checks to see if the database is in unicode mode ?
2008-05-15 21:40:00 +00:00
* @ return bool
*/
public function setup_is_unicodedb () {
return true ;
}
/**
2012-01-19 10:15:11 +08:00
* Enable / disable very detailed debugging .
2008-05-15 21:40:00 +00:00
* @ param bool $state
2010-09-06 14:10:52 +00:00
* @ return void
2008-05-15 21:40:00 +00:00
*/
2008-11-21 20:09:13 +00:00
public function set_debug ( $state ) {
$this -> debug = $state ;
}
2008-05-15 21:40:00 +00:00
/**
* Returns debug status
* @ return bool $state
*/
2008-11-21 20:09:13 +00:00
public function get_debug () {
return $this -> debug ;
}
2008-05-15 21:40:00 +00:00
/**
* Enable / disable detailed sql logging
* @ param bool $state
*/
2008-11-21 20:09:13 +00:00
public function set_logging ( $state ) {
2009-06-13 09:16:30 +00:00
// adodb sql logging shares one table without prefix per db - this is no longer acceptable :-(
2008-11-21 20:09:13 +00:00
// we must create one table shared by all drivers
}
2008-05-15 21:40:00 +00:00
/**
2012-01-19 10:15:11 +08:00
* Do NOT use in code , this is for use by database_manager only !
2008-05-15 21:40:00 +00:00
* @ param string $sql query
2008-11-21 20:09:13 +00:00
* @ return bool true
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public abstract function change_database_structure ( $sql );
/**
2012-01-19 10:15:11 +08:00
* Executes a general sql query . Should be used only when no other method suitable .
2008-05-15 21:40:00 +00:00
* Do NOT use this to make changes in db structure , use database_manager :: execute_sql () instead !
* @ param string $sql query
* @ param array $params query parameters
2008-11-21 20:09:13 +00:00
* @ return bool true
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public abstract function execute ( $sql , array $params = null );
/**
2008-07-25 18:41:35 +00:00
* Get a number of records as a moodle_recordset where all the given conditions met .
2008-05-15 21:40:00 +00:00
*
* Selects records from the table $table .
*
* If specified , only records meeting $conditions .
*
* If specified , the results will be sorted as specified by $sort . This
* is added to the SQL as " ORDER BY $sort " . Example values of $sort
2010-05-21 18:18:42 +00:00
* might be " time ASC " or " time DESC " .
2008-05-15 21:40:00 +00:00
*
* If $fields is specified , only those fields are returned .
*
* Since this method is a little less readable , use of it should be restricted to
* code where it ' s possible there might be large datasets being returned . For known
* small datasets use get_records - it leads to simpler code .
*
* If you only want some of the records , specify $limitfrom and $limitnum .
* The query will skip the first $limitfrom records ( according to the sort
* order ) and then return the next $limitnum records . If either of $limitfrom
* or $limitnum is specified , both must be present .
*
* The return value is a moodle_recordset
2010-05-21 18:18:42 +00:00
* if the query succeeds . If an error occurs , false is returned .
2008-05-15 21:40:00 +00:00
*
* @ param string $table the table to query .
* @ param array $conditions optional array $fieldname => requestedvalue with AND in between
* @ param string $sort an order to sort the results in ( optional , a valid SQL ORDER BY parameter ) .
* @ param string $fields a comma separated list of fields to return ( optional , by default all fields are returned ) .
2012-01-19 10:15:11 +08:00
* @ param int $limitfrom return a subset of records , starting at this point ( optional ) .
2008-05-15 21:40:00 +00:00
* @ param int $limitnum return a subset comprising this many records ( optional , required if $limitfrom is set ) .
2012-01-19 10:15:11 +08:00
* @ return moodle_recordset A moodle_recordset instance
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public function get_recordset ( $table , array $conditions = null , $sort = '' , $fields = '*' , $limitfrom = 0 , $limitnum = 0 ) {
2010-11-18 06:00:51 +00:00
list ( $select , $params ) = $this -> where_clause ( $table , $conditions );
2008-05-15 21:40:00 +00:00
return $this -> get_recordset_select ( $table , $select , $params , $sort , $fields , $limitfrom , $limitnum );
}
/**
2008-07-25 18:41:35 +00:00
* Get a number of records as a moodle_recordset where one field match one list of values .
2008-05-15 21:40:00 +00:00
*
* Only records where $field takes one of the values $values are returned .
2008-06-18 14:53:01 +00:00
* $values must be an array of values .
2008-05-15 21:40:00 +00:00
*
2012-02-16 10:29:45 +08:00
* Other arguments and the return type are like { @ link function get_recordset } .
2008-05-15 21:40:00 +00:00
*
* @ param string $table the table to query .
* @ param string $field a field to check ( optional ) .
* @ param array $values array of values the field must have
* @ param string $sort an order to sort the results in ( optional , a valid SQL ORDER BY parameter ) .
* @ param string $fields a comma separated list of fields to return ( optional , by default all fields are returned ) .
2012-01-19 10:15:11 +08:00
* @ param int $limitfrom return a subset of records , starting at this point ( optional ) .
2008-05-15 21:40:00 +00:00
* @ param int $limitnum return a subset comprising this many records ( optional , required if $limitfrom is set ) .
2012-01-19 10:15:11 +08:00
* @ return moodle_recordset A moodle_recordset instance .
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public function get_recordset_list ( $table , $field , array $values , $sort = '' , $fields = '*' , $limitfrom = 0 , $limitnum = 0 ) {
2008-12-15 02:13:11 +00:00
list ( $select , $params ) = $this -> where_clause_list ( $field , $values );
2008-12-15 21:41:09 +00:00
if ( empty ( $select )) {
2010-09-14 19:19:30 +00:00
$select = '1 = 2' ; /// Fake condition, won't return rows ever. MDL-17645
$params = array ();
2008-12-15 21:41:09 +00:00
}
2008-06-14 00:00:26 +00:00
return $this -> get_recordset_select ( $table , $select , $params , $sort , $fields , $limitfrom , $limitnum );
2008-05-15 21:40:00 +00:00
}
/**
2008-07-25 18:41:35 +00:00
* Get a number of records as a moodle_recordset which match a particular WHERE clause .
2008-05-15 21:40:00 +00:00
*
* If given , $select is used as the SELECT parameter in the SQL query ,
* otherwise all records from the table are returned .
*
2012-02-16 10:29:45 +08:00
* Other arguments and the return type are like { @ link function get_recordset } .
2008-05-15 21:40:00 +00:00
*
* @ param string $table the table to query .
* @ param string $select A fragment of SQL to be used in a where clause in the SQL call .
* @ param array $params array of sql parameters
* @ param string $sort an order to sort the results in ( optional , a valid SQL ORDER BY parameter ) .
* @ param string $fields a comma separated list of fields to return ( optional , by default all fields are returned ) .
2012-01-19 10:15:11 +08:00
* @ param int $limitfrom return a subset of records , starting at this point ( optional ) .
2008-05-15 21:40:00 +00:00
* @ param int $limitnum return a subset comprising this many records ( optional , required if $limitfrom is set ) .
2012-01-19 10:15:11 +08:00
* @ return moodle_recordset A moodle_recordset instance .
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public function get_recordset_select ( $table , $select , array $params = null , $sort = '' , $fields = '*' , $limitfrom = 0 , $limitnum = 0 ) {
2008-12-05 00:10:27 +00:00
$sql = " SELECT $fields FROM { " . $table . " } " ;
2008-05-15 21:40:00 +00:00
if ( $select ) {
2008-12-05 00:10:27 +00:00
$sql .= " WHERE $select " ;
2008-05-15 21:40:00 +00:00
}
if ( $sort ) {
2008-12-05 00:10:27 +00:00
$sql .= " ORDER BY $sort " ;
2008-05-15 21:40:00 +00:00
}
2008-12-05 00:10:27 +00:00
return $this -> get_recordset_sql ( $sql , $params , $limitfrom , $limitnum );
2008-05-15 21:40:00 +00:00
}
/**
2008-07-25 18:41:35 +00:00
* Get a number of records as a moodle_recordset using a SQL statement .
*
2008-05-15 21:40:00 +00:00
* Since this method is a little less readable , use of it should be restricted to
* code where it ' s possible there might be large datasets being returned . For known
* small datasets use get_records_sql - it leads to simpler code .
*
2012-02-16 10:29:45 +08:00
* The return type is like { @ link function get_recordset } .
2008-05-15 21:40:00 +00:00
*
* @ param string $sql the SQL select query to execute .
* @ param array $params array of sql parameters
2012-01-19 10:15:11 +08:00
* @ param int $limitfrom return a subset of records , starting at this point ( optional ) .
2008-05-15 21:40:00 +00:00
* @ param int $limitnum return a subset comprising this many records ( optional , required if $limitfrom is set ) .
2012-01-19 10:15:11 +08:00
* @ return moodle_recordset A moodle_recordset instance .
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public abstract function get_recordset_sql ( $sql , array $params = null , $limitfrom = 0 , $limitnum = 0 );
/**
2008-07-25 17:51:37 +00:00
* Get a number of records as an array of objects where all the given conditions met .
2008-05-15 21:40:00 +00:00
*
* If the query succeeds and returns at least one record , the
* return value is an array of objects , one object for each
* record found . The array key is the value from the first
* column of the result set . The object associated with that key
* has a member variable for each column of the results .
*
* @ param string $table the table to query .
* @ param array $conditions optional array $fieldname => requestedvalue with AND in between
* @ param string $sort an order to sort the results in ( optional , a valid SQL ORDER BY parameter ) .
* @ param string $fields a comma separated list of fields to return ( optional , by default
* all fields are returned ) . The first field will be used as key for the
* array so must be a unique field such as 'id' .
2012-01-19 10:15:11 +08:00
* @ param int $limitfrom return a subset of records , starting at this point ( optional ) .
* @ param int $limitnum return a subset comprising this many records in total ( optional , required if $limitfrom is set ) .
* @ return array An array of Objects indexed by first column .
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public function get_records ( $table , array $conditions = null , $sort = '' , $fields = '*' , $limitfrom = 0 , $limitnum = 0 ) {
2010-11-18 06:00:51 +00:00
list ( $select , $params ) = $this -> where_clause ( $table , $conditions );
2008-05-15 21:40:00 +00:00
return $this -> get_records_select ( $table , $select , $params , $sort , $fields , $limitfrom , $limitnum );
}
/**
2008-07-25 17:51:37 +00:00
* Get a number of records as an array of objects where one field match one list of values .
2008-05-15 21:40:00 +00:00
*
2012-02-16 10:29:45 +08:00
* Return value is like { @ link function get_records } .
2008-05-15 21:40:00 +00:00
*
* @ param string $table The database table to be checked against .
* @ param string $field The field to search
2012-01-19 10:15:11 +08:00
* @ param array $values An array of values
2008-05-15 21:40:00 +00:00
* @ param string $sort Sort order ( as valid SQL sort parameter )
* @ param string $fields A comma separated list of fields to be returned from the chosen table . If specified ,
* the first field should be a unique one such as 'id' since it will be used as a key in the associative
* array .
2012-01-19 10:15:11 +08:00
* @ return array An array of objects indexed by first column
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
2008-06-01 15:42:48 +00:00
public function get_records_list ( $table , $field , array $values , $sort = '' , $fields = '*' , $limitfrom = 0 , $limitnum = 0 ) {
2008-12-15 02:13:11 +00:00
list ( $select , $params ) = $this -> where_clause_list ( $field , $values );
2008-06-01 15:42:48 +00:00
if ( empty ( $select )) {
// nothing to return
return array ();
}
2008-05-15 21:40:00 +00:00
return $this -> get_records_select ( $table , $select , $params , $sort , $fields , $limitfrom , $limitnum );
}
/**
2008-07-25 17:51:37 +00:00
* Get a number of records as an array of objects which match a particular WHERE clause .
2008-05-15 21:40:00 +00:00
*
2012-02-16 10:29:45 +08:00
* Return value is like { @ link function get_records } .
2008-05-15 21:40:00 +00:00
*
2012-01-19 10:15:11 +08:00
* @ param string $table The table to query .
2008-05-15 21:40:00 +00:00
* @ param string $select A fragment of SQL to be used in a where clause in the SQL call .
2012-01-19 10:15:11 +08:00
* @ param array $params An array of sql parameters
* @ param string $sort An order to sort the results in ( optional , a valid SQL ORDER BY parameter ) .
* @ param string $fields A comma separated list of fields to return
2008-05-15 21:40:00 +00:00
* ( optional , by default all fields are returned ) . The first field will be used as key for the
* array so must be a unique field such as 'id' .
2012-01-19 10:15:11 +08:00
* @ param int $limitfrom return a subset of records , starting at this point ( optional ) .
* @ param int $limitnum return a subset comprising this many records in total ( optional , required if $limitfrom is set ) .
2008-11-21 20:09:13 +00:00
* @ return array of objects indexed by first column
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public function get_records_select ( $table , $select , array $params = null , $sort = '' , $fields = '*' , $limitfrom = 0 , $limitnum = 0 ) {
if ( $select ) {
$select = " WHERE $select " ;
}
if ( $sort ) {
$sort = " ORDER BY $sort " ;
}
2009-08-29 00:08:55 +00:00
return $this -> get_records_sql ( " SELECT $fields FROM { " . $table . " } $select $sort " , $params , $limitfrom , $limitnum );
2008-05-15 21:40:00 +00:00
}
/**
2008-07-25 17:51:37 +00:00
* Get a number of records as an array of objects using a SQL statement .
2008-05-15 21:40:00 +00:00
*
2012-02-16 10:29:45 +08:00
* Return value is like { @ link function get_records } .
2008-05-15 21:40:00 +00:00
*
* @ param string $sql the SQL select query to execute . The first column of this SELECT statement
* must be a unique value ( usually the 'id' field ), as it will be used as the key of the
* returned array .
* @ param array $params array of sql parameters
2012-01-19 10:15:11 +08:00
* @ param int $limitfrom return a subset of records , starting at this point ( optional ) .
* @ param int $limitnum return a subset comprising this many records in total ( optional , required if $limitfrom is set ) .
2008-11-21 20:09:13 +00:00
* @ return array of objects indexed by first column
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public abstract function get_records_sql ( $sql , array $params = null , $limitfrom = 0 , $limitnum = 0 );
/**
2008-07-25 17:51:37 +00:00
* Get the first two columns from a number of records as an associative array where all the given conditions met .
2008-05-15 21:40:00 +00:00
*
2012-02-16 10:29:45 +08:00
* Arguments are like { @ link function get_recordset } .
2008-05-15 21:40:00 +00:00
*
* If no errors occur the return value
* is an associative whose keys come from the first field of each record ,
* and whose values are the corresponding second fields .
* False is returned if an error occurs .
*
* @ param string $table the table to query .
* @ param array $conditions optional array $fieldname => requestedvalue with AND in between
* @ param string $sort an order to sort the results in ( optional , a valid SQL ORDER BY parameter ) .
* @ param string $fields a comma separated list of fields to return - the number of fields should be 2 !
2012-01-19 10:15:11 +08:00
* @ param int $limitfrom return a subset of records , starting at this point ( optional ) .
2008-05-15 21:40:00 +00:00
* @ param int $limitnum return a subset comprising this many records ( optional , required if $limitfrom is set ) .
2008-11-21 20:09:13 +00:00
* @ return array an associative array
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public function get_records_menu ( $table , array $conditions = null , $sort = '' , $fields = '*' , $limitfrom = 0 , $limitnum = 0 ) {
$menu = array ();
if ( $records = $this -> get_records ( $table , $conditions , $sort , $fields , $limitfrom , $limitnum )) {
foreach ( $records as $record ) {
$record = ( array ) $record ;
$key = array_shift ( $record );
$value = array_shift ( $record );
$menu [ $key ] = $value ;
}
}
return $menu ;
}
/**
2008-07-25 17:51:37 +00:00
* Get the first two columns from a number of records as an associative array which match a particular WHERE clause .
2008-05-15 21:40:00 +00:00
*
2012-02-16 10:29:45 +08:00
* Arguments are like { @ link function get_recordset_select } .
* Return value is like { @ link function get_records_menu } .
2008-05-15 21:40:00 +00:00
*
* @ param string $table The database table to be checked against .
* @ param string $select A fragment of SQL to be used in a where clause in the SQL call .
* @ param array $params array of sql parameters
* @ param string $sort Sort order ( optional ) - a valid SQL order parameter
* @ param string $fields A comma separated list of fields to be returned from the chosen table - the number of fields should be 2 !
2012-01-19 10:15:11 +08:00
* @ param int $limitfrom return a subset of records , starting at this point ( optional ) .
2008-05-15 21:40:00 +00:00
* @ param int $limitnum return a subset comprising this many records ( optional , required if $limitfrom is set ) .
2008-11-21 20:09:13 +00:00
* @ return array an associative array
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public function get_records_select_menu ( $table , $select , array $params = null , $sort = '' , $fields = '*' , $limitfrom = 0 , $limitnum = 0 ) {
$menu = array ();
if ( $records = $this -> get_records_select ( $table , $select , $params , $sort , $fields , $limitfrom , $limitnum )) {
foreach ( $records as $record ) {
2008-06-04 09:14:17 +00:00
$record = ( array ) $record ;
$key = array_shift ( $record );
$value = array_shift ( $record );
2008-05-15 21:40:00 +00:00
$menu [ $key ] = $value ;
}
}
return $menu ;
}
/**
2008-07-25 17:51:37 +00:00
* Get the first two columns from a number of records as an associative array using a SQL statement .
2008-05-15 21:40:00 +00:00
*
2012-02-16 10:29:45 +08:00
* Arguments are like { @ link function get_recordset_sql } .
* Return value is like { @ link function get_records_menu } .
2008-05-15 21:40:00 +00:00
*
* @ param string $sql The SQL string you wish to be executed .
* @ param array $params array of sql parameters
2012-01-19 10:15:11 +08:00
* @ param int $limitfrom return a subset of records , starting at this point ( optional ) .
2008-05-15 21:40:00 +00:00
* @ param int $limitnum return a subset comprising this many records ( optional , required if $limitfrom is set ) .
2008-11-21 20:09:13 +00:00
* @ return array an associative array
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public function get_records_sql_menu ( $sql , array $params = null , $limitfrom = 0 , $limitnum = 0 ) {
$menu = array ();
if ( $records = $this -> get_records_sql ( $sql , $params , $limitfrom , $limitnum )) {
foreach ( $records as $record ) {
2008-06-04 09:14:17 +00:00
$record = ( array ) $record ;
$key = array_shift ( $record );
$value = array_shift ( $record );
2008-05-15 21:40:00 +00:00
$menu [ $key ] = $value ;
}
}
return $menu ;
}
/**
2008-07-25 17:51:37 +00:00
* Get a single database record as an object where all the given conditions met .
2008-05-15 21:40:00 +00:00
*
* @ param string $table The table to select from .
* @ param array $conditions optional array $fieldname => requestedvalue with AND in between
* @ param string $fields A comma separated list of fields to be returned from the chosen table .
2009-07-04 09:30:59 +00:00
* @ param int $strictness IGNORE_MISSING means compatible mode , false returned if record not found , debug message if more found ;
* IGNORE_MULTIPLE means return first , ignore multiple records found ( not recommended );
2012-01-19 10:15:11 +08:00
* MUST_EXIST means we will throw an exception if no record or multiple records found .
*
* @ todo MDL - 30407 MUST_EXIST option should not throw a dml_exception , it should throw a different exception as it ' s a requested check .
2009-07-03 22:38:56 +00:00
* @ return mixed a fieldset object containing the first matching record , false or exception if error not found depending on mode
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
2009-07-04 10:53:57 +00:00
public function get_record ( $table , array $conditions , $fields = '*' , $strictness = IGNORE_MISSING ) {
2010-11-18 06:00:51 +00:00
list ( $select , $params ) = $this -> where_clause ( $table , $conditions );
2009-07-03 22:38:56 +00:00
return $this -> get_record_select ( $table , $select , $params , $fields , $strictness );
2008-05-15 21:40:00 +00:00
}
/**
2008-07-25 17:51:37 +00:00
* Get a single database record as an object which match a particular WHERE clause .
2008-05-15 21:40:00 +00:00
*
* @ param string $table The database table to be checked against .
* @ param string $select A fragment of SQL to be used in a where clause in the SQL call .
* @ param array $params array of sql parameters
2009-07-04 09:30:59 +00:00
* @ param int $strictness IGNORE_MISSING means compatible mode , false returned if record not found , debug message if more found ;
* IGNORE_MULTIPLE means return first , ignore multiple records found ( not recommended );
* MUST_EXIST means throw exception if no record or multiple records found
2009-07-03 22:38:56 +00:00
* @ return mixed a fieldset object containing the first matching record , false or exception if error not found depending on mode
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
2009-07-04 10:53:57 +00:00
public function get_record_select ( $table , $select , array $params = null , $fields = '*' , $strictness = IGNORE_MISSING ) {
2008-05-15 21:40:00 +00:00
if ( $select ) {
$select = " WHERE $select " ;
}
2009-07-03 22:38:56 +00:00
try {
2009-08-29 00:08:55 +00:00
return $this -> get_record_sql ( " SELECT $fields FROM { " . $table . " } $select " , $params , $strictness );
2009-07-03 22:38:56 +00:00
} catch ( dml_missing_record_exception $e ) {
// create new exception which will contain correct table name
throw new dml_missing_record_exception ( $table , $e -> sql , $e -> params );
}
2008-05-15 21:40:00 +00:00
}
/**
2008-07-25 17:51:37 +00:00
* Get a single database record as an object using a SQL statement .
2008-05-15 21:40:00 +00:00
*
2009-07-03 22:38:56 +00:00
* The SQL statement should normally only return one record .
* It is recommended to use get_records_sql () if more matches possible !
2008-05-15 21:40:00 +00:00
*
* @ param string $sql The SQL string you wish to be executed , should normally only return one record .
* @ param array $params array of sql parameters
2009-07-04 09:30:59 +00:00
* @ param int $strictness IGNORE_MISSING means compatible mode , false returned if record not found , debug message if more found ;
* IGNORE_MULTIPLE means return first , ignore multiple records found ( not recommended );
* MUST_EXIST means throw exception if no record or multiple records found
2009-07-03 22:38:56 +00:00
* @ return mixed a fieldset object containing the first matching record , false or exception if error not found depending on mode
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
2009-07-04 10:53:57 +00:00
public function get_record_sql ( $sql , array $params = null , $strictness = IGNORE_MISSING ) {
2009-07-04 09:30:59 +00:00
$strictness = ( int ) $strictness ; // we support true/false for BC reasons too
if ( $strictness == IGNORE_MULTIPLE ) {
2009-07-03 22:38:56 +00:00
$count = 1 ;
} else {
$count = 0 ;
}
2008-10-27 15:30:38 +00:00
if ( ! $records = $this -> get_records_sql ( $sql , $params , 0 , $count )) {
2008-11-21 20:09:13 +00:00
// not found
2009-07-04 09:30:59 +00:00
if ( $strictness == MUST_EXIST ) {
2009-07-03 22:38:56 +00:00
throw new dml_missing_record_exception ( '' , $sql , $params );
}
2008-05-15 21:40:00 +00:00
return false ;
}
2009-07-03 22:38:56 +00:00
if ( count ( $records ) > 1 ) {
2009-07-04 09:30:59 +00:00
if ( $strictness == MUST_EXIST ) {
2009-07-03 22:38:56 +00:00
throw new dml_multiple_records_exception ( $sql , $params );
}
2008-05-15 21:40:00 +00:00
debugging ( 'Error: mdb->get_record() found more than one record!' );
}
2008-10-27 15:30:38 +00:00
$return = reset ( $records );
2008-05-15 21:40:00 +00:00
return $return ;
}
/**
2008-07-25 17:51:37 +00:00
* Get a single field value from a table record where all the given conditions met .
2008-05-15 21:40:00 +00:00
*
* @ param string $table the table to query .
* @ param string $return the field to return the value of .
* @ param array $conditions optional array $fieldname => requestedvalue with AND in between
2009-07-04 09:30:59 +00:00
* @ param int $strictness IGNORE_MISSING means compatible mode , false returned if record not found , debug message if more found ;
* IGNORE_MULTIPLE means return first , ignore multiple records found ( not recommended );
* MUST_EXIST means throw exception if no record or multiple records found
2008-11-21 20:09:13 +00:00
* @ return mixed the specified value false if not found
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
2009-07-04 10:53:57 +00:00
public function get_field ( $table , $return , array $conditions , $strictness = IGNORE_MISSING ) {
2010-11-18 06:00:51 +00:00
list ( $select , $params ) = $this -> where_clause ( $table , $conditions );
2009-07-03 22:38:56 +00:00
return $this -> get_field_select ( $table , $return , $select , $params , $strictness );
2008-05-15 21:40:00 +00:00
}
/**
2008-07-25 17:51:37 +00:00
* Get a single field value from a table record which match a particular WHERE clause .
2008-05-15 21:40:00 +00:00
*
* @ param string $table the table to query .
* @ param string $return the field to return the value of .
* @ param string $select A fragment of SQL to be used in a where clause returning one row with one column
* @ param array $params array of sql parameters
2009-07-04 09:30:59 +00:00
* @ param int $strictness IGNORE_MISSING means compatible mode , false returned if record not found , debug message if more found ;
* IGNORE_MULTIPLE means return first , ignore multiple records found ( not recommended );
* MUST_EXIST means throw exception if no record or multiple records found
2008-11-21 20:09:13 +00:00
* @ return mixed the specified value false if not found
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
2009-07-04 10:53:57 +00:00
public function get_field_select ( $table , $return , $select , array $params = null , $strictness = IGNORE_MISSING ) {
2008-05-15 21:40:00 +00:00
if ( $select ) {
$select = " WHERE $select " ;
}
2009-07-03 22:38:56 +00:00
try {
return $this -> get_field_sql ( " SELECT $return FROM { " . $table . " } $select " , $params , $strictness );
} catch ( dml_missing_record_exception $e ) {
// create new exception which will contain correct table name
throw new dml_missing_record_exception ( $table , $e -> sql , $e -> params );
}
2008-05-15 21:40:00 +00:00
}
/**
2008-07-25 18:41:35 +00:00
* Get a single field value ( first field ) using a SQL statement .
2008-05-15 21:40:00 +00:00
*
* @ param string $table the table to query .
* @ param string $return the field to return the value of .
* @ param string $sql The SQL query returning one row with one column
* @ param array $params array of sql parameters
2009-07-04 09:30:59 +00:00
* @ param int $strictness IGNORE_MISSING means compatible mode , false returned if record not found , debug message if more found ;
* IGNORE_MULTIPLE means return first , ignore multiple records found ( not recommended );
* MUST_EXIST means throw exception if no record or multiple records found
2008-11-21 20:09:13 +00:00
* @ return mixed the specified value false if not found
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
2009-07-04 10:53:57 +00:00
public function get_field_sql ( $sql , array $params = null , $strictness = IGNORE_MISSING ) {
2009-07-03 22:38:56 +00:00
if ( ! $record = $this -> get_record_sql ( $sql , $params , $strictness )) {
return false ;
2008-05-15 21:40:00 +00:00
}
2009-07-03 22:38:56 +00:00
$record = ( array ) $record ;
return reset ( $record ); // first column
2008-05-15 21:40:00 +00:00
}
/**
2008-07-25 18:41:35 +00:00
* Selects records and return values of chosen field as an array which match a particular WHERE clause .
2008-05-15 21:40:00 +00:00
*
* @ param string $table the table to query .
* @ param string $return the field we are intered in
* @ param string $select A fragment of SQL to be used in a where clause in the SQL call .
* @ param array $params array of sql parameters
2010-08-22 19:00:28 +00:00
* @ return array of values
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public function get_fieldset_select ( $table , $return , $select , array $params = null ) {
if ( $select ) {
$select = " WHERE $select " ;
}
2009-08-29 00:08:55 +00:00
return $this -> get_fieldset_sql ( " SELECT $return FROM { " . $table . " } $select " , $params );
2008-05-15 21:40:00 +00:00
}
/**
2008-07-25 18:41:35 +00:00
* Selects records and return values ( first field ) as an array using a SQL statement .
2008-05-15 21:40:00 +00:00
*
* @ param string $sql The SQL query
* @ param array $params array of sql parameters
2010-08-22 19:00:28 +00:00
* @ return array of values
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public abstract function get_fieldset_sql ( $sql , array $params = null );
/**
* Insert new record into database , as fast as possible , no safety checks , lobs not supported .
* @ param string $table name
* @ param mixed $params data record as object or array
2012-01-19 10:15:11 +08:00
* @ param bool $returnid Returns id of inserted record .
2008-05-15 21:40:00 +00:00
* @ param bool $bulk true means repeated inserts expected
2008-08-25 21:00:47 +00:00
* @ param bool $customsequence true if 'id' included in $params , disables $returnid
2010-08-22 19:00:28 +00:00
* @ return bool | int true or new id
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
2008-08-25 21:00:47 +00:00
public abstract function insert_record_raw ( $table , $params , $returnid = true , $bulk = false , $customsequence = false );
2008-05-15 21:40:00 +00:00
/**
2008-07-25 17:51:37 +00:00
* Insert a record into a table and return the " id " field if required .
*
2008-05-15 21:40:00 +00:00
* Some conversions and safety checks are carried out . Lobs are supported .
* If the return ID isn ' t required , then this just reports success as true / false .
* $data is an object containing needed data
* @ param string $table The database table to be inserted into
* @ param object $data A data object with values for one or more fields in the record
* @ param bool $returnid Should the id of the newly created record entry be returned ? If this option is not requested then true / false is returned .
2010-08-22 19:00:28 +00:00
* @ return bool | int true or new id
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public abstract function insert_record ( $table , $dataobject , $returnid = true , $bulk = false );
2008-08-25 21:00:47 +00:00
/**
* Import a record into a table , id field is required .
* Safety checks are NOT carried out . Lobs are supported .
*
* @ param string $table name of database table to be inserted into
* @ param object $dataobject A data object with values for one or more fields in the record
2008-11-21 20:09:13 +00:00
* @ return bool true
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-08-25 21:00:47 +00:00
*/
public abstract function import_record ( $table , $dataobject );
2008-05-15 21:40:00 +00:00
/**
* Update record in database , as fast as possible , no safety checks , lobs not supported .
* @ param string $table name
* @ param mixed $params data record as object or array
2012-01-19 10:15:11 +08:00
* @ param bool $bulk True means repeated updates expected .
2008-11-21 20:09:13 +00:00
* @ return bool true
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public abstract function update_record_raw ( $table , $params , $bulk = false );
/**
* Update a record in a table
*
* $dataobject is an object containing needed data
* Relies on $dataobject having a variable " id " to
* specify the record to update
*
* @ param string $table The database table to be checked against .
* @ param object $dataobject An object with contents equal to fieldname => fieldvalue . Must have an entry for 'id' to map to the table specified .
2012-01-19 10:15:11 +08:00
* @ param bool $bulk True means repeated updates expected .
2008-11-21 20:09:13 +00:00
* @ return bool true
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public abstract function update_record ( $table , $dataobject , $bulk = false );
/**
2008-07-25 17:51:37 +00:00
* Set a single field in every table record where all the given conditions met .
2008-05-15 21:40:00 +00:00
*
* @ param string $table The database table to be checked against .
* @ param string $newfield the field to set .
* @ param string $newvalue the value to set the field to .
* @ param array $conditions optional array $fieldname => requestedvalue with AND in between
2008-11-21 20:09:13 +00:00
* @ return bool true
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public function set_field ( $table , $newfield , $newvalue , array $conditions = null ) {
2010-11-18 06:00:51 +00:00
list ( $select , $params ) = $this -> where_clause ( $table , $conditions );
2008-05-15 21:40:00 +00:00
return $this -> set_field_select ( $table , $newfield , $newvalue , $select , $params );
}
/**
2008-07-25 17:51:37 +00:00
* Set a single field in every table record which match a particular WHERE clause .
2008-05-15 21:40:00 +00:00
*
* @ param string $table The database table to be checked against .
* @ param string $newfield the field to set .
* @ param string $newvalue the value to set the field to .
* @ param string $select A fragment of SQL to be used in a where clause in the SQL call .
* @ param array $params array of sql parameters
2008-11-21 20:09:13 +00:00
* @ return bool true
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public abstract function set_field_select ( $table , $newfield , $newvalue , $select , array $params = null );
/**
* Count the records in a table where all the given conditions met .
*
* @ param string $table The table to query .
* @ param array $conditions optional array $fieldname => requestedvalue with AND in between
* @ return int The count of records returned from the specified criteria .
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
2008-06-01 14:08:44 +00:00
public function count_records ( $table , array $conditions = null ) {
2010-11-18 06:00:51 +00:00
list ( $select , $params ) = $this -> where_clause ( $table , $conditions );
2008-05-15 21:40:00 +00:00
return $this -> count_records_select ( $table , $select , $params );
}
/**
* Count the records in a table which match a particular WHERE clause .
*
* @ param string $table The database table to be checked against .
* @ param string $select A fragment of SQL to be used in a WHERE clause in the SQL call .
* @ param array $params array of sql parameters
* @ param string $countitem The count string to be used in the SQL call . Default is COUNT ( 'x' ) .
* @ return int The count of records returned from the specified criteria .
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public function count_records_select ( $table , $select , array $params = null , $countitem = " COUNT('x') " ) {
if ( $select ) {
$select = " WHERE $select " ;
}
2009-08-29 00:08:55 +00:00
return $this -> count_records_sql ( " SELECT $countitem FROM { " . $table . " } $select " , $params );
2008-05-15 21:40:00 +00:00
}
/**
* Get the result of a SQL SELECT COUNT ( ... ) query .
*
* Given a query that counts rows , return that count . ( In fact ,
* given any query , return the first field of the first record
* returned . However , this method should only be used for the
2010-05-21 18:18:42 +00:00
* intended purpose . ) If an error occurs , 0 is returned .
2008-05-15 21:40:00 +00:00
*
* @ param string $sql The SQL string you wish to be executed .
* @ param array $params array of sql parameters
2008-11-21 20:09:13 +00:00
* @ return int the count
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public function count_records_sql ( $sql , array $params = null ) {
if ( $count = $this -> get_field_sql ( $sql , $params )) {
return $count ;
} else {
return 0 ;
}
}
/**
* Test whether a record exists in a table where all the given conditions met .
*
* The record to test is specified by giving up to three fields that must
* equal the corresponding values .
*
* @ param string $table The table to check .
* @ param array $conditions optional array $fieldname => requestedvalue with AND in between
* @ return bool true if a matching record exists , else false .
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public function record_exists ( $table , array $conditions ) {
2010-11-18 06:00:51 +00:00
list ( $select , $params ) = $this -> where_clause ( $table , $conditions );
2008-05-15 21:40:00 +00:00
return $this -> record_exists_select ( $table , $select , $params );
}
/**
* Test whether any records exists in a table which match a particular WHERE clause .
*
* @ param string $table The database table to be checked against .
* @ param string $select A fragment of SQL to be used in a WHERE clause in the SQL call .
* @ param array $params array of sql parameters
* @ return bool true if a matching record exists , else false .
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public function record_exists_select ( $table , $select , array $params = null ) {
if ( $select ) {
$select = " WHERE $select " ;
}
2009-08-29 00:08:55 +00:00
return $this -> record_exists_sql ( " SELECT 'x' FROM { " . $table . " } $select " , $params );
2008-05-15 21:40:00 +00:00
}
/**
* Test whether a SQL SELECT statement returns any records .
*
* This function returns true if the SQL statement executes
* without any errors and returns at least one record .
*
* @ param string $sql The SQL statement to execute .
* @ param array $params array of sql parameters
* @ return bool true if the SQL executes without errors and returns at least one record .
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public function record_exists_sql ( $sql , array $params = null ) {
2011-01-02 17:12:17 +01:00
$mrs = $this -> get_recordset_sql ( $sql , $params , 0 , 1 );
$return = $mrs -> valid ();
$mrs -> close ();
return $return ;
2008-05-15 21:40:00 +00:00
}
/**
* Delete the records from a table where all the given conditions met .
2008-05-31 15:32:28 +00:00
* If conditions not specified , table is truncated .
2008-05-15 21:40:00 +00:00
*
* @ param string $table the table to delete from .
* @ param array $conditions optional array $fieldname => requestedvalue with AND in between
2008-11-21 20:09:13 +00:00
* @ return bool true .
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
2008-05-31 15:32:28 +00:00
public function delete_records ( $table , array $conditions = null ) {
2011-09-01 11:05:21 +02:00
// truncate is drop/create (DDL), not transactional safe,
// so we don't use the shortcut within them. MDL-29198
if ( is_null ( $conditions ) && empty ( $this -> transactions )) {
2008-05-31 15:32:28 +00:00
return $this -> execute ( " TRUNCATE TABLE { " . $table . " } " );
}
2010-11-18 06:00:51 +00:00
list ( $select , $params ) = $this -> where_clause ( $table , $conditions );
2008-05-15 21:40:00 +00:00
return $this -> delete_records_select ( $table , $select , $params );
}
2008-12-15 02:13:11 +00:00
/**
* Delete the records from a table where one field match one list of values .
*
* @ param string $table the table to delete from .
* @ param string $field The field to search
2010-08-22 19:32:37 +00:00
* @ param array $values array of values
2008-12-15 02:13:11 +00:00
* @ return bool true .
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-12-15 02:13:11 +00:00
*/
2008-12-15 21:41:09 +00:00
public function delete_records_list ( $table , $field , array $values ) {
2008-12-15 02:13:11 +00:00
list ( $select , $params ) = $this -> where_clause_list ( $field , $values );
if ( empty ( $select )) {
// nothing to delete
2008-12-15 21:41:09 +00:00
return true ;
2008-12-15 02:13:11 +00:00
}
return $this -> delete_records_select ( $table , $select , $params );
}
2008-05-15 21:40:00 +00:00
/**
2008-07-25 17:51:37 +00:00
* Delete one or more records from a table which match a particular WHERE clause .
2008-05-15 21:40:00 +00:00
*
* @ param string $table The database table to be checked against .
* @ param string $select A fragment of SQL to be used in a where clause in the SQL call ( used to define the selection criteria ) .
* @ param array $params array of sql parameters
2008-11-21 20:09:13 +00:00
* @ return bool true .
2012-01-19 10:15:11 +08:00
* @ throws dml_exception A DML specific exception is thrown for any errors .
2008-05-15 21:40:00 +00:00
*/
public abstract function delete_records_select ( $table , $select , array $params = null );
2010-05-21 18:18:42 +00:00
/// sql constructs
2008-11-22 19:32:16 +00:00
/**
* Returns the FROM clause required by some DBs in all SELECT statements .
*
* To be used in queries not having FROM clause to provide cross_db
* Most DBs don 't need it, hence the default is ' '
2010-08-22 19:26:48 +00:00
* @ return string
2008-11-22 19:32:16 +00:00
*/
public function sql_null_from_clause () {
return '' ;
}
2008-05-15 21:40:00 +00:00
/**
* Returns the SQL text to be used in order to perform one bitwise AND operation
* between 2 integers .
2009-01-07 18:55:32 +00:00
*
* NOTE : The SQL result is a number and can not be used directly in
* SQL condition , please compare it to some number to get a bool !!
*
2012-01-19 10:15:11 +08:00
* @ param int $int1 First integer in the operation .
* @ param int $int2 Second integer in the operation .
* @ return string The piece of SQL code to be used in your statement .
2008-05-15 21:40:00 +00:00
*/
public function sql_bitand ( $int1 , $int2 ) {
return '((' . $int1 . ') & (' . $int2 . '))' ;
}
/**
* Returns the SQL text to be used in order to perform one bitwise NOT operation
* with 1 integer .
2008-07-25 23:31:08 +00:00
*
2012-01-19 10:15:11 +08:00
* @ param int $int1 The operand integer in the operation .
* @ return string The piece of SQL code to be used in your statement .
2008-05-15 21:40:00 +00:00
*/
public function sql_bitnot ( $int1 ) {
return '(~(' . $int1 . '))' ;
}
/**
* Returns the SQL text to be used in order to perform one bitwise OR operation
* between 2 integers .
2008-07-25 23:31:08 +00:00
*
2009-01-07 18:55:32 +00:00
* NOTE : The SQL result is a number and can not be used directly in
* SQL condition , please compare it to some number to get a bool !!
*
2012-01-19 10:15:11 +08:00
* @ param int $int1 The first operand integer in the operation .
* @ param int $int2 The second operand integer in the operation .
* @ return string The piece of SQL code to be used in your statement .
2008-05-15 21:40:00 +00:00
*/
public function sql_bitor ( $int1 , $int2 ) {
return '((' . $int1 . ') | (' . $int2 . '))' ;
}
/**
* Returns the SQL text to be used in order to perform one bitwise XOR operation
* between 2 integers .
2008-07-25 23:31:08 +00:00
*
2009-01-07 18:55:32 +00:00
* NOTE : The SQL result is a number and can not be used directly in
* SQL condition , please compare it to some number to get a bool !!
*
2012-01-19 10:15:11 +08:00
* @ param int $int1 The first operand integer in the operation .
* @ param int $int2 The second operand integer in the operation .
* @ return string The piece of SQL code to be used in your statement .
2008-05-15 21:40:00 +00:00
*/
public function sql_bitxor ( $int1 , $int2 ) {
return '((' . $int1 . ') ^ (' . $int2 . '))' ;
}
2008-11-26 08:19:45 +00:00
/**
* Returns the SQL text to be used in order to perform module '%'
2010-05-21 18:18:42 +00:00
* operation - remainder after division
2008-11-26 08:19:45 +00:00
*
2012-01-19 10:15:11 +08:00
* @ param int $int1 The first operand integer in the operation .
* @ param int $int2 The second operand integer in the operation .
* @ return string The piece of SQL code to be used in your statement .
2008-11-26 08:19:45 +00:00
*/
public function sql_modulo ( $int1 , $int2 ) {
return '((' . $int1 . ') % (' . $int2 . '))' ;
}
2008-06-28 18:25:25 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns the cross db correct CEIL ( ceiling ) expression applied to fieldname .
* note : Most DBs use CEIL (), hence it ' s the default here .
2008-07-25 23:31:08 +00:00
*
2012-01-19 10:15:11 +08:00
* @ param string $fieldname The field ( or expression ) we are going to ceil .
* @ return string The piece of SQL code to be used in your ceiling statement .
2008-06-28 18:25:25 +00:00
*/
public function sql_ceil ( $fieldname ) {
return ' CEIL(' . $fieldname . ')' ;
}
2008-05-15 21:40:00 +00:00
/**
* Returns the SQL to be used in order to CAST one CHAR column to INTEGER .
*
* Be aware that the CHAR column you ' re trying to cast contains really
* int values or the RDBMS will throw an error !
*
2012-01-19 10:15:11 +08:00
* @ param string $fieldname The name of the field to be casted .
* @ param bool $text Specifies if the original column is one TEXT ( CLOB ) column ( true ) . Defaults to false .
* @ return string The piece of SQL code to be used in your statement .
2008-05-15 21:40:00 +00:00
*/
public function sql_cast_char2int ( $fieldname , $text = false ) {
return ' ' . $fieldname . ' ' ;
}
2008-05-31 14:35:58 +00:00
/**
* Returns the SQL to be used in order to CAST one CHAR column to REAL number .
*
* Be aware that the CHAR column you ' re trying to cast contains really
* numbers or the RDBMS will throw an error !
*
2012-01-19 10:15:11 +08:00
* @ param string $fieldname The name of the field to be casted .
* @ param bool $text Specifies if the original column is one TEXT ( CLOB ) column ( true ) . Defaults to false .
* @ return string The piece of SQL code to be used in your statement .
2008-05-31 14:35:58 +00:00
*/
public function sql_cast_char2real ( $fieldname , $text = false ) {
return ' ' . $fieldname . ' ' ;
}
2009-04-10 09:33:26 +00:00
/**
* Returns the SQL to be used in order to an UNSIGNED INTEGER column to SIGNED .
*
* ( Only MySQL needs this . MySQL things that 1 * - 1 = 18446744073709551615
* if the 1 comes from an unsigned column ) .
*
2012-01-22 18:01:16 +01:00
* @ deprecated since 2.3
2012-01-19 10:15:11 +08:00
* @ param string $fieldname The name of the field to be cast
* @ return string The piece of SQL code to be used in your statement .
2009-04-10 09:33:26 +00:00
*/
public function sql_cast_2signed ( $fieldname ) {
return ' ' . $fieldname . ' ' ;
}
2008-05-15 21:40:00 +00:00
/**
* Returns the SQL text to be used to compare one TEXT ( clob ) column with
* one varchar column , because some RDBMS doesn ' t support such direct
* comparisons .
2008-07-25 23:31:08 +00:00
*
2012-01-19 10:15:11 +08:00
* @ param string $fieldname The name of the TEXT field we need to order by
* @ param int $numchars Number of chars to use for the ordering ( defaults to 32 ) .
* @ return string The piece of SQL code to be used in your statement .
2008-05-15 21:40:00 +00:00
*/
public function sql_compare_text ( $fieldname , $numchars = 32 ) {
return $this -> sql_order_by_text ( $fieldname , $numchars );
}
2010-08-24 21:50:53 +00:00
/**
* Returns 'LIKE' part of a query .
*
2012-01-19 10:15:11 +08:00
* @ param string $fieldname Usually the name of the table column .
* @ param string $param Usually the bound query parameter ( ? , : named ) .
* @ param bool $casesensitive Use case sensitive search when set to true ( default ) .
* @ param bool $accentsensitive Use accent sensitive search when set to true ( default ) . ( not all databases support accent insensitive )
* @ param bool $notlike True means " NOT LIKE " .
* @ param string $escapechar The escape char for '%' and '_' .
* @ return string The SQL code fragment .
2010-08-24 21:50:53 +00:00
*/
2010-09-04 14:39:01 +00:00
public function sql_like ( $fieldname , $param , $casesensitive = true , $accentsensitive = true , $notlike = false , $escapechar = '\\' ) {
2010-08-24 21:50:53 +00:00
if ( strpos ( $param , '%' ) !== false ) {
2010-09-04 14:23:50 +00:00
debugging ( 'Potential SQL injection detected, sql_like() expects bound parameters (? or :named)' );
2010-08-24 21:50:53 +00:00
}
2010-09-04 14:39:01 +00:00
$LIKE = $notlike ? 'NOT LIKE' : 'LIKE' ;
2010-08-24 21:50:53 +00:00
// by default ignore any sensitiveness - each database does it in a different way
2010-09-04 14:39:01 +00:00
return " $fieldname $LIKE $param ESCAPE ' $escapechar ' " ;
2010-08-24 21:50:53 +00:00
}
/**
2012-01-19 10:15:11 +08:00
* Escape sql LIKE special characters like '_' or '%' .
* @ param string $text The string containing characters needing escaping .
* @ param string $escapechar The desired escape character , defaults to '\\' .
* @ return string The escaped sql LIKE string .
2010-08-24 21:50:53 +00:00
*/
public function sql_like_escape ( $text , $escapechar = '\\' ) {
$text = str_replace ( '_' , $escapechar . '_' , $text );
$text = str_replace ( '%' , $escapechar . '%' , $text );
return $text ;
}
2008-11-22 19:32:16 +00:00
/**
* Returns the proper SQL to do LIKE in a case - insensitive way .
*
* Note the LIKE are case sensitive for Oracle . Oracle 10 g is required to use
2010-05-21 18:18:42 +00:00
* the case insensitive search using regexp_like () or NLS_COMP = LINGUISTIC :- (
2008-11-22 19:32:16 +00:00
* See http :// docs . moodle . org / en / XMLDB_Problems #Case-insensitive_searches
*
2012-01-19 10:15:11 +08:00
* @ deprecated since Moodle 2.0 MDL - 23925 - please do not use this function any more .
* @ todo MDL - 31280 to remove deprecated functions prior to 2.3 release .
2012-02-16 10:29:45 +08:00
* @ return string Do not use this function !
* @ see sql_like ()
2008-11-22 19:32:16 +00:00
*/
public function sql_ilike () {
2010-09-04 14:23:50 +00:00
debugging ( 'sql_ilike() is deprecated, please use sql_like() instead' );
2008-11-22 19:32:16 +00:00
return 'LIKE' ;
}
2008-05-15 21:40:00 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns the proper SQL to do CONCAT between the elements ( fieldnames ) passed .
2008-05-15 21:40:00 +00:00
*
2010-08-22 19:32:37 +00:00
* This function accepts variable number of string parameters .
2012-01-19 10:15:11 +08:00
* All strings / fieldnames will used in the SQL concatenate statement generated .
2010-08-22 19:32:37 +00:00
*
2012-02-07 10:58:55 +08:00
* @ return string The SQL to concatenate strings passed in .
* @ uses func_get_args () and thus parameters are unlimited OPTIONAL number of additional field names .
2008-05-15 21:40:00 +00:00
*/
public abstract function sql_concat ();
/**
* Returns the proper SQL to do CONCAT between the elements passed
* with a given separator
*
2012-01-19 10:15:11 +08:00
* @ param string $separator The separator desired for the SQL concatenating $elements .
* @ param array $elements The array of strings to be concatenated .
* @ return string The SQL to concatenate the strings .
2008-05-15 21:40:00 +00:00
*/
public abstract function sql_concat_join ( $separator = " ' ' " , $elements = array ());
/**
* Returns the proper SQL ( for the dbms in use ) to concatenate $firstname and $lastname
*
2012-01-19 10:15:11 +08:00
* @ todo MDL - 31233 This may not be needed here .
*
* @ param string $first User 's first name (default:' firstname ' ) .
* @ param string $last User 's last name (default:' lastname ' ) .
* @ return string The SQL to concatenate strings .
2008-05-15 21:40:00 +00:00
*/
function sql_fullname ( $first = 'firstname' , $last = 'lastname' ) {
return $this -> sql_concat ( $first , " ' ' " , $last );
}
/**
* Returns the SQL text to be used to order by one TEXT ( clob ) column , because
* some RDBMS doesn ' t support direct ordering of such fields .
2008-07-25 23:31:08 +00:00
*
2008-05-15 21:40:00 +00:00
* Note that the use or queries being ordered by TEXT columns must be minimised ,
* because it ' s really slooooooow .
2010-08-22 19:32:37 +00:00
*
2012-01-19 10:15:11 +08:00
* @ param string $fieldname The name of the TEXT field we need to order by .
* @ param string $numchars The number of chars to use for the ordering ( defaults to 32 ) .
* @ return string The piece of SQL code to be used in your statement .
2008-05-15 21:40:00 +00:00
*/
public function sql_order_by_text ( $fieldname , $numchars = 32 ) {
return $fieldname ;
}
2009-02-15 23:17:56 +00:00
/**
* Returns the SQL text to be used to calculate the length in characters of one expression .
2012-01-19 10:15:11 +08:00
* @ param string $fieldname The fieldname / expression to calculate its length in characters .
2009-02-15 23:17:56 +00:00
* @ return string the piece of SQL code to be used in the statement .
*/
public function sql_length ( $fieldname ) {
return ' LENGTH(' . $fieldname . ')' ;
}
2008-05-15 21:40:00 +00:00
/**
2009-10-09 10:02:39 +00:00
* Returns the proper substr () SQL text used to extract substrings from DB
2008-10-28 15:11:10 +00:00
* NOTE : this was originally returning only function name
2008-07-25 23:31:08 +00:00
*
2012-01-19 10:15:11 +08:00
* @ param string $expr Some string field , no aggregates .
* @ param mixed $start Integer or expression evaluating to integer ( 1 based value ; first char has index 1 )
* @ param mixed $length Optional integer or expression evaluating to integer .
* @ return string The sql substring extraction fragment .
2008-05-15 21:40:00 +00:00
*/
2008-10-28 15:11:10 +00:00
public function sql_substr ( $expr , $start , $length = false ) {
if ( count ( func_get_args ()) < 2 ) {
2010-05-21 18:18:42 +00:00
throw new coding_exception ( 'moodle_database::sql_substr() requires at least two parameters' , 'Originally this function was only returning name of SQL substring function, it now requires all parameters.' );
2008-10-28 15:11:10 +00:00
}
if ( $length === false ) {
2008-10-28 17:57:51 +00:00
return " SUBSTR( $expr , $start ) " ;
2008-10-28 15:11:10 +00:00
} else {
return " SUBSTR( $expr , $start , $length ) " ;
}
}
2008-05-15 21:40:00 +00:00
2008-08-20 06:51:46 +00:00
/**
* Returns the SQL for returning searching one string for the location of another .
2012-01-19 10:15:11 +08:00
*
2008-08-25 12:52:49 +00:00
* Note , there is no guarantee which order $needle , $haystack will be in
2012-01-19 10:15:11 +08:00
* the resulting SQL so when using this method , and both arguments contain
2008-08-20 06:51:46 +00:00
* placeholders , you should use named placeholders .
2012-01-19 10:15:11 +08:00
*
2008-08-20 06:51:46 +00:00
* @ param string $needle the SQL expression that will be searched for .
* @ param string $haystack the SQL expression that will be searched in .
2012-01-19 10:15:11 +08:00
* @ return string The required searching SQL part .
2008-08-20 06:51:46 +00:00
*/
public function sql_position ( $needle , $haystack ) {
// Implementation using standard SQL.
return " POSITION(( $needle ) IN ( $haystack )) " ;
}
2008-05-15 21:40:00 +00:00
/**
* Returns the empty string char used by every supported DB . To be used when
* we are searching for that values in our queries . Only Oracle uses this
* for now ( will be out , once we migrate to proper NULLs if that days arrives )
2012-01-19 10:15:11 +08:00
* @ return string An empty string .
2008-05-15 21:40:00 +00:00
*/
function sql_empty () {
return '' ;
}
/**
* Returns the proper SQL to know if one field is empty .
*
* Note that the function behavior strongly relies on the
* parameters passed describing the field so , please , be accurate
2010-05-21 18:18:42 +00:00
* when specifying them .
2008-05-15 21:40:00 +00:00
*
* Also , note that this function is not suitable to look for
* fields having NULL contents at all . It ' s all for empty values !
*
2010-05-21 18:18:42 +00:00
* This function should be applied in all the places where conditions of
2008-05-15 21:40:00 +00:00
* the type :
*
* ... AND fieldname = '' ;
*
* are being used . Final result should be :
*
* ... AND ' . sql_isempty(' tablename ', ' fieldname ' , true / false , true / false );
*
* ( see parameters description below )
*
2012-01-19 10:15:11 +08:00
* @ param string $tablename Name of the table ( without prefix ) . Not used for now but can be
2008-05-15 21:40:00 +00:00
* necessary in the future if we want to use some introspection using
* meta information against the DB . /// TODO ///
2012-01-19 10:15:11 +08:00
* @ param string $fieldname Name of the field we are going to check
* @ param bool $nullablefield For specifying if the field is nullable ( true ) or no ( false ) in the DB .
* @ param bool $textfield For specifying if it is a text ( also called clob ) field ( true ) or a varchar one ( false )
2008-05-15 21:40:00 +00:00
* @ return string the sql code to be added to check for empty values
*/
public function sql_isempty ( $tablename , $fieldname , $nullablefield , $textfield ) {
2010-01-07 14:59:54 +00:00
return " ( $fieldname = '') " ;
2008-05-15 21:40:00 +00:00
}
/**
* Returns the proper SQL to know if one field is not empty .
*
* Note that the function behavior strongly relies on the
* parameters passed describing the field so , please , be accurate
2010-05-21 18:18:42 +00:00
* when specifying them .
2008-05-15 21:40:00 +00:00
*
* This function should be applied in all the places where conditions of
* the type :
*
* ... AND fieldname != '' ;
*
* are being used . Final result should be :
*
* ... AND ' . sql_isnotempty(' tablename ', ' fieldname ' , true / false , true / false );
*
* ( see parameters description below )
*
2012-01-19 10:15:11 +08:00
* @ param string $tablename Name of the table ( without prefix ) . This is not used for now but can be
2008-05-15 21:40:00 +00:00
* necessary in the future if we want to use some introspection using
2012-01-19 10:15:11 +08:00
* meta information against the DB .
* @ param string $fieldname The name of the field we are going to check .
* @ param bool $nullablefield Specifies if the field is nullable ( true ) or not ( false ) in the DB .
* @ param bool $textfield Specifies if it is a text ( also called clob ) field ( true ) or a varchar one ( false ) .
* @ return string The sql code to be added to check for non empty values .
2008-05-15 21:40:00 +00:00
*/
public function sql_isnotempty ( $tablename , $fieldname , $nullablefield , $textfield ) {
return ' ( NOT ' . $this -> sql_isempty ( $tablename , $fieldname , $nullablefield , $textfield ) . ') ' ;
}
2008-05-25 20:43:46 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns true if this database driver supports regex syntax when searching .
* @ return bool True if supported .
2008-05-25 20:43:46 +00:00
*/
public function sql_regex_supported () {
return false ;
}
/**
2012-01-19 10:15:11 +08:00
* Returns the driver specific syntax ( SQL part ) for matching regex positively or negatively ( inverted matching ) .
* Eg : 'REGEXP' : 'NOT REGEXP' or '~*' : '!~*'
2008-05-25 20:43:46 +00:00
* @ param bool $positivematch
* @ return string or empty if not supported
*/
public function sql_regex ( $positivematch = true ) {
return '' ;
}
2008-05-15 21:40:00 +00:00
/// transactions
2009-11-07 08:52:56 +00:00
/**
2012-01-19 10:15:11 +08:00
* Checks and returns true if transactions are supported .
*
2009-11-07 08:52:56 +00:00
* It is not responsible to run productions servers
* on databases without transaction support ; - )
*
* Override in driver if needed .
*
* @ return bool
*/
protected function transactions_supported () {
// protected for now, this might be changed to public if really necessary
return true ;
}
2009-06-13 10:16:29 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns true if a transaction is in progress .
2009-06-13 10:16:29 +00:00
* @ return bool
*/
2009-11-07 08:52:56 +00:00
public function is_transaction_started () {
return ! empty ( $this -> transactions );
}
/**
2012-01-19 10:15:11 +08:00
* This is a test that throws an exception if transaction in progress .
2009-11-07 08:52:56 +00:00
* This test does not force rollback of active transactions .
* @ return void
*/
public function transactions_forbidden () {
if ( $this -> is_transaction_started ()) {
throw new dml_transaction_exception ( 'This code can not be excecuted in transaction' );
}
2009-06-13 10:16:29 +00:00
}
2008-05-15 21:40:00 +00:00
/**
2009-11-07 08:52:56 +00:00
* On DBs that support it , switch to transaction mode and begin a transaction
2010-06-16 10:13:41 +00:00
* you ' ll need to ensure you call allow_commit () on the returned object
* or your changes * will * be lost .
2008-05-15 21:40:00 +00:00
*
* this is _very_ useful for massive updates
2009-06-12 07:55:44 +00:00
*
2009-11-07 08:52:56 +00:00
* Delegated database transactions can be nested , but only one actual database
* transaction is used for the outer - most delegated transaction . This method
* returns a transaction object which you should keep until the end of the
* delegated transaction . The actual database transaction will
* only be committed if all the nested delegated transactions commit
* successfully . If any part of the transaction rolls back then the whole
* thing is rolled back .
*
* @ return moodle_transaction
*/
public function start_delegated_transaction () {
$transaction = new moodle_transaction ( $this );
$this -> transactions [] = $transaction ;
if ( count ( $this -> transactions ) == 1 ) {
$this -> begin_transaction ();
}
return $transaction ;
}
/**
* Driver specific start of real database transaction ,
* this can not be used directly in code .
* @ return void
2008-05-15 21:40:00 +00:00
*/
2009-11-07 08:52:56 +00:00
protected abstract function begin_transaction ();
/**
* Indicates delegated transaction finished successfully .
* The real database transaction is committed only if
* all delegated transactions committed .
* @ return void
2012-01-19 10:15:11 +08:00
* @ throws dml_transaction_exception Creates and throws transaction related exceptions .
2009-11-07 08:52:56 +00:00
*/
public function commit_delegated_transaction ( moodle_transaction $transaction ) {
if ( $transaction -> is_disposed ()) {
throw new dml_transaction_exception ( 'Transactions already disposed' , $transaction );
2009-06-12 07:55:44 +00:00
}
2009-11-07 08:52:56 +00:00
// mark as disposed so that it can not be used again
$transaction -> dispose ();
if ( empty ( $this -> transactions )) {
throw new dml_transaction_exception ( 'Transaction not started' , $transaction );
}
if ( $this -> force_rollback ) {
throw new dml_transaction_exception ( 'Tried to commit transaction after lower level rollback' , $transaction );
}
if ( $transaction !== $this -> transactions [ count ( $this -> transactions ) - 1 ]) {
// one incorrect commit at any level rollbacks everything
$this -> force_rollback = true ;
throw new dml_transaction_exception ( 'Invalid transaction commit attempt' , $transaction );
}
if ( count ( $this -> transactions ) == 1 ) {
// only commit the top most level
$this -> commit_transaction ();
}
array_pop ( $this -> transactions );
2008-05-15 21:40:00 +00:00
}
/**
2009-11-07 08:52:56 +00:00
* Driver specific commit of real database transaction ,
* this can not be used directly in code .
* @ return void
2008-05-15 21:40:00 +00:00
*/
2009-11-07 08:52:56 +00:00
protected abstract function commit_transaction ();
/**
* Call when delegated transaction failed , this rolls back
* all delegated transactions up to the top most level .
*
* In many cases you do not need to call this method manually ,
* because all open delegated transactions are rolled back
2010-05-21 18:18:42 +00:00
* automatically if exceptions not caught .
2009-11-07 08:52:56 +00:00
*
2012-01-19 10:15:11 +08:00
* @ param moodle_transaction $transaction An instance of a moodle_transaction .
* @ param Exception $e The related exception to this transaction rollback .
* @ return void This does not return , instead the exception passed in will be rethrown .
2009-11-07 08:52:56 +00:00
*/
public function rollback_delegated_transaction ( moodle_transaction $transaction , Exception $e ) {
if ( $transaction -> is_disposed ()) {
throw new dml_transaction_exception ( 'Transactions already disposed' , $transaction );
2009-06-12 07:55:44 +00:00
}
2009-11-07 08:52:56 +00:00
// mark as disposed so that it can not be used again
$transaction -> dispose ();
// one rollback at any level rollbacks everything
$this -> force_rollback = true ;
if ( empty ( $this -> transactions ) or $transaction !== $this -> transactions [ count ( $this -> transactions ) - 1 ]) {
// this may or may not be a coding problem, better just rethrow the exception,
// because we do not want to loose the original $e
throw $e ;
}
if ( count ( $this -> transactions ) == 1 ) {
// only rollback the top most level
$this -> rollback_transaction ();
}
array_pop ( $this -> transactions );
if ( empty ( $this -> transactions )) {
// finally top most level rolled back
$this -> force_rollback = false ;
}
throw $e ;
2008-05-15 21:40:00 +00:00
}
/**
2010-05-21 18:18:42 +00:00
* Driver specific abort of real database transaction ,
2009-11-07 08:52:56 +00:00
* this can not be used directly in code .
* @ return void
2008-05-15 21:40:00 +00:00
*/
2009-11-07 08:52:56 +00:00
protected abstract function rollback_transaction ();
/**
2010-05-21 18:18:42 +00:00
* Force rollback of all delegated transaction .
2012-01-19 10:15:11 +08:00
* Does not throw any exceptions and does not log anything .
2009-11-07 08:52:56 +00:00
*
* This method should be used only from default exception handlers and other
* core code .
*
* @ return void
*/
public function force_transaction_rollback () {
if ( $this -> transactions ) {
try {
$this -> rollback_transaction ();
} catch ( dml_exception $e ) {
// ignore any sql errors here, the connection might be broken
}
2009-06-12 07:55:44 +00:00
}
2009-11-07 08:52:56 +00:00
// now enable transactions again
$this -> transactions = array (); // unfortunately all unfinished exceptions are kept in memory
$this -> force_rollback = false ;
2008-05-15 21:40:00 +00:00
}
2008-06-16 21:01:54 +00:00
2009-01-16 23:02:24 +00:00
/// session locking
2009-06-12 08:27:19 +00:00
/**
* Is session lock supported in this driver ?
* @ return bool
*/
2009-01-17 14:31:29 +00:00
public function session_lock_supported () {
return false ;
}
2009-06-12 08:27:19 +00:00
/**
2012-01-19 10:15:11 +08:00
* Obtains the session lock .
* @ param int $rowid The id of the row with session record .
* @ param int $timeout The maximum allowed time to wait for the lock in seconds .
* @ return void
* @ throws dml_exception A DML specific exception is thrown for any errors .
2009-06-12 08:27:19 +00:00
*/
2011-11-06 17:10:23 +01:00
public function get_session_lock ( $rowid , $timeout ) {
2009-01-17 14:31:29 +00:00
$this -> used_for_db_sessions = true ;
2009-01-16 23:02:24 +00:00
}
2009-06-12 08:27:19 +00:00
/**
2012-01-19 10:15:11 +08:00
* Releases the session lock .
* @ param int $rowid The id of the row with session record .
* @ return void
* @ throws dml_exception A DML specific exception is thrown for any errors .
2009-06-12 08:27:19 +00:00
*/
2009-01-17 12:12:48 +00:00
public function release_session_lock ( $rowid ) {
2009-01-16 23:02:24 +00:00
}
2008-06-18 08:26:41 +00:00
/// performance and logging
2008-06-18 08:26:40 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns the number of reads done by this database .
* @ return int Number of reads .
2008-06-18 08:26:40 +00:00
*/
2008-06-16 21:01:54 +00:00
public function perf_get_reads () {
return $this -> reads ;
}
2008-06-18 08:26:40 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns the number of writes done by this database .
* @ return int Number of writes .
2008-06-18 08:26:40 +00:00
*/
2008-06-16 21:01:54 +00:00
public function perf_get_writes () {
return $this -> writes ;
}
2008-06-18 08:26:40 +00:00
/**
2012-01-19 10:15:11 +08:00
* Returns the number of queries done by this database .
* @ return int Number of queries .
2008-06-18 08:26:40 +00:00
*/
public function perf_get_queries () {
return $this -> writes + $this -> reads ;
}
2008-05-15 21:40:00 +00:00
}