From be67559fe155bedff60fdf194e066dac10de778b Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 5 Sep 2013 16:49:11 +0200 Subject: [PATCH 01/15] added CUBIRD DB Schema class --- framework/yii/db/Connection.php | 5 +- framework/yii/db/cubrid/Schema.php | 222 +++++++++++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 framework/yii/db/cubrid/Schema.php 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; + } +} From f4fb2d94efef724c7aac1f098f13d8ee103eef2b Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 5 Sep 2013 17:29:47 +0200 Subject: [PATCH 02/15] finalizing cubrid Schema --- framework/yii/db/Command.php | 2 +- framework/yii/db/QueryBuilder.php | 2 +- framework/yii/db/cubrid/Schema.php | 22 +++++++++++----------- framework/yii/db/mysql/QueryBuilder.php | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/framework/yii/db/Command.php b/framework/yii/db/Command.php index 460cd46..c439775 100644 --- a/framework/yii/db/Command.php +++ b/framework/yii/db/Command.php @@ -472,7 +472,7 @@ class Command extends \yii\base\Component * ))->execute(); * ~~~ * - * Not that the values in each row must match the corresponding column names. + * Note that the values in each row must match the corresponding column names. * * @param string $table the table that new rows will be inserted into. * @param array $columns the column names diff --git a/framework/yii/db/QueryBuilder.php b/framework/yii/db/QueryBuilder.php index f67038c..00d21c0 100644 --- a/framework/yii/db/QueryBuilder.php +++ b/framework/yii/db/QueryBuilder.php @@ -134,7 +134,7 @@ class QueryBuilder extends \yii\base\Object * ))->execute(); * ~~~ * - * Not that the values in each row must match the corresponding column names. + * Note that the values in each row must match the corresponding column names. * * @param string $table the table that new rows will be inserted into. * @param array $columns the column names diff --git a/framework/yii/db/cubrid/Schema.php b/framework/yii/db/cubrid/Schema.php index 3b60b64..9242dc1 100644 --- a/framework/yii/db/cubrid/Schema.php +++ b/framework/yii/db/cubrid/Schema.php @@ -43,9 +43,6 @@ class Schema extends \yii\db\Schema '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, @@ -56,6 +53,9 @@ class Schema extends \yii\db\Schema // BLOB/CLOB data types 'blob' => self::TYPE_BINARY, 'clob' => self::TYPE_BINARY, + // Bit string data types +// 'bit' => self::TYPE_STRING, +// 'bit varying' => self::TYPE_STRING, // Collection data types (TODO are considered strings for now, naybe support conversion?) // 'set' => self::TYPE_STRING, // 'multiset' => self::TYPE_STRING, @@ -106,7 +106,7 @@ class Schema extends \yii\db\Schema $tableInfo = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_TABLE, $name); if (isset($tableInfo[0]['NAME'])) { - $table = new TableSchema; + $table = new TableSchema(); $table->name = $tableInfo[0]['NAME']; $sql = 'SHOW FULL COLUMNS FROM ' . $this->quoteSimpleTableName($table->name); @@ -145,7 +145,7 @@ class Schema extends \yii\db\Schema */ protected function loadColumnSchema($info) { - $column = new ColumnSchema; + $column = new ColumnSchema(); $column->name = $info['Field']; $column->allowNull = $info['Null'] === 'YES'; @@ -174,13 +174,13 @@ class Schema extends \yii\db\Schema 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'; + if ($type === 'bit' || $type === 'bit varying') { + if ($column->size === 1) { + $column->type = self::TYPE_BOOLEAN; + } elseif ($column->size > 32) { + $column->type = self::TYPE_BIGINT; } elseif ($column->size === 32) { - $column->type = 'integer'; + $column->type = self::TYPE_INTEGER; } } } diff --git a/framework/yii/db/mysql/QueryBuilder.php b/framework/yii/db/mysql/QueryBuilder.php index 0307abd..c7a4256 100644 --- a/framework/yii/db/mysql/QueryBuilder.php +++ b/framework/yii/db/mysql/QueryBuilder.php @@ -152,7 +152,7 @@ class QueryBuilder extends \yii\db\QueryBuilder * ))->execute(); * ~~~ * - * Not that the values in each row must match the corresponding column names. + * Note that the values in each row must match the corresponding column names. * * @param string $table the table that new rows will be inserted into. * @param array $columns the column names From 57a91c842afe84f9651410cf7314f4c65f055b65 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 5 Sep 2013 17:30:18 +0200 Subject: [PATCH 03/15] CUBRID Query builder --- framework/yii/db/cubrid/QueryBuilder.php | 116 +++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 framework/yii/db/cubrid/QueryBuilder.php diff --git a/framework/yii/db/cubrid/QueryBuilder.php b/framework/yii/db/cubrid/QueryBuilder.php new file mode 100644 index 0000000..28b6466 --- /dev/null +++ b/framework/yii/db/cubrid/QueryBuilder.php @@ -0,0 +1,116 @@ + + * @since 2.0 + */ +class QueryBuilder extends \yii\db\QueryBuilder +{ + /** + * @var array mapping from abstract column types (keys) to physical column types (values). + */ + public $typeMap = array( + Schema::TYPE_PK => 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY', + Schema::TYPE_STRING => 'varchar(255)', + Schema::TYPE_TEXT => 'varchar', + Schema::TYPE_SMALLINT => 'smallint', + Schema::TYPE_INTEGER => 'int', + Schema::TYPE_BIGINT => 'bigint', + Schema::TYPE_FLOAT => 'float(7)', + Schema::TYPE_DECIMAL => 'decimal(10,0)', + Schema::TYPE_DATETIME => 'datetime', + Schema::TYPE_TIMESTAMP => 'timestamp', + Schema::TYPE_TIME => 'time', + Schema::TYPE_DATE => 'date', + Schema::TYPE_BINARY => 'blob', + Schema::TYPE_BOOLEAN => 'bit(1)', + Schema::TYPE_MONEY => 'decimal(19,4)', + ); + + /** + * Creates a SQL statement for resetting the sequence value of a table's primary key. + * The sequence will be reset such that the primary key of the next new row inserted + * will have the specified value or 1. + * @param string $tableName the name of the table whose primary key sequence will be reset + * @param mixed $value the value for the primary key of the next new row inserted. If this is not set, + * the next new row's primary key will have a value 1. + * @return string the SQL statement for resetting sequence + * @throws InvalidParamException if the table does not exist or there is no sequence associated with the table. + */ + public function resetSequence($tableName, $value = null) + { + $table = $this->db->getTableSchema($tableName); + if ($table !== null && $table->sequenceName !== null) { + $tableName = $this->db->quoteTableName($tableName); + if ($value === null) { + $key = reset($table->primaryKey); + $value = (int)$this->db->createCommand("SELECT MAX(`$key`) FROM " . $this->db->schema->quoteTableName($tableName))->queryScalar() + 1; + } else { + $value = (int)$value; + } + return "ALTER TABLE " . $this->db->schema->quoteTableName($tableName) . " AUTO_INCREMENT=$value;"; + } elseif ($table === null) { + throw new InvalidParamException("Table not found: $tableName"); + } else { + throw new InvalidParamException("There is not sequence associated with table '$tableName'."); + } + } + + /** + * Generates a batch INSERT SQL statement. + * For example, + * + * ~~~ + * $connection->createCommand()->batchInsert('tbl_user', array('name', 'age'), array( + * array('Tom', 30), + * array('Jane', 20), + * array('Linda', 25), + * ))->execute(); + * ~~~ + * + * Note that the values in each row must match the corresponding column names. + * + * @param string $table the table that new rows will be inserted into. + * @param array $columns the column names + * @param array $rows the rows to be batch inserted into the table + * @return string the batch INSERT SQL statement + */ + public function batchInsert($table, $columns, $rows) + { + if (($tableSchema = $this->db->getTableSchema($table)) !== null) { + $columnSchemas = $tableSchema->columns; + } else { + $columnSchemas = array(); + } + + foreach ($columns as $i => $name) { + $columns[$i] = $this->db->quoteColumnName($name); + } + + $values = array(); + foreach ($rows as $row) { + $vs = array(); + foreach ($row as $i => $value) { + if (!is_array($value) && isset($columnSchemas[$columns[$i]])) { + $value = $columnSchemas[$columns[$i]]->typecast($value); + } + $vs[] = is_string($value) ? $this->db->quoteValue($value) : $value; + } + $values[] = '(' . implode(', ', $vs) . ')'; + } + + return 'INSERT INTO ' . $this->db->quoteTableName($table) + . ' (' . implode(', ', $columns) . ') VALUES ' . implode(', ', $values); + } +} From 2387d003415647bcd20750c60b0ca7c93fcfb69e Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 5 Sep 2013 18:22:24 +0200 Subject: [PATCH 04/15] CUBRID added exception about wrong implementation of quoteValue --- framework/yii/db/cubrid/QueryBuilder.php | 2 +- framework/yii/db/cubrid/Schema.php | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/framework/yii/db/cubrid/QueryBuilder.php b/framework/yii/db/cubrid/QueryBuilder.php index 28b6466..2132b58 100644 --- a/framework/yii/db/cubrid/QueryBuilder.php +++ b/framework/yii/db/cubrid/QueryBuilder.php @@ -21,7 +21,7 @@ class QueryBuilder extends \yii\db\QueryBuilder * @var array mapping from abstract column types (keys) to physical column types (values). */ public $typeMap = array( - Schema::TYPE_PK => 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY', + Schema::TYPE_PK => 'int NOT NULL AUTO_INCREMENT PRIMARY KEY', Schema::TYPE_STRING => 'varchar(255)', Schema::TYPE_TEXT => 'varchar', Schema::TYPE_SMALLINT => 'smallint', diff --git a/framework/yii/db/cubrid/Schema.php b/framework/yii/db/cubrid/Schema.php index 9242dc1..f0b909b 100644 --- a/framework/yii/db/cubrid/Schema.php +++ b/framework/yii/db/cubrid/Schema.php @@ -7,6 +7,7 @@ namespace yii\db\cubrid; +use yii\base\NotSupportedException; use yii\db\Expression; use yii\db\TableSchema; use yii\db\ColumnSchema; @@ -87,6 +88,29 @@ class Schema extends \yii\db\Schema } /** + * Quotes a string value for use in a query. + * Note that if the parameter is not a string, it will be returned without change. + * @param string $str string to be quoted + * @return string the properly quoted string + * @see http://www.php.net/manual/en/function.PDO-quote.php + */ + public function quoteValue($str) + { + throw new NotSupportedException('quoteValue is currently broken in cubrid PDO'); + // TODO implement workaround +/* if (!is_string($str)) { + return $str; + } + + $this->db->open(); + if (($value = $this->db->pdo->quote($str)) !== false) { + return $value; + } else { // the driver doesn't support quote (e.g. oci) + return "'" . addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032") . "'"; + }*/ + } + + /** * Creates a query builder for the CUBRID database. * @return QueryBuilder query builder instance */ From 825258efb865a864d51ad7a0a9f655c80f3aa470 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 5 Sep 2013 18:23:25 +0200 Subject: [PATCH 05/15] cubrid unit tests WIP --- tests/unit/data/config.php | 6 ++ tests/unit/data/cubrid.sql | 100 +++++++++++++++++++++ tests/unit/framework/db/QueryBuilderTest.php | 3 + .../framework/db/cubrid/CubridActiveRecordTest.php | 13 +++ .../unit/framework/db/cubrid/CubridCommandTest.php | 13 +++ .../framework/db/cubrid/CubridConnectionTest.php | 13 +++ .../framework/db/cubrid/CubridQueryBuilderTest.php | 80 +++++++++++++++++ tests/unit/framework/db/cubrid/CubridQueryTest.php | 13 +++ 8 files changed, 241 insertions(+) create mode 100644 tests/unit/data/cubrid.sql create mode 100644 tests/unit/framework/db/cubrid/CubridActiveRecordTest.php create mode 100644 tests/unit/framework/db/cubrid/CubridCommandTest.php create mode 100644 tests/unit/framework/db/cubrid/CubridConnectionTest.php create mode 100644 tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php create mode 100644 tests/unit/framework/db/cubrid/CubridQueryTest.php diff --git a/tests/unit/data/config.php b/tests/unit/data/config.php index 8ead605..fda2be1 100644 --- a/tests/unit/data/config.php +++ b/tests/unit/data/config.php @@ -1,6 +1,12 @@ array( + 'cubrid' => array( + 'dsn' => 'cubrid:dbname=demodb;host=localhost;port=33000', + 'username' => 'dba', + 'password' => '', + 'fixture' => __DIR__ . '/cubrid.sql', + ), 'mysql' => array( 'dsn' => 'mysql:host=127.0.0.1;dbname=yiitest', 'username' => 'travis', diff --git a/tests/unit/data/cubrid.sql b/tests/unit/data/cubrid.sql new file mode 100644 index 0000000..2cf7716 --- /dev/null +++ b/tests/unit/data/cubrid.sql @@ -0,0 +1,100 @@ +/** + * This is the database schema for testing CUBRID support of Yii DAO and Active Record. + * The database setup in config.php is required to perform then relevant tests: + */ + +DROP TABLE IF EXISTS tbl_order_item; +DROP TABLE IF EXISTS tbl_item; +DROP TABLE IF EXISTS tbl_order; +DROP TABLE IF EXISTS tbl_category; +DROP TABLE IF EXISTS tbl_customer; +DROP TABLE IF EXISTS tbl_type; +DROP TABLE IF EXISTS tbl_constraints; + +CREATE TABLE `tbl_constraints` +( + `id` integer not null, + `field1` varchar(255) +); + + +CREATE TABLE `tbl_customer` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `email` varchar(128) NOT NULL, + `name` varchar(128) NOT NULL, + `address` string, + `status` int (11) DEFAULT 0, + PRIMARY KEY (`id`) +); + +CREATE TABLE `tbl_category` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(128) NOT NULL, + PRIMARY KEY (`id`) +); + +CREATE TABLE `tbl_item` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(128) NOT NULL, + `category_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `FK_item_category_id` FOREIGN KEY (`category_id`) REFERENCES `tbl_category` (`id`) ON DELETE CASCADE +); + +CREATE TABLE `tbl_order` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `customer_id` int(11) NOT NULL, + `create_time` int(11) NOT NULL, + `total` decimal(10,0) NOT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `FK_order_customer_id` FOREIGN KEY (`customer_id`) REFERENCES `tbl_customer` (`id`) ON DELETE CASCADE +); + +CREATE TABLE `tbl_order_item` ( + `order_id` int(11) NOT NULL, + `item_id` int(11) NOT NULL, + `quantity` int(11) NOT NULL, + `subtotal` decimal(10,0) NOT NULL, + PRIMARY KEY (`order_id`,`item_id`), + CONSTRAINT `FK_order_item_order_id` FOREIGN KEY (`order_id`) REFERENCES `tbl_order` (`id`) ON DELETE CASCADE, + CONSTRAINT `FK_order_item_item_id` FOREIGN KEY (`item_id`) REFERENCES `tbl_item` (`id`) ON DELETE CASCADE +); + +CREATE TABLE `tbl_type` ( + `int_col` int(11) NOT NULL, + `int_col2` int(11) DEFAULT '1', + `char_col` char(100) NOT NULL, + `char_col2` varchar(100) DEFAULT 'something', + `char_col3` string, + `float_col` double NOT NULL, + `float_col2` double DEFAULT '1.23', + `blob_col` blob, + `numeric_col` decimal(5,2) DEFAULT '33.22', + `time` timestamp NOT NULL DEFAULT '2002-01-01 00:00:00', + `bool_col` bit(1) NOT NULL, + `bool_col2` bit(1) DEFAULT B'1' +); + +INSERT INTO tbl_customer (email, name, address, status) VALUES ('user1@example.com', 'user1', 'address1', 1); +INSERT INTO tbl_customer (email, name, address, status) VALUES ('user2@example.com', 'user2', 'address2', 1); +INSERT INTO tbl_customer (email, name, address, status) VALUES ('user3@example.com', 'user3', 'address3', 2); + +INSERT INTO tbl_category (name) VALUES ('Books'); +INSERT INTO tbl_category (name) VALUES ('Movies'); + +INSERT INTO tbl_item (name, category_id) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); +INSERT INTO tbl_item (name, category_id) VALUES ('Yii 1.1 Application Development Cookbook', 1); +INSERT INTO tbl_item (name, category_id) VALUES ('Ice Age', 2); +INSERT INTO tbl_item (name, category_id) VALUES ('Toy Story', 2); +INSERT INTO tbl_item (name, category_id) VALUES ('Cars', 2); + +INSERT INTO tbl_order (customer_id, create_time, total) VALUES (1, 1325282384, 110.0); +INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325334482, 33.0); +INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325502201, 40.0); + +INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); +INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); +INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); +INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); +INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); +INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); diff --git a/tests/unit/framework/db/QueryBuilderTest.php b/tests/unit/framework/db/QueryBuilderTest.php index e08ac87..81a8156 100644 --- a/tests/unit/framework/db/QueryBuilderTest.php +++ b/tests/unit/framework/db/QueryBuilderTest.php @@ -8,6 +8,7 @@ use yii\db\mysql\QueryBuilder as MysqlQueryBuilder; use yii\db\sqlite\QueryBuilder as SqliteQueryBuilder; use yii\db\mssql\QueryBuilder as MssqlQueryBuilder; use yii\db\pgsql\QueryBuilder as PgsqlQueryBuilder; +use yii\db\cubrid\QueryBuilder as CubridQueryBuilder; class QueryBuilderTest extends DatabaseTestCase { @@ -32,6 +33,8 @@ class QueryBuilderTest extends DatabaseTestCase return new MssqlQueryBuilder($this->getConnection()); case 'pgsql': return new PgsqlQueryBuilder($this->getConnection()); + case 'cubrid': + return new CubridQueryBuilder($this->getConnection()); } throw new \Exception('Test is not implemented for ' . $this->driverName); } diff --git a/tests/unit/framework/db/cubrid/CubridActiveRecordTest.php b/tests/unit/framework/db/cubrid/CubridActiveRecordTest.php new file mode 100644 index 0000000..b30880b --- /dev/null +++ b/tests/unit/framework/db/cubrid/CubridActiveRecordTest.php @@ -0,0 +1,13 @@ +driverName = 'cubrid'; + parent::setUp(); + } +} diff --git a/tests/unit/framework/db/cubrid/CubridCommandTest.php b/tests/unit/framework/db/cubrid/CubridCommandTest.php new file mode 100644 index 0000000..60e422f --- /dev/null +++ b/tests/unit/framework/db/cubrid/CubridCommandTest.php @@ -0,0 +1,13 @@ +driverName = 'cubrid'; + parent::setUp(); + } +} diff --git a/tests/unit/framework/db/cubrid/CubridConnectionTest.php b/tests/unit/framework/db/cubrid/CubridConnectionTest.php new file mode 100644 index 0000000..2937d22 --- /dev/null +++ b/tests/unit/framework/db/cubrid/CubridConnectionTest.php @@ -0,0 +1,13 @@ +driverName = 'cubrid'; + parent::setUp(); + } +} diff --git a/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php b/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php new file mode 100644 index 0000000..36967d7 --- /dev/null +++ b/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php @@ -0,0 +1,80 @@ + 5)', 'int NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'), + array(Schema::TYPE_PK . '(8) CHECK (value > 5)', 'int NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'), + array(Schema::TYPE_STRING, 'varchar(255)'), + array(Schema::TYPE_STRING . '(32)', 'varchar(32)'), + array(Schema::TYPE_STRING . ' CHECK (value LIKE "test%")', 'varchar(255) CHECK (value LIKE "test%")'), + array(Schema::TYPE_STRING . '(32) CHECK (value LIKE "test%")', 'varchar(32) CHECK (value LIKE "test%")'), + array(Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'), + array(Schema::TYPE_TEXT, 'varchar'), + array(Schema::TYPE_TEXT . '(255)', 'varchar'), + array(Schema::TYPE_TEXT . ' CHECK (value LIKE "test%")', 'varchar CHECK (value LIKE "test%")'), + array(Schema::TYPE_TEXT . '(255) CHECK (value LIKE "test%")', 'varchar CHECK (value LIKE "test%")'), + array(Schema::TYPE_TEXT . ' NOT NULL', 'varchar NOT NULL'), + array(Schema::TYPE_TEXT . '(255) NOT NULL', 'varchar NOT NULL'), + array(Schema::TYPE_SMALLINT, 'smallint'), + array(Schema::TYPE_SMALLINT . '(8)', 'smallint'), + array(Schema::TYPE_INTEGER, 'int'), + array(Schema::TYPE_INTEGER . '(8)', 'int'), + array(Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'int CHECK (value > 5)'), + array(Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'int CHECK (value > 5)'), + array(Schema::TYPE_INTEGER . ' NOT NULL', 'int NOT NULL'), + array(Schema::TYPE_BIGINT, 'bigint'), + array(Schema::TYPE_BIGINT . '(8)', 'bigint'), + array(Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint CHECK (value > 5)'), + array(Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint CHECK (value > 5)'), + array(Schema::TYPE_BIGINT . ' NOT NULL', 'bigint NOT NULL'), + array(Schema::TYPE_FLOAT, 'float(7)'), + array(Schema::TYPE_FLOAT . '(16)', 'float(16)'), + array(Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'float(7) CHECK (value > 5.6)'), + array(Schema::TYPE_FLOAT . '(16) CHECK (value > 5.6)', 'float(16) CHECK (value > 5.6)'), + array(Schema::TYPE_FLOAT . ' NOT NULL', 'float(7) NOT NULL'), + array(Schema::TYPE_DECIMAL, 'decimal(10,0)'), + array(Schema::TYPE_DECIMAL . '(12,4)', 'decimal(12,4)'), + array(Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'decimal(10,0) CHECK (value > 5.6)'), + array(Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'decimal(12,4) CHECK (value > 5.6)'), + array(Schema::TYPE_DECIMAL . ' NOT NULL', 'decimal(10,0) NOT NULL'), + array(Schema::TYPE_DATETIME, 'datetime'), + array(Schema::TYPE_DATETIME . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "datetime CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"), + array(Schema::TYPE_DATETIME . ' NOT NULL', 'datetime NOT NULL'), + array(Schema::TYPE_TIMESTAMP, 'timestamp'), + array(Schema::TYPE_TIMESTAMP . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"), + array(Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp NOT NULL'), + array(Schema::TYPE_TIME, 'time'), + array(Schema::TYPE_TIME . " CHECK(value BETWEEN '12:00:00' AND '13:01:01')", "time CHECK(value BETWEEN '12:00:00' AND '13:01:01')"), + array(Schema::TYPE_TIME . ' NOT NULL', 'time NOT NULL'), + array(Schema::TYPE_DATE, 'date'), + array(Schema::TYPE_DATE . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"), + array(Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'), + array(Schema::TYPE_BINARY, 'blob'), + array(Schema::TYPE_BOOLEAN, 'bit(1)'), + array(Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'bit(1) NOT NULL DEFAULT 1'), + array(Schema::TYPE_MONEY, 'decimal(19,4)'), + array(Schema::TYPE_MONEY . '(16,2)', 'decimal(16,2)'), + array(Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'decimal(19,4) CHECK (value > 0.0)'), + array(Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'decimal(16,2) CHECK (value > 0.0)'), + array(Schema::TYPE_MONEY . ' NOT NULL', 'decimal(19,4) NOT NULL'), + ); + } + +} diff --git a/tests/unit/framework/db/cubrid/CubridQueryTest.php b/tests/unit/framework/db/cubrid/CubridQueryTest.php new file mode 100644 index 0000000..0503fbc --- /dev/null +++ b/tests/unit/framework/db/cubrid/CubridQueryTest.php @@ -0,0 +1,13 @@ +driverName = 'cubrid'; + parent::setUp(); + } +} From d6ff097cbbc952d643fdf16777bba72d04adf755 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Fri, 6 Sep 2013 10:28:10 +0200 Subject: [PATCH 06/15] avoid hanging test on bindValue problems (close db connection in tearDown) --- tests/unit/framework/db/DatabaseTestCase.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/unit/framework/db/DatabaseTestCase.php b/tests/unit/framework/db/DatabaseTestCase.php index 1fd2d56..1dd8cfc 100644 --- a/tests/unit/framework/db/DatabaseTestCase.php +++ b/tests/unit/framework/db/DatabaseTestCase.php @@ -1,12 +1,16 @@ db) { + $this->db->close(); + } + } + /** * @param bool $reset whether to clean up the test database * @param bool $open whether to open and populate test database From e446a118640fae9ecad414022ad5d2799d4dab0b Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Fri, 6 Sep 2013 11:38:54 +0200 Subject: [PATCH 07/15] added CURBID to the docs --- docs/guide/database-basics.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/guide/database-basics.md b/docs/guide/database-basics.md index 71510f4..310e3f5 100644 --- a/docs/guide/database-basics.md +++ b/docs/guide/database-basics.md @@ -2,8 +2,14 @@ Database basics =============== Yii has a database access layer built on top of PHP's [PDO](http://www.php.net/manual/en/ref.pdo.php). It provides -uniform API and solves some inconsistencies between different DBMS. By default Yii supports MySQL, SQLite, PostgreSQL, -Oracle and MSSQL. +uniform API and solves some inconsistencies between different DBMS. By default Yii supports the following DBMS: + +- [MySQL](http://www.mysql.com/) +- [SQLite](http://sqlite.org/) +- [PostgreSQL](http://www.postgresql.org/) +- [CUBRID](http://www.cubrid.org/) (version 9.1.0 and higher). +- Oracle +- MSSQL Configuration @@ -22,6 +28,7 @@ return array( 'dsn' => 'mysql:host=localhost;dbname=mydatabase', // MySQL, MariaDB //'dsn' => 'sqlite:/path/to/database/file', // SQLite //'dsn' => 'pgsql:host=localhost;port=5432;dbname=mydatabase', // PostgreSQL + //'dsn' => 'cubrid:dbname=demodb;host=localhost;port=33000', // CUBRID //'dsn' => 'sqlsrv:Server=localhost;Database=mydatabase', // MS SQL Server, sqlsrv driver //'dsn' => 'dblib:host=localhost;dbname=mydatabase', // MS SQL Server, dblib driver //'dsn' => 'mssql:host=localhost;dbname=mydatabase', // MS SQL Server, mssql driver @@ -34,8 +41,10 @@ return array( // ... ); ``` +Please refer to the [PHP manual](http://www.php.net/manual/en/function.PDO-construct.php) for more details +on the format of the DSN string. -After the component is configured you can access it using the following syntax: +After the connection component is configured you can access it using the following syntax: ```php $connection = \Yii::$app->db; From c6ef7ec9d5acd00720cb306018960244dcd08938 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Fri, 6 Sep 2013 11:40:29 +0200 Subject: [PATCH 08/15] moved Command::getPdoType() to Schema this allows different implementation in different DBMS CUBRID does not supprt PDO::TYPE_BOOL, so we use STRING here which will be casted by the DBMS --- framework/yii/db/Command.php | 25 +++---------------------- framework/yii/db/Schema.php | 19 +++++++++++++++++++ framework/yii/db/cubrid/QueryBuilder.php | 2 +- framework/yii/db/cubrid/Schema.php | 19 +++++++++++++++++++ 4 files changed, 42 insertions(+), 23 deletions(-) diff --git a/framework/yii/db/Command.php b/framework/yii/db/Command.php index c439775..7f2d81d 100644 --- a/framework/yii/db/Command.php +++ b/framework/yii/db/Command.php @@ -181,7 +181,7 @@ class Command extends \yii\base\Component { $this->prepare(); if ($dataType === null) { - $this->pdoStatement->bindParam($name, $value, $this->getPdoType($value)); + $this->pdoStatement->bindParam($name, $value, $this->db->schema->getPdoType($value)); } elseif ($length === null) { $this->pdoStatement->bindParam($name, $value, $dataType); } elseif ($driverOptions === null) { @@ -208,7 +208,7 @@ class Command extends \yii\base\Component { $this->prepare(); if ($dataType === null) { - $this->pdoStatement->bindValue($name, $value, $this->getPdoType($value)); + $this->pdoStatement->bindValue($name, $value, $this->db->schema->getPdoType($value)); } else { $this->pdoStatement->bindValue($name, $value, $dataType); } @@ -236,7 +236,7 @@ class Command extends \yii\base\Component $type = $value[1]; $value = $value[0]; } else { - $type = $this->getPdoType($value); + $type = $this->db->schema->getPdoType($value); } $this->pdoStatement->bindValue($name, $value, $type); $this->_params[$name] = $value; @@ -246,25 +246,6 @@ class Command extends \yii\base\Component } /** - * Determines the PDO type for the give PHP data value. - * @param mixed $data the data whose PDO type is to be determined - * @return integer the PDO type - * @see http://www.php.net/manual/en/pdo.constants.php - */ - private function getPdoType($data) - { - static $typeMap = array( - 'boolean' => \PDO::PARAM_BOOL, - 'integer' => \PDO::PARAM_INT, - 'string' => \PDO::PARAM_STR, - 'resource' => \PDO::PARAM_LOB, - 'NULL' => \PDO::PARAM_NULL, - ); - $type = gettype($data); - return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR; - } - - /** * Executes the SQL statement. * This method should only be used for executing non-query SQL statement, such as `INSERT`, `DELETE`, `UPDATE` SQLs. * No result set will be returned. diff --git a/framework/yii/db/Schema.php b/framework/yii/db/Schema.php index 4fd1cd1..9839144 100644 --- a/framework/yii/db/Schema.php +++ b/framework/yii/db/Schema.php @@ -376,4 +376,23 @@ abstract class Schema extends Object return 'string'; } } + + /** + * Determines the PDO type for the give PHP data value. + * @param mixed $data the data whose PDO type is to be determined + * @return integer the PDO type + * @see http://www.php.net/manual/en/pdo.constants.php + */ + public function getPdoType($data) + { + static $typeMap = array( // php type => PDO type + 'boolean' => \PDO::PARAM_BOOL, + 'integer' => \PDO::PARAM_INT, + 'string' => \PDO::PARAM_STR, + 'resource' => \PDO::PARAM_LOB, + 'NULL' => \PDO::PARAM_NULL, + ); + $type = gettype($data); + return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR; + } } diff --git a/framework/yii/db/cubrid/QueryBuilder.php b/framework/yii/db/cubrid/QueryBuilder.php index 2132b58..4e5121a 100644 --- a/framework/yii/db/cubrid/QueryBuilder.php +++ b/framework/yii/db/cubrid/QueryBuilder.php @@ -10,7 +10,7 @@ namespace yii\db\cubrid; use yii\base\InvalidParamException; /** - * QueryBuilder is the query builder for CUBRID databases. + * QueryBuilder is the query builder for CUBRID databases (version 9.1.x and higher). * * @author Carsten Brandt * @since 2.0 diff --git a/framework/yii/db/cubrid/Schema.php b/framework/yii/db/cubrid/Schema.php index f0b909b..a423296 100644 --- a/framework/yii/db/cubrid/Schema.php +++ b/framework/yii/db/cubrid/Schema.php @@ -243,4 +243,23 @@ class Schema extends \yii\db\Schema } return $tableNames; } + + /** + * Determines the PDO type for the give PHP data value. + * @param mixed $data the data whose PDO type is to be determined + * @return integer the PDO type + * @see http://www.php.net/manual/en/pdo.constants.php + */ + public function getPdoType($data) + { + static $typeMap = array( + 'boolean' => \PDO::PARAM_STR, // CUBRID PDO does not support PARAM_BOOL + 'integer' => \PDO::PARAM_INT, + 'string' => \PDO::PARAM_STR, + 'resource' => \PDO::PARAM_LOB, + 'NULL' => \PDO::PARAM_NULL, + ); + $type = gettype($data); + return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR; + } } From 791f9d3f4e815244cc67c6cc2e928d57d884c76b Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Fri, 6 Sep 2013 13:21:35 +0200 Subject: [PATCH 09/15] better use int for boolean representation bit has special syntax for storing and retreiving so we'd need a converter for that. Storing 1 bit will result in one byte left padded on the disc so the result of a query for boolean 0 will be 0x00 and for boolean 1 will be 0x80. --- framework/yii/db/cubrid/QueryBuilder.php | 2 +- framework/yii/db/cubrid/Schema.php | 11 +---------- tests/unit/data/cubrid.sql | 4 ++-- tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php | 4 ++-- 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/framework/yii/db/cubrid/QueryBuilder.php b/framework/yii/db/cubrid/QueryBuilder.php index 4e5121a..935b3d3 100644 --- a/framework/yii/db/cubrid/QueryBuilder.php +++ b/framework/yii/db/cubrid/QueryBuilder.php @@ -34,7 +34,7 @@ class QueryBuilder extends \yii\db\QueryBuilder Schema::TYPE_TIME => 'time', Schema::TYPE_DATE => 'date', Schema::TYPE_BINARY => 'blob', - Schema::TYPE_BOOLEAN => 'bit(1)', + Schema::TYPE_BOOLEAN => 'smallint', Schema::TYPE_MONEY => 'decimal(19,4)', ); diff --git a/framework/yii/db/cubrid/Schema.php b/framework/yii/db/cubrid/Schema.php index a423296..c07602f 100644 --- a/framework/yii/db/cubrid/Schema.php +++ b/framework/yii/db/cubrid/Schema.php @@ -198,15 +198,6 @@ class Schema extends \yii\db\Schema if (isset($values[1])) { $column->scale = (int)$values[1]; } - if ($type === 'bit' || $type === 'bit varying') { - if ($column->size === 1) { - $column->type = self::TYPE_BOOLEAN; - } elseif ($column->size > 32) { - $column->type = self::TYPE_BIGINT; - } elseif ($column->size === 32) { - $column->type = self::TYPE_INTEGER; - } - } } } } @@ -253,7 +244,7 @@ class Schema extends \yii\db\Schema public function getPdoType($data) { static $typeMap = array( - 'boolean' => \PDO::PARAM_STR, // CUBRID PDO does not support PARAM_BOOL + 'boolean' => \PDO::PARAM_INT, // CUBRID PDO does not support PARAM_BOOL 'integer' => \PDO::PARAM_INT, 'string' => \PDO::PARAM_STR, 'resource' => \PDO::PARAM_LOB, diff --git a/tests/unit/data/cubrid.sql b/tests/unit/data/cubrid.sql index 2cf7716..5525418 100644 --- a/tests/unit/data/cubrid.sql +++ b/tests/unit/data/cubrid.sql @@ -71,8 +71,8 @@ CREATE TABLE `tbl_type` ( `blob_col` blob, `numeric_col` decimal(5,2) DEFAULT '33.22', `time` timestamp NOT NULL DEFAULT '2002-01-01 00:00:00', - `bool_col` bit(1) NOT NULL, - `bool_col2` bit(1) DEFAULT B'1' + `bool_col` smallint NOT NULL, + `bool_col2` smallint DEFAULT 1 ); INSERT INTO tbl_customer (email, name, address, status) VALUES ('user1@example.com', 'user1', 'address1', 1); diff --git a/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php b/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php index 36967d7..94a002e 100644 --- a/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php +++ b/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php @@ -67,8 +67,8 @@ class CubridQueryBuilderTest extends QueryBuilderTest array(Schema::TYPE_DATE . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"), array(Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'), array(Schema::TYPE_BINARY, 'blob'), - array(Schema::TYPE_BOOLEAN, 'bit(1)'), - array(Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'bit(1) NOT NULL DEFAULT 1'), + array(Schema::TYPE_BOOLEAN, 'smallint'), + array(Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'smallint NOT NULL DEFAULT 1'), array(Schema::TYPE_MONEY, 'decimal(19,4)'), array(Schema::TYPE_MONEY . '(16,2)', 'decimal(16,2)'), array(Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'decimal(19,4) CHECK (value > 0.0)'), From 58f8293b8455d242d47c3b1894351371624ad2cd Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Fri, 6 Sep 2013 13:24:36 +0200 Subject: [PATCH 10/15] custom bindValue test for cubrid --- tests/unit/data/cubrid.sql | 1 + .../unit/framework/db/cubrid/CubridCommandTest.php | 63 ++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/tests/unit/data/cubrid.sql b/tests/unit/data/cubrid.sql index 5525418..8ea20a8 100644 --- a/tests/unit/data/cubrid.sql +++ b/tests/unit/data/cubrid.sql @@ -66,6 +66,7 @@ CREATE TABLE `tbl_type` ( `char_col` char(100) NOT NULL, `char_col2` varchar(100) DEFAULT 'something', `char_col3` string, + `enum_col` enum('a', 'b'), `float_col` double NOT NULL, `float_col2` double DEFAULT '1.23', `blob_col` blob, diff --git a/tests/unit/framework/db/cubrid/CubridCommandTest.php b/tests/unit/framework/db/cubrid/CubridCommandTest.php index 60e422f..6f10113 100644 --- a/tests/unit/framework/db/cubrid/CubridCommandTest.php +++ b/tests/unit/framework/db/cubrid/CubridCommandTest.php @@ -10,4 +10,67 @@ class CubridCommandTest extends CommandTest $this->driverName = 'cubrid'; parent::setUp(); } + + public function testBindParamValue() + { + $db = $this->getConnection(); + + // bindParam + $sql = 'INSERT INTO tbl_customer(email, name, address) VALUES (:email, :name, :address)'; + $command = $db->createCommand($sql); + $email = 'user4@example.com'; + $name = 'user4'; + $address = 'address4'; + $command->bindParam(':email', $email); + $command->bindParam(':name', $name); + $command->bindParam(':address', $address); + $command->execute(); + + $sql = 'SELECT name FROM tbl_customer WHERE email=:email'; + $command = $db->createCommand($sql); + $command->bindParam(':email', $email); + $this->assertEquals($name, $command->queryScalar()); + + $sql = "INSERT INTO tbl_type (int_col, char_col, char_col2, enum_col, float_col, blob_col, numeric_col, bool_col, bool_col2) VALUES (:int_col, '', :char_col, :enum_col, :float_col, CHAR_TO_BLOB(:blob_col), :numeric_col, :bool_col, :bool_col2)"; + $command = $db->createCommand($sql); + $intCol = 123; + $charCol = 'abc'; + $enumCol = 'a'; + $floatCol = 1.23; + $blobCol = "\x10\x11\x12"; + $numericCol = '1.23'; + $boolCol = false; + $boolCol2 = true; + $command->bindParam(':int_col', $intCol); + $command->bindParam(':char_col', $charCol); + $command->bindParam(':enum_col', $enumCol); + $command->bindParam(':float_col', $floatCol); + $command->bindParam(':blob_col', $blobCol); + $command->bindParam(':numeric_col', $numericCol); + $command->bindParam(':bool_col', $boolCol); + $command->bindParam(':bool_col2', $boolCol2); + $this->assertEquals(1, $command->execute()); + + $sql = 'SELECT * FROM tbl_type'; + $row = $db->createCommand($sql)->queryOne(); + $this->assertEquals($intCol, $row['int_col']); + $this->assertEquals($enumCol, $row['enum_col']); + $this->assertEquals($charCol, $row['char_col2']); + $this->assertEquals($floatCol, $row['float_col']); + $this->assertEquals($blobCol, fread($row['blob_col'], 3)); + $this->assertEquals($numericCol, $row['numeric_col']); + $this->assertEquals($boolCol, $row['bool_col']); + $this->assertEquals($boolCol2, $row['bool_col2']); + + // bindValue + $sql = 'INSERT INTO tbl_customer(email, name, address) VALUES (:email, \'user5\', \'address5\')'; + $command = $db->createCommand($sql); + $command->bindValue(':email', 'user5@example.com'); + $command->execute(); + + $sql = 'SELECT email FROM tbl_customer WHERE name=:name'; + $command = $db->createCommand($sql); + $command->bindValue(':name', 'user5'); + $this->assertEquals('user5@example.com', $command->queryScalar()); + } } From e996f3dfd579eed51f24eaa6415b367f7cb1b1f7 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Fri, 6 Sep 2013 13:53:33 +0200 Subject: [PATCH 11/15] Workaround for broken PDO::quote() in CUBRID 9.1.0 http://jira.cubrid.org/browse/APIS-658 --- framework/yii/db/cubrid/Schema.php | 13 ++++++------- tests/unit/framework/db/cubrid/CubridConnectionTest.php | 8 ++++++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/framework/yii/db/cubrid/Schema.php b/framework/yii/db/cubrid/Schema.php index c07602f..d1fdc10 100644 --- a/framework/yii/db/cubrid/Schema.php +++ b/framework/yii/db/cubrid/Schema.php @@ -96,18 +96,17 @@ class Schema extends \yii\db\Schema */ public function quoteValue($str) { - throw new NotSupportedException('quoteValue is currently broken in cubrid PDO'); - // TODO implement workaround -/* if (!is_string($str)) { + if (!is_string($str)) { return $str; } $this->db->open(); - if (($value = $this->db->pdo->quote($str)) !== false) { - return $value; - } else { // the driver doesn't support quote (e.g. oci) + // workaround for broken PDO::quote() implementation in CUBRID 9.1.0 http://jira.cubrid.org/browse/APIS-658 + if (version_compare($this->db->pdo->getAttribute(\PDO::ATTR_CLIENT_VERSION), '9.1.0', '<=')) { return "'" . addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032") . "'"; - }*/ + } else { + return $this->db->pdo->quote($str); + } } /** diff --git a/tests/unit/framework/db/cubrid/CubridConnectionTest.php b/tests/unit/framework/db/cubrid/CubridConnectionTest.php index 2937d22..bfd2c90 100644 --- a/tests/unit/framework/db/cubrid/CubridConnectionTest.php +++ b/tests/unit/framework/db/cubrid/CubridConnectionTest.php @@ -10,4 +10,12 @@ class CubridConnectionTest extends ConnectionTest $this->driverName = 'cubrid'; parent::setUp(); } + + public function testQuoteValue() + { + $connection = $this->getConnection(false); + $this->assertEquals(123, $connection->quoteValue(123)); + $this->assertEquals("'string'", $connection->quoteValue('string')); + $this->assertEquals("'It''s interesting'", $connection->quoteValue("It's interesting")); + } } From 544e412af824487bba1911b509a25f1d7ee99108 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Fri, 6 Sep 2013 15:03:25 +0200 Subject: [PATCH 12/15] unit test cleanup --- tests/unit/framework/db/CommandTest.php | 6 ------ tests/unit/framework/db/ConnectionTest.php | 6 ------ tests/unit/framework/db/DatabaseTestCase.php | 3 ++- tests/unit/framework/db/QueryBuilderTest.php | 6 ------ tests/unit/framework/db/QueryTest.php | 6 ------ tests/unit/framework/db/cubrid/CubridActiveRecordTest.php | 6 +----- tests/unit/framework/db/cubrid/CubridCommandTest.php | 6 +----- tests/unit/framework/db/cubrid/CubridConnectionTest.php | 6 +----- tests/unit/framework/db/cubrid/CubridQueryTest.php | 6 +----- tests/unit/framework/db/mssql/MssqlActiveRecordTest.php | 6 +----- tests/unit/framework/db/mssql/MssqlCommandTest.php | 6 +----- tests/unit/framework/db/mssql/MssqlConnectionTest.php | 6 +----- tests/unit/framework/db/mssql/MssqlQueryTest.php | 6 +----- tests/unit/framework/db/pgsql/PostgreSQLActiveRecordTest.php | 6 +----- tests/unit/framework/db/pgsql/PostgreSQLConnectionTest.php | 6 +----- tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php | 2 -- tests/unit/framework/db/sqlite/SqliteActiveRecordTest.php | 6 +----- tests/unit/framework/db/sqlite/SqliteCommandTest.php | 6 +----- tests/unit/framework/db/sqlite/SqliteConnectionTest.php | 6 +----- tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php | 2 +- tests/unit/framework/db/sqlite/SqliteQueryTest.php | 6 +----- 21 files changed, 17 insertions(+), 98 deletions(-) diff --git a/tests/unit/framework/db/CommandTest.php b/tests/unit/framework/db/CommandTest.php index 52fd046..229545d 100644 --- a/tests/unit/framework/db/CommandTest.php +++ b/tests/unit/framework/db/CommandTest.php @@ -9,12 +9,6 @@ use yii\db\DataReader; class CommandTest extends DatabaseTestCase { - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - public function testConstruct() { $db = $this->getConnection(false); diff --git a/tests/unit/framework/db/ConnectionTest.php b/tests/unit/framework/db/ConnectionTest.php index 42b470b..f2895f1 100644 --- a/tests/unit/framework/db/ConnectionTest.php +++ b/tests/unit/framework/db/ConnectionTest.php @@ -6,12 +6,6 @@ use yii\db\Connection; class ConnectionTest extends DatabaseTestCase { - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - public function testConstruct() { $connection = $this->getConnection(false); diff --git a/tests/unit/framework/db/DatabaseTestCase.php b/tests/unit/framework/db/DatabaseTestCase.php index 1dd8cfc..d8d2916 100644 --- a/tests/unit/framework/db/DatabaseTestCase.php +++ b/tests/unit/framework/db/DatabaseTestCase.php @@ -16,7 +16,6 @@ abstract class DatabaseTestCase extends TestCase protected function setUp() { parent::setUp(); - $this->mockApplication(); $databases = $this->getParam('databases'); $this->database = $databases[$this->driverName]; $pdo_database = 'pdo_'.$this->driverName; @@ -24,6 +23,7 @@ abstract class DatabaseTestCase extends TestCase if (!extension_loaded('pdo') || !extension_loaded($pdo_database)) { $this->markTestSkipped('pdo and pdo_'.$pdo_database.' extension are required.'); } + $this->mockApplication(); } protected function tearDown() @@ -31,6 +31,7 @@ abstract class DatabaseTestCase extends TestCase if ($this->db) { $this->db->close(); } + $this->destroyApplication(); } /** diff --git a/tests/unit/framework/db/QueryBuilderTest.php b/tests/unit/framework/db/QueryBuilderTest.php index 81a8156..a2815e8 100644 --- a/tests/unit/framework/db/QueryBuilderTest.php +++ b/tests/unit/framework/db/QueryBuilderTest.php @@ -12,12 +12,6 @@ use yii\db\cubrid\QueryBuilder as CubridQueryBuilder; class QueryBuilderTest extends DatabaseTestCase { - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - /** * @throws \Exception * @return QueryBuilder diff --git a/tests/unit/framework/db/QueryTest.php b/tests/unit/framework/db/QueryTest.php index 5d1f1a9..dfb6c9f 100644 --- a/tests/unit/framework/db/QueryTest.php +++ b/tests/unit/framework/db/QueryTest.php @@ -9,12 +9,6 @@ use yii\db\DataReader; class QueryTest extends DatabaseTestCase { - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - public function testSelect() { // default diff --git a/tests/unit/framework/db/cubrid/CubridActiveRecordTest.php b/tests/unit/framework/db/cubrid/CubridActiveRecordTest.php index b30880b..6633e11 100644 --- a/tests/unit/framework/db/cubrid/CubridActiveRecordTest.php +++ b/tests/unit/framework/db/cubrid/CubridActiveRecordTest.php @@ -5,9 +5,5 @@ use yiiunit\framework\db\ActiveRecordTest; class CubridActiveRecordTest extends ActiveRecordTest { - protected function setUp() - { - $this->driverName = 'cubrid'; - parent::setUp(); - } + public $driverName = 'cubrid'; } diff --git a/tests/unit/framework/db/cubrid/CubridCommandTest.php b/tests/unit/framework/db/cubrid/CubridCommandTest.php index 6f10113..5fe8848 100644 --- a/tests/unit/framework/db/cubrid/CubridCommandTest.php +++ b/tests/unit/framework/db/cubrid/CubridCommandTest.php @@ -5,11 +5,7 @@ use yiiunit\framework\db\CommandTest; class CubridCommandTest extends CommandTest { - protected function setUp() - { - $this->driverName = 'cubrid'; - parent::setUp(); - } + public $driverName = 'cubrid'; public function testBindParamValue() { diff --git a/tests/unit/framework/db/cubrid/CubridConnectionTest.php b/tests/unit/framework/db/cubrid/CubridConnectionTest.php index bfd2c90..6924883 100644 --- a/tests/unit/framework/db/cubrid/CubridConnectionTest.php +++ b/tests/unit/framework/db/cubrid/CubridConnectionTest.php @@ -5,11 +5,7 @@ use yiiunit\framework\db\ConnectionTest; class CubridConnectionTest extends ConnectionTest { - protected function setUp() - { - $this->driverName = 'cubrid'; - parent::setUp(); - } + public $driverName = 'cubrid'; public function testQuoteValue() { diff --git a/tests/unit/framework/db/cubrid/CubridQueryTest.php b/tests/unit/framework/db/cubrid/CubridQueryTest.php index 0503fbc..2c68a35 100644 --- a/tests/unit/framework/db/cubrid/CubridQueryTest.php +++ b/tests/unit/framework/db/cubrid/CubridQueryTest.php @@ -5,9 +5,5 @@ use yiiunit\framework\db\QueryTest; class CubridQueryTest extends QueryTest { - protected function setUp() - { - $this->driverName = 'cubrid'; - parent::setUp(); - } + public $driverName = 'cubrid'; } diff --git a/tests/unit/framework/db/mssql/MssqlActiveRecordTest.php b/tests/unit/framework/db/mssql/MssqlActiveRecordTest.php index 5647411..92e4da2 100644 --- a/tests/unit/framework/db/mssql/MssqlActiveRecordTest.php +++ b/tests/unit/framework/db/mssql/MssqlActiveRecordTest.php @@ -6,9 +6,5 @@ use yiiunit\framework\db\ActiveRecordTest; class MssqlActiveRecordTest extends ActiveRecordTest { - protected function setUp() - { - $this->driverName = 'sqlsrv'; - parent::setUp(); - } + protected $driverName = 'sqlsrv'; } diff --git a/tests/unit/framework/db/mssql/MssqlCommandTest.php b/tests/unit/framework/db/mssql/MssqlCommandTest.php index e27fcee..1908f65 100644 --- a/tests/unit/framework/db/mssql/MssqlCommandTest.php +++ b/tests/unit/framework/db/mssql/MssqlCommandTest.php @@ -6,11 +6,7 @@ use yiiunit\framework\db\CommandTest; class MssqlCommandTest extends CommandTest { - public function setUp() - { - $this->driverName = 'sqlsrv'; - parent::setUp(); - } + protected $driverName = 'sqlsrv'; public function testAutoQuoting() { diff --git a/tests/unit/framework/db/mssql/MssqlConnectionTest.php b/tests/unit/framework/db/mssql/MssqlConnectionTest.php index 7bbaae7..854c81f 100644 --- a/tests/unit/framework/db/mssql/MssqlConnectionTest.php +++ b/tests/unit/framework/db/mssql/MssqlConnectionTest.php @@ -6,11 +6,7 @@ use yiiunit\framework\db\ConnectionTest; class MssqlConnectionTest extends ConnectionTest { - public function setUp() - { - $this->driverName = 'sqlsrv'; - parent::setUp(); - } + protected $driverName = 'sqlsrv'; public function testQuoteValue() { diff --git a/tests/unit/framework/db/mssql/MssqlQueryTest.php b/tests/unit/framework/db/mssql/MssqlQueryTest.php index 4f37c14..e07ac1d 100644 --- a/tests/unit/framework/db/mssql/MssqlQueryTest.php +++ b/tests/unit/framework/db/mssql/MssqlQueryTest.php @@ -6,9 +6,5 @@ use yiiunit\framework\db\QueryTest; class MssqlQueryTest extends QueryTest { - public function setUp() - { - $this->driverName = 'sqlsrv'; - parent::setUp(); - } + protected $driverName = 'sqlsrv'; } diff --git a/tests/unit/framework/db/pgsql/PostgreSQLActiveRecordTest.php b/tests/unit/framework/db/pgsql/PostgreSQLActiveRecordTest.php index 2836223..aef09fd 100644 --- a/tests/unit/framework/db/pgsql/PostgreSQLActiveRecordTest.php +++ b/tests/unit/framework/db/pgsql/PostgreSQLActiveRecordTest.php @@ -6,9 +6,5 @@ use yiiunit\framework\db\ActiveRecordTest; class PostgreSQLActiveRecordTest extends ActiveRecordTest { - protected function setUp() - { - $this->driverName = 'pgsql'; - parent::setUp(); - } + protected $driverName = 'pgsql'; } diff --git a/tests/unit/framework/db/pgsql/PostgreSQLConnectionTest.php b/tests/unit/framework/db/pgsql/PostgreSQLConnectionTest.php index 7ac65c5..cd76a97 100644 --- a/tests/unit/framework/db/pgsql/PostgreSQLConnectionTest.php +++ b/tests/unit/framework/db/pgsql/PostgreSQLConnectionTest.php @@ -5,11 +5,7 @@ use yiiunit\framework\db\ConnectionTest; class PostgreSQLConnectionTest extends ConnectionTest { - public function setUp() - { - $this->driverName = 'pgsql'; - parent::setUp(); - } + protected $driverName = 'pgsql'; public function testConnection() { diff --git a/tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php b/tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php index 7c31190..bf2dd73 100644 --- a/tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php +++ b/tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php @@ -2,13 +2,11 @@ namespace yiiunit\framework\db\pgsql; -use yii\base\NotSupportedException; use yii\db\pgsql\Schema; use yiiunit\framework\db\QueryBuilderTest; class PostgreSQLQueryBuilderTest extends QueryBuilderTest { - public $driverName = 'pgsql'; public function columnTypes() diff --git a/tests/unit/framework/db/sqlite/SqliteActiveRecordTest.php b/tests/unit/framework/db/sqlite/SqliteActiveRecordTest.php index 2e76162..1088280 100644 --- a/tests/unit/framework/db/sqlite/SqliteActiveRecordTest.php +++ b/tests/unit/framework/db/sqlite/SqliteActiveRecordTest.php @@ -5,9 +5,5 @@ use yiiunit\framework\db\ActiveRecordTest; class SqliteActiveRecordTest extends ActiveRecordTest { - protected function setUp() - { - $this->driverName = 'sqlite'; - parent::setUp(); - } + protected $driverName = 'sqlite'; } diff --git a/tests/unit/framework/db/sqlite/SqliteCommandTest.php b/tests/unit/framework/db/sqlite/SqliteCommandTest.php index e330c7e..af9a323 100644 --- a/tests/unit/framework/db/sqlite/SqliteCommandTest.php +++ b/tests/unit/framework/db/sqlite/SqliteCommandTest.php @@ -5,11 +5,7 @@ use yiiunit\framework\db\CommandTest; class SqliteCommandTest extends CommandTest { - protected function setUp() - { - $this->driverName = 'sqlite'; - parent::setUp(); - } + protected $driverName = 'sqlite'; public function testAutoQuoting() { diff --git a/tests/unit/framework/db/sqlite/SqliteConnectionTest.php b/tests/unit/framework/db/sqlite/SqliteConnectionTest.php index 2065200..f1d5b94 100644 --- a/tests/unit/framework/db/sqlite/SqliteConnectionTest.php +++ b/tests/unit/framework/db/sqlite/SqliteConnectionTest.php @@ -5,11 +5,7 @@ use yiiunit\framework\db\ConnectionTest; class SqliteConnectionTest extends ConnectionTest { - protected function setUp() - { - $this->driverName = 'sqlite'; - parent::setUp(); - } + protected $driverName = 'sqlite'; public function testConstruct() { diff --git a/tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php b/tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php index 3291187..2e3a615 100644 --- a/tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php +++ b/tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php @@ -8,7 +8,7 @@ use yiiunit\framework\db\QueryBuilderTest; class SqliteQueryBuilderTest extends QueryBuilderTest { - public $driverName = 'sqlite'; + protected $driverName = 'sqlite'; public function columnTypes() { diff --git a/tests/unit/framework/db/sqlite/SqliteQueryTest.php b/tests/unit/framework/db/sqlite/SqliteQueryTest.php index ebbb1bb..3f112dc 100644 --- a/tests/unit/framework/db/sqlite/SqliteQueryTest.php +++ b/tests/unit/framework/db/sqlite/SqliteQueryTest.php @@ -5,9 +5,5 @@ use yiiunit\framework\db\QueryTest; class SqliteQueryTest extends QueryTest { - protected function setUp() - { - $this->driverName = 'sqlite'; - parent::setUp(); - } + protected $driverName = 'sqlite'; } From 8abeed03bd827a3684350f4775a23f5e92e7c317 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Fri, 6 Sep 2013 15:03:57 +0200 Subject: [PATCH 13/15] added SchemaTest --- framework/yii/db/cubrid/Schema.php | 2 +- tests/unit/framework/db/SchemaTest.php | 70 ++++++++++++++++++++++ .../unit/framework/db/cubrid/CubridSchemaTest.php | 31 ++++++++++ .../unit/framework/db/sqlite/SqliteSchemaTest.php | 9 +++ 4 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 tests/unit/framework/db/SchemaTest.php create mode 100644 tests/unit/framework/db/cubrid/CubridSchemaTest.php create mode 100644 tests/unit/framework/db/sqlite/SqliteSchemaTest.php diff --git a/framework/yii/db/cubrid/Schema.php b/framework/yii/db/cubrid/Schema.php index d1fdc10..d221073 100644 --- a/framework/yii/db/cubrid/Schema.php +++ b/framework/yii/db/cubrid/Schema.php @@ -227,7 +227,7 @@ class Schema extends \yii\db\Schema $tableNames = array(); foreach($tables as $table) { // do not list system tables - if ($table['TYPE'] !== 0) { + if ($table['TYPE'] != 0) { $tableNames[] = $table['NAME']; } } diff --git a/tests/unit/framework/db/SchemaTest.php b/tests/unit/framework/db/SchemaTest.php new file mode 100644 index 0000000..66aa410 --- /dev/null +++ b/tests/unit/framework/db/SchemaTest.php @@ -0,0 +1,70 @@ +getConnection()->schema; + + foreach($values as $value) { + $this->assertEquals($value[1], $schema->getPdoType($value[0])); + } + fclose($fp); + } + + public function testFindTableNames() + { + /** @var Schema $schema */ + $schema = $this->getConnection()->schema; + + $tables = $schema->getTableNames(); + $this->assertTrue(in_array('tbl_customer', $tables)); + $this->assertTrue(in_array('tbl_category', $tables)); + $this->assertTrue(in_array('tbl_item', $tables)); + $this->assertTrue(in_array('tbl_order', $tables)); + $this->assertTrue(in_array('tbl_order_item', $tables)); + $this->assertTrue(in_array('tbl_type', $tables)); + } + + public function testGetTableSchemas() + { + /** @var Schema $schema */ + $schema = $this->getConnection()->schema; + + $tables = $schema->getTableSchemas(); + $this->assertEquals(count($schema->getTableNames()), count($tables)); + foreach($tables as $table) { + $this->assertInstanceOf('yii\db\TableSchema', $table); + } + } + + public function testSchemaCache() + { + /** @var Schema $schema */ + $schema = $this->getConnection()->schema; + + $schema->db->enableSchemaCache = true; + $schema->db->schemaCache = new FileCache(); + $noCacheTable = $schema->getTableSchema('tbl_type', true); + $cachedTable = $schema->getTableSchema('tbl_type', true); + $this->assertEquals($noCacheTable, $cachedTable); + } +} diff --git a/tests/unit/framework/db/cubrid/CubridSchemaTest.php b/tests/unit/framework/db/cubrid/CubridSchemaTest.php new file mode 100644 index 0000000..d235b40 --- /dev/null +++ b/tests/unit/framework/db/cubrid/CubridSchemaTest.php @@ -0,0 +1,31 @@ + \PDO::PARAM_NULL, + '' => \PDO::PARAM_STR, + 'hello' => \PDO::PARAM_STR, + 0 => \PDO::PARAM_INT, + 1 => \PDO::PARAM_INT, + 1337 => \PDO::PARAM_INT, + true => \PDO::PARAM_INT, // CUBRID PDO does not support PARAM_BOOL + false => \PDO::PARAM_INT, // CUBRID PDO does not support PARAM_BOOL + ); + + $schema = $this->getConnection()->schema; + + foreach($values as $value => $type) { + $this->assertEquals($type, $schema->getPdoType($value)); + } + $this->assertEquals(\PDO::PARAM_LOB, $schema->getPdoType($fp=fopen(__FILE__, 'rb'))); + fclose($fp); + } +} diff --git a/tests/unit/framework/db/sqlite/SqliteSchemaTest.php b/tests/unit/framework/db/sqlite/SqliteSchemaTest.php new file mode 100644 index 0000000..f3f6b60 --- /dev/null +++ b/tests/unit/framework/db/sqlite/SqliteSchemaTest.php @@ -0,0 +1,9 @@ + Date: Fri, 6 Sep 2013 15:32:33 +0200 Subject: [PATCH 14/15] Add support for composite FK to cubrid --- framework/yii/db/cubrid/Schema.php | 14 +++++++++----- tests/unit/data/cubrid.sql | 9 +++++++++ tests/unit/data/mysql.sql | 9 +++++++++ tests/unit/data/sqlite.sql | 9 +++++++++ tests/unit/framework/db/SchemaTest.php | 19 +++++++++++++++++++ tests/unit/framework/db/sqlite/SqliteSchemaTest.php | 5 +++++ 6 files changed, 60 insertions(+), 5 deletions(-) diff --git a/framework/yii/db/cubrid/Schema.php b/framework/yii/db/cubrid/Schema.php index d221073..e3b125b 100644 --- a/framework/yii/db/cubrid/Schema.php +++ b/framework/yii/db/cubrid/Schema.php @@ -148,12 +148,16 @@ class Schema extends \yii\db\Schema $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 - ); + if (isset($table->foreignKeys[$key['FK_NAME']])) { + $table->foreignKeys[$key['FK_NAME']][$key['FKCOLUMN_NAME']] = $key['PKCOLUMN_NAME']; + } else { + $table->foreignKeys[$key['FK_NAME']] = array( + $key['PKTABLE_NAME'], + $key['FKCOLUMN_NAME'] => $key['PKCOLUMN_NAME'] + ); + } } + $table->foreignKeys = array_values($table->foreignKeys); return $table; } else { diff --git a/tests/unit/data/cubrid.sql b/tests/unit/data/cubrid.sql index 8ea20a8..bfaf85c 100644 --- a/tests/unit/data/cubrid.sql +++ b/tests/unit/data/cubrid.sql @@ -3,6 +3,7 @@ * The database setup in config.php is required to perform then relevant tests: */ +DROP TABLE IF EXISTS tbl_composite_fk; DROP TABLE IF EXISTS tbl_order_item; DROP TABLE IF EXISTS tbl_item; DROP TABLE IF EXISTS tbl_order; @@ -76,6 +77,14 @@ CREATE TABLE `tbl_type` ( `bool_col2` smallint DEFAULT 1 ); +CREATE TABLE `tbl_composite_fk` ( + `id` int(11) NOT NULL, + `order_id` int(11) NOT NULL, + `item_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `FK_composite_fk_order_item` FOREIGN KEY (`order_id`,`item_id`) REFERENCES `tbl_order_item` (`order_id`,`item_id`) ON DELETE CASCADE +); + INSERT INTO tbl_customer (email, name, address, status) VALUES ('user1@example.com', 'user1', 'address1', 1); INSERT INTO tbl_customer (email, name, address, status) VALUES ('user2@example.com', 'user2', 'address2', 1); INSERT INTO tbl_customer (email, name, address, status) VALUES ('user3@example.com', 'user3', 'address3', 2); diff --git a/tests/unit/data/mysql.sql b/tests/unit/data/mysql.sql index 2e9458e..133348d 100644 --- a/tests/unit/data/mysql.sql +++ b/tests/unit/data/mysql.sql @@ -3,6 +3,7 @@ * The database setup in config.php is required to perform then relevant tests: */ +DROP TABLE IF EXISTS tbl_composite_fk CASCADE; DROP TABLE IF EXISTS tbl_order_item CASCADE; DROP TABLE IF EXISTS tbl_item CASCADE; DROP TABLE IF EXISTS tbl_order CASCADE; @@ -62,6 +63,14 @@ CREATE TABLE `tbl_order_item` ( CONSTRAINT `FK_order_item_item_id` FOREIGN KEY (`item_id`) REFERENCES `tbl_item` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE `tbl_composite_fk` ( + `id` int(11) NOT NULL, + `order_id` int(11) NOT NULL, + `item_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `FK_composite_fk_order_item` FOREIGN KEY (`order_id`,`item_id`) REFERENCES `tbl_order_item` (`order_id`,`item_id`) ON DELETE CASCADE +); + CREATE TABLE `tbl_type` ( `int_col` int(11) NOT NULL, `int_col2` int(11) DEFAULT '1', diff --git a/tests/unit/data/sqlite.sql b/tests/unit/data/sqlite.sql index f75bfa6..f031ac3 100644 --- a/tests/unit/data/sqlite.sql +++ b/tests/unit/data/sqlite.sql @@ -3,6 +3,7 @@ * The database setup in config.php is required to perform then relevant tests: */ +DROP TABLE IF EXISTS tbl_composite_fk; DROP TABLE IF EXISTS tbl_order_item; DROP TABLE IF EXISTS tbl_item; DROP TABLE IF EXISTS tbl_order; @@ -48,6 +49,14 @@ CREATE TABLE tbl_order_item ( PRIMARY KEY (order_id, item_id) ); +CREATE TABLE `tbl_composite_fk` ( + `id` int(11) NOT NULL, + `order_id` int(11) NOT NULL, + `item_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `FK_composite_fk_order_item` FOREIGN KEY (`order_id`,`item_id`) REFERENCES `tbl_order_item` (`order_id`,`item_id`) ON DELETE CASCADE +); + CREATE TABLE tbl_type ( int_col INTEGER NOT NULL, int_col2 INTEGER DEFAULT '1', diff --git a/tests/unit/framework/db/SchemaTest.php b/tests/unit/framework/db/SchemaTest.php index 66aa410..5f504e1 100644 --- a/tests/unit/framework/db/SchemaTest.php +++ b/tests/unit/framework/db/SchemaTest.php @@ -56,6 +56,11 @@ class SchemaTest extends DatabaseTestCase } } + public function testGetNonExistingTableSchema() + { + $this->assertNull($this->getConnection()->schema->getTableSchema('nonexisting_table')); + } + public function testSchemaCache() { /** @var Schema $schema */ @@ -67,4 +72,18 @@ class SchemaTest extends DatabaseTestCase $cachedTable = $schema->getTableSchema('tbl_type', true); $this->assertEquals($noCacheTable, $cachedTable); } + + public function testCompositeFk() + { + /** @var Schema $schema */ + $schema = $this->getConnection()->schema; + + $table = $schema->getTableSchema('tbl_composite_fk'); + + $this->assertCount(1, $table->foreignKeys); + $this->assertTrue(isset($table->foreignKeys[0])); + $this->assertEquals('tbl_order_item', $table->foreignKeys[0][0]); + $this->assertEquals('order_id', $table->foreignKeys[0]['order_id']); + $this->assertEquals('item_id', $table->foreignKeys[0]['item_id']); + } } diff --git a/tests/unit/framework/db/sqlite/SqliteSchemaTest.php b/tests/unit/framework/db/sqlite/SqliteSchemaTest.php index f3f6b60..9b17a1d 100644 --- a/tests/unit/framework/db/sqlite/SqliteSchemaTest.php +++ b/tests/unit/framework/db/sqlite/SqliteSchemaTest.php @@ -6,4 +6,9 @@ use yiiunit\framework\db\SchemaTest; class SqliteSchemaTest extends SchemaTest { protected $driverName = 'sqlite'; + + public function testCompositeFk() + { + $this->markTestSkipped('sqlite does not allow getting enough information about composite FK.'); + } } From 23b858a2ccd0e3eb7ad468ba011aeaf7eab98c86 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Fri, 6 Sep 2013 15:51:30 +0200 Subject: [PATCH 15/15] removed comments --- framework/yii/db/cubrid/Schema.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/framework/yii/db/cubrid/Schema.php b/framework/yii/db/cubrid/Schema.php index e3b125b..fae932f 100644 --- a/framework/yii/db/cubrid/Schema.php +++ b/framework/yii/db/cubrid/Schema.php @@ -55,14 +55,14 @@ class Schema extends \yii\db\Schema 'blob' => self::TYPE_BINARY, 'clob' => self::TYPE_BINARY, // Bit string data types -// 'bit' => self::TYPE_STRING, -// 'bit varying' => self::TYPE_STRING, - // 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, + 'bit' => self::TYPE_STRING, + 'bit varying' => self::TYPE_STRING, + // Collection data types (considered strings for now, may add support for them later) + 'set' => self::TYPE_STRING, + 'multiset' => self::TYPE_STRING, + 'list' => self::TYPE_STRING, + 'sequence' => self::TYPE_STRING, + 'enum' => self::TYPE_STRING, ); /**