Gevik Babakhani
12 years ago
10 changed files with 590 additions and 149 deletions
@ -0,0 +1,103 @@
|
||||
<?php |
||||
|
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db\pgsql; |
||||
|
||||
/** |
||||
* This is an extension of the default PDO class for PostgreSQL drivers. |
||||
* It provides additional low level functionality for setting database |
||||
* configuration parameters. |
||||
* |
||||
* @author Gevik babakhani <gevikb@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class PDO extends \PDO |
||||
{ |
||||
|
||||
const OPT_SEARCH_PATH = 'search_path'; |
||||
const OPT_DEFAULT_SCHEMA = 'default_schema'; |
||||
const DEFAULT_SCHEMA = 'public'; |
||||
|
||||
private $_currentDatabase; |
||||
|
||||
/** |
||||
* Returns value of the last inserted ID. |
||||
* @param string|null $sequence the sequence name. Defaults to null. |
||||
* @return integer last inserted ID value. |
||||
*/ |
||||
public function lastInsertId($sequence = null) { |
||||
if ($sequence !== null) { |
||||
$sequence = $this->quote($sequence); |
||||
return $this->query("SELECT currval({$sequence})")->fetchColumn(); |
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Here we override the default PDO constructor in order to |
||||
* find and set the default schema search path. |
||||
*/ |
||||
public function __construct($dsn, $username, $passwd, $options) { |
||||
$searchPath = null; |
||||
if (is_array($options)) { |
||||
if (isset($options[self::OPT_SEARCH_PATH])) { |
||||
$matches = null; |
||||
if (preg_match("/(\s?)+(\w)+((\s+)?,(\s+)?\w+)*/", $options[self::OPT_SEARCH_PATH], $matches) === 1) { |
||||
$searchPath = $matches[0]; |
||||
} |
||||
} |
||||
if (isset($options[self::OPT_DEFAULT_SCHEMA])) { |
||||
$schema = trim($options[self::OPT_DEFAULT_SCHEMA]); |
||||
if (!empty($schema)) { |
||||
Schema::$DEFAULT_SCHEMA = $schema; |
||||
} |
||||
} |
||||
if (is_null(Schema::$DEFAULT_SCHEMA) || empty(Schema::$DEFAULT_SCHEMA)) { |
||||
Schema::$DEFAULT_SCHEMA = self::DEFAULT_SCHEMA; |
||||
} |
||||
} |
||||
parent::__construct($dsn, $username, $passwd, $options); |
||||
if (!is_null($searchPath)) { |
||||
$this->setSchemaSearchPath($searchPath); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns the name of the current (connected) database |
||||
* @return string |
||||
*/ |
||||
public function getCurrentDatabase() { |
||||
if (is_null($this->_currentDatabase)) { |
||||
return $this->query('select current_database()')->fetchColumn(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Sets the schema search path of the current users session. |
||||
* The syntax of the path is a comma separated string with |
||||
* your custom search path at the beginning and the "public" |
||||
* schema at the end. |
||||
* |
||||
* This method automatically adds the "public" schema at the |
||||
* end of the search path if it is not provied. |
||||
* @param string custom schema search path. defaults to public |
||||
*/ |
||||
public function setSchemaSearchPath($searchPath = 'public') { |
||||
$schemas = explode(',', str_replace(' ', '', $searchPath)); |
||||
if (end($schemas) !== 'public') { |
||||
$schemas[] = 'public'; |
||||
} |
||||
foreach ($schemas as $k => $item) { |
||||
$schemas[$k] = '"' . str_replace(array('"', "'", ';'), '', $item) . '"'; |
||||
} |
||||
$path = implode(', ', $schemas); |
||||
$this->exec('SET search_path TO ' . $path); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,41 @@
|
||||
<?php |
||||
|
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db\pgsql; |
||||
|
||||
/** |
||||
* QueryBuilder is the query builder for PostgreSQL databases. |
||||
* |
||||
* @author Gevik Babakhani <gevikb@gmail.com> |
||||
* @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 => 'serial not null primary key', |
||||
Schema::TYPE_STRING => 'varchar', |
||||
Schema::TYPE_TEXT => 'text', |
||||
Schema::TYPE_SMALLINT => 'smallint', |
||||
Schema::TYPE_INTEGER => 'integer', |
||||
Schema::TYPE_BIGINT => 'bigint', |
||||
Schema::TYPE_FLOAT => 'double precision', |
||||
Schema::TYPE_DECIMAL => 'numeric', |
||||
Schema::TYPE_DATETIME => 'timestamp', |
||||
Schema::TYPE_TIMESTAMP => 'timestamp', |
||||
Schema::TYPE_TIME => 'time', |
||||
Schema::TYPE_DATE => 'date', |
||||
Schema::TYPE_BINARY => 'bytea', |
||||
Schema::TYPE_BOOLEAN => 'boolean', |
||||
Schema::TYPE_MONEY => 'numeric(19,4)', |
||||
); |
||||
|
||||
} |
@ -0,0 +1,294 @@
|
||||
<?php |
||||
|
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db\pgsql; |
||||
|
||||
use yii\db\TableSchema; |
||||
use yii\db\ColumnSchema; |
||||
|
||||
/** |
||||
* Schema is the class for retrieving metadata from a PostgreSQL database |
||||
* (version 9.x and above). |
||||
* |
||||
* @author Gevik Babakhani <gevikb@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class Schema extends \yii\db\Schema |
||||
{ |
||||
|
||||
/** |
||||
* The default schema used for the current session. This value is |
||||
* automatically set to "public" by the PDO driver. |
||||
* @var string |
||||
*/ |
||||
public static $DEFAULT_SCHEMA; |
||||
|
||||
/** |
||||
* @var array mapping from physical column types (keys) to abstract |
||||
* column types (values) |
||||
*/ |
||||
public $typeMap = array( |
||||
'abstime' => self::TYPE_TIMESTAMP, |
||||
'bit' => self::TYPE_STRING, |
||||
'boolean' => self::TYPE_BOOLEAN, |
||||
'box' => self::TYPE_STRING, |
||||
'character' => self::TYPE_STRING, |
||||
'bytea' => self::TYPE_BINARY, |
||||
'char' => self::TYPE_STRING, |
||||
'cidr' => self::TYPE_STRING, |
||||
'circle' => self::TYPE_STRING, |
||||
'date' => self::TYPE_DATE, |
||||
'real' => self::TYPE_FLOAT, |
||||
'double precision' => self::TYPE_DECIMAL, |
||||
'inet' => self::TYPE_STRING, |
||||
'smallint' => self::TYPE_SMALLINT, |
||||
'integer' => self::TYPE_INTEGER, |
||||
'bigint' => self::TYPE_BIGINT, |
||||
'interval' => self::TYPE_STRING, |
||||
'json' => self::TYPE_STRING, |
||||
'line' => self::TYPE_STRING, |
||||
'macaddr' => self::TYPE_STRING, |
||||
'money' => self::TYPE_MONEY, |
||||
'name' => self::TYPE_STRING, |
||||
'numeric' => self::TYPE_STRING, |
||||
'numrange' => self::TYPE_DECIMAL, |
||||
'oid' => self::TYPE_BIGINT, // should not be used. it's pg internal! |
||||
'path' => self::TYPE_STRING, |
||||
'point' => self::TYPE_STRING, |
||||
'polygon' => self::TYPE_STRING, |
||||
'text' => self::TYPE_TEXT, |
||||
'time without time zone' => self::TYPE_TIME, |
||||
'timestamp without time zone' => self::TYPE_TIMESTAMP, |
||||
'timestamp with time zone' => self::TYPE_TIMESTAMP, |
||||
'time with time zone' => self::TYPE_TIMESTAMP, |
||||
'unknown' => self::TYPE_STRING, |
||||
'uuid' => self::TYPE_STRING, |
||||
'bit varying' => self::TYPE_STRING, |
||||
'character varying' => self::TYPE_STRING, |
||||
'xml' => self::TYPE_STRING |
||||
); |
||||
|
||||
/** |
||||
* Creates a query builder for the MySQL database. |
||||
* @return QueryBuilder query builder instance |
||||
*/ |
||||
public function createQueryBuilder() { |
||||
return new QueryBuilder($this->db); |
||||
} |
||||
|
||||
/** |
||||
* Resolves the table name and schema name (if any). |
||||
* @param TableSchema $table the table metadata object |
||||
* @param string $name the table name |
||||
*/ |
||||
protected function resolveTableNames($table, $name) { |
||||
$parts = explode('.', str_replace('"', '', $name)); |
||||
if (isset($parts[1])) { |
||||
$table->schemaName = $parts[0]; |
||||
$table->name = $parts[1]; |
||||
} else { |
||||
$table->name = $parts[0]; |
||||
} |
||||
if ($table->schemaName === null) { |
||||
$table->schemaName = self::$DEFAULT_SCHEMA; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 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 . '"'; |
||||
} |
||||
|
||||
/** |
||||
* Loads the metadata for the specified table. |
||||
* @param string $name table name |
||||
* @return TableSchema|null driver dependent table metadata. Null if the table does not exist. |
||||
*/ |
||||
public function loadTableSchema($name) { |
||||
$table = new TableSchema(); |
||||
$this->resolveTableNames($table, $name); |
||||
if ($this->findColumns($table)) { |
||||
$this->findConstraints($table); |
||||
return $table; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Collects the foreign key column details for the given table. |
||||
* @param TableSchema $table the table metadata |
||||
*/ |
||||
protected function findConstraints($table) { |
||||
|
||||
$tableName = $this->quoteValue($table->name); |
||||
$tableSchema = $this->quoteValue($table->schemaName); |
||||
$database = $this->quoteValue($this->db->pdo->getCurrentDatabase()); |
||||
|
||||
//We need to extract the constraints de hard way since: |
||||
//http://www.postgresql.org/message-id/26677.1086673982@sss.pgh.pa.us |
||||
|
||||
$sql = <<<SQL |
||||
select |
||||
ct.conname as containst, |
||||
c.relname as table_name, |
||||
ns.nspname as table_schema, |
||||
current_database() as table_catalog, |
||||
(select string_agg(attname,',') attname from pg_attribute where attrelid=ct.conrelid and attnum = any(ct.conkey)) as columns, |
||||
fc.relname as foreign_table_name, |
||||
fns.nspname as foreign_table_schema, |
||||
current_database() as foreign_table_catalog, |
||||
(select string_agg(attname,',') attname from pg_attribute where attrelid=ct.confrelid and attnum = any(ct.confkey)) as foreign_columns |
||||
from |
||||
pg_constraint ct |
||||
inner join pg_class c on c.oid=ct.conrelid |
||||
inner join pg_namespace ns on c.relnamespace=ns.oid |
||||
left join pg_class fc on fc.oid=ct.confrelid |
||||
left join pg_namespace fns on fc.relnamespace=fns.oid |
||||
|
||||
where |
||||
ct.contype='f' |
||||
and c.relname={$tableName} |
||||
and ns.nspname={$tableSchema} |
||||
and current_database() = {$database} |
||||
SQL; |
||||
|
||||
try { |
||||
$constraints = $this->db->createCommand($sql)->queryAll(); |
||||
} catch (\Exception $e) { |
||||
return false; |
||||
} |
||||
foreach ($constraints as $constraint) { |
||||
$columns = explode(',', $constraint['columns']); |
||||
$fcolumns = explode(',', $constraint['foreign_columns']); |
||||
$citem = array($constraint['foreign_table_name']); |
||||
foreach ($columns as $idx => $column) { |
||||
$citem[] = array($fcolumns[$idx] => $column); |
||||
} |
||||
$table->foreignKeys[] = $citem; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Collects the metadata of table columns. |
||||
* @param TableSchema $table the table metadata |
||||
* @return boolean whether the table exists in the database |
||||
*/ |
||||
protected function findColumns($table) { |
||||
$dbname = $this->db->quoteValue($this->db->pdo->getCurrentDatabase()); |
||||
$tableName = $this->db->quoteValue($table->name); |
||||
$schemaName = $this->db->quoteValue($table->schemaName); |
||||
$sql = <<<SQL |
||||
SELECT |
||||
current_database() as table_catalog, |
||||
d.nspname AS table_schema, |
||||
c.relname AS table_name, |
||||
a.attname AS column_name, |
||||
t.typname AS data_type, |
||||
a.attlen AS character_maximum_length, |
||||
pg_catalog.col_description(c.oid, a.attnum) AS column_comment, |
||||
a.atttypmod AS modifier, |
||||
a.attnotnull = false AS is_nullable, |
||||
CAST(pg_get_expr(ad.adbin, ad.adrelid) AS varchar) AS column_default, |
||||
coalesce(pg_get_expr(ad.adbin, ad.adrelid) ~ 'nextval',false) AS is_autoinc, |
||||
array_to_string((select array_agg(enumlabel) from pg_enum where enumtypid=a.atttypid)::varchar[],',') as enum_values, |
||||
CASE atttypid |
||||
WHEN 21 /*int2*/ THEN 16 |
||||
WHEN 23 /*int4*/ THEN 32 |
||||
WHEN 20 /*int8*/ THEN 64 |
||||
WHEN 1700 /*numeric*/ THEN |
||||
CASE WHEN atttypmod = -1 |
||||
THEN null |
||||
ELSE ((atttypmod - 4) >> 16) & 65535 |
||||
END |
||||
WHEN 700 /*float4*/ THEN 24 /*FLT_MANT_DIG*/ |
||||
WHEN 701 /*float8*/ THEN 53 /*DBL_MANT_DIG*/ |
||||
ELSE null |
||||
END AS numeric_precision, |
||||
CASE |
||||
WHEN atttypid IN (21, 23, 20) THEN 0 |
||||
WHEN atttypid IN (1700) THEN |
||||
CASE |
||||
WHEN atttypmod = -1 THEN null |
||||
ELSE (atttypmod - 4) & 65535 |
||||
END |
||||
ELSE null |
||||
END AS numeric_scale, |
||||
CAST( |
||||
information_schema._pg_char_max_length(information_schema._pg_truetypid(a, t), information_schema._pg_truetypmod(a, t)) |
||||
AS numeric |
||||
) AS size, |
||||
a.attnum = any (ct.conkey) as is_pkey |
||||
FROM |
||||
pg_class c |
||||
LEFT JOIN pg_attribute a ON a.attrelid = c.oid |
||||
LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum |
||||
LEFT JOIN pg_type t ON a.atttypid = t.oid |
||||
LEFT JOIN pg_namespace d ON d.oid = c.relnamespace |
||||
LEFT join pg_constraint ct on ct.conrelid=c.oid and ct.contype='p' |
||||
WHERE |
||||
a.attnum > 0 |
||||
and c.relname = {$tableName} |
||||
and d.nspname = {$schemaName} |
||||
and current_database() = {$dbname} |
||||
ORDER BY |
||||
a.attnum; |
||||
SQL; |
||||
|
||||
try { |
||||
$columns = $this->db->createCommand($sql)->queryAll(); |
||||
} catch (\Exception $e) { |
||||
return false; |
||||
} |
||||
foreach ($columns as $column) { |
||||
$column = $this->loadColumnSchema($column); |
||||
$table->columns[$column->name] = $column; |
||||
if ($column->isPrimaryKey === true) { |
||||
$table->primaryKey[] = $column->name; |
||||
if ($table->sequenceName === null && preg_match("/nextval\('\w+'(::regclass)?\)/", $column->defaultValue) === 1) { |
||||
$table->sequenceName = preg_replace(array('/nextval/', '/::/', '/regclass/', '/\'\)/', '/\(\'/'), '', $column->defaultValue); |
||||
} |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 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->allowNull = $info['is_nullable']; |
||||
$column->autoIncrement = $info['is_autoinc']; |
||||
$column->comment = $info['column_comment']; |
||||
$column->dbType = $info['data_type']; |
||||
$column->defaultValue = $info['column_default']; |
||||
$column->enumValues = explode(',', str_replace(array("''"), array("'"), $info['enum_values'])); |
||||
$column->unsigned = false; // has no meanining in PG |
||||
$column->isPrimaryKey = $info['is_pkey']; |
||||
$column->name = $info['column_name']; |
||||
$column->precision = $info['numeric_precision']; |
||||
$column->scale = $info['numeric_scale']; |
||||
$column->size = $info['size']; |
||||
|
||||
if (isset($this->typeMap[$column->dbType])) { |
||||
$column->type = $this->typeMap[$column->dbType]; |
||||
} else { |
||||
$column->type = self::TYPE_STRING; |
||||
} |
||||
$column->phpType = $this->getColumnPhpType($column); |
||||
return $column; |
||||
} |
||||
|
||||
} |
@ -1,165 +1,87 @@
|
||||
/** |
||||
* This is the database schema for testing PostgreSQL support of yii Active Record. |
||||
* To test this feature, you need to create a database named 'yii' on 'localhost' |
||||
* and create an account 'test/test' which owns this test database. |
||||
* To test this feature, you need to create a database named 'yiitest' on 'localhost' |
||||
* and create an account 'postgres/postgres' which owns this test database. |
||||
*/ |
||||
CREATE SCHEMA test; |
||||
|
||||
CREATE TABLE test.users |
||||
( |
||||
id SERIAL NOT NULL PRIMARY KEY, |
||||
username VARCHAR(128) NOT NULL, |
||||
password VARCHAR(128) NOT NULL, |
||||
email VARCHAR(128) NOT NULL |
||||
DROP TABLE IF EXISTS tbl_order_item CASCADE; |
||||
DROP TABLE IF EXISTS tbl_item CASCADE; |
||||
DROP TABLE IF EXISTS tbl_order CASCADE; |
||||
DROP TABLE IF EXISTS tbl_category CASCADE; |
||||
DROP TABLE IF EXISTS tbl_customer CASCADE; |
||||
DROP TABLE IF EXISTS tbl_type CASCADE; |
||||
|
||||
CREATE TABLE tbl_customer ( |
||||
id serial not null primary key, |
||||
email varchar(128) NOT NULL, |
||||
name varchar(128) NOT NULL, |
||||
address text, |
||||
status integer DEFAULT 0 |
||||
); |
||||
|
||||
INSERT INTO test.users (username, password, email) VALUES ('user1','pass1','email1'); |
||||
INSERT INTO test.users (username, password, email) VALUES ('user2','pass2','email2'); |
||||
INSERT INTO test.users (username, password, email) VALUES ('user3','pass3','email3'); |
||||
comment on column public.tbl_customer.email is 'someone@example.com'; |
||||
|
||||
CREATE TABLE test.user_friends |
||||
( |
||||
id INTEGER NOT NULL, |
||||
friend INTEGER NOT NULL, |
||||
PRIMARY KEY (id, friend), |
||||
CONSTRAINT FK_user_id FOREIGN KEY (id) |
||||
REFERENCES test.users (id) ON DELETE CASCADE ON UPDATE RESTRICT, |
||||
CONSTRAINT FK_friend_id FOREIGN KEY (friend) |
||||
REFERENCES test.users (id) ON DELETE CASCADE ON UPDATE RESTRICT |
||||
CREATE TABLE tbl_category ( |
||||
id serial not null primary key, |
||||
name varchar(128) NOT NULL |
||||
); |
||||
|
||||
INSERT INTO test.user_friends VALUES (1,2); |
||||
INSERT INTO test.user_friends VALUES (1,3); |
||||
INSERT INTO test.user_friends VALUES (2,3); |
||||
|
||||
CREATE TABLE test.profiles |
||||
( |
||||
id SERIAL NOT NULL PRIMARY KEY, |
||||
first_name VARCHAR(128) NOT NULL, |
||||
last_name VARCHAR(128) NOT NULL, |
||||
user_id INTEGER NOT NULL, |
||||
CONSTRAINT FK_profile_user FOREIGN KEY (user_id) |
||||
REFERENCES test.users (id) ON DELETE CASCADE ON UPDATE RESTRICT |
||||
); |
||||
|
||||
INSERT INTO test.profiles (first_name, last_name, user_id) VALUES ('first 1','last 1',1); |
||||
INSERT INTO test.profiles (first_name, last_name, user_id) VALUES ('first 2','last 2',2); |
||||
|
||||
CREATE TABLE test.posts |
||||
( |
||||
id SERIAL NOT NULL PRIMARY KEY, |
||||
title VARCHAR(128) NOT NULL, |
||||
create_time TIMESTAMP NOT NULL, |
||||
author_id INTEGER NOT NULL, |
||||
content TEXT, |
||||
CONSTRAINT FK_post_author FOREIGN KEY (author_id) |
||||
REFERENCES test.users (id) ON DELETE CASCADE ON UPDATE RESTRICT |
||||
); |
||||
|
||||
INSERT INTO test.posts (title, create_time, author_id, content) VALUES ('post 1',TIMESTAMP '2004-10-19 10:23:54',1,'content 1'); |
||||
INSERT INTO test.posts (title, create_time, author_id, content) VALUES ('post 2',TIMESTAMP '2004-10-19 10:23:54',2,'content 2'); |
||||
INSERT INTO test.posts (title, create_time, author_id, content) VALUES ('post 3',TIMESTAMP '2004-10-19 10:23:54',2,'content 3'); |
||||
INSERT INTO test.posts (title, create_time, author_id, content) VALUES ('post 4',TIMESTAMP '2004-10-19 10:23:54',2,'content 4'); |
||||
INSERT INTO test.posts (title, create_time, author_id, content) VALUES ('post 5',TIMESTAMP '2004-10-19 10:23:54',3,'content 5'); |
||||
|
||||
CREATE TABLE test.comments |
||||
( |
||||
id SERIAL NOT NULL PRIMARY KEY, |
||||
content TEXT NOT NULL, |
||||
post_id INTEGER NOT NULL, |
||||
author_id INTEGER NOT NULL, |
||||
CONSTRAINT FK_post_comment FOREIGN KEY (post_id) |
||||
REFERENCES test.posts (id) ON DELETE CASCADE ON UPDATE RESTRICT, |
||||
CONSTRAINT FK_user_comment FOREIGN KEY (author_id) |
||||
REFERENCES test.users (id) ON DELETE CASCADE ON UPDATE RESTRICT |
||||
CREATE TABLE tbl_item ( |
||||
id serial not null primary key, |
||||
name varchar(128) NOT NULL, |
||||
category_id integer NOT NULL references tbl_category(id) on UPDATE CASCADE on DELETE CASCADE |
||||
); |
||||
|
||||
INSERT INTO test.comments (content, post_id, author_id) VALUES ('comment 1',1, 2); |
||||
INSERT INTO test.comments (content, post_id, author_id) VALUES ('comment 2',1, 2); |
||||
INSERT INTO test.comments (content, post_id, author_id) VALUES ('comment 3',1, 2); |
||||
INSERT INTO test.comments (content, post_id, author_id) VALUES ('comment 4',2, 2); |
||||
INSERT INTO test.comments (content, post_id, author_id) VALUES ('comment 5',2, 2); |
||||
INSERT INTO test.comments (content, post_id, author_id) VALUES ('comment 6',3, 2); |
||||
INSERT INTO test.comments (content, post_id, author_id) VALUES ('comment 7',3, 2); |
||||
INSERT INTO test.comments (content, post_id, author_id) VALUES ('comment 8',3, 2); |
||||
INSERT INTO test.comments (content, post_id, author_id) VALUES ('comment 9',3, 2); |
||||
INSERT INTO test.comments (content, post_id, author_id) VALUES ('comment 10',5, 3); |
||||
|
||||
CREATE TABLE test.categories |
||||
( |
||||
id SERIAL NOT NULL PRIMARY KEY, |
||||
name VARCHAR(128) NOT NULL, |
||||
parent_id INTEGER, |
||||
CONSTRAINT FK_category_category FOREIGN KEY (parent_id) |
||||
REFERENCES test.categories (id) ON DELETE CASCADE ON UPDATE RESTRICT |
||||
CREATE TABLE tbl_order ( |
||||
id serial not null primary key, |
||||
customer_id integer NOT NULL references tbl_customer(id) on UPDATE CASCADE on DELETE CASCADE, |
||||
create_time integer NOT NULL, |
||||
total decimal(10,0) NOT NULL |
||||
); |
||||
|
||||
INSERT INTO test.categories (name, parent_id) VALUES ('cat 1',NULL); |
||||
INSERT INTO test.categories (name, parent_id) VALUES ('cat 2',NULL); |
||||
INSERT INTO test.categories (name, parent_id) VALUES ('cat 3',NULL); |
||||
INSERT INTO test.categories (name, parent_id) VALUES ('cat 4',1); |
||||
INSERT INTO test.categories (name, parent_id) VALUES ('cat 5',1); |
||||
INSERT INTO test.categories (name, parent_id) VALUES ('cat 6',5); |
||||
INSERT INTO test.categories (name, parent_id) VALUES ('cat 7',5); |
||||
|
||||
CREATE TABLE test.post_category |
||||
( |
||||
category_id INTEGER NOT NULL, |
||||
post_id INTEGER NOT NULL, |
||||
PRIMARY KEY (category_id, post_id), |
||||
CONSTRAINT FK_post_category_post FOREIGN KEY (post_id) |
||||
REFERENCES test.posts (id) ON DELETE CASCADE ON UPDATE RESTRICT, |
||||
CONSTRAINT FK_post_category_category FOREIGN KEY (category_id) |
||||
REFERENCES test.categories (id) ON DELETE CASCADE ON UPDATE RESTRICT |
||||
CREATE TABLE tbl_order_item ( |
||||
order_id integer NOT NULL references tbl_order(id) on UPDATE CASCADE on DELETE CASCADE, |
||||
item_id integer NOT NULL references tbl_item(id) on UPDATE CASCADE on DELETE CASCADE, |
||||
quantity integer NOT NULL, |
||||
subtotal decimal(10,0) NOT NULL, |
||||
PRIMARY KEY (order_id,item_id) |
||||
); |
||||
|
||||
INSERT INTO test.post_category (category_id, post_id) VALUES (1,1); |
||||
INSERT INTO test.post_category (category_id, post_id) VALUES (2,1); |
||||
INSERT INTO test.post_category (category_id, post_id) VALUES (3,1); |
||||
INSERT INTO test.post_category (category_id, post_id) VALUES (4,2); |
||||
INSERT INTO test.post_category (category_id, post_id) VALUES (1,2); |
||||
INSERT INTO test.post_category (category_id, post_id) VALUES (1,3); |
||||
|
||||
CREATE TABLE test.orders |
||||
( |
||||
key1 INTEGER NOT NULL, |
||||
key2 INTEGER NOT NULL, |
||||
name VARCHAR(128), |
||||
PRIMARY KEY (key1, key2) |
||||
CREATE TABLE tbl_type ( |
||||
int_col integer NOT NULL, |
||||
int_col2 integer DEFAULT '1', |
||||
char_col char(100) NOT NULL, |
||||
char_col2 varchar(100) DEFAULT 'something', |
||||
char_col3 text, |
||||
float_col double precision NOT NULL, |
||||
float_col2 double precision DEFAULT '1.23', |
||||
blob_col bytea, |
||||
numeric_col decimal(5,2) DEFAULT '33.22', |
||||
time timestamp NOT NULL DEFAULT '2002-01-01 00:00:00', |
||||
bool_col smallint NOT NULL, |
||||
bool_col2 smallint DEFAULT '1' |
||||
); |
||||
|
||||
INSERT INTO test.orders (key1,key2,name) VALUES (1,2,'order 12'); |
||||
INSERT INTO test.orders (key1,key2,name) VALUES (1,3,'order 13'); |
||||
INSERT INTO test.orders (key1,key2,name) VALUES (2,1,'order 21'); |
||||
INSERT INTO test.orders (key1,key2,name) VALUES (2,2,'order 22'); |
||||
|
||||
CREATE TABLE test.items |
||||
( |
||||
id SERIAL NOT NULL PRIMARY KEY, |
||||
name VARCHAR(128), |
||||
col1 INTEGER NOT NULL, |
||||
col2 INTEGER NOT NULL, |
||||
CONSTRAINT FK_order_item FOREIGN KEY (col1,col2) |
||||
REFERENCES test.orders (key1,key2) ON DELETE CASCADE ON UPDATE RESTRICT |
||||
); |
||||
|
||||
INSERT INTO test.items (name,col1,col2) VALUES ('item 1',1,2); |
||||
INSERT INTO test.items (name,col1,col2) VALUES ('item 2',1,2); |
||||
INSERT INTO test.items (name,col1,col2) VALUES ('item 3',1,3); |
||||
INSERT INTO test.items (name,col1,col2) VALUES ('item 4',2,2); |
||||
INSERT INTO test.items (name,col1,col2) VALUES ('item 5',2,2); |
||||
|
||||
CREATE TABLE public.yii_types |
||||
( |
||||
int_col INT NOT NULL, |
||||
int_col2 INTEGER DEFAULT 1, |
||||
char_col CHAR(100) NOT NULL, |
||||
char_col2 VARCHAR(100) DEFAULT 'something', |
||||
char_col3 TEXT, |
||||
numeric_col NUMERIC(4,3) NOT NULL, |
||||
real_col REAL DEFAULT 1.23, |
||||
blob_col BYTEA, |
||||
time TIMESTAMP, |
||||
bool_col BOOL NOT NULL, |
||||
bool_col2 BOOLEAN DEFAULT TRUE |
||||
); |
||||
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); |
||||
|
@ -0,0 +1,14 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\framework\db\pgsql; |
||||
|
||||
use yiiunit\framework\db\ActiveRecordTest; |
||||
|
||||
class PostgreSQLActiveRecordTest extends ActiveRecordTest |
||||
{ |
||||
protected function setUp() |
||||
{ |
||||
$this->driverName = 'pgsql'; |
||||
parent::setUp(); |
||||
} |
||||
} |
@ -0,0 +1,51 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\framework\db\pgsql; |
||||
|
||||
use yiiunit\framework\db\ConnectionTest; |
||||
|
||||
class PostgreSQLConnectionTest extends ConnectionTest { |
||||
|
||||
public function setUp() { |
||||
$this->driverName = 'pgsql'; |
||||
parent::setUp(); |
||||
} |
||||
|
||||
public function testConnection() { |
||||
$connection = $this->getConnection(true); |
||||
} |
||||
|
||||
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")); |
||||
} |
||||
|
||||
function testQuoteTableName() |
||||
{ |
||||
$connection = $this->getConnection(false); |
||||
$this->assertEquals('"table"', $connection->quoteTableName('table')); |
||||
$this->assertEquals('"table"', $connection->quoteTableName('"table"')); |
||||
$this->assertEquals('"schema"."table"', $connection->quoteTableName('schema.table')); |
||||
$this->assertEquals('"schema"."table"', $connection->quoteTableName('schema."table"')); |
||||
$this->assertEquals('"schema"."table"', $connection->quoteTableName('"schema"."table"')); |
||||
$this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); |
||||
$this->assertEquals('(table)', $connection->quoteTableName('(table)')); |
||||
} |
||||
|
||||
function testQuoteColumnName() |
||||
{ |
||||
$connection = $this->getConnection(false); |
||||
$this->assertEquals('"column"', $connection->quoteColumnName('column')); |
||||
$this->assertEquals('"column"', $connection->quoteColumnName('"column"')); |
||||
$this->assertEquals('"table"."column"', $connection->quoteColumnName('table.column')); |
||||
$this->assertEquals('"table"."column"', $connection->quoteColumnName('table."column"')); |
||||
$this->assertEquals('"table"."column"', $connection->quoteColumnName('"table"."column"')); |
||||
$this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); |
||||
$this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); |
||||
$this->assertEquals('(column)', $connection->quoteColumnName('(column)')); |
||||
} |
||||
|
||||
|
||||
} |
Loading…
Reference in new issue