Driver.php 10 KB

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