diff options
Diffstat (limited to 'framework/Data/Common')
| -rw-r--r-- | framework/Data/Common/Mssql/TMssqlMetaData.php | 468 | ||||
| -rw-r--r-- | framework/Data/Common/Pgsql/TPgsqlMetaData.php | 670 | 
2 files changed, 569 insertions, 569 deletions
| diff --git a/framework/Data/Common/Mssql/TMssqlMetaData.php b/framework/Data/Common/Mssql/TMssqlMetaData.php index 37ce124f..7b222d89 100644 --- a/framework/Data/Common/Mssql/TMssqlMetaData.php +++ b/framework/Data/Common/Mssql/TMssqlMetaData.php @@ -1,235 +1,235 @@ -<?php
 -/**
 - * TMssqlMetaData class file.
 - *
 - * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 - * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2007 PradoSoft
 - * @license http://www.pradosoft.com/license/
 - * @version $Id: TPgsqlMetaData.php 1866 2007-04-14 05:02:29Z wei $
 - * @package System.Data.Common.Pgsql
 - */
 -
 -/**
 - * Load the base TDbMetaData class.
 - */
 -Prado::using('System.Data.Common.TDbMetaData');
 -Prado::using('System.Data.Common.Mssql.TMssqlTableInfo');
 -
 -/**
 - * TMssqlMetaData loads MSSQL database table and column information.
 - *
 - * @author Wei Zhuo <weizho[at]gmail[dot]com>
 - * @version $Id: TPgsqlMetaData.php 1866 2007-04-14 05:02:29Z wei $
 - * @package System.Data.Commom.Pgsql
 - * @since 3.1
 - */
 -class TMssqlMetaData extends TDbMetaData
 -{
 -	/**
 -	 * @return string TDbTableInfo class name.
 -	 */
 -	protected function getTableInfoClass()
 -	{
 -		return 'TMssqlTableInfo';
 -	}
 -
 -	/**
 -	 * Get the column definitions for given table.
 -	 * @param string table name.
 -	 * @return TMssqlTableInfo table information.
 -	 */
 -	protected function createTableInfo($table)
 -	{
 -		list($catalogName,$schemaName,$tableName) = $this->getCatalogSchemaTableName($table);
 -		$this->getDbConnection()->setActive(true);
 -		$sql = <<<EOD
 -				SELECT t.*,
 -                         c.*,
 -					columnproperty(object_id(c.table_schema + '.' + c.table_name), c.column_name,'IsIdentity') as IsIdentity
 -                    FROM INFORMATION_SCHEMA.TABLES t,
 -                         INFORMATION_SCHEMA.COLUMNS c
 -                   WHERE t.table_name = c.table_name
 -                     AND t.table_name = :table
 -EOD;
 -		if($schemaName!==null)
 -			$sql .= ' AND t.schema_name = :schema';
 -		if($catalogName!==null)
 -			$sql .= ' AND t.catalog_name = :catalog';
 -
 -		$command = $this->getDbConnection()->createCommand($sql);
 -		$command->bindValue(':table', $tableName);
 -		if($schemaName!==null)
 -			$command->bindValue(':schema', $schemaName);
 -		if($catalogName!==null)
 -			$command->bindValue(':catalog', $catalogName);
 -
 -		$tableInfo=null;
 -		foreach($command->query() as $col)
 -		{
 -			if($tableInfo===null)
 -				$tableInfo = $this->createNewTableInfo($col);
 -			$this->processColumn($tableInfo,$col);
 -		}
 -		if($tableInfo===null)
 -			throw new TDbException('dbmetadata_invalid_table_view', $table);
 -		return $tableInfo;
 -	}
 -
 -	/**
 -	 * @param string table name
 -	 * @return array tuple($catalogName,$schemaName,$tableName)
 -	 */
 -	protected function getCatalogSchemaTableName($table)
 -	{
 -		//remove possible delimiters
 -		$result = explode('.', preg_replace('/\[|\]|"/', '', $table));
 -		if(count($result)===1)
 -			return array(null,null,$result[0]);
 -		if(count($result)===2)
 -			return array(null,$result[0],$result[1]);
 -		if(count($result)>2)
 -			return array($result[0],$result[1],$result[2]);
 -	}
 -
 -	/**
 -	 * @param TMssqlTableInfo table information.
 -	 * @param array column information.
 -	 */
 -	protected function processColumn($tableInfo, $col)
 -	{
 -		$columnId = $col['COLUMN_NAME'];
 -
 -		$info['ColumnName'] = "[$columnId]"; //quote the column names!
 -		$info['ColumnId'] = $columnId;
 -		$info['ColumnIndex'] = intval($col['ORDINAL_POSITION'])-1; //zero-based index
 -		if($col['IS_NULLABLE']!=='NO')
 -			$info['AllowNull'] = true;
 -		if($col['COLUMN_DEFAULT']!==null)
 -			$info['DefaultValue'] = $col['COLUMN_DEFAULT'];
 -
 -		if(in_array($columnId, $tableInfo->getPrimaryKeys()))
 -			$info['IsPrimaryKey'] = true;
 -		if($this->isForeignKeyColumn($columnId, $tableInfo))
 -			$info['IsForeignKey'] = true;
 -
 -		if($col['IsIdentity']==='1')
 -			$info['AutoIncrement'] = true;
 -		$info['DbType'] = $col['DATA_TYPE'];
 -		if($col['CHARACTER_MAXIMUM_LENGTH']!==null)
 -			$info['ColumnSize'] = intval($col['CHARACTER_MAXIMUM_LENGTH']);
 -		if($col['NUMERIC_PRECISION'] !== null)
 -			$info['NumericPrecision'] = intval($col['NUMERIC_PRECISION']);
 -		if($col['NUMERIC_SCALE']!==null)
 -			$info['NumericScale'] = intval($col['NUMERIC_SCALE']);
 -		$tableInfo->Columns[$columnId] = new TMssqlTableColumn($info);
 -	}
 -
 -	/**
 -	 * @param string table schema name
 -	 * @param string table name.
 -	 * @return TMssqlTableInfo
 -	 */
 -	protected function createNewTableInfo($col)
 -	{
 -		$info['CatalogName'] = $col['TABLE_CATALOG'];
 -		$info['SchemaName'] = $col['TABLE_SCHEMA'];
 -		$info['TableName'] = $col['TABLE_NAME'];
 -		if($col['TABLE_TYPE']==='VIEW')
 -			$info['IsView'] = true;
 -		list($primary, $foreign) = $this->getConstraintKeys($col);
 -		$class = $this->getTableInfoClass();
 -		return new $class($info,$primary,$foreign);
 -	}
 -
 -	/**
 -	 * Gets the primary and foreign key column details for the given table.
 -	 * @param string schema name
 -	 * @param string table name.
 -	 * @return array tuple ($primary, $foreign)
 -	 */
 -	protected function getConstraintKeys($col)
 -	{
 -		$sql = <<<EOD
 -		SELECT k.column_name field_name
 -		    FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE k
 -		    LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS c
 -		      ON k.table_name = c.table_name
 -		     AND k.constraint_name = c.constraint_name
 -		   WHERE k.constraint_catalog = DB_NAME()
 -		AND
 -			c.constraint_type ='PRIMARY KEY'
 -		    AND k.table_name = :table
 -EOD;
 -		$command = $this->getDbConnection()->createCommand($sql);
 -		$command->bindValue(':table', $col['TABLE_NAME']);
 -		$primary = array();
 -		foreach($command->query()->readAll() as $field)
 -			$primary[] = $field['field_name'];
 -		$foreign = $this->getForeignConstraints($col);
 -		return array($primary,$foreign);
 -	}
 -
 -	/**
 -	 * Gets foreign relationship constraint keys and table name
 -	 * @param string database name
 -	 * @param string table name
 -	 * @return array foreign relationship table name and keys.
 -	 */
 -	protected function getForeignConstraints($col)
 -	{
 -		//From http://msdn2.microsoft.com/en-us/library/aa175805(SQL.80).aspx
 -		$sql = <<<EOD
 -		SELECT
 -		     KCU1.CONSTRAINT_NAME AS 'FK_CONSTRAINT_NAME'
 -		   , KCU1.TABLE_NAME AS 'FK_TABLE_NAME'
 -		   , KCU1.COLUMN_NAME AS 'FK_COLUMN_NAME'
 -		   , KCU1.ORDINAL_POSITION AS 'FK_ORDINAL_POSITION'
 -		   , KCU2.CONSTRAINT_NAME AS 'UQ_CONSTRAINT_NAME'
 -		   , KCU2.TABLE_NAME AS 'UQ_TABLE_NAME'
 -		   , KCU2.COLUMN_NAME AS 'UQ_COLUMN_NAME'
 -		   , KCU2.ORDINAL_POSITION AS 'UQ_ORDINAL_POSITION'
 -		FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC
 -		JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU1
 -		ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG
 -		   AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA
 -		   AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
 -		JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU2
 -		ON KCU2.CONSTRAINT_CATALOG =
 -		RC.UNIQUE_CONSTRAINT_CATALOG
 -		   AND KCU2.CONSTRAINT_SCHEMA =
 -		RC.UNIQUE_CONSTRAINT_SCHEMA
 -		   AND KCU2.CONSTRAINT_NAME =
 -		RC.UNIQUE_CONSTRAINT_NAME
 -		   AND KCU2.ORDINAL_POSITION = KCU1.ORDINAL_POSITION
 -		WHERE KCU1.TABLE_NAME = :table
 -EOD;
 -		$command = $this->getDbConnection()->createCommand($sql);
 -		$command->bindValue(':table', $col['TABLE_NAME']);
 -		$fkeys=array();
 -		$catalogSchema = "[{$col['TABLE_CATALOG']}].[{$col['TABLE_SCHEMA']}]";
 -		foreach($command->query() as $info)
 -		{
 -			$fkeys[$info['FK_CONSTRAINT_NAME']]['keys'][$info['FK_COLUMN_NAME']] = $info['UQ_COLUMN_NAME'];
 -			$fkeys[$info['FK_CONSTRAINT_NAME']]['table'] = $info['UQ_TABLE_NAME'];
 -		}
 -		return count($fkeys) > 0 ? array_values($fkeys) : $fkeys;
 -	}
 -
 -	/**
 -	 * @param string column name.
 -	 * @param TPgsqlTableInfo table information.
 -	 * @return boolean true if column is a foreign key.
 -	 */
 -	protected function isForeignKeyColumn($columnId, $tableInfo)
 -	{
 -		foreach($tableInfo->getForeignKeys() as $fk)
 -		{
 -			if(in_array($columnId, array_keys($fk['keys'])))
 -				return true;
 -		}
 -		return false;
 -	}
 -}
 -
 +<?php +/** + * TMssqlMetaData class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2007 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id: TPgsqlMetaData.php 1866 2007-04-14 05:02:29Z wei $ + * @package System.Data.Common.Pgsql + */ + +/** + * Load the base TDbMetaData class. + */ +Prado::using('System.Data.Common.TDbMetaData'); +Prado::using('System.Data.Common.Mssql.TMssqlTableInfo'); + +/** + * TMssqlMetaData loads MSSQL database table and column information. + * + * @author Wei Zhuo <weizho[at]gmail[dot]com> + * @version $Id: TPgsqlMetaData.php 1866 2007-04-14 05:02:29Z wei $ + * @package System.Data.Common.Mssql + * @since 3.1 + */ +class TMssqlMetaData extends TDbMetaData +{ +	/** +	 * @return string TDbTableInfo class name. +	 */ +	protected function getTableInfoClass() +	{ +		return 'TMssqlTableInfo'; +	} + +	/** +	 * Get the column definitions for given table. +	 * @param string table name. +	 * @return TMssqlTableInfo table information. +	 */ +	protected function createTableInfo($table) +	{ +		list($catalogName,$schemaName,$tableName) = $this->getCatalogSchemaTableName($table); +		$this->getDbConnection()->setActive(true); +		$sql = <<<EOD +				SELECT t.*, +                         c.*, +					columnproperty(object_id(c.table_schema + '.' + c.table_name), c.column_name,'IsIdentity') as IsIdentity +                    FROM INFORMATION_SCHEMA.TABLES t, +                         INFORMATION_SCHEMA.COLUMNS c +                   WHERE t.table_name = c.table_name +                     AND t.table_name = :table +EOD; +		if($schemaName!==null) +			$sql .= ' AND t.schema_name = :schema'; +		if($catalogName!==null) +			$sql .= ' AND t.catalog_name = :catalog'; + +		$command = $this->getDbConnection()->createCommand($sql); +		$command->bindValue(':table', $tableName); +		if($schemaName!==null) +			$command->bindValue(':schema', $schemaName); +		if($catalogName!==null) +			$command->bindValue(':catalog', $catalogName); + +		$tableInfo=null; +		foreach($command->query() as $col) +		{ +			if($tableInfo===null) +				$tableInfo = $this->createNewTableInfo($col); +			$this->processColumn($tableInfo,$col); +		} +		if($tableInfo===null) +			throw new TDbException('dbmetadata_invalid_table_view', $table); +		return $tableInfo; +	} + +	/** +	 * @param string table name +	 * @return array tuple($catalogName,$schemaName,$tableName) +	 */ +	protected function getCatalogSchemaTableName($table) +	{ +		//remove possible delimiters +		$result = explode('.', preg_replace('/\[|\]|"/', '', $table)); +		if(count($result)===1) +			return array(null,null,$result[0]); +		if(count($result)===2) +			return array(null,$result[0],$result[1]); +		if(count($result)>2) +			return array($result[0],$result[1],$result[2]); +	} + +	/** +	 * @param TMssqlTableInfo table information. +	 * @param array column information. +	 */ +	protected function processColumn($tableInfo, $col) +	{ +		$columnId = $col['COLUMN_NAME']; + +		$info['ColumnName'] = "[$columnId]"; //quote the column names! +		$info['ColumnId'] = $columnId; +		$info['ColumnIndex'] = intval($col['ORDINAL_POSITION'])-1; //zero-based index +		if($col['IS_NULLABLE']!=='NO') +			$info['AllowNull'] = true; +		if($col['COLUMN_DEFAULT']!==null) +			$info['DefaultValue'] = $col['COLUMN_DEFAULT']; + +		if(in_array($columnId, $tableInfo->getPrimaryKeys())) +			$info['IsPrimaryKey'] = true; +		if($this->isForeignKeyColumn($columnId, $tableInfo)) +			$info['IsForeignKey'] = true; + +		if($col['IsIdentity']==='1') +			$info['AutoIncrement'] = true; +		$info['DbType'] = $col['DATA_TYPE']; +		if($col['CHARACTER_MAXIMUM_LENGTH']!==null) +			$info['ColumnSize'] = intval($col['CHARACTER_MAXIMUM_LENGTH']); +		if($col['NUMERIC_PRECISION'] !== null) +			$info['NumericPrecision'] = intval($col['NUMERIC_PRECISION']); +		if($col['NUMERIC_SCALE']!==null) +			$info['NumericScale'] = intval($col['NUMERIC_SCALE']); +		$tableInfo->Columns[$columnId] = new TMssqlTableColumn($info); +	} + +	/** +	 * @param string table schema name +	 * @param string table name. +	 * @return TMssqlTableInfo +	 */ +	protected function createNewTableInfo($col) +	{ +		$info['CatalogName'] = $col['TABLE_CATALOG']; +		$info['SchemaName'] = $col['TABLE_SCHEMA']; +		$info['TableName'] = $col['TABLE_NAME']; +		if($col['TABLE_TYPE']==='VIEW') +			$info['IsView'] = true; +		list($primary, $foreign) = $this->getConstraintKeys($col); +		$class = $this->getTableInfoClass(); +		return new $class($info,$primary,$foreign); +	} + +	/** +	 * Gets the primary and foreign key column details for the given table. +	 * @param string schema name +	 * @param string table name. +	 * @return array tuple ($primary, $foreign) +	 */ +	protected function getConstraintKeys($col) +	{ +		$sql = <<<EOD +		SELECT k.column_name field_name +		    FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE k +		    LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS c +		      ON k.table_name = c.table_name +		     AND k.constraint_name = c.constraint_name +		   WHERE k.constraint_catalog = DB_NAME() +		AND +			c.constraint_type ='PRIMARY KEY' +		    AND k.table_name = :table +EOD; +		$command = $this->getDbConnection()->createCommand($sql); +		$command->bindValue(':table', $col['TABLE_NAME']); +		$primary = array(); +		foreach($command->query()->readAll() as $field) +			$primary[] = $field['field_name']; +		$foreign = $this->getForeignConstraints($col); +		return array($primary,$foreign); +	} + +	/** +	 * Gets foreign relationship constraint keys and table name +	 * @param string database name +	 * @param string table name +	 * @return array foreign relationship table name and keys. +	 */ +	protected function getForeignConstraints($col) +	{ +		//From http://msdn2.microsoft.com/en-us/library/aa175805(SQL.80).aspx +		$sql = <<<EOD +		SELECT +		     KCU1.CONSTRAINT_NAME AS 'FK_CONSTRAINT_NAME' +		   , KCU1.TABLE_NAME AS 'FK_TABLE_NAME' +		   , KCU1.COLUMN_NAME AS 'FK_COLUMN_NAME' +		   , KCU1.ORDINAL_POSITION AS 'FK_ORDINAL_POSITION' +		   , KCU2.CONSTRAINT_NAME AS 'UQ_CONSTRAINT_NAME' +		   , KCU2.TABLE_NAME AS 'UQ_TABLE_NAME' +		   , KCU2.COLUMN_NAME AS 'UQ_COLUMN_NAME' +		   , KCU2.ORDINAL_POSITION AS 'UQ_ORDINAL_POSITION' +		FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC +		JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU1 +		ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG +		   AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA +		   AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME +		JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU2 +		ON KCU2.CONSTRAINT_CATALOG = +		RC.UNIQUE_CONSTRAINT_CATALOG +		   AND KCU2.CONSTRAINT_SCHEMA = +		RC.UNIQUE_CONSTRAINT_SCHEMA +		   AND KCU2.CONSTRAINT_NAME = +		RC.UNIQUE_CONSTRAINT_NAME +		   AND KCU2.ORDINAL_POSITION = KCU1.ORDINAL_POSITION +		WHERE KCU1.TABLE_NAME = :table +EOD; +		$command = $this->getDbConnection()->createCommand($sql); +		$command->bindValue(':table', $col['TABLE_NAME']); +		$fkeys=array(); +		$catalogSchema = "[{$col['TABLE_CATALOG']}].[{$col['TABLE_SCHEMA']}]"; +		foreach($command->query() as $info) +		{ +			$fkeys[$info['FK_CONSTRAINT_NAME']]['keys'][$info['FK_COLUMN_NAME']] = $info['UQ_COLUMN_NAME']; +			$fkeys[$info['FK_CONSTRAINT_NAME']]['table'] = $info['UQ_TABLE_NAME']; +		} +		return count($fkeys) > 0 ? array_values($fkeys) : $fkeys; +	} + +	/** +	 * @param string column name. +	 * @param TPgsqlTableInfo table information. +	 * @return boolean true if column is a foreign key. +	 */ +	protected function isForeignKeyColumn($columnId, $tableInfo) +	{ +		foreach($tableInfo->getForeignKeys() as $fk) +		{ +			if(in_array($columnId, array_keys($fk['keys']))) +				return true; +		} +		return false; +	} +} +  ?>
\ No newline at end of file diff --git a/framework/Data/Common/Pgsql/TPgsqlMetaData.php b/framework/Data/Common/Pgsql/TPgsqlMetaData.php index 0b647445..eee5b264 100644 --- a/framework/Data/Common/Pgsql/TPgsqlMetaData.php +++ b/framework/Data/Common/Pgsql/TPgsqlMetaData.php @@ -1,338 +1,338 @@  <?php -/**
 - * TPgsqlMetaData class file.
 - *
 - * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 - * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2007 PradoSoft
 - * @license http://www.pradosoft.com/license/
 - * @version $Id$
 - * @package System.Data.Common.Pgsql
 - */
 -
 -/**
 - * Load the base TDbMetaData class.
 - */
 -Prado::using('System.Data.Common.TDbMetaData');
 -Prado::using('System.Data.Common.Pgsql.TPgsqlTableInfo');
 -
 -/**
 - * TPgsqlMetaData loads PostgreSQL database table and column information.
 - *
 - * @author Wei Zhuo <weizho[at]gmail[dot]com>
 - * @version $Id$
 - * @package System.Data.Commom.Pgsql
 - * @since 3.1
 - */
 -class TPgsqlMetaData extends TDbMetaData
 -{
 -	private $_defaultSchema = 'public';
 -
 -	/**
 -	 * @return string TDbTableInfo class name.
 -	 */
 -	protected function getTableInfoClass()
 -	{
 -		return 'TPgsqlTableInfo';
 -	}
 -
 -	/**
 -	 * @param string default schema.
 -	 */
 -	public function setDefaultSchema($schema)
 -	{
 -		$this->_defaultSchema=$schema;
 -	}
 -
 -	/**
 -	 * @return string default schema.
 -	 */
 -	public function getDefaultSchema()
 -	{
 -		return $this->_defaultSchema;
 -	}
 -
 -	/**
 -	 * @param string table name with optional schema name prefix, uses default schema name prefix is not provided.
 -	 * @return array tuple as ($schemaName,$tableName)
 -	 */
 -	protected function getSchemaTableName($table)
 -	{
 -		if(count($parts= explode('.', str_replace('"','',$table))) > 1)
 -			return array($parts[0], $parts[1]);
 -		else
 -			return array($this->getDefaultSchema(),$parts[0]);
 -	}
 -
 -	/**
 -	 * Get the column definitions for given table.
 -	 * @param string table name.
 -	 * @return TPgsqlTableInfo table information.
 -	 */
 -	protected function createTableInfo($table)
 -	{
 -		list($schemaName,$tableName) = $this->getSchemaTableName($table);
 -
 -		// This query is made much more complex by the addition of the 'attisserial' field.
 -		// The subquery to get that field checks to see if there is an internally dependent
 -		// sequence on the field.
 -		$sql =
 -<<<EOD
 -		SELECT
 -			a.attname,
 -			pg_catalog.format_type(a.atttypid, a.atttypmod) as type,
 -			a.atttypmod,
 -			a.attnotnull, a.atthasdef, adef.adsrc,
 -			(
 -				SELECT 1 FROM pg_catalog.pg_depend pd, pg_catalog.pg_class pc
 -				WHERE pd.objid=pc.oid
 -				AND pd.classid=pc.tableoid
 -				AND pd.refclassid=pc.tableoid
 -				AND pd.refobjid=a.attrelid
 -				AND pd.refobjsubid=a.attnum
 -				AND pd.deptype='i'
 -				AND pc.relkind='S'
 -			) IS NOT NULL AS attisserial
 -
 -		FROM
 -			pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_attrdef adef
 -			ON a.attrelid=adef.adrelid
 -			AND a.attnum=adef.adnum
 -			LEFT JOIN pg_catalog.pg_type t ON a.atttypid=t.oid
 -		WHERE
 -			a.attrelid = (SELECT oid FROM pg_catalog.pg_class WHERE relname=:table
 -				AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE
 -				nspname = :schema))
 -			AND a.attnum > 0 AND NOT a.attisdropped
 -		ORDER BY a.attnum
 -EOD;
 -		$this->getDbConnection()->setActive(true);
 -		$command = $this->getDbConnection()->createCommand($sql);
 -		$command->bindValue(':table', $tableName);
 -		$command->bindValue(':schema', $schemaName);
 -		$tableInfo = $this->createNewTableInfo($schemaName, $tableName);
 -		$index=0;
 -		foreach($command->query() as $col)
 -		{
 -			$col['index'] = $index++;
 -			$this->processColumn($tableInfo, $col);
 -		}
 -		if($index===0)
 -			throw new TDbException('dbmetadata_invalid_table_view', $table);
 -		return $tableInfo;
 -	}
 -
 -	/**
 -	 * @param string table schema name
 -	 * @param string table name.
 -	 * @return TPgsqlTableInfo
 -	 */
 -	protected function createNewTableInfo($schemaName,$tableName)
 -	{
 -		$info['SchemaName'] = $this->assertIdentifier($schemaName);
 -		$info['TableName'] = $this->assertIdentifier($tableName);
 -		if($this->getIsView($schemaName,$tableName))
 -			$info['IsView'] = true;
 -		list($primary, $foreign) = $this->getConstraintKeys($schemaName, $tableName);
 -		$class = $this->getTableInfoClass();
 -		return new $class($info,$primary,$foreign);
 -	}
 -
 -	/**
 -	 * @param string table name, schema name or column name.
 -	 * @return string a valid identifier.
 -	 * @throws TDbException when table name contains a double quote (").
 -	 */
 -	protected function assertIdentifier($name)
 -	{
 -		if(strpos($name, '"')!==false)
 -		{
 -			$ref = 'http://www.postgresql.org/docs/7.4/static/sql-syntax.html#SQL-SYNTAX-IDENTIFIERS';
 -			throw new TDbException('dbcommon_invalid_identifier_name', $name, $ref);
 -		}
 -		return $name;
 -	}
 -
 -	/**
 -	 * @param string table schema name
 -	 * @param string table name.
 -	 * @return boolean true if the table is a view.
 -	 */
 -	protected function getIsView($schemaName,$tableName)
 -	{
 -		$sql =
 -<<<EOD
 -		SELECT count(c.relname) FROM pg_catalog.pg_class c
 -		LEFT JOIN pg_catalog.pg_namespace n ON (n.oid = c.relnamespace)
 -		WHERE (n.nspname=:schema) AND (c.relkind = 'v'::"char") AND c.relname = :table
 -EOD;
 -		$this->getDbConnection()->setActive(true);
 -		$command = $this->getDbConnection()->createCommand($sql);
 -		$command->bindValue(':schema',$schemaName);
 -		$command->bindValue(':table', $tableName);
 -		return intval($command->queryScalar()) === 1;
 -	}
 -
 -	/**
 -	 * @param TPgsqlTableInfo table information.
 -	 * @param array column information.
 -	 */
 -	protected function processColumn($tableInfo, $col)
 -	{
 -		$columnId = $col['attname']; //use column name as column Id
 -
 -		$info['ColumnName'] = '"'.$columnId.'"'; //quote the column names!
 -		$info['ColumnId'] = $columnId;
 -		$info['ColumnIndex'] = $col['index'];
 -		if(!$col['attnotnull'])
 -			$info['AllowNull'] = true;
 -		if(in_array($columnId, $tableInfo->getPrimaryKeys()))
 -			$info['IsPrimaryKey'] = true;
 -		if($this->isForeignKeyColumn($columnId, $tableInfo))
 -			$info['IsForeignKey'] = true;
 -
 -		if($col['atttypmod'] > 0)
 -			$info['ColumnSize'] =  $col['atttypmod'] - 4;
 -		if($col['atthasdef'])
 -			$info['DefaultValue'] = $col['adsrc'];
 -		if($col['attisserial'] || substr($col['adsrc'],0,8) === 'nextval(')
 -		{
 -			if(($sequence = $this->getSequenceName($tableInfo, $col['adsrc']))!==null)
 -			{
 -				$info['SequenceName'] = $sequence;
 -				unset($info['DefaultValue']);
 -			}
 -		}
 -		$matches = array();
 -		if(preg_match('/\((\d+)(?:,(\d+))?+\)/', $col['type'], $matches))
 -		{
 -			$info['DbType'] = preg_replace('/\(\d+(?:,\d+)?\)/','',$col['type']);
 -			if($this->isPrecisionType($info['DbType']))
 -			{
 -				$info['NumericPrecision'] = intval($matches[1]);
 -				if(count($matches) > 2)
 -					$info['NumericScale'] = intval($matches[2]);
 -			}
 -			else
 -				$info['ColumnSize'] = intval($matches[1]);
 -		}
 -		else
 -			$info['DbType'] = $col['type'];
 -
 -		$tableInfo->Columns[$columnId] = new TPgsqlTableColumn($info);
 -	}
 -
 -	/**
 -	 * @return string serial name if found, null otherwise.
 -	 */
 -	protected function getSequenceName($tableInfo,$src)
 -	{
 -		$matches = array();
 -		if(preg_match('/nextval\([^\']*\'([^\']+)\'[^\)]*\)/i',$src,$matches))
 -		{
 -			if(is_int(strpos($matches[1], '.')))
 -				return $matches[1];
 -			else
 -				return $tableInfo->getSchemaName().'.'.$matches[1];
 -		}
 -	}
 -
 -	/**
 -	 * @return boolean true if column type if "numeric", "interval" or begins with "time".
 -	 */
 -	protected function isPrecisionType($type)
 -	{
 -		$type = strtolower(trim($type));
 -		return $type==='numeric' || $type==='interval' || strpos($type, 'time')===0;
 -	}
 -
 -	/**
 -	 * Gets the primary and foreign key column details for the given table.
 -	 * @param string schema name
 -	 * @param string table name.
 -	 * @return array tuple ($primary, $foreign)
 -	 */
 -	protected function getConstraintKeys($schemaName, $tableName)
 -	{
 -		$sql = 'SELECT
 -				pg_catalog.pg_get_constraintdef(pc.oid, true) AS consrc,
 -				pc.contype
 -			FROM
 -				pg_catalog.pg_constraint pc
 -			WHERE
 -				pc.conrelid = (SELECT oid FROM pg_catalog.pg_class WHERE relname=:table
 -					AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace
 -					WHERE nspname=:schema))
 -		';
 -		$this->getDbConnection()->setActive(true);
 -		$command = $this->getDbConnection()->createCommand($sql);
 -		$command->bindValue(':table', $tableName);
 -		$command->bindValue(':schema', $schemaName);
 -		$primary = array();
 -		$foreign = array();
 -		foreach($command->query() as $row)
 -		{
 -			switch($row['contype'])
 -			{
 -				case 'p':
 -					$primary = $this->getPrimaryKeys($row['consrc']);
 -					break;
 -				case 'f':
 -					if(($fkey = $this->getForeignKeys($row['consrc']))!==null)
 -						$foreign[] = $fkey;
 -					break;
 -			}
 -		}
 -		return array($primary,$foreign);
 -	}
 -
 -	/**
 -	 * Gets the primary key field names
 -	 * @param string pgsql primary key definition
 -	 * @return array primary key field names.
 -	 */
 -	protected function getPrimaryKeys($src)
 -	{
 -		$matches = array();
 -		if(preg_match('/PRIMARY\s+KEY\s+\(([^\)]+)\)/i', $src, $matches))
 -			return preg_split('/,\s+/',$matches[1]);
 -		return array();
 -	}
 -
 -	/**
 -	 * Gets foreign relationship constraint keys and table name
 -	 * @param string pgsql foreign key definition
 -	 * @return array foreign relationship table name and keys, null otherwise
 -	 */
 -	protected function getForeignKeys($src)
 -	{
 -		$matches = array();
 -		$brackets = '\(([^\)]+)\)';
 -		$find = "/FOREIGN\s+KEY\s+{$brackets}\s+REFERENCES\s+([^\(]+){$brackets}/i";
 -		if(preg_match($find, $src, $matches))
 -		{
 -			$keys = preg_split('/,\s+/', $matches[1]);
 -			$fkeys = array();
 -			foreach(preg_split('/,\s+/', $matches[3]) as $i => $fkey)
 -				$fkeys[$keys[$i]] = $fkey;
 -			return array('table' => str_replace('"','',$matches[2]), 'keys' => $fkeys);
 -		}
 -	}
 -
 -	/**
 -	 * @param string column name.
 -	 * @param TPgsqlTableInfo table information.
 -	 * @return boolean true if column is a foreign key.
 -	 */
 -	protected function isForeignKeyColumn($columnId, $tableInfo)
 -	{
 -		foreach($tableInfo->getForeignKeys() as $fk)
 -		{
 -			if(in_array($columnId, array_keys($fk['keys'])))
 -				return true;
 -		}
 -		return false;
 -	}
 -}
 +/** + * TPgsqlMetaData class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2007 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Data.Common.Pgsql + */ + +/** + * Load the base TDbMetaData class. + */ +Prado::using('System.Data.Common.TDbMetaData'); +Prado::using('System.Data.Common.Pgsql.TPgsqlTableInfo'); + +/** + * TPgsqlMetaData loads PostgreSQL database table and column information. + * + * @author Wei Zhuo <weizho[at]gmail[dot]com> + * @version $Id$ + * @package System.Data.Common.Pgsql + * @since 3.1 + */ +class TPgsqlMetaData extends TDbMetaData +{ +	private $_defaultSchema = 'public'; + +	/** +	 * @return string TDbTableInfo class name. +	 */ +	protected function getTableInfoClass() +	{ +		return 'TPgsqlTableInfo'; +	} + +	/** +	 * @param string default schema. +	 */ +	public function setDefaultSchema($schema) +	{ +		$this->_defaultSchema=$schema; +	} + +	/** +	 * @return string default schema. +	 */ +	public function getDefaultSchema() +	{ +		return $this->_defaultSchema; +	} + +	/** +	 * @param string table name with optional schema name prefix, uses default schema name prefix is not provided. +	 * @return array tuple as ($schemaName,$tableName) +	 */ +	protected function getSchemaTableName($table) +	{ +		if(count($parts= explode('.', str_replace('"','',$table))) > 1) +			return array($parts[0], $parts[1]); +		else +			return array($this->getDefaultSchema(),$parts[0]); +	} + +	/** +	 * Get the column definitions for given table. +	 * @param string table name. +	 * @return TPgsqlTableInfo table information. +	 */ +	protected function createTableInfo($table) +	{ +		list($schemaName,$tableName) = $this->getSchemaTableName($table); + +		// This query is made much more complex by the addition of the 'attisserial' field. +		// The subquery to get that field checks to see if there is an internally dependent +		// sequence on the field. +		$sql = +<<<EOD +		SELECT +			a.attname, +			pg_catalog.format_type(a.atttypid, a.atttypmod) as type, +			a.atttypmod, +			a.attnotnull, a.atthasdef, adef.adsrc, +			( +				SELECT 1 FROM pg_catalog.pg_depend pd, pg_catalog.pg_class pc +				WHERE pd.objid=pc.oid +				AND pd.classid=pc.tableoid +				AND pd.refclassid=pc.tableoid +				AND pd.refobjid=a.attrelid +				AND pd.refobjsubid=a.attnum +				AND pd.deptype='i' +				AND pc.relkind='S' +			) IS NOT NULL AS attisserial + +		FROM +			pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_attrdef adef +			ON a.attrelid=adef.adrelid +			AND a.attnum=adef.adnum +			LEFT JOIN pg_catalog.pg_type t ON a.atttypid=t.oid +		WHERE +			a.attrelid = (SELECT oid FROM pg_catalog.pg_class WHERE relname=:table +				AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE +				nspname = :schema)) +			AND a.attnum > 0 AND NOT a.attisdropped +		ORDER BY a.attnum +EOD; +		$this->getDbConnection()->setActive(true); +		$command = $this->getDbConnection()->createCommand($sql); +		$command->bindValue(':table', $tableName); +		$command->bindValue(':schema', $schemaName); +		$tableInfo = $this->createNewTableInfo($schemaName, $tableName); +		$index=0; +		foreach($command->query() as $col) +		{ +			$col['index'] = $index++; +			$this->processColumn($tableInfo, $col); +		} +		if($index===0) +			throw new TDbException('dbmetadata_invalid_table_view', $table); +		return $tableInfo; +	} + +	/** +	 * @param string table schema name +	 * @param string table name. +	 * @return TPgsqlTableInfo +	 */ +	protected function createNewTableInfo($schemaName,$tableName) +	{ +		$info['SchemaName'] = $this->assertIdentifier($schemaName); +		$info['TableName'] = $this->assertIdentifier($tableName); +		if($this->getIsView($schemaName,$tableName)) +			$info['IsView'] = true; +		list($primary, $foreign) = $this->getConstraintKeys($schemaName, $tableName); +		$class = $this->getTableInfoClass(); +		return new $class($info,$primary,$foreign); +	} + +	/** +	 * @param string table name, schema name or column name. +	 * @return string a valid identifier. +	 * @throws TDbException when table name contains a double quote ("). +	 */ +	protected function assertIdentifier($name) +	{ +		if(strpos($name, '"')!==false) +		{ +			$ref = 'http://www.postgresql.org/docs/7.4/static/sql-syntax.html#SQL-SYNTAX-IDENTIFIERS'; +			throw new TDbException('dbcommon_invalid_identifier_name', $name, $ref); +		} +		return $name; +	} + +	/** +	 * @param string table schema name +	 * @param string table name. +	 * @return boolean true if the table is a view. +	 */ +	protected function getIsView($schemaName,$tableName) +	{ +		$sql = +<<<EOD +		SELECT count(c.relname) FROM pg_catalog.pg_class c +		LEFT JOIN pg_catalog.pg_namespace n ON (n.oid = c.relnamespace) +		WHERE (n.nspname=:schema) AND (c.relkind = 'v'::"char") AND c.relname = :table +EOD; +		$this->getDbConnection()->setActive(true); +		$command = $this->getDbConnection()->createCommand($sql); +		$command->bindValue(':schema',$schemaName); +		$command->bindValue(':table', $tableName); +		return intval($command->queryScalar()) === 1; +	} + +	/** +	 * @param TPgsqlTableInfo table information. +	 * @param array column information. +	 */ +	protected function processColumn($tableInfo, $col) +	{ +		$columnId = $col['attname']; //use column name as column Id + +		$info['ColumnName'] = '"'.$columnId.'"'; //quote the column names! +		$info['ColumnId'] = $columnId; +		$info['ColumnIndex'] = $col['index']; +		if(!$col['attnotnull']) +			$info['AllowNull'] = true; +		if(in_array($columnId, $tableInfo->getPrimaryKeys())) +			$info['IsPrimaryKey'] = true; +		if($this->isForeignKeyColumn($columnId, $tableInfo)) +			$info['IsForeignKey'] = true; + +		if($col['atttypmod'] > 0) +			$info['ColumnSize'] =  $col['atttypmod'] - 4; +		if($col['atthasdef']) +			$info['DefaultValue'] = $col['adsrc']; +		if($col['attisserial'] || substr($col['adsrc'],0,8) === 'nextval(') +		{ +			if(($sequence = $this->getSequenceName($tableInfo, $col['adsrc']))!==null) +			{ +				$info['SequenceName'] = $sequence; +				unset($info['DefaultValue']); +			} +		} +		$matches = array(); +		if(preg_match('/\((\d+)(?:,(\d+))?+\)/', $col['type'], $matches)) +		{ +			$info['DbType'] = preg_replace('/\(\d+(?:,\d+)?\)/','',$col['type']); +			if($this->isPrecisionType($info['DbType'])) +			{ +				$info['NumericPrecision'] = intval($matches[1]); +				if(count($matches) > 2) +					$info['NumericScale'] = intval($matches[2]); +			} +			else +				$info['ColumnSize'] = intval($matches[1]); +		} +		else +			$info['DbType'] = $col['type']; + +		$tableInfo->Columns[$columnId] = new TPgsqlTableColumn($info); +	} + +	/** +	 * @return string serial name if found, null otherwise. +	 */ +	protected function getSequenceName($tableInfo,$src) +	{ +		$matches = array(); +		if(preg_match('/nextval\([^\']*\'([^\']+)\'[^\)]*\)/i',$src,$matches)) +		{ +			if(is_int(strpos($matches[1], '.'))) +				return $matches[1]; +			else +				return $tableInfo->getSchemaName().'.'.$matches[1]; +		} +	} + +	/** +	 * @return boolean true if column type if "numeric", "interval" or begins with "time". +	 */ +	protected function isPrecisionType($type) +	{ +		$type = strtolower(trim($type)); +		return $type==='numeric' || $type==='interval' || strpos($type, 'time')===0; +	} + +	/** +	 * Gets the primary and foreign key column details for the given table. +	 * @param string schema name +	 * @param string table name. +	 * @return array tuple ($primary, $foreign) +	 */ +	protected function getConstraintKeys($schemaName, $tableName) +	{ +		$sql = 'SELECT +				pg_catalog.pg_get_constraintdef(pc.oid, true) AS consrc, +				pc.contype +			FROM +				pg_catalog.pg_constraint pc +			WHERE +				pc.conrelid = (SELECT oid FROM pg_catalog.pg_class WHERE relname=:table +					AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace +					WHERE nspname=:schema)) +		'; +		$this->getDbConnection()->setActive(true); +		$command = $this->getDbConnection()->createCommand($sql); +		$command->bindValue(':table', $tableName); +		$command->bindValue(':schema', $schemaName); +		$primary = array(); +		$foreign = array(); +		foreach($command->query() as $row) +		{ +			switch($row['contype']) +			{ +				case 'p': +					$primary = $this->getPrimaryKeys($row['consrc']); +					break; +				case 'f': +					if(($fkey = $this->getForeignKeys($row['consrc']))!==null) +						$foreign[] = $fkey; +					break; +			} +		} +		return array($primary,$foreign); +	} + +	/** +	 * Gets the primary key field names +	 * @param string pgsql primary key definition +	 * @return array primary key field names. +	 */ +	protected function getPrimaryKeys($src) +	{ +		$matches = array(); +		if(preg_match('/PRIMARY\s+KEY\s+\(([^\)]+)\)/i', $src, $matches)) +			return preg_split('/,\s+/',$matches[1]); +		return array(); +	} + +	/** +	 * Gets foreign relationship constraint keys and table name +	 * @param string pgsql foreign key definition +	 * @return array foreign relationship table name and keys, null otherwise +	 */ +	protected function getForeignKeys($src) +	{ +		$matches = array(); +		$brackets = '\(([^\)]+)\)'; +		$find = "/FOREIGN\s+KEY\s+{$brackets}\s+REFERENCES\s+([^\(]+){$brackets}/i"; +		if(preg_match($find, $src, $matches)) +		{ +			$keys = preg_split('/,\s+/', $matches[1]); +			$fkeys = array(); +			foreach(preg_split('/,\s+/', $matches[3]) as $i => $fkey) +				$fkeys[$keys[$i]] = $fkey; +			return array('table' => str_replace('"','',$matches[2]), 'keys' => $fkeys); +		} +	} + +	/** +	 * @param string column name. +	 * @param TPgsqlTableInfo table information. +	 * @return boolean true if column is a foreign key. +	 */ +	protected function isForeignKeyColumn($columnId, $tableInfo) +	{ +		foreach($tableInfo->getForeignKeys() as $fk) +		{ +			if(in_array($columnId, array_keys($fk['keys']))) +				return true; +		} +		return false; +	} +}  ?>
\ No newline at end of file | 
