PageRenderTime 70ms CodeModel.GetById 39ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/database/classes/kohana/database/mysql.php

https://github.com/drslice/regform
PHP | 381 lines | 277 code | 50 blank | 54 comment | 24 complexity | 2762910c0ae439c22079a3dae551705b MD5 | raw file
  1. <?php defined('SYSPATH') or die('No direct script access.');
  2. /**
  3. * MySQL database connection.
  4. *
  5. * @package Kohana/Database
  6. * @category Drivers
  7. * @author Kohana Team
  8. * @copyright (c) 2008-2009 Kohana Team
  9. * @license http://kohanaphp.com/license
  10. */
  11. class Kohana_Database_MySQL extends Database {
  12. // Database in use by each connection
  13. protected static $_current_databases = array();
  14. // Use SET NAMES to set the character set
  15. protected static $_set_names;
  16. // Identifier for this connection within the PHP driver
  17. protected $_connection_id;
  18. // MySQL uses a backtick for identifiers
  19. protected $_identifier = '`';
  20. public function connect()
  21. {
  22. if ($this->_connection)
  23. return;
  24. if (Database_MySQL::$_set_names === NULL)
  25. {
  26. // Determine if we can use mysql_set_charset(), which is only
  27. // available on PHP 5.2.3+ when compiled against MySQL 5.0+
  28. Database_MySQL::$_set_names = ! function_exists('mysql_set_charset');
  29. }
  30. // Extract the connection parameters, adding required variabels
  31. extract($this->_config['connection'] + array(
  32. 'database' => '',
  33. 'hostname' => '',
  34. 'username' => '',
  35. 'password' => '',
  36. 'persistent' => FALSE,
  37. ));
  38. // Prevent this information from showing up in traces
  39. unset($this->_config['connection']['username'], $this->_config['connection']['password']);
  40. try
  41. {
  42. if ($persistent)
  43. {
  44. // Create a persistent connection
  45. $this->_connection = mysql_pconnect($hostname, $username, $password);
  46. }
  47. else
  48. {
  49. // Create a connection and force it to be a new link
  50. $this->_connection = mysql_connect($hostname, $username, $password, TRUE);
  51. }
  52. }
  53. catch (ErrorException $e)
  54. {
  55. // No connection exists
  56. $this->_connection = NULL;
  57. throw new Database_Exception(':error',
  58. array(':error' => mysql_error()),
  59. mysql_errno());
  60. }
  61. // \xFF is a better delimiter, but the PHP driver uses underscore
  62. $this->_connection_id = sha1($hostname.'_'.$username.'_'.$password);
  63. $this->_select_db($database);
  64. if ( ! empty($this->_config['charset']))
  65. {
  66. // Set the character set
  67. $this->set_charset($this->_config['charset']);
  68. }
  69. }
  70. /**
  71. * Select the database
  72. *
  73. * @param string Database
  74. * @return void
  75. */
  76. protected function _select_db($database)
  77. {
  78. if ( ! mysql_select_db($database, $this->_connection))
  79. {
  80. // Unable to select database
  81. throw new Database_Exception(':error',
  82. array(':error' => mysql_error($this->_connection)),
  83. mysql_errno($this->_connection));
  84. }
  85. Database_MySQL::$_current_databases[$this->_connection_id] = $database;
  86. }
  87. public function disconnect()
  88. {
  89. try
  90. {
  91. // Database is assumed disconnected
  92. $status = TRUE;
  93. if (is_resource($this->_connection))
  94. {
  95. if ($status = mysql_close($this->_connection))
  96. {
  97. // Clear the connection
  98. $this->_connection = NULL;
  99. // Clear the instance
  100. parent::disconnect();
  101. }
  102. }
  103. }
  104. catch (Exception $e)
  105. {
  106. // Database is probably not disconnected
  107. $status = ! is_resource($this->_connection);
  108. }
  109. return $status;
  110. }
  111. public function set_charset($charset)
  112. {
  113. // Make sure the database is connected
  114. $this->_connection or $this->connect();
  115. if (Database_MySQL::$_set_names === TRUE)
  116. {
  117. // PHP is compiled against MySQL 4.x
  118. $status = (bool) mysql_query('SET NAMES '.$this->quote($charset), $this->_connection);
  119. }
  120. else
  121. {
  122. // PHP is compiled against MySQL 5.x
  123. $status = mysql_set_charset($charset, $this->_connection);
  124. }
  125. if ($status === FALSE)
  126. {
  127. throw new Database_Exception(':error',
  128. array(':error' => mysql_error($this->_connection)),
  129. mysql_errno($this->_connection));
  130. }
  131. }
  132. public function query($type, $sql, $as_object = FALSE, array $params = NULL)
  133. {
  134. // Make sure the database is connected
  135. $this->_connection or $this->connect();
  136. if ( ! empty($this->_config['profiling']))
  137. {
  138. // Benchmark this query for the current instance
  139. $benchmark = Profiler::start("Database ({$this->_instance})", $sql);
  140. }
  141. if ( ! empty($this->_config['connection']['persistent']) AND $this->_config['connection']['database'] !== Database_MySQL::$_current_databases[$this->_connection_id])
  142. {
  143. // Select database on persistent connections
  144. $this->_select_db($this->_config['connection']['database']);
  145. }
  146. // Execute the query
  147. if (($result = mysql_query($sql, $this->_connection)) === FALSE)
  148. {
  149. if (isset($benchmark))
  150. {
  151. // This benchmark is worthless
  152. Profiler::delete($benchmark);
  153. }
  154. throw new Database_Exception(':error [ :query ]',
  155. array(':error' => mysql_error($this->_connection), ':query' => $sql),
  156. mysql_errno($this->_connection));
  157. }
  158. if (isset($benchmark))
  159. {
  160. Profiler::stop($benchmark);
  161. }
  162. // Set the last query
  163. $this->last_query = $sql;
  164. if ($type === Database::SELECT)
  165. {
  166. // Return an iterator of results
  167. return new Database_MySQL_Result($result, $sql, $as_object, $params);
  168. }
  169. elseif ($type === Database::INSERT)
  170. {
  171. // Return a list of insert id and rows created
  172. return array(
  173. mysql_insert_id($this->_connection),
  174. mysql_affected_rows($this->_connection),
  175. );
  176. }
  177. else
  178. {
  179. // Return the number of rows affected
  180. return mysql_affected_rows($this->_connection);
  181. }
  182. }
  183. public function datatype($type)
  184. {
  185. static $types = array
  186. (
  187. 'blob' => array('type' => 'string', 'binary' => TRUE, 'character_maximum_length' => '65535'),
  188. 'bool' => array('type' => 'bool'),
  189. 'bigint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '18446744073709551615'),
  190. 'datetime' => array('type' => 'string'),
  191. 'decimal unsigned' => array('type' => 'float', 'exact' => TRUE, 'min' => '0'),
  192. 'double' => array('type' => 'float'),
  193. 'double precision unsigned' => array('type' => 'float', 'min' => '0'),
  194. 'double unsigned' => array('type' => 'float', 'min' => '0'),
  195. 'enum' => array('type' => 'string'),
  196. 'fixed' => array('type' => 'float', 'exact' => TRUE),
  197. 'fixed unsigned' => array('type' => 'float', 'exact' => TRUE, 'min' => '0'),
  198. 'float unsigned' => array('type' => 'float', 'min' => '0'),
  199. 'int unsigned' => array('type' => 'int', 'min' => '0', 'max' => '4294967295'),
  200. 'integer unsigned' => array('type' => 'int', 'min' => '0', 'max' => '4294967295'),
  201. 'longblob' => array('type' => 'string', 'binary' => TRUE, 'character_maximum_length' => '4294967295'),
  202. 'longtext' => array('type' => 'string', 'character_maximum_length' => '4294967295'),
  203. 'mediumblob' => array('type' => 'string', 'binary' => TRUE, 'character_maximum_length' => '16777215'),
  204. 'mediumint' => array('type' => 'int', 'min' => '-8388608', 'max' => '8388607'),
  205. 'mediumint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '16777215'),
  206. 'mediumtext' => array('type' => 'string', 'character_maximum_length' => '16777215'),
  207. 'national varchar' => array('type' => 'string'),
  208. 'numeric unsigned' => array('type' => 'float', 'exact' => TRUE, 'min' => '0'),
  209. 'nvarchar' => array('type' => 'string'),
  210. 'point' => array('type' => 'string', 'binary' => TRUE),
  211. 'real unsigned' => array('type' => 'float', 'min' => '0'),
  212. 'set' => array('type' => 'string'),
  213. 'smallint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '65535'),
  214. 'text' => array('type' => 'string', 'character_maximum_length' => '65535'),
  215. 'tinyblob' => array('type' => 'string', 'binary' => TRUE, 'character_maximum_length' => '255'),
  216. 'tinyint' => array('type' => 'int', 'min' => '-128', 'max' => '127'),
  217. 'tinyint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '255'),
  218. 'tinytext' => array('type' => 'string', 'character_maximum_length' => '255'),
  219. 'year' => array('type' => 'string'),
  220. );
  221. $type = str_replace(' zerofill', '', $type);
  222. if (isset($types[$type]))
  223. return $types[$type];
  224. return parent::datatype($type);
  225. }
  226. public function list_tables($like = NULL)
  227. {
  228. if (is_string($like))
  229. {
  230. // Search for table names
  231. $result = $this->query(Database::SELECT, 'SHOW TABLES LIKE '.$this->quote($like), FALSE);
  232. }
  233. else
  234. {
  235. // Find all table names
  236. $result = $this->query(Database::SELECT, 'SHOW TABLES', FALSE);
  237. }
  238. $tables = array();
  239. foreach ($result as $row)
  240. {
  241. $tables[] = reset($row);
  242. }
  243. return $tables;
  244. }
  245. public function list_columns($table, $like = NULL, $add_prefix = TRUE)
  246. {
  247. // Quote the table name
  248. $table = ($add_prefix === TRUE) ? $this->quote_table($table) : $table;
  249. if (is_string($like))
  250. {
  251. // Search for column names
  252. $result = $this->query(Database::SELECT, 'SHOW FULL COLUMNS FROM '.$table.' LIKE '.$this->quote($like), FALSE);
  253. }
  254. else
  255. {
  256. // Find all column names
  257. $result = $this->query(Database::SELECT, 'SHOW FULL COLUMNS FROM '.$table, FALSE);
  258. }
  259. $count = 0;
  260. $columns = array();
  261. foreach ($result as $row)
  262. {
  263. list($type, $length) = $this->_parse_type($row['Type']);
  264. $column = $this->datatype($type);
  265. $column['column_name'] = $row['Field'];
  266. $column['column_default'] = $row['Default'];
  267. $column['data_type'] = $type;
  268. $column['is_nullable'] = ($row['Null'] == 'YES');
  269. $column['ordinal_position'] = ++$count;
  270. switch ($column['type'])
  271. {
  272. case 'float':
  273. if (isset($length))
  274. {
  275. list($column['numeric_precision'], $column['numeric_scale']) = explode(',', $length);
  276. }
  277. break;
  278. case 'int':
  279. if (isset($length))
  280. {
  281. // MySQL attribute
  282. $column['display'] = $length;
  283. }
  284. break;
  285. case 'string':
  286. switch ($column['data_type'])
  287. {
  288. case 'binary':
  289. case 'varbinary':
  290. $column['character_maximum_length'] = $length;
  291. break;
  292. case 'char':
  293. case 'varchar':
  294. $column['character_maximum_length'] = $length;
  295. case 'text':
  296. case 'tinytext':
  297. case 'mediumtext':
  298. case 'longtext':
  299. $column['collation_name'] = $row['Collation'];
  300. break;
  301. case 'enum':
  302. case 'set':
  303. $column['collation_name'] = $row['Collation'];
  304. $column['options'] = explode('\',\'', substr($length, 1, -1));
  305. break;
  306. }
  307. break;
  308. }
  309. // MySQL attributes
  310. $column['comment'] = $row['Comment'];
  311. $column['extra'] = $row['Extra'];
  312. $column['key'] = $row['Key'];
  313. $column['privileges'] = $row['Privileges'];
  314. $columns[$row['Field']] = $column;
  315. }
  316. return $columns;
  317. }
  318. public function escape($value)
  319. {
  320. // Make sure the database is connected
  321. $this->_connection or $this->connect();
  322. if (($value = mysql_real_escape_string( (string) $value, $this->_connection)) === FALSE)
  323. {
  324. throw new Database_Exception(':error',
  325. array(':error' => mysql_error($this->_connection)),
  326. mysql_errno($this->_connection));
  327. }
  328. // SQL standard is to use single-quotes for all values
  329. return "'$value'";
  330. }
  331. } // End Database_MySQL