AbstractMySQLDriver.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <?php
  2. namespace Doctrine\DBAL\Driver;
  3. use Doctrine\DBAL\Connection;
  4. use Doctrine\DBAL\DBALException;
  5. use Doctrine\DBAL\Driver;
  6. use Doctrine\DBAL\Exception;
  7. use Doctrine\DBAL\Platforms\MariaDb1027Platform;
  8. use Doctrine\DBAL\Platforms\MySQL57Platform;
  9. use Doctrine\DBAL\Platforms\MySQL80Platform;
  10. use Doctrine\DBAL\Platforms\MySqlPlatform;
  11. use Doctrine\DBAL\Schema\MySqlSchemaManager;
  12. use Doctrine\DBAL\VersionAwarePlatformDriver;
  13. use function preg_match;
  14. use function stripos;
  15. use function version_compare;
  16. /**
  17. * Abstract base implementation of the {@link Doctrine\DBAL\Driver} interface for MySQL based drivers.
  18. */
  19. abstract class AbstractMySQLDriver implements Driver, ExceptionConverterDriver, VersionAwarePlatformDriver
  20. {
  21. /**
  22. * {@inheritdoc}
  23. *
  24. * @link http://dev.mysql.com/doc/refman/5.7/en/error-messages-client.html
  25. * @link http://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
  26. */
  27. public function convertException($message, DriverException $exception)
  28. {
  29. switch ($exception->getErrorCode()) {
  30. case '1213':
  31. return new Exception\DeadlockException($message, $exception);
  32. case '1205':
  33. return new Exception\LockWaitTimeoutException($message, $exception);
  34. case '1050':
  35. return new Exception\TableExistsException($message, $exception);
  36. case '1051':
  37. case '1146':
  38. return new Exception\TableNotFoundException($message, $exception);
  39. case '1216':
  40. case '1217':
  41. case '1451':
  42. case '1452':
  43. case '1701':
  44. return new Exception\ForeignKeyConstraintViolationException($message, $exception);
  45. case '1062':
  46. case '1557':
  47. case '1569':
  48. case '1586':
  49. return new Exception\UniqueConstraintViolationException($message, $exception);
  50. case '1054':
  51. case '1166':
  52. case '1611':
  53. return new Exception\InvalidFieldNameException($message, $exception);
  54. case '1052':
  55. case '1060':
  56. case '1110':
  57. return new Exception\NonUniqueFieldNameException($message, $exception);
  58. case '1064':
  59. case '1149':
  60. case '1287':
  61. case '1341':
  62. case '1342':
  63. case '1343':
  64. case '1344':
  65. case '1382':
  66. case '1479':
  67. case '1541':
  68. case '1554':
  69. case '1626':
  70. return new Exception\SyntaxErrorException($message, $exception);
  71. case '1044':
  72. case '1045':
  73. case '1046':
  74. case '1049':
  75. case '1095':
  76. case '1142':
  77. case '1143':
  78. case '1227':
  79. case '1370':
  80. case '1429':
  81. case '2002':
  82. case '2005':
  83. return new Exception\ConnectionException($message, $exception);
  84. case '1048':
  85. case '1121':
  86. case '1138':
  87. case '1171':
  88. case '1252':
  89. case '1263':
  90. case '1364':
  91. case '1566':
  92. return new Exception\NotNullConstraintViolationException($message, $exception);
  93. }
  94. return new Exception\DriverException($message, $exception);
  95. }
  96. /**
  97. * {@inheritdoc}
  98. *
  99. * @throws DBALException
  100. */
  101. public function createDatabasePlatformForVersion($version)
  102. {
  103. $mariadb = stripos($version, 'mariadb') !== false;
  104. if ($mariadb && version_compare($this->getMariaDbMysqlVersionNumber($version), '10.2.7', '>=')) {
  105. return new MariaDb1027Platform();
  106. }
  107. if (! $mariadb) {
  108. $oracleMysqlVersion = $this->getOracleMysqlVersionNumber($version);
  109. if (version_compare($oracleMysqlVersion, '8', '>=')) {
  110. return new MySQL80Platform();
  111. }
  112. if (version_compare($oracleMysqlVersion, '5.7.9', '>=')) {
  113. return new MySQL57Platform();
  114. }
  115. }
  116. return $this->getDatabasePlatform();
  117. }
  118. /**
  119. * Get a normalized 'version number' from the server string
  120. * returned by Oracle MySQL servers.
  121. *
  122. * @param string $versionString Version string returned by the driver, i.e. '5.7.10'
  123. *
  124. * @throws DBALException
  125. */
  126. private function getOracleMysqlVersionNumber(string $versionString) : string
  127. {
  128. if (! preg_match(
  129. '/^(?P<major>\d+)(?:\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?)?/',
  130. $versionString,
  131. $versionParts
  132. )) {
  133. throw DBALException::invalidPlatformVersionSpecified(
  134. $versionString,
  135. '<major_version>.<minor_version>.<patch_version>'
  136. );
  137. }
  138. $majorVersion = $versionParts['major'];
  139. $minorVersion = $versionParts['minor'] ?? 0;
  140. $patchVersion = $versionParts['patch'] ?? null;
  141. if ($majorVersion === '5' && $minorVersion === '7' && $patchVersion === null) {
  142. $patchVersion = '9';
  143. }
  144. return $majorVersion . '.' . $minorVersion . '.' . $patchVersion;
  145. }
  146. /**
  147. * Detect MariaDB server version, including hack for some mariadb distributions
  148. * that starts with the prefix '5.5.5-'
  149. *
  150. * @param string $versionString Version string as returned by mariadb server, i.e. '5.5.5-Mariadb-10.0.8-xenial'
  151. *
  152. * @throws DBALException
  153. */
  154. private function getMariaDbMysqlVersionNumber(string $versionString) : string
  155. {
  156. if (! preg_match(
  157. '/^(?:5\.5\.5-)?(mariadb-)?(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)/i',
  158. $versionString,
  159. $versionParts
  160. )) {
  161. throw DBALException::invalidPlatformVersionSpecified(
  162. $versionString,
  163. '^(?:5\.5\.5-)?(mariadb-)?<major_version>.<minor_version>.<patch_version>'
  164. );
  165. }
  166. return $versionParts['major'] . '.' . $versionParts['minor'] . '.' . $versionParts['patch'];
  167. }
  168. /**
  169. * {@inheritdoc}
  170. */
  171. public function getDatabase(Connection $conn)
  172. {
  173. $params = $conn->getParams();
  174. return $params['dbname'] ?? $conn->query('SELECT DATABASE()')->fetchColumn();
  175. }
  176. /**
  177. * {@inheritdoc}
  178. *
  179. * @return MySqlPlatform
  180. */
  181. public function getDatabasePlatform()
  182. {
  183. return new MySqlPlatform();
  184. }
  185. /**
  186. * {@inheritdoc}
  187. *
  188. * @return MySqlSchemaManager
  189. */
  190. public function getSchemaManager(Connection $conn)
  191. {
  192. return new MySqlSchemaManager($conn);
  193. }
  194. }