123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499 |
- <?php
- /**
- *
- * Cube Framework $Id$ d2ibV6IrsImXE7ik3/w9UNhhd5mwvaSQ8uOcH9btDJo=
- *
- * @link http://codecu.be/framework
- * @copyright Copyright (c) 2014 CodeCube SRL
- * @license http://codecu.be/framework/license Commercial License
- *
- * @version 1.0
- */
- /**
- * pdo mysql database adapter
- */
- namespace Cube\Db\Adapter\PDO;
- use Cube\Db\Adapter\AbstractAdapter,
- Cube\Db\Select,
- Cube\Exception;
- class Mysql extends AbstractAdapter
- {
- /**
- *
- * default statement class for this adapter
- *
- * @var string
- */
- protected $_defaultStmtClass = '\\Cube\\Db\\Statement\\Pdo';
- /**
- *
- * adapter type
- *
- * @var string
- */
- protected $_pdoType = 'mysql';
- /**
- * Creates a PDO DSN for the adapter from $this->_config settings.
- *
- * @return string
- */
- protected function _dsn()
- {
- // baseline of DSN parts
- $dsn = $this->_config;
- // don't pass the username, password, charset, persistent and driver_options in the DSN
- unset($dsn['username']);
- unset($dsn['password']);
- unset($dsn['options']);
- unset($dsn['charset']);
- unset($dsn['persistent']);
- unset($dsn['driver_options']);
- // use all remaining parts in the DSN
- foreach ($dsn as $key => $val) {
- $dsn[$key] = "$key=$val";
- }
- $dsn = implode(';', $dsn);
- if (isset($this->_config['charset'])) {
- $dsn .= ';charset=' . (string)$this->_config['charset'];
- }
- return $this->_pdoType . ':' . $dsn;
- }
- /**
- * Creates a PDO object and connects to the database.
- *
- * @throws \RuntimeException
- * @throws \Cube\Exception
- * @return void
- */
- protected function _connect()
- {
- if ($this->_connection) {
- return;
- }
- if (isset($this->_config['charset'])) {
- $initCommand = "SET NAMES '" . $this->_config['charset'] . "'";
- $this->_config['driver_options'][1002] = $initCommand; // 1002 = PDO::MYSQL_ATTR_INIT_COMMAND
- }
- // get the dsn first, because some adapters alter the $_pdoType
- $dsn = $this->_dsn();
- // check for PDO extension
- if (!extension_loaded('pdo')) {
- /**
- * @see Zend_Db_Adapter_Exception
- */
- throw new \RuntimeException('The PDO extension is required for this adapter but the extension is not loaded');
- }
- // create PDO connection
- try {
- $this->_connection = @new \PDO(
- $dsn,
- $this->_config['username'],
- $this->_config['password'],
- $this->_config['driver_options']
- );
- $this->_connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
- } catch (\PDOException $e) {
- throw new Exception($e->getMessage(), $e->getCode(), $e);
- }
- }
- /**
- * Test if a connection is active
- *
- * @return bool
- */
- public function isConnected()
- {
- return ((bool)($this->_connection instanceof \PDO));
- }
- /**
- * connect and return whether the connection was successful
- *
- * @return bool
- */
- public function canConnect()
- {
- $this->_connect();
- return $this->isConnected();
- }
- /**
- * Force the connection to close.
- *
- * @return void
- */
- public function closeConnection()
- {
- $this->_connection = null;
- }
- /**
- * Prepares an SQL statement.
- *
- * @param string $sql The SQL statement with placeholders.
- *
- * @throws \RuntimeException
- * @return \PDOStatement
- */
- public function prepare($sql)
- {
- $this->_connect();
- $stmtClass = $this->_defaultStmtClass;
- if (!class_exists($stmtClass)) {
- throw new \RuntimeException(
- sprintf("Could not load the statement class '%s'", $stmtClass));
- }
- /** @var \Cube\Db\Statement\AbstractStatement $stmt */
- $stmt = new $stmtClass($this, $sql);
- $stmt->setFetchMode($this->_fetchMode);
- return $stmt;
- }
- /**
- * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column.
- *
- * As a convention, on RDBMS brands that support sequences
- * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence
- * from the arguments and returns the last id generated by that sequence.
- * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method
- * returns the last value generated for such a column, and the table name
- * argument is disregarded.
- *
- * On RDBMS brands that don't support sequences, $tableName and $primaryKey
- * are ignored.
- *
- * @param string $tableName OPTIONAL Name of table.
- * @param string $primaryKey OPTIONAL Name of primary key column.
- *
- * @return string
- */
- public function lastInsertId($tableName = null, $primaryKey = null)
- {
- $this->_connect();
- return $this->_connection->lastInsertId();
- }
- /**
- * Special handling for PDO query().
- * All bind parameter names must begin with ':'
- *
- * @param string|\Cube\Db\Select $sql The SQL statement with placeholders.
- * @param array $bind An array of data to bind to the placeholders.
- *
- * @return \Cube\Db\Adapter\AbstractAdapter
- * @throws \Cube\Exception To re-throw PDOException.
- */
- public function query($sql, $bind = array())
- {
- if (empty($bind) && $sql instanceof Select) {
- $bind = $sql->getBind();
- }
- if (is_array($bind)) {
- foreach ($bind as $name => $value) {
- if (!is_int($name) && !preg_match('/^:/', $name)) {
- $newName = ":$name";
- unset($bind[$name]);
- $bind[$newName] = $value;
- }
- }
- }
- try {
- return parent::query($sql, $bind);
- } catch (\PDOException $e) {
- throw new Exception($e->getMessage(), $e->getCode(), $e);
- }
- }
- /**
- * Executes an SQL statement and return the number of affected rows
- *
- * @param mixed $sql The SQL statement with placeholders.
- * May be a string or a \Cube\Db\Select object.
- *
- * @throws \Cube\Exception
- * @return integer Number of rows that were modified
- * or deleted by the SQL statement
- */
- public function exec($sql)
- {
- if ($sql instanceof Select) {
- $sql = $sql->assemble();
- }
- try {
- $affected = $this->getConnection()->exec($sql);
- if ($affected === false) {
- $errorInfo = $this->getConnection()->errorInfo();
- throw new Exception($errorInfo[2]);
- }
- return $affected;
- } catch (\PDOException $e) {
- throw new Exception($e->getMessage(), $e->getCode(), $e);
- }
- }
- /**
- * Quote a raw string.
- *
- * @param string $value Raw string
- *
- * @return string Quoted string
- */
- protected function _quote($value)
- {
- if (is_int($value) || is_float($value)) {
- return $value;
- }
- $this->_connect();
- return $this->_connection->quote($value);
- }
- /**
- * Begin a transaction.
- */
- protected function _beginTransaction()
- {
- $this->_connect();
- $this->_connection->beginTransaction();
- }
- /**
- * Commit a transaction.
- */
- protected function _commit()
- {
- $this->_connect();
- $this->_connection->commit();
- }
- /**
- * Roll-back a transaction.
- */
- protected function _rollBack()
- {
- $this->_connect();
- $this->_connection->rollBack();
- }
- /**
- * Set the PDO fetch mode.
- *
- * @param int $mode A PDO fetch mode.
- *
- * @throws \RuntimeException
- * @throws \InvalidArgumentException
- * @return void
- */
- public function setFetchMode($mode)
- {
- //check for PDO extension
- if (!extension_loaded('pdo')) {
- throw new \RuntimeException('The PDO extension is required for this adapter but the extension is not loaded');
- }
- switch ($mode) {
- case \PDO::FETCH_LAZY:
- case \PDO::FETCH_ASSOC:
- case \PDO::FETCH_NUM:
- case \PDO::FETCH_BOTH:
- case \PDO::FETCH_NAMED:
- case \PDO::FETCH_OBJ:
- $this->_fetchMode = $mode;
- break;
- default:
- throw new \InvalidArgumentException("Invalid fetch mode '$mode' specified");
- break;
- }
- }
- /**
- * Check if the adapter supports real SQL parameters.
- *
- * @param string $type 'positional' or 'named'
- *
- * @return bool
- */
- public function supportsParameters($type)
- {
- switch ($type) {
- case 'positional':
- case 'named':
- default:
- return true;
- }
- }
- /**
- * @return string
- */
- public function getQuoteIdentifierSymbol()
- {
- return "`";
- }
- /**
- * Returns the column descriptions for a table.
- *
- * The return value is an associative array keyed by the column name,
- * as returned by the RDBMS.
- *
- * The value of each array element is an associative array
- * with the following keys:
- *
- * TABLE_NAME => string;
- * COLUMN_NAME => string; column name
- * COLUMN_POSITION => number; ordinal position of column in table
- * DATA_TYPE => string; SQL datatype name of column
- * DEFAULT => string; default expression of column, null if none
- * NULLABLE => bool; true if column can have nulls
- * LENGTH => number; length of CHAR/VARCHAR
- * SCALE => number; scale of NUMERIC/DECIMAL
- * PRECISION => number; precision of NUMERIC/DECIMAL
- * UNSIGNED => bool; unsigned property of an integer type
- * PRIMARY => bool; true if column is part of the primary key
- * PRIMARY_POSITION => integer; position of column in primary key
- * IDENTITY => integer; true if column is auto-generated with unique values
- *
- * @param string $tableName
- *
- * @return array
- */
- public function describeTable($tableName)
- {
- $sql = 'DESCRIBE ' . $this->quoteIdentifier($tableName, true);
- $stmt = $this->query($sql);
- // Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection
- $result = $stmt->fetchAll(\PDO::FETCH_NUM);
- $field = 0;
- $type = 1;
- $null = 2;
- $key = 3;
- $default = 4;
- $extra = 5;
- $desc = array();
- $i = 1;
- $p = 1;
- foreach ($result as $row) {
- list($length, $scale, $precision, $unsigned, $primary, $primaryPosition, $identity)
- = array(null, null, null, null, false, null, false);
- if (preg_match('/unsigned/', $row[$type])) {
- $unsigned = true;
- }
- if (preg_match('/^((?:var)?char)\((\d+)\)/', $row[$type], $matches)) {
- $row[$type] = $matches[1];
- $length = $matches[2];
- }
- else if (preg_match('/^decimal\((\d+),(\d+)\)/', $row[$type], $matches)) {
- $row[$type] = 'decimal';
- $precision = $matches[1];
- $scale = $matches[2];
- }
- else if (preg_match('/^float\((\d+),(\d+)\)/', $row[$type], $matches)) {
- $row[$type] = 'float';
- $precision = $matches[1];
- $scale = $matches[2];
- }
- else if (preg_match('/^((?:big|medium|small|tiny)?int)\((\d+)\)/', $row[$type], $matches)) {
- $row[$type] = $matches[1];
- }
- if (strtoupper($row[$key]) == 'PRI') {
- $primary = true;
- $primaryPosition = $p;
- if ($row[$extra] == 'auto_increment') {
- $identity = true;
- }
- else {
- $identity = false;
- }
- $p++;
- }
- $desc[$row[$field]] = array(
- 'TABLE_NAME' => $tableName,
- 'COLUMN_NAME' => $row[$field],
- 'COLUMN_POSITION' => $i,
- 'DATA_TYPE' => $row[$type],
- 'DEFAULT' => $row[$default],
- 'NULLABLE' => (bool)($row[$null] == 'YES'),
- 'LENGTH' => $length,
- 'SCALE' => $scale,
- 'PRECISION' => $precision,
- 'UNSIGNED' => $unsigned,
- 'PRIMARY' => $primary,
- 'PRIMARY_POSITION' => $primaryPosition,
- 'IDENTITY' => $identity
- );
- $i++;
- }
- return $desc;
- }
- /**
- * Adds an adapter-specific LIMIT clause to the SELECT statement.
- *
- * @param string $sql
- * @param integer $count
- * @param integer $offset OPTIONAL
- *
- * @throws \InvalidArgumentException
- * @return string
- */
- public function limit($sql, $count, $offset = 0)
- {
- $count = intval($count);
- if ($count <= 0) {
- /** @see Zend_Db_Adapter_Exception */
- throw new \InvalidArgumentException("LIMIT argument count=$count is not valid");
- }
- $offset = intval($offset);
- if ($offset < 0) {
- throw new \InvalidArgumentException("LIMIT argument offset=$offset is not valid");
- }
- $sql .= " LIMIT $count";
- if ($offset > 0) {
- $sql .= " OFFSET $offset";
- }
- return $sql;
- }
- }
|