PageRenderTime 39ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/fuel/core/classes/database/pdo/connection.php

https://bitbucket.org/codeyash/bootstrap
PHP | 356 lines | 257 code | 45 blank | 54 comment | 21 complexity | 919e247891db1dbf2d6afabb8995774f MD5 | raw file
Possible License(s): MIT, Apache-2.0
  1. <?php
  2. /**
  3. * PDO database connection.
  4. *
  5. * @package Fuel/Database
  6. * @category Drivers
  7. * @author Kohana Team
  8. * @copyright (c) 2008-2009 Kohana Team
  9. * @license http://kohanaphp.com/license
  10. */
  11. namespace Fuel\Core;
  12. class Database_PDO_Connection extends \Database_Connection
  13. {
  14. /**
  15. * @var \PDO Raw server connection
  16. */
  17. protected $_connection;
  18. /**
  19. * @var string PDO uses no quoting by default for identifiers
  20. */
  21. protected $_identifier = '';
  22. /**
  23. * @var bool Allows transactions
  24. */
  25. protected $_in_transaction = false;
  26. /**
  27. * @var string Which kind of DB is used
  28. */
  29. public $_db_type = '';
  30. protected function __construct($name, array $config)
  31. {
  32. parent::__construct($name, $config);
  33. if (isset($this->_config['identifier']))
  34. {
  35. // Allow the identifier to be overloaded per-connection
  36. $this->_identifier = (string) $this->_config['identifier'];
  37. }
  38. }
  39. public function connect()
  40. {
  41. if ($this->_connection)
  42. {
  43. return;
  44. }
  45. // Extract the connection parameters, adding required variabels
  46. extract($this->_config['connection'] + array(
  47. 'dsn' => '',
  48. 'username' => null,
  49. 'password' => null,
  50. 'persistent' => false,
  51. 'compress' => false,
  52. ));
  53. // Clear the connection parameters for security
  54. $this->_config['connection'] = array();
  55. // determine db type
  56. $_dsn_find_collon = strpos($dsn, ':');
  57. $this->_db_type = $_dsn_find_collon ? substr($dsn, 0, $_dsn_find_collon) : null;
  58. // Force PDO to use exceptions for all errors
  59. $attrs = array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION);
  60. if ( ! empty($persistent))
  61. {
  62. // Make the connection persistent
  63. $attrs[\PDO::ATTR_PERSISTENT] = true;
  64. }
  65. if (in_array(strtolower($this->_db_type), array('mysql', 'mysqli')) and $compress)
  66. {
  67. // Use client compression with mysql or mysqli (doesn't work with mysqlnd)
  68. $attrs[\PDO::MYSQL_ATTR_COMPRESS] = true;
  69. }
  70. try
  71. {
  72. // Create a new PDO connection
  73. $this->_connection = new \PDO($dsn, $username, $password, $attrs);
  74. }
  75. catch (\PDOException $e)
  76. {
  77. $error_code = is_numeric($e->getCode()) ? $e->getCode() : 0;
  78. throw new \Database_Exception($e->getMessage(), $error_code, $e);
  79. }
  80. if ( ! empty($this->_config['charset']))
  81. {
  82. // Set Charset for SQL Server connection
  83. if (strtolower($this->driver_name()) == 'sqlsrv')
  84. {
  85. $this->_connection->setAttribute(\PDO::SQLSRV_ATTR_ENCODING, \PDO::SQLSRV_ENCODING_SYSTEM);
  86. }
  87. else
  88. {
  89. // Set the character set
  90. $this->set_charset($this->_config['charset']);
  91. }
  92. }
  93. }
  94. public function disconnect()
  95. {
  96. // Destroy the PDO object
  97. $this->_connection = null;
  98. return true;
  99. }
  100. /**
  101. * Get the current PDO Driver name
  102. * @return string
  103. */
  104. public function driver_name()
  105. {
  106. return $this->_connection->getAttribute(\PDO::ATTR_DRIVER_NAME);
  107. }
  108. public function set_charset($charset)
  109. {
  110. // Make sure the database is connected
  111. $this->_connection or $this->connect();
  112. // Execute a raw SET NAMES query
  113. $this->_connection->exec('SET NAMES '.$this->quote($charset));
  114. }
  115. public function query($type, $sql, $as_object)
  116. {
  117. // Make sure the database is connected
  118. $this->_connection or $this->connect();
  119. if ( ! empty($this->_config['profiling']))
  120. {
  121. // Benchmark this query for the current instance
  122. $benchmark = \Profiler::start("Database ({$this->_instance})", $sql);
  123. }
  124. // run the query. if the connection is lost, try 3 times to reconnect
  125. $attempts = 3;
  126. do
  127. {
  128. try
  129. {
  130. $result = $this->_connection->query($sql);
  131. break;
  132. }
  133. catch (\Exception $e)
  134. {
  135. if (strpos($e->getMessage(), '2006 MySQL') !== false)
  136. {
  137. $this->connect();
  138. }
  139. else
  140. {
  141. if (isset($benchmark))
  142. {
  143. // This benchmark is worthless
  144. \Profiler::delete($benchmark);
  145. }
  146. // Convert the exception in a database exception
  147. $error_code = is_numeric($e->getCode()) ? $e->getCode() : 0;
  148. throw new \Database_Exception($e->getMessage().' with query: "'.$sql.'"', $error_code, $e);
  149. }
  150. }
  151. }
  152. while ($attempts-- > 0);
  153. if (isset($benchmark))
  154. {
  155. \Profiler::stop($benchmark);
  156. }
  157. // Set the last query
  158. $this->last_query = $sql;
  159. if ($type === \DB::SELECT)
  160. {
  161. // Convert the result into an array, as PDOStatement::rowCount is not reliable
  162. if ($as_object === false)
  163. {
  164. $result = $result->fetchAll(\PDO::FETCH_ASSOC);
  165. }
  166. elseif (is_string($as_object))
  167. {
  168. $result = $result->fetchAll(\PDO::FETCH_CLASS, $as_object);
  169. }
  170. else
  171. {
  172. $result = $result->fetchAll(\PDO::FETCH_CLASS, 'stdClass');
  173. }
  174. // Return an iterator of results
  175. return new \Database_Result_Cached($result, $sql, $as_object);
  176. }
  177. elseif ($type === \DB::INSERT)
  178. {
  179. // Return a list of insert id and rows created
  180. return array(
  181. $this->_connection->lastInsertId(),
  182. $result->rowCount(),
  183. );
  184. }
  185. else
  186. {
  187. // Return the number of rows affected
  188. return $result->errorCode() === '00000' ? $result->rowCount() : -1;
  189. }
  190. }
  191. public function list_tables($like = null)
  192. {
  193. throw new \FuelException('Database method '.__METHOD__.' is not supported by '.__CLASS__);
  194. }
  195. public function list_columns($table, $like = null)
  196. {
  197. $this->_connection or $this->connect();
  198. $q = $this->_connection->prepare("DESCRIBE ".$table);
  199. $q->execute();
  200. $result = $q->fetchAll();
  201. $count = 0;
  202. $columns = array();
  203. ! is_null($like) and $like = str_replace('%', '.*', $like);
  204. foreach ($result as $row)
  205. {
  206. if ( ! is_null($like) and ! preg_match('#'.$like.'#', $row['Field'])) continue;
  207. list($type, $length) = $this->_parse_type($row['Type']);
  208. $column = $this->datatype($type);
  209. $column['name'] = $row['Field'];
  210. $column['default'] = $row['Default'];
  211. $column['data_type'] = $type;
  212. $column['null'] = ($row['Null'] == 'YES');
  213. $column['ordinal_position'] = ++$count;
  214. switch ($column['type'])
  215. {
  216. case 'float':
  217. if (isset($length))
  218. {
  219. list($column['numeric_precision'], $column['numeric_scale']) = explode(',', $length);
  220. }
  221. break;
  222. case 'int':
  223. if (isset($length))
  224. {
  225. // MySQL attribute
  226. $column['display'] = $length;
  227. }
  228. break;
  229. case 'string':
  230. switch ($column['data_type'])
  231. {
  232. case 'binary':
  233. case 'varbinary':
  234. $column['character_maximum_length'] = $length;
  235. break;
  236. case 'char':
  237. case 'varchar':
  238. $column['character_maximum_length'] = $length;
  239. case 'text':
  240. case 'tinytext':
  241. case 'mediumtext':
  242. case 'longtext':
  243. $column['collation_name'] = isset($row['Collation']) ? $row['Collation'] : null;
  244. break;
  245. case 'enum':
  246. case 'set':
  247. $column['collation_name'] = isset($row['Collation']) ? $row['Collation'] : null;
  248. $column['options'] = explode('\',\'', substr($length, 1, - 1));
  249. break;
  250. }
  251. break;
  252. }
  253. // MySQL attributes
  254. $column['comment'] = isset($row['Comment']) ? $row['Comment'] : null;
  255. $column['extra'] = $row['Extra'];
  256. $column['key'] = $row['Key'];
  257. $column['privileges'] = isset($row['Privileges']) ? $row['Privileges'] : null;
  258. $columns[$row['Field']] = $column;
  259. }
  260. return $columns;
  261. }
  262. public function datatype($type)
  263. {
  264. // try to determine the datatype
  265. $datatype = parent::datatype($type);
  266. // if not an ANSI database, assume it's string
  267. return empty($datatype) ? array('type' => 'string') : $datatype;
  268. }
  269. public function escape($value)
  270. {
  271. // Make sure the database is connected
  272. $this->_connection or $this->connect();
  273. $result = $this->_connection->quote($value);
  274. // poor-mans workaround for the fact that not all drivers implement quote()
  275. if (empty($result))
  276. {
  277. $result = "'".str_replace("'", "''", $value)."'";
  278. }
  279. return $result;
  280. }
  281. public function error_info()
  282. {
  283. return $this->_connection->errorInfo();
  284. }
  285. public function in_transaction()
  286. {
  287. return $this->_in_transaction;
  288. }
  289. public function start_transaction()
  290. {
  291. $this->_connection or $this->connect();
  292. $this->_in_transaction = true;
  293. return $this->_connection->beginTransaction();
  294. }
  295. public function commit_transaction()
  296. {
  297. $this->_in_transaction = false;
  298. return $this->_connection->commit();
  299. }
  300. public function rollback_transaction()
  301. {
  302. $this->_in_transaction = false;
  303. return $this->_connection->rollBack();
  304. }
  305. }