Driver.php 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Database;
  16. use Cake\Database\Query;
  17. use Cake\Database\Statement\PDOStatement;
  18. use InvalidArgumentException;
  19. use PDO;
  20. use PDOException;
  21. /**
  22. * Represents a database driver containing all specificities for
  23. * a database engine including its SQL dialect.
  24. */
  25. abstract class Driver implements DriverInterface
  26. {
  27. /**
  28. * Instance of PDO.
  29. *
  30. * @var \PDO|null
  31. */
  32. protected $_connection;
  33. /**
  34. * Configuration data.
  35. *
  36. * @var array
  37. */
  38. protected $_config;
  39. /**
  40. * Base configuration that is merged into the user
  41. * supplied configuration data.
  42. *
  43. * @var array
  44. */
  45. protected $_baseConfig = [];
  46. /**
  47. * Indicates whether or not the driver is doing automatic identifier quoting
  48. * for all queries
  49. *
  50. * @var bool
  51. */
  52. protected $_autoQuoting = false;
  53. /**
  54. * Constructor
  55. *
  56. * @param array $config The configuration for the driver.
  57. * @throws \InvalidArgumentException
  58. */
  59. public function __construct($config = [])
  60. {
  61. if (empty($config['username']) && !empty($config['login'])) {
  62. throw new InvalidArgumentException(
  63. 'Please pass "username" instead of "login" for connecting to the database'
  64. );
  65. }
  66. $config += $this->_baseConfig;
  67. $this->_config = $config;
  68. if (!empty($config['quoteIdentifiers'])) {
  69. $this->enableAutoQuoting();
  70. }
  71. }
  72. /**
  73. * Establishes a connection to the database server
  74. *
  75. * @param string $dsn A Driver-specific PDO-DSN
  76. * @param array $config configuration to be used for creating connection
  77. * @return bool true on success
  78. */
  79. protected function _connect($dsn, array $config)
  80. {
  81. $connection = new PDO(
  82. $dsn,
  83. $config['username'],
  84. $config['password'],
  85. $config['flags']
  86. );
  87. $this->setConnection($connection);
  88. return true;
  89. }
  90. /**
  91. * {@inheritDoc}
  92. */
  93. abstract public function connect();
  94. /**
  95. * {@inheritDoc}
  96. */
  97. public function disconnect()
  98. {
  99. $this->_connection = null;
  100. }
  101. /**
  102. * Returns correct connection resource or object that is internally used
  103. * If first argument is passed, it will set internal connection object or
  104. * result to the value passed.
  105. *
  106. * @param mixed $connection The PDO connection instance.
  107. * @return mixed Connection object used internally.
  108. * @deprecated 3.6.0 Use getConnection()/setConnection() instead.
  109. */
  110. public function connection($connection = null)
  111. {
  112. deprecationWarning(
  113. get_called_class() . '::connection() is deprecated. ' .
  114. 'Use setConnection()/getConnection() instead.'
  115. );
  116. if ($connection !== null) {
  117. $this->_connection = $connection;
  118. }
  119. return $this->_connection;
  120. }
  121. /**
  122. * Get the internal PDO connection instance.
  123. *
  124. * @return \PDO
  125. */
  126. public function getConnection()
  127. {
  128. return $this->_connection;
  129. }
  130. /**
  131. * Set the internal PDO connection instance.
  132. *
  133. * @param \PDO $connection PDO instance.
  134. * @return $this
  135. */
  136. public function setConnection($connection)
  137. {
  138. $this->_connection = $connection;
  139. return $this;
  140. }
  141. /**
  142. * {@inheritDoc}
  143. */
  144. abstract public function enabled();
  145. /**
  146. * {@inheritDoc}
  147. */
  148. public function prepare($query)
  149. {
  150. $this->connect();
  151. $isObject = $query instanceof Query;
  152. $statement = $this->_connection->prepare($isObject ? $query->sql() : $query);
  153. return new PDOStatement($statement, $this);
  154. }
  155. /**
  156. * {@inheritDoc}
  157. */
  158. public function beginTransaction()
  159. {
  160. $this->connect();
  161. if ($this->_connection->inTransaction()) {
  162. return true;
  163. }
  164. return $this->_connection->beginTransaction();
  165. }
  166. /**
  167. * {@inheritDoc}
  168. */
  169. public function commitTransaction()
  170. {
  171. $this->connect();
  172. if (!$this->_connection->inTransaction()) {
  173. return false;
  174. }
  175. return $this->_connection->commit();
  176. }
  177. /**
  178. * {@inheritDoc}
  179. */
  180. public function rollbackTransaction()
  181. {
  182. $this->connect();
  183. if (!$this->_connection->inTransaction()) {
  184. return false;
  185. }
  186. return $this->_connection->rollBack();
  187. }
  188. /**
  189. * {@inheritDoc}
  190. */
  191. abstract public function releaseSavePointSQL($name);
  192. /**
  193. * {@inheritDoc}
  194. */
  195. abstract public function savePointSQL($name);
  196. /**
  197. * {@inheritDoc}
  198. */
  199. abstract public function rollbackSavePointSQL($name);
  200. /**
  201. * {@inheritDoc}
  202. */
  203. abstract public function disableForeignKeySQL();
  204. /**
  205. * {@inheritDoc}
  206. */
  207. abstract public function enableForeignKeySQL();
  208. /**
  209. * {@inheritDoc}
  210. */
  211. abstract public function supportsDynamicConstraints();
  212. /**
  213. * {@inheritDoc}
  214. */
  215. public function supportsSavePoints()
  216. {
  217. return true;
  218. }
  219. /**
  220. * {@inheritDoc}
  221. */
  222. public function quote($value, $type)
  223. {
  224. $this->connect();
  225. return $this->_connection->quote($value, $type);
  226. }
  227. /**
  228. * Checks if the driver supports quoting, as PDO_ODBC does not support it.
  229. *
  230. * @return bool
  231. */
  232. public function supportsQuoting()
  233. {
  234. $this->connect();
  235. return $this->_connection->getAttribute(PDO::ATTR_DRIVER_NAME) !== 'odbc';
  236. }
  237. /**
  238. * {@inheritDoc}
  239. */
  240. abstract public function queryTranslator($type);
  241. /**
  242. * {@inheritDoc}
  243. */
  244. abstract public function schemaDialect();
  245. /**
  246. * {@inheritDoc}
  247. */
  248. abstract public function quoteIdentifier($identifier);
  249. /**
  250. * {@inheritDoc}
  251. */
  252. public function schemaValue($value)
  253. {
  254. if ($value === null) {
  255. return 'NULL';
  256. }
  257. if ($value === false) {
  258. return 'FALSE';
  259. }
  260. if ($value === true) {
  261. return 'TRUE';
  262. }
  263. if (is_float($value)) {
  264. return str_replace(',', '.', (string)$value);
  265. }
  266. if ((is_int($value) || $value === '0') || (
  267. is_numeric($value) && strpos($value, ',') === false &&
  268. $value[0] !== '0' && strpos($value, 'e') === false)
  269. ) {
  270. return (string)$value;
  271. }
  272. return $this->_connection->quote($value, PDO::PARAM_STR);
  273. }
  274. /**
  275. * {@inheritDoc}
  276. */
  277. public function schema()
  278. {
  279. return $this->_config['schema'];
  280. }
  281. /**
  282. * {@inheritDoc}
  283. */
  284. public function lastInsertId($table = null, $column = null)
  285. {
  286. $this->connect();
  287. if ($this->_connection instanceof PDO) {
  288. return $this->_connection->lastInsertId($table);
  289. }
  290. return $this->_connection->lastInsertId($table, $column);
  291. }
  292. /**
  293. * {@inheritDoc}
  294. */
  295. public function isConnected()
  296. {
  297. if ($this->_connection === null) {
  298. $connected = false;
  299. } else {
  300. try {
  301. $connected = $this->_connection->query('SELECT 1');
  302. } catch (PDOException $e) {
  303. $connected = false;
  304. }
  305. }
  306. return (bool)$connected;
  307. }
  308. /**
  309. * {@inheritDoc}
  310. */
  311. public function enableAutoQuoting($enable = true)
  312. {
  313. $this->_autoQuoting = (bool)$enable;
  314. return $this;
  315. }
  316. /**
  317. * Disable auto quoting of identifiers in queries.
  318. *
  319. * @return $this
  320. */
  321. public function disableAutoQuoting()
  322. {
  323. $this->_autoQuoting = false;
  324. return $this;
  325. }
  326. /**
  327. * {@inheritDoc}
  328. */
  329. public function isAutoQuotingEnabled()
  330. {
  331. return $this->_autoQuoting;
  332. }
  333. /**
  334. * Returns whether or not this driver should automatically quote identifiers
  335. * in queries
  336. *
  337. * If called with a boolean argument, it will toggle the auto quoting setting
  338. * to the passed value
  339. *
  340. * @deprecated 3.4.0 use enableAutoQuoting()/isAutoQuotingEnabled() instead.
  341. * @param bool|null $enable Whether to enable auto quoting
  342. * @return bool
  343. */
  344. public function autoQuoting($enable = null)
  345. {
  346. deprecationWarning(
  347. 'Driver::autoQuoting() is deprecated. ' .
  348. 'Use Driver::enableAutoQuoting()/isAutoQuotingEnabled() instead.'
  349. );
  350. if ($enable !== null) {
  351. $this->enableAutoQuoting($enable);
  352. }
  353. return $this->isAutoQuotingEnabled();
  354. }
  355. /**
  356. * {@inheritDoc}
  357. */
  358. public function compileQuery(Query $query, ValueBinder $generator)
  359. {
  360. $processor = $this->newCompiler();
  361. $translator = $this->queryTranslator($query->type());
  362. $query = $translator($query);
  363. return [$query, $processor->compile($query, $generator)];
  364. }
  365. /**
  366. * {@inheritDoc}
  367. */
  368. public function newCompiler()
  369. {
  370. return new QueryCompiler();
  371. }
  372. /**
  373. * Destructor
  374. */
  375. public function __destruct()
  376. {
  377. $this->_connection = null;
  378. }
  379. /**
  380. * Returns an array that can be used to describe the internal state of this
  381. * object.
  382. *
  383. * @return array
  384. */
  385. public function __debugInfo()
  386. {
  387. return [
  388. 'connected' => $this->_connection !== null
  389. ];
  390. }
  391. }