Browse Source

Savepoint: WIP implementing columns

tags/2.0.0-beta
Gevik Babakhani 11 years ago
parent
commit
103621ad05
  1. 35
      framework/yii/db/pgsql/PDO.php
  2. 161
      framework/yii/db/pgsql/Schema.php
  3. 14
      tests/unit/data/postgres.sql

35
framework/yii/db/pgsql/PDO.php

@ -18,16 +18,33 @@ namespace yii\db\pgsql;
*/
class PDO extends \PDO {
const OPT_SEARCH_PATH = 'search_path';
const OPT_DEFAULT_SCHEMA = 'default_schema';
const DEFAULT_SCHEMA = 'public';
private $_currentDatabase = 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) && isset($options['search_path'])) {
$matches = null;
if (preg_match("/(\s?)+(\w)+((\s+)?,(\s+)?\w+)*/", $options['search_path'], $matches) === 1) {
$searchPath = $matches[0];
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 ($schema !== '') {
Schema::$DEFAULT_SCHEMA = $schema;
}
}
if (Schema::$DEFAULT_SCHEMA === null || Schema::$DEFAULT_SCHEMA === '') {
Schema::$DEFAULT_SCHEMA = self::DEFAULT_SCHEMA;
}
}
parent::__construct($dsn, $username, $passwd, $options);
@ -37,6 +54,16 @@ class PDO extends \PDO {
}
/**
* 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"

161
framework/yii/db/pgsql/Schema.php

@ -12,7 +12,8 @@ use yii\db\TableSchema;
use yii\db\ColumnSchema;
/**
* Schema is the class for retrieving metadata from a PostgreSQL database (version 9.x and above).
* 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
@ -20,6 +21,85 @@ use yii\db\ColumnSchema;
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,
//'aclitem' => self::TYPE_STRING,
'bit' => self::TYPE_STRING,
'boolean' => self::TYPE_BOOLEAN,
'box' => self::TYPE_STRING,
'character' => self::TYPE_STRING,
'bytea' => self::TYPE_BINARY,
'char' => self::TYPE_STRING,
//'cid' => self::TYPE_STRING,
'cidr' => self::TYPE_STRING,
'circle' => self::TYPE_STRING,
'date' => self::TYPE_DATE,
//'daterange' => self::TYPE_STRING,
'real' => self::TYPE_FLOAT,
'double precision' => self::TYPE_DECIMAL,
//'gtsvector' => self::TYPE_STRING,
'inet' => self::TYPE_STRING,
'smallint' => self::TYPE_SMALLINT,
'integer' => self::TYPE_INTEGER,
//'int4range' => self::TYPE_STRING, //unknown
'bigint' => self::TYPE_BIGINT,
//'int8range' => self::TYPE_STRING, // unknown
'interval' => self::TYPE_STRING,
'json' => self::TYPE_STRING,
'line' => self::TYPE_STRING,
//'lseg' => 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,
//'pg_node_tree' => self::TYPE_STRING,
'point' => self::TYPE_STRING,
'polygon' => self::TYPE_STRING,
//'refcursor' => self::TYPE_STRING,
//'regclass' => self::TYPE_STRING,
//'regconfig' => self::TYPE_STRING,
//'regdictionary' => self::TYPE_STRING,
//'regoper' => self::TYPE_STRING,
//'regoperator' => self::TYPE_STRING,
//'regproc' => self::TYPE_STRING,
//'regprocedure' => self::TYPE_STRING,
//'regtype' => self::TYPE_STRING,
//'reltime' => self::TYPE_STRING,
//'smgr' => self::TYPE_STRING,
'text' => self::TYPE_TEXT,
//'tid' => self::TYPE_STRING,
'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,
//'tinterval' => self::TYPE_STRING,
//'tsquery' => self::TYPE_STRING,
//'tsrange' => self::TYPE_STRING,
//'tstzrange' => self::TYPE_STRING,
//'tsvector' => self::TYPE_STRING,
//'txid_snapshot' => self::TYPE_STRING,
'unknown' => self::TYPE_STRING,
'uuid' => self::TYPE_STRING,
'bit varying' => self::TYPE_STRING,
'character varying' => self::TYPE_STRING,
//'xid' => self::TYPE_STRING,
'xml' => self::TYPE_STRING
);
/**
* Resolves the table name and schema name (if any).
* @param TableSchema $table the table metadata object
* @param string $name the table name
@ -32,6 +112,9 @@ class Schema extends \yii\db\Schema {
} else {
$table->name = $parts[0];
}
if ($table->schemaName === null) {
$table->schemaName = self::$DEFAULT_SCHEMA;
}
}
/**
@ -52,11 +135,85 @@ class Schema extends \yii\db\Schema {
public function loadTableSchema($name) {
$table = new TableSchema();
$this->resolveTableNames($table, $name);
$this->findPrimaryKeys($table);
if ($this->findColumns($table)) {
$this->findForeignKeys($table);
return $table;
}
}
/**
* 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
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
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);
if ($column->name == 'numbers')
print_r($column);
}
die();
}
/**
* 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->isPrimaryKey
$column->name = $info['column_name'];
//$column->phpType
//$column->precision
//$column->scale
//$column->size;
//$column->type
//$column->unsigned
return $column;
}
}

14
tests/unit/data/postgres.sql

@ -11,14 +11,26 @@ DROP TABLE IF EXISTS tbl_category CASCADE;
DROP TABLE IF EXISTS tbl_customer CASCADE;
DROP TABLE IF EXISTS tbl_type CASCADE;
drop type if exists fullname cascade;
create type fullname as (firstname varchar,lastname varchar);
drop type if exists mood cascade;
create type mood as enum ('sad','ok','happy',E'own\'s',E'\"quoted\"');
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
status integer DEFAULT 0,
fullname fullname,
mood mood,
numbers integer[]
);
comment on column public.tbl_customer.email is 'someone@example.com';
CREATE TABLE tbl_category (
id serial not null primary key,
name varchar(128) NOT NULL

Loading…
Cancel
Save