diff --git a/framework/yii/db/Connection.php b/framework/yii/db/Connection.php index 342fa15..69bf6a5 100644 --- a/framework/yii/db/Connection.php +++ b/framework/yii/db/Connection.php @@ -201,7 +201,7 @@ class Connection extends Component public $queryCache = 'cache'; /** * @var string the charset used for database connection. The property is only used - * for MySQL and PostgreSQL databases. Defaults to null, meaning using default charset + * for MySQL, PostgreSQL and CUBRID databases. Defaults to null, meaning using default charset * as specified by the database. * * Note that if you're using GBK or BIG5 then it's highly recommended to @@ -244,6 +244,7 @@ class Connection extends Component 'oci' => 'yii\db\oci\Schema', // Oracle driver 'mssql' => 'yii\db\mssql\Schema', // older MSSQL driver on MS Windows hosts 'dblib' => 'yii\db\mssql\Schema', // dblib drivers on GNU/Linux (and maybe other OSes) hosts + 'cubrid' => 'yii\db\cubrid\Schema', // CUBRID ); /** * @var Transaction the currently active transaction @@ -361,7 +362,7 @@ class Connection extends Component if ($this->emulatePrepare !== null && constant('PDO::ATTR_EMULATE_PREPARES')) { $this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->emulatePrepare); } - if ($this->charset !== null && in_array($this->getDriverName(), array('pgsql', 'mysql', 'mysqli'))) { + if ($this->charset !== null && in_array($this->getDriverName(), array('pgsql', 'mysql', 'mysqli', 'cubrid'))) { $this->pdo->exec('SET NAMES ' . $this->pdo->quote($this->charset)); } $this->trigger(self::EVENT_AFTER_OPEN); diff --git a/framework/yii/db/cubrid/Schema.php b/framework/yii/db/cubrid/Schema.php new file mode 100644 index 0000000..3b60b64 --- /dev/null +++ b/framework/yii/db/cubrid/Schema.php @@ -0,0 +1,222 @@ + + * @since 2.0 + */ +class Schema extends \yii\db\Schema +{ + /** + * @var array mapping from physical column types (keys) to abstract column types (values) + * Please refer to [CUBRID manual](http://www.cubrid.org/manual/91/en/sql/datatype.html) for + * details on data types. + */ + public $typeMap = array( + // Numeric data types + 'short' => self::TYPE_SMALLINT, + 'smallint' => self::TYPE_SMALLINT, + 'int' => self::TYPE_INTEGER, + 'integer' => self::TYPE_INTEGER, + 'bigint' => self::TYPE_BIGINT, + 'numeric' => self::TYPE_DECIMAL, + 'decimal' => self::TYPE_DECIMAL, + 'float' => self::TYPE_FLOAT, + 'real' => self::TYPE_FLOAT, + 'double' => self::TYPE_FLOAT, + 'double precision' => self::TYPE_FLOAT, + 'monetary' => self::TYPE_MONEY, + // Date/Time data types + 'date' => self::TYPE_DATE, + 'time' => self::TYPE_TIME, + 'timestamp' => self::TYPE_TIMESTAMP, + 'datetime' => self::TYPE_DATETIME, + // Bit string data types +// 'bit' => self::TYPE_BINARY, // TODO +// 'bit varying' => self::TYPE_BINARY, + // String data types + 'char' => self::TYPE_STRING, + 'varchar' => self::TYPE_STRING, + 'char varying' => self::TYPE_STRING, + 'nchar' => self::TYPE_STRING, + 'nchar varying' => self::TYPE_STRING, + 'string' => self::TYPE_STRING, + // BLOB/CLOB data types + 'blob' => self::TYPE_BINARY, + 'clob' => self::TYPE_BINARY, + // Collection data types (TODO are considered strings for now, naybe support conversion?) +// 'set' => self::TYPE_STRING, +// 'multiset' => self::TYPE_STRING, +// 'list' => self::TYPE_STRING, +// 'sequence' => self::TYPE_STRING, +// 'enum' => self::TYPE_STRING, + ); + + /** + * Quotes a table name for use in a query. + * A simple table name has no schema prefix. + * @param string $name table name + * @return string the properly quoted table name + */ + public function quoteSimpleTableName($name) + { + return strpos($name, "`") !== false ? $name : "`" . $name . "`"; + } + + /** + * Quotes a column name for use in a query. + * A simple column name has no prefix. + * @param string $name column name + * @return string the properly quoted column name + */ + public function quoteSimpleColumnName($name) + { + return strpos($name, '`') !== false || $name === '*' ? $name : '`' . $name . '`'; + } + + /** + * Creates a query builder for the CUBRID database. + * @return QueryBuilder query builder instance + */ + public function createQueryBuilder() + { + return new QueryBuilder($this->db); + } + + /** + * Loads the metadata for the specified table. + * @param string $name table name + * @return TableSchema driver dependent table metadata. Null if the table does not exist. + */ + protected function loadTableSchema($name) + { + $this->db->open(); + $tableInfo = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_TABLE, $name); + + if (isset($tableInfo[0]['NAME'])) { + $table = new TableSchema; + $table->name = $tableInfo[0]['NAME']; + + $sql = 'SHOW FULL COLUMNS FROM ' . $this->quoteSimpleTableName($table->name); + $columns = $this->db->createCommand($sql)->queryAll(); + + foreach ($columns as $info) { + $column = $this->loadColumnSchema($info); + $table->columns[$column->name] = $column; + if ($column->isPrimaryKey) { + $table->primaryKey[] = $column->name; + if ($column->autoIncrement) { + $table->sequenceName = ''; + } + } + } + + $foreignKeys = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_IMPORTED_KEYS, $table->name); + foreach($foreignKeys as $key) { + $table->foreignKeys[] = array( + $key['PKTABLE_NAME'], + $key['FKCOLUMN_NAME'] => $key['PKCOLUMN_NAME'] + // TODO support composite foreign keys + ); + } + + return $table; + } else { + return null; + } + } + + /** + * Loads the column information into a [[ColumnSchema]] object. + * @param array $info column information + * @return ColumnSchema the column schema object + */ + protected function loadColumnSchema($info) + { + $column = new ColumnSchema; + + $column->name = $info['Field']; + $column->allowNull = $info['Null'] === 'YES'; + $column->isPrimaryKey = strpos($info['Key'], 'PRI') !== false; + $column->autoIncrement = stripos($info['Extra'], 'auto_increment') !== false; + + $column->dbType = strtolower($info['Type']); + $column->unsigned = strpos($column->dbType, 'unsigned') !== false; + + $column->type = self::TYPE_STRING; + if (preg_match('/^([\w ]+)(?:\(([^\)]+)\))?/', $column->dbType, $matches)) { + $type = $matches[1]; + if (isset($this->typeMap[$type])) { + $column->type = $this->typeMap[$type]; + } + if (!empty($matches[2])) { + if ($type === 'enum') { + $values = explode(',', $matches[2]); + foreach ($values as $i => $value) { + $values[$i] = trim($value, "'"); + } + $column->enumValues = $values; + } else { + $values = explode(',', $matches[2]); + $column->size = $column->precision = (int)$values[0]; + if (isset($values[1])) { + $column->scale = (int)$values[1]; + } + if ($column->size === 1 && ($type === 'tinyint' || $type === 'bit')) { + $column->type = 'boolean'; + } elseif ($type === 'bit' || $type === 'bit varying') { + if ($column->size > 32) { + $column->type = 'bigint'; + } elseif ($column->size === 32) { + $column->type = 'integer'; + } + } + } + } + } + + $column->phpType = $this->getColumnPhpType($column); + + if ($column->type === 'timestamp' && $info['Default'] === 'CURRENT_TIMESTAMP' || + $column->type === 'datetime' && $info['Default'] === 'SYS_DATETIME' || + $column->type === 'date' && $info['Default'] === 'SYS_DATE' || + $column->type === 'time' && $info['Default'] === 'SYS_TIME') { + $column->defaultValue = new Expression($info['Default']); + } else { + $column->defaultValue = $column->typecast($info['Default']); + } + + return $column; + } + + /** + * Returns all table names in the database. + * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. + * @return array all table names in the database. The names have NO schema name prefix. + */ + protected function findTableNames($schema = '') + { + $this->db->open(); + $tables = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_TABLE); + $tableNames = array(); + foreach($tables as $table) { + // do not list system tables + if ($table['TYPE'] !== 0) { + $tableNames[] = $table['NAME']; + } + } + return $tableNames; + } +}