CC-2166: Packaging Improvements. Moved the Zend app into airtime_mvc. It is now installed to /var/www/airtime. Storage is now set to /srv/airtime/stor. Utils are now installed to /usr/lib/airtime/utils/. Added install/airtime-dircheck.php as a simple test to see if everything is install/uninstalled correctly.
This commit is contained in:
parent
514777e8d2
commit
b11cbd8159
4546 changed files with 138 additions and 51 deletions
|
@ -0,0 +1,188 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Propel package.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
require_once 'reverse/SchemaParser.php';
|
||||
|
||||
/**
|
||||
* Base class for reverse engineering a database schema.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1612 $
|
||||
* @package propel.generator.reverse
|
||||
*/
|
||||
abstract class BaseSchemaParser implements SchemaParser
|
||||
{
|
||||
|
||||
/**
|
||||
* The database connection.
|
||||
* @var PDO
|
||||
*/
|
||||
protected $dbh;
|
||||
|
||||
/**
|
||||
* Stack of warnings.
|
||||
*
|
||||
* @var array string[]
|
||||
*/
|
||||
protected $warnings = array();
|
||||
|
||||
/**
|
||||
* GeneratorConfig object holding build properties.
|
||||
*
|
||||
* @var GeneratorConfig
|
||||
*/
|
||||
private $generatorConfig;
|
||||
|
||||
/**
|
||||
* Map native DB types to Propel types.
|
||||
* (Override in subclasses.)
|
||||
* @var array
|
||||
*/
|
||||
protected $nativeToPropelTypeMap;
|
||||
|
||||
/**
|
||||
* Map to hold reverse type mapping (initialized on-demand).
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $reverseTypeMap;
|
||||
|
||||
/**
|
||||
* @param PDO $dbh Optional database connection
|
||||
*/
|
||||
public function __construct(PDO $dbh = null)
|
||||
{
|
||||
if ($dbh) $this->setConnection($dbh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database connection.
|
||||
*
|
||||
* @param PDO $dbh
|
||||
*/
|
||||
public function setConnection(PDO $dbh)
|
||||
{
|
||||
$this->dbh = $dbh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the database connection.
|
||||
* @return PDO
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->dbh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes a message onto the stack of warnings.
|
||||
*
|
||||
* @param string $msg The warning message.
|
||||
*/
|
||||
protected function warn($msg)
|
||||
{
|
||||
$this->warnings[] = $msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets array of warning messages.
|
||||
*
|
||||
* @return array string[]
|
||||
*/
|
||||
public function getWarnings()
|
||||
{
|
||||
return $this->warnings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the GeneratorConfig to use in the parsing.
|
||||
*
|
||||
* @param GeneratorConfig $config
|
||||
*/
|
||||
public function setGeneratorConfig(GeneratorConfig $config)
|
||||
{
|
||||
$this->generatorConfig = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the GeneratorConfig option.
|
||||
*
|
||||
* @return GeneratorConfig
|
||||
*/
|
||||
public function getGeneratorConfig()
|
||||
{
|
||||
return $this->generatorConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a specific propel (renamed) property from the build.
|
||||
*
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function getBuildProperty($name)
|
||||
{
|
||||
if ($this->generatorConfig !== null) {
|
||||
return $this->generatorConfig->getBuildProperty($name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a type mapping from native type to Propel type.
|
||||
*
|
||||
* @return array The mapped Propel type.
|
||||
*/
|
||||
abstract protected function getTypeMapping();
|
||||
|
||||
/**
|
||||
* Gets a mapped Propel type for specified native type.
|
||||
*
|
||||
* @param string $nativeType
|
||||
* @return string The mapped Propel type.
|
||||
*/
|
||||
protected function getMappedPropelType($nativeType)
|
||||
{
|
||||
if ($this->nativeToPropelTypeMap === null) {
|
||||
$this->nativeToPropelTypeMap = $this->getTypeMapping();
|
||||
}
|
||||
if (isset($this->nativeToPropelTypeMap[$nativeType])) {
|
||||
return $this->nativeToPropelTypeMap[$nativeType];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Give a best guess at the native type.
|
||||
*
|
||||
* @param string $propelType
|
||||
* @return string The native SQL type that best matches the specified Propel type.
|
||||
*/
|
||||
protected function getMappedNativeType($propelType)
|
||||
{
|
||||
if ($this->reverseTypeMap === null) {
|
||||
$this->reverseTypeMap = array_flip($this->getTypeMapping());
|
||||
}
|
||||
return isset($this->reverseTypeMap[$propelType]) ? $this->reverseTypeMap[$propelType] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a new VendorInfo object for this platform with specified params.
|
||||
*
|
||||
* @param array $params
|
||||
*/
|
||||
protected function getNewVendorInfoObject(array $params)
|
||||
{
|
||||
$type = $this->getGeneratorConfig()->getConfiguredPlatform()->getDatabaseType();
|
||||
$vi = new VendorInfo($type);
|
||||
$vi->setParameters($params);
|
||||
return $vi;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Propel package.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interface for reverse engineering schema parsers.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1612 $
|
||||
* @package propel.generator.reverse
|
||||
*/
|
||||
interface SchemaParser
|
||||
{
|
||||
|
||||
/**
|
||||
* Gets the database connection.
|
||||
* @return PDO
|
||||
*/
|
||||
public function getConnection();
|
||||
|
||||
/**
|
||||
* Sets the database connection.
|
||||
*
|
||||
* @param PDO $dbh
|
||||
*/
|
||||
public function setConnection(PDO $dbh);
|
||||
|
||||
/**
|
||||
* Sets the GeneratorConfig to use in the parsing.
|
||||
*
|
||||
* @param GeneratorConfig $config
|
||||
*/
|
||||
public function setGeneratorConfig(GeneratorConfig $config);
|
||||
|
||||
/**
|
||||
* Gets a specific propel (renamed) property from the build.
|
||||
*
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function getBuildProperty($name);
|
||||
|
||||
/**
|
||||
* Gets array of warning messages.
|
||||
* @return array string[]
|
||||
*/
|
||||
public function getWarnings();
|
||||
|
||||
/**
|
||||
* Parse the schema and populate passed-in Database model object.
|
||||
*
|
||||
* @param Database $database
|
||||
*
|
||||
* @return int number of generated tables
|
||||
*/
|
||||
public function parse(Database $database, PDOTask $task = null);
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Propel package.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
require_once 'reverse/BaseSchemaParser.php';
|
||||
|
||||
/**
|
||||
* Microsoft SQL Server database schema parser.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1612 $
|
||||
* @package propel.generator.reverse.mssql
|
||||
*/
|
||||
class MssqlSchemaParser extends BaseSchemaParser
|
||||
{
|
||||
|
||||
/**
|
||||
* Map MSSQL native types to Propel types.
|
||||
* @var array
|
||||
*/
|
||||
private static $mssqlTypeMap = array(
|
||||
"binary" => PropelTypes::BINARY,
|
||||
"bit" => PropelTypes::BOOLEAN,
|
||||
"char" => PropelTypes::CHAR,
|
||||
"datetime" => PropelTypes::TIMESTAMP,
|
||||
"decimal() identity" => PropelTypes::DECIMAL,
|
||||
"decimal" => PropelTypes::DECIMAL,
|
||||
"image" => PropelTypes::LONGVARBINARY,
|
||||
"int" => PropelTypes::INTEGER,
|
||||
"int identity" => PropelTypes::INTEGER,
|
||||
"integer" => PropelTypes::INTEGER,
|
||||
"money" => PropelTypes::DECIMAL,
|
||||
"nchar" => PropelTypes::CHAR,
|
||||
"ntext" => PropelTypes::LONGVARCHAR,
|
||||
"numeric() identity" => PropelTypes::NUMERIC,
|
||||
"numeric" => PropelTypes::NUMERIC,
|
||||
"nvarchar" => PropelTypes::VARCHAR,
|
||||
"real" => PropelTypes::REAL,
|
||||
"float" => PropelTypes::FLOAT,
|
||||
"smalldatetime" => PropelTypes::TIMESTAMP,
|
||||
"smallint" => PropelTypes::SMALLINT,
|
||||
"smallint identity" => PropelTypes::SMALLINT,
|
||||
"smallmoney" => PropelTypes::DECIMAL,
|
||||
"sysname" => PropelTypes::VARCHAR,
|
||||
"text" => PropelTypes::LONGVARCHAR,
|
||||
"timestamp" => PropelTypes::BINARY,
|
||||
"tinyint identity" => PropelTypes::TINYINT,
|
||||
"tinyint" => PropelTypes::TINYINT,
|
||||
"uniqueidentifier" => PropelTypes::CHAR,
|
||||
"varbinary" => PropelTypes::VARBINARY,
|
||||
"varchar" => PropelTypes::VARCHAR,
|
||||
"uniqueidentifier" => PropelTypes::CHAR,
|
||||
// SQL Server 2000 only
|
||||
"bigint identity" => PropelTypes::BIGINT,
|
||||
"bigint" => PropelTypes::BIGINT,
|
||||
"sql_variant" => PropelTypes::VARCHAR,
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets a type mapping from native types to Propel types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTypeMapping()
|
||||
{
|
||||
return self::$mssqlTypeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function parse(Database $database, PDOTask $task = null)
|
||||
{
|
||||
$stmt = $this->dbh->query("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME <> 'dtproperties'");
|
||||
|
||||
// First load the tables (important that this happen before filling out details of tables)
|
||||
$tables = array();
|
||||
while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
|
||||
$name = $row[0];
|
||||
$table = new Table($name);
|
||||
$database->addTable($table);
|
||||
$tables[] = $table;
|
||||
}
|
||||
|
||||
// Now populate only columns.
|
||||
foreach ($tables as $table) {
|
||||
$this->addColumns($table);
|
||||
}
|
||||
|
||||
// Now add indexes and constraints.
|
||||
foreach ($tables as $table) {
|
||||
$this->addForeignKeys($table);
|
||||
$this->addIndexes($table);
|
||||
$this->addPrimaryKey($table);
|
||||
}
|
||||
|
||||
return count($tables);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds Columns to the specified table.
|
||||
*
|
||||
* @param Table $table The Table model class to add columns to.
|
||||
*/
|
||||
protected function addColumns(Table $table)
|
||||
{
|
||||
$stmt = $this->dbh->query("sp_columns '" . $table->getName() . "'");
|
||||
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
$name = $row['COLUMN_NAME'];
|
||||
$type = $row['TYPE_NAME'];
|
||||
$size = $row['LENGTH'];
|
||||
$is_nullable = $row['NULLABLE'];
|
||||
$default = $row['COLUMN_DEF'];
|
||||
$precision = $row['PRECISION'];
|
||||
$scale = $row['SCALE'];
|
||||
$autoincrement = false;
|
||||
if (strtolower($type) == "int identity") {
|
||||
$autoincrement = true;
|
||||
}
|
||||
|
||||
$propelType = $this->getMappedPropelType($type);
|
||||
if (!$propelType) {
|
||||
$propelType = Column::DEFAULT_TYPE;
|
||||
$this->warn("Column [" . $table->getName() . "." . $name. "] has a column type (".$type.") that Propel does not support.");
|
||||
}
|
||||
|
||||
$column = new Column($name);
|
||||
$column->setTable($table);
|
||||
$column->setDomainForType($propelType);
|
||||
// We may want to provide an option to include this:
|
||||
// $column->getDomain()->replaceSqlType($type);
|
||||
$column->getDomain()->replaceSize($size);
|
||||
$column->getDomain()->replaceScale($scale);
|
||||
if ($default !== null) {
|
||||
$column->getDomain()->setDefaultValue(new ColumnDefaultValue($default, ColumnDefaultValue::TYPE_VALUE));
|
||||
}
|
||||
$column->setAutoIncrement($autoincrement);
|
||||
$column->setNotNull(!$is_nullable);
|
||||
|
||||
$table->addColumn($column);
|
||||
}
|
||||
|
||||
|
||||
} // addColumn()
|
||||
|
||||
/**
|
||||
* Load foreign keys for this table.
|
||||
*/
|
||||
protected function addForeignKeys(Table $table)
|
||||
{
|
||||
$database = $table->getDatabase();
|
||||
|
||||
$stmt = $this->dbh->query("SELECT ccu1.TABLE_NAME, ccu1.COLUMN_NAME, ccu2.TABLE_NAME AS FK_TABLE_NAME, ccu2.COLUMN_NAME AS FK_COLUMN_NAME
|
||||
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu1 INNER JOIN
|
||||
INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc1 ON tc1.CONSTRAINT_NAME = ccu1.CONSTRAINT_NAME AND
|
||||
CONSTRAINT_TYPE = 'Foreign Key' INNER JOIN
|
||||
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc1 ON rc1.CONSTRAINT_NAME = tc1.CONSTRAINT_NAME INNER JOIN
|
||||
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu2 ON ccu2.CONSTRAINT_NAME = rc1.UNIQUE_CONSTRAINT_NAME
|
||||
WHERE (ccu1.table_name = '".$table->getName()."')");
|
||||
|
||||
$row = $stmt->fetch(PDO::FETCH_NUM);
|
||||
|
||||
$foreignKeys = array(); // local store to avoid duplicates
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
$lcol = $row['COLUMN_NAME'];
|
||||
$ftbl = $row['FK_TABLE_NAME'];
|
||||
$fcol = $row['FK_COLUMN_NAME'];
|
||||
|
||||
|
||||
$foreignTable = $database->getTable($ftbl);
|
||||
$foreignColumn = $foreignTable->getColumn($fcol);
|
||||
$localColumn = $table->getColumn($lcol);
|
||||
|
||||
if (!isset($foreignKeys[$name])) {
|
||||
$fk = new ForeignKey($name);
|
||||
$fk->setForeignTableName($foreignTable->getName());
|
||||
//$fk->setOnDelete($fkactions['ON DELETE']);
|
||||
//$fk->setOnUpdate($fkactions['ON UPDATE']);
|
||||
$table->addForeignKey($fk);
|
||||
$foreignKeys[$name] = $fk;
|
||||
}
|
||||
$foreignKeys[$name]->addReference($localColumn, $foreignColumn);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Load indexes for this table
|
||||
*/
|
||||
protected function addIndexes(Table $table)
|
||||
{
|
||||
$stmt = $this->dbh->query("sp_indexes_rowset " . $table->getName());
|
||||
|
||||
$indexes = array();
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$colName = $row["COLUMN_NAME"];
|
||||
$name = $row['INDEX_NAME'];
|
||||
|
||||
// FIXME -- Add UNIQUE support
|
||||
if (!isset($indexes[$name])) {
|
||||
$indexes[$name] = new Index($name);
|
||||
$table->addIndex($indexes[$name]);
|
||||
}
|
||||
|
||||
$indexes[$name]->addColumn($table->getColumn($colName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the primary key for this table.
|
||||
*/
|
||||
protected function addPrimaryKey(Table $table)
|
||||
{
|
||||
$stmt = $this->dbh->query("SELECT COLUMN_NAME
|
||||
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
|
||||
INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ON
|
||||
INFORMATION_SCHEMA.TABLE_CONSTRAINTS.CONSTRAINT_NAME = INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE.constraint_name
|
||||
WHERE (INFORMATION_SCHEMA.TABLE_CONSTRAINTS.CONSTRAINT_TYPE = 'PRIMARY KEY') AND
|
||||
(INFORMATION_SCHEMA.TABLE_CONSTRAINTS.TABLE_NAME = '".$table->getName()."')");
|
||||
|
||||
// Loop through the returned results, grouping the same key_name together
|
||||
// adding each column for that key.
|
||||
while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
|
||||
$name = $row[0];
|
||||
$table->getColumn($name)->setPrimaryKey(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,340 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Propel package.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
require_once 'reverse/BaseSchemaParser.php';
|
||||
|
||||
/**
|
||||
* Mysql database schema parser.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1612 $
|
||||
* @package propel.generator.reverse.mysql
|
||||
*/
|
||||
class MysqlSchemaParser extends BaseSchemaParser
|
||||
{
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
private $addVendorInfo = false;
|
||||
|
||||
/**
|
||||
* Map MySQL native types to Propel types.
|
||||
* @var array
|
||||
*/
|
||||
private static $mysqlTypeMap = array(
|
||||
'tinyint' => PropelTypes::TINYINT,
|
||||
'smallint' => PropelTypes::SMALLINT,
|
||||
'mediumint' => PropelTypes::SMALLINT,
|
||||
'int' => PropelTypes::INTEGER,
|
||||
'integer' => PropelTypes::INTEGER,
|
||||
'bigint' => PropelTypes::BIGINT,
|
||||
'int24' => PropelTypes::BIGINT,
|
||||
'real' => PropelTypes::REAL,
|
||||
'float' => PropelTypes::FLOAT,
|
||||
'decimal' => PropelTypes::DECIMAL,
|
||||
'numeric' => PropelTypes::NUMERIC,
|
||||
'double' => PropelTypes::DOUBLE,
|
||||
'char' => PropelTypes::CHAR,
|
||||
'varchar' => PropelTypes::VARCHAR,
|
||||
'date' => PropelTypes::DATE,
|
||||
'time' => PropelTypes::TIME,
|
||||
'year' => PropelTypes::INTEGER,
|
||||
'datetime' => PropelTypes::TIMESTAMP,
|
||||
'timestamp' => PropelTypes::TIMESTAMP,
|
||||
'tinyblob' => PropelTypes::BINARY,
|
||||
'blob' => PropelTypes::BLOB,
|
||||
'mediumblob' => PropelTypes::BLOB,
|
||||
'longblob' => PropelTypes::BLOB,
|
||||
'longtext' => PropelTypes::CLOB,
|
||||
'tinytext' => PropelTypes::VARCHAR,
|
||||
'mediumtext' => PropelTypes::LONGVARCHAR,
|
||||
'text' => PropelTypes::LONGVARCHAR,
|
||||
'enum' => PropelTypes::CHAR,
|
||||
'set' => PropelTypes::CHAR,
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets a type mapping from native types to Propel types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTypeMapping()
|
||||
{
|
||||
return self::$mysqlTypeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function parse(Database $database, PDOTask $task = null)
|
||||
{
|
||||
$this->addVendorInfo = $this->getGeneratorConfig()->getBuildProperty('addVendorInfo');
|
||||
|
||||
$stmt = $this->dbh->query("SHOW TABLES");
|
||||
|
||||
// First load the tables (important that this happen before filling out details of tables)
|
||||
$tables = array();
|
||||
$task->log("Reverse Engineering Tables");
|
||||
while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
|
||||
$name = $row[0];
|
||||
$task->log(" Adding table '" . $name . "'");
|
||||
$table = new Table($name);
|
||||
$database->addTable($table);
|
||||
$tables[] = $table;
|
||||
}
|
||||
|
||||
// Now populate only columns.
|
||||
$task->log("Reverse Engineering Columns");
|
||||
foreach ($tables as $table) {
|
||||
$task->log(" Adding columns for table '" . $table->getName() . "'");
|
||||
$this->addColumns($table);
|
||||
}
|
||||
|
||||
// Now add indices and constraints.
|
||||
$task->log("Reverse Engineering Indices And Constraints");
|
||||
foreach ($tables as $table) {
|
||||
$task->log(" Adding indices and constraints for table '" . $table->getName() . "'");
|
||||
$this->addForeignKeys($table);
|
||||
$this->addIndexes($table);
|
||||
$this->addPrimaryKey($table);
|
||||
if ($this->addVendorInfo) {
|
||||
$this->addTableVendorInfo($table);
|
||||
}
|
||||
}
|
||||
|
||||
return count($tables);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds Columns to the specified table.
|
||||
*
|
||||
* @param Table $table The Table model class to add columns to.
|
||||
*/
|
||||
protected function addColumns(Table $table)
|
||||
{
|
||||
$stmt = $this->dbh->query("SHOW COLUMNS FROM `" . $table->getName() . "`");
|
||||
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
$name = $row['Field'];
|
||||
$is_nullable = ($row['Null'] == 'YES');
|
||||
$autoincrement = (strpos($row['Extra'], 'auto_increment') !== false);
|
||||
$size = null;
|
||||
$precision = null;
|
||||
$scale = null;
|
||||
|
||||
if (preg_match('/^(\w+)[\(]?([\d,]*)[\)]?( |$)/', $row['Type'], $matches)) {
|
||||
// colname[1] size/precision[2]
|
||||
$nativeType = $matches[1];
|
||||
if ($matches[2]) {
|
||||
if ( ($cpos = strpos($matches[2], ',')) !== false) {
|
||||
$size = (int) substr($matches[2], 0, $cpos);
|
||||
$precision = $size;
|
||||
$scale = (int) substr($matches[2], $cpos + 1);
|
||||
} else {
|
||||
$size = (int) $matches[2];
|
||||
}
|
||||
}
|
||||
} elseif (preg_match('/^(\w+)\(/', $row['Type'], $matches)) {
|
||||
$nativeType = $matches[1];
|
||||
} else {
|
||||
$nativeType = $row['Type'];
|
||||
}
|
||||
|
||||
//BLOBs can't have any default values in MySQL
|
||||
$default = preg_match('~blob|text~', $nativeType) ? null : $row['Default'];
|
||||
|
||||
$propelType = $this->getMappedPropelType($nativeType);
|
||||
if (!$propelType) {
|
||||
$propelType = Column::DEFAULT_TYPE;
|
||||
$this->warn("Column [" . $table->getName() . "." . $name. "] has a column type (".$nativeType.") that Propel does not support.");
|
||||
}
|
||||
|
||||
$column = new Column($name);
|
||||
$column->setTable($table);
|
||||
$column->setDomainForType($propelType);
|
||||
// We may want to provide an option to include this:
|
||||
// $column->getDomain()->replaceSqlType($type);
|
||||
$column->getDomain()->replaceSize($size);
|
||||
$column->getDomain()->replaceScale($scale);
|
||||
if ($default !== null) {
|
||||
if (in_array($default, array('CURRENT_TIMESTAMP'))) {
|
||||
$type = ColumnDefaultValue::TYPE_EXPR;
|
||||
} else {
|
||||
$type = ColumnDefaultValue::TYPE_VALUE;
|
||||
}
|
||||
$column->getDomain()->setDefaultValue(new ColumnDefaultValue($default, $type));
|
||||
}
|
||||
$column->setAutoIncrement($autoincrement);
|
||||
$column->setNotNull(!$is_nullable);
|
||||
|
||||
if ($this->addVendorInfo) {
|
||||
$vi = $this->getNewVendorInfoObject($row);
|
||||
$column->addVendorInfo($vi);
|
||||
}
|
||||
|
||||
$table->addColumn($column);
|
||||
}
|
||||
|
||||
|
||||
} // addColumn()
|
||||
|
||||
/**
|
||||
* Load foreign keys for this table.
|
||||
*/
|
||||
protected function addForeignKeys(Table $table)
|
||||
{
|
||||
$database = $table->getDatabase();
|
||||
|
||||
$stmt = $this->dbh->query("SHOW CREATE TABLE `" . $table->getName(). "`");
|
||||
$row = $stmt->fetch(PDO::FETCH_NUM);
|
||||
|
||||
$foreignKeys = array(); // local store to avoid duplicates
|
||||
|
||||
// Get the information on all the foreign keys
|
||||
$regEx = '/CONSTRAINT `([^`]+)` FOREIGN KEY \((.+)\) REFERENCES `([^`]*)` \((.+)\)(.*)/';
|
||||
if (preg_match_all($regEx,$row[1],$matches)) {
|
||||
$tmpArray = array_keys($matches[0]);
|
||||
foreach ($tmpArray as $curKey) {
|
||||
$name = $matches[1][$curKey];
|
||||
$rawlcol = $matches[2][$curKey];
|
||||
$ftbl = $matches[3][$curKey];
|
||||
$rawfcol = $matches[4][$curKey];
|
||||
$fkey = $matches[5][$curKey];
|
||||
|
||||
$lcols = array();
|
||||
foreach(preg_split('/`, `/', $rawlcol) as $piece) {
|
||||
$lcols[] = trim($piece, '` ');
|
||||
}
|
||||
|
||||
$fcols = array();
|
||||
foreach(preg_split('/`, `/', $rawfcol) as $piece) {
|
||||
$fcols[] = trim($piece, '` ');
|
||||
}
|
||||
|
||||
//typical for mysql is RESTRICT
|
||||
$fkactions = array(
|
||||
'ON DELETE' => ForeignKey::RESTRICT,
|
||||
'ON UPDATE' => ForeignKey::RESTRICT,
|
||||
);
|
||||
|
||||
if ($fkey) {
|
||||
//split foreign key information -> search for ON DELETE and afterwords for ON UPDATE action
|
||||
foreach (array_keys($fkactions) as $fkaction) {
|
||||
$result = NULL;
|
||||
preg_match('/' . $fkaction . ' (' . ForeignKey::CASCADE . '|' . ForeignKey::SETNULL . ')/', $fkey, $result);
|
||||
if ($result && is_array($result) && isset($result[1])) {
|
||||
$fkactions[$fkaction] = $result[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$localColumns = array();
|
||||
$foreignColumns = array();
|
||||
|
||||
$foreignTable = $database->getTable($ftbl);
|
||||
|
||||
foreach($fcols as $fcol) {
|
||||
$foreignColumns[] = $foreignTable->getColumn($fcol);
|
||||
}
|
||||
foreach($lcols as $lcol) {
|
||||
$localColumns[] = $table->getColumn($lcol);
|
||||
}
|
||||
|
||||
if (!isset($foreignKeys[$name])) {
|
||||
$fk = new ForeignKey($name);
|
||||
$fk->setForeignTableName($foreignTable->getName());
|
||||
$fk->setOnDelete($fkactions['ON DELETE']);
|
||||
$fk->setOnUpdate($fkactions['ON UPDATE']);
|
||||
$table->addForeignKey($fk);
|
||||
$foreignKeys[$name] = $fk;
|
||||
}
|
||||
|
||||
for($i=0; $i < count($localColumns); $i++) {
|
||||
$foreignKeys[$name]->addReference($localColumns[$i], $foreignColumns[$i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Load indexes for this table
|
||||
*/
|
||||
protected function addIndexes(Table $table)
|
||||
{
|
||||
$stmt = $this->dbh->query("SHOW INDEX FROM `" . $table->getName() . "`");
|
||||
|
||||
// Loop through the returned results, grouping the same key_name together
|
||||
// adding each column for that key.
|
||||
|
||||
$indexes = array();
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$colName = $row["Column_name"];
|
||||
$name = $row["Key_name"];
|
||||
|
||||
if ($name == "PRIMARY") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($indexes[$name])) {
|
||||
$isUnique = ($row["Non_unique"] == 0);
|
||||
if ($isUnique) {
|
||||
$indexes[$name] = new Unique($name);
|
||||
} else {
|
||||
$indexes[$name] = new Index($name);
|
||||
}
|
||||
if ($this->addVendorInfo) {
|
||||
$vi = $this->getNewVendorInfoObject($row);
|
||||
$indexes[$name]->addVendorInfo($vi);
|
||||
}
|
||||
$table->addIndex($indexes[$name]);
|
||||
}
|
||||
|
||||
$indexes[$name]->addColumn($table->getColumn($colName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the primary key for this table.
|
||||
*/
|
||||
protected function addPrimaryKey(Table $table)
|
||||
{
|
||||
$stmt = $this->dbh->query("SHOW KEYS FROM `" . $table->getName() . "`");
|
||||
|
||||
// Loop through the returned results, grouping the same key_name together
|
||||
// adding each column for that key.
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
// Skip any non-primary keys.
|
||||
if ($row['Key_name'] !== 'PRIMARY') {
|
||||
continue;
|
||||
}
|
||||
$name = $row["Column_name"];
|
||||
$table->getColumn($name)->setPrimaryKey(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds vendor-specific info for table.
|
||||
*
|
||||
* @param Table $table
|
||||
*/
|
||||
protected function addTableVendorInfo(Table $table)
|
||||
{
|
||||
$stmt = $this->dbh->query("SHOW TABLE STATUS LIKE '" . $table->getName() . "'");
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$vi = $this->getNewVendorInfoObject($row);
|
||||
$table->addVendorInfo($vi);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Propel package.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
require_once 'reverse/BaseSchemaParser.php';
|
||||
|
||||
/**
|
||||
* Oracle database schema parser.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @author Guillermo Gutierrez <ggutierrez@dailycosas.net> (Adaptation)
|
||||
* @version $Revision: 1612 $
|
||||
* @package propel.generator.reverse.oracle
|
||||
*/
|
||||
class OracleSchemaParser extends BaseSchemaParser
|
||||
{
|
||||
|
||||
/**
|
||||
* Map Oracle native types to Propel types.
|
||||
*
|
||||
* There really aren't any Oracle native types, so we're just
|
||||
* using the MySQL ones here.
|
||||
*
|
||||
* Left as unsupported:
|
||||
* BFILE,
|
||||
* RAW,
|
||||
* ROWID
|
||||
*
|
||||
* Supported but non existant as a specific type in Oracle:
|
||||
* DECIMAL (NUMBER with scale),
|
||||
* DOUBLE (FLOAT with precision = 126)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $oracleTypeMap = array(
|
||||
'BLOB' => PropelTypes::BLOB,
|
||||
'CHAR' => PropelTypes::CHAR,
|
||||
'CLOB' => PropelTypes::CLOB,
|
||||
'DATE' => PropelTypes::DATE,
|
||||
'DECIMAL' => PropelTypes::DECIMAL,
|
||||
'DOUBLE' => PropelTypes::DOUBLE,
|
||||
'FLOAT' => PropelTypes::FLOAT,
|
||||
'LONG' => PropelTypes::LONGVARCHAR,
|
||||
'NCHAR' => PropelTypes::CHAR,
|
||||
'NCLOB' => PropelTypes::CLOB,
|
||||
'NUMBER' => PropelTypes::BIGINT,
|
||||
'NVARCHAR2' => PropelTypes::VARCHAR,
|
||||
'TIMESTAMP' => PropelTypes::TIMESTAMP,
|
||||
'VARCHAR2' => PropelTypes::VARCHAR,
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets a type mapping from native types to Propel types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTypeMapping()
|
||||
{
|
||||
return self::$oracleTypeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for tables in the database. Maybe we want to search also the views.
|
||||
* @param Database $database The Database model class to add tables to.
|
||||
*/
|
||||
public function parse(Database $database, PDOTask $task = null)
|
||||
{
|
||||
$tables = array();
|
||||
$stmt = $this->dbh->query("SELECT OBJECT_NAME FROM USER_OBJECTS WHERE OBJECT_TYPE = 'TABLE'");
|
||||
|
||||
$task->log("Reverse Engineering Table Structures");
|
||||
// First load the tables (important that this happen before filling out details of tables)
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
if (strpos($row['OBJECT_NAME'], '$') !== false) {
|
||||
// this is an Oracle internal table or materialized view - prune
|
||||
continue;
|
||||
}
|
||||
$table = new Table($row['OBJECT_NAME']);
|
||||
$task->log("Adding table '" . $table->getName() . "'");
|
||||
$database->addTable($table);
|
||||
// Add columns, primary keys and indexes.
|
||||
$this->addColumns($table);
|
||||
$this->addPrimaryKey($table);
|
||||
$this->addIndexes($table);
|
||||
$tables[] = $table;
|
||||
}
|
||||
|
||||
$task->log("Reverse Engineering Foreign Keys");
|
||||
|
||||
foreach ($tables as $table) {
|
||||
$task->log("Adding foreign keys for table '" . $table->getName() . "'");
|
||||
$this->addForeignKeys($table);
|
||||
}
|
||||
|
||||
return count($tables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds Columns to the specified table.
|
||||
*
|
||||
* @param Table $table The Table model class to add columns to.
|
||||
*/
|
||||
protected function addColumns(Table $table)
|
||||
{
|
||||
$stmt = $this->dbh->query("SELECT COLUMN_NAME, DATA_TYPE, NULLABLE, DATA_LENGTH, DATA_SCALE, DATA_DEFAULT FROM USER_TAB_COLS WHERE TABLE_NAME = '" . $table->getName() . "'");
|
||||
/* @var stmt PDOStatement */
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
if (strpos($row['COLUMN_NAME'], '$') !== false) {
|
||||
// this is an Oracle internal column - prune
|
||||
continue;
|
||||
}
|
||||
$size = $row["DATA_LENGTH"];
|
||||
$scale = $row["DATA_SCALE"];
|
||||
$default = $row['DATA_DEFAULT'];
|
||||
$type = $row["DATA_TYPE"];
|
||||
$isNullable = ($row['NULLABLE'] == 'Y');
|
||||
if ($type == "NUMBER" && $row["DATA_SCALE"] > 0) {
|
||||
$type = "DECIMAL";
|
||||
}
|
||||
if ($type == "FLOAT"&& $row["DATA_PRECISION"] == 126) {
|
||||
$type = "DOUBLE";
|
||||
}
|
||||
if (strpos($type, 'TIMESTAMP(') !== false) {
|
||||
$type = substr($type, 0, strpos($type, '('));
|
||||
$default = "0000-00-00 00:00:00";
|
||||
$size = null;
|
||||
$scale = null;
|
||||
}
|
||||
if ($type == "DATE") {
|
||||
$default = "0000-00-00";
|
||||
$size = null;
|
||||
$scale = null;
|
||||
}
|
||||
|
||||
$propelType = $this->getMappedPropelType($type);
|
||||
if (!$propelType) {
|
||||
$propelType = Column::DEFAULT_TYPE;
|
||||
$this->warn("Column [" . $table->getName() . "." . $row['COLUMN_NAME']. "] has a column type (".$row["DATA_TYPE"].") that Propel does not support.");
|
||||
}
|
||||
|
||||
$column = new Column($row['COLUMN_NAME']);
|
||||
$column->setPhpName(); // Prevent problems with strange col names
|
||||
$column->setTable($table);
|
||||
$column->setDomainForType($propelType);
|
||||
$column->getDomain()->replaceSize($size);
|
||||
$column->getDomain()->replaceScale($scale);
|
||||
if ($default !== null) {
|
||||
$column->getDomain()->setDefaultValue(new ColumnDefaultValue($default, ColumnDefaultValue::TYPE_VALUE));
|
||||
}
|
||||
$column->setAutoIncrement(false); // Not yet supported
|
||||
$column->setNotNull(!$isNullable);
|
||||
$table->addColumn($column);
|
||||
}
|
||||
|
||||
} // addColumn()
|
||||
|
||||
/**
|
||||
* Adds Indexes to the specified table.
|
||||
*
|
||||
* @param Table $table The Table model class to add columns to.
|
||||
*/
|
||||
protected function addIndexes(Table $table)
|
||||
{
|
||||
$stmt = $this->dbh->query("SELECT COLUMN_NAME, INDEX_NAME FROM USER_IND_COLUMNS WHERE TABLE_NAME = '" . $table->getName() . "' ORDER BY COLUMN_NAME");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$indices = array();
|
||||
foreach ($rows as $row) {
|
||||
$indices[$row['INDEX_NAME']][]= $row['COLUMN_NAME'];
|
||||
}
|
||||
|
||||
foreach ($indices as $indexName => $columnNames) {
|
||||
$index = new Index($indexName);
|
||||
foreach($columnNames AS $columnName) {
|
||||
// Oracle deals with complex indices using an internal reference, so...
|
||||
// let's ignore this kind of index
|
||||
if ($table->hasColumn($columnName)) {
|
||||
$index->addColumn($table->getColumn($columnName));
|
||||
}
|
||||
}
|
||||
// since some of the columns are pruned above, we must only add an index if it has columns
|
||||
if ($index->hasColumns()) {
|
||||
$table->addIndex($index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load foreign keys for this table.
|
||||
*
|
||||
* @param Table $table The Table model class to add FKs to
|
||||
*/
|
||||
protected function addForeignKeys(Table $table)
|
||||
{
|
||||
// local store to avoid duplicates
|
||||
$foreignKeys = array();
|
||||
|
||||
$stmt = $this->dbh->query("SELECT CONSTRAINT_NAME, DELETE_RULE, R_CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE CONSTRAINT_TYPE = 'R' AND TABLE_NAME = '" . $table->getName(). "'");
|
||||
/* @var stmt PDOStatement */
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
// Local reference
|
||||
$stmt2 = $this->dbh->query("SELECT COLUMN_NAME FROM USER_CONS_COLUMNS WHERE CONSTRAINT_NAME = '".$row['CONSTRAINT_NAME']."' AND TABLE_NAME = '" . $table->getName(). "'");
|
||||
/* @var stmt2 PDOStatement */
|
||||
$localReferenceInfo = $stmt2->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// Foreign reference
|
||||
$stmt2 = $this->dbh->query("SELECT TABLE_NAME, COLUMN_NAME FROM USER_CONS_COLUMNS WHERE CONSTRAINT_NAME = '".$row['R_CONSTRAINT_NAME']."'");
|
||||
$foreignReferenceInfo = $stmt2->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!isset($foreignKeys[$row["CONSTRAINT_NAME"]])) {
|
||||
$fk = new ForeignKey($row["CONSTRAINT_NAME"]);
|
||||
$fk->setForeignTableName($foreignReferenceInfo['TABLE_NAME']);
|
||||
$onDelete = ($row["DELETE_RULE"] == 'NO ACTION') ? 'NONE' : $row["DELETE_RULE"];
|
||||
$fk->setOnDelete($onDelete);
|
||||
$fk->setOnUpdate($onDelete);
|
||||
$fk->addReference(array("local" => $localReferenceInfo['COLUMN_NAME'], "foreign" => $foreignReferenceInfo['COLUMN_NAME']));
|
||||
$table->addForeignKey($fk);
|
||||
$foreignKeys[$row["CONSTRAINT_NAME"]] = $fk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the primary key for this table.
|
||||
*
|
||||
* @param Table $table The Table model class to add PK to.
|
||||
*/
|
||||
protected function addPrimaryKey(Table $table)
|
||||
{
|
||||
$stmt = $this->dbh->query("SELECT COLS.COLUMN_NAME FROM USER_CONSTRAINTS CONS, USER_CONS_COLUMNS COLS WHERE CONS.CONSTRAINT_NAME = COLS.CONSTRAINT_NAME AND CONS.TABLE_NAME = '".$table->getName()."' AND CONS.CONSTRAINT_TYPE = 'P'");
|
||||
/* @var stmt PDOStatement */
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
// This fixes a strange behavior by PDO. Sometimes the
|
||||
// row values are inside an index 0 of an array
|
||||
if (array_key_exists(0, $row)) {
|
||||
$row = $row[0];
|
||||
}
|
||||
$table->getColumn($row['COLUMN_NAME'])->setPrimaryKey(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,548 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Propel package.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
require_once 'reverse/BaseSchemaParser.php';
|
||||
|
||||
/**
|
||||
* Postgresql database schema parser.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1667 $
|
||||
* @package propel.generator.reverse.pgsql
|
||||
*/
|
||||
class PgsqlSchemaParser extends BaseSchemaParser
|
||||
{
|
||||
|
||||
/**
|
||||
* Map PostgreSQL native types to Propel types.
|
||||
* @var array
|
||||
*/
|
||||
/** Map MySQL native types to Propel (JDBC) types. */
|
||||
private static $pgsqlTypeMap = array(
|
||||
'bool' => PropelTypes::BOOLEAN,
|
||||
'boolean' => PropelTypes::BOOLEAN,
|
||||
'tinyint' => PropelTypes::TINYINT,
|
||||
'smallint' => PropelTypes::SMALLINT,
|
||||
'mediumint' => PropelTypes::SMALLINT,
|
||||
'int' => PropelTypes::INTEGER,
|
||||
'int4' => PropelTypes::INTEGER,
|
||||
'integer' => PropelTypes::INTEGER,
|
||||
'int8' => PropelTypes::BIGINT,
|
||||
'bigint' => PropelTypes::BIGINT,
|
||||
'int24' => PropelTypes::BIGINT,
|
||||
'real' => PropelTypes::REAL,
|
||||
'float' => PropelTypes::FLOAT,
|
||||
'decimal' => PropelTypes::DECIMAL,
|
||||
'numeric' => PropelTypes::NUMERIC,
|
||||
'double' => PropelTypes::DOUBLE,
|
||||
'char' => PropelTypes::CHAR,
|
||||
'varchar' => PropelTypes::VARCHAR,
|
||||
'date' => PropelTypes::DATE,
|
||||
'time' => PropelTypes::TIME,
|
||||
'timetz' => PropelTypes::TIME,
|
||||
//'year' => PropelTypes::YEAR, PropelTypes::YEAR does not exist... does this need to be mapped to a different propel type?
|
||||
'datetime' => PropelTypes::TIMESTAMP,
|
||||
'timestamp' => PropelTypes::TIMESTAMP,
|
||||
'timestamptz' => PropelTypes::TIMESTAMP,
|
||||
'bytea' => PropelTypes::BLOB,
|
||||
'text' => PropelTypes::LONGVARCHAR,
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets a type mapping from native types to Propel types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTypeMapping()
|
||||
{
|
||||
return self::$pgsqlTypeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function parse(Database $database, PDOTask $task = null)
|
||||
{
|
||||
$stmt = $this->dbh->query("SELECT version() as ver");
|
||||
$nativeVersion = $stmt->fetchColumn();
|
||||
|
||||
if (!$nativeVersion) {
|
||||
throw new EngineException("Failed to get database version");
|
||||
}
|
||||
|
||||
$arrVersion = sscanf ($nativeVersion, '%*s %d.%d');
|
||||
$version = sprintf ("%d.%d", $arrVersion[0], $arrVersion[1]);
|
||||
|
||||
// Clean up
|
||||
$stmt = null;
|
||||
|
||||
$stmt = $this->dbh->query("SELECT c.oid,
|
||||
case when n.nspname='public' then c.relname else n.nspname||'.'||c.relname end as relname
|
||||
FROM pg_class c join pg_namespace n on (c.relnamespace=n.oid)
|
||||
WHERE c.relkind = 'r'
|
||||
AND n.nspname NOT IN ('information_schema','pg_catalog')
|
||||
AND n.nspname NOT LIKE 'pg_temp%'
|
||||
AND n.nspname NOT LIKE 'pg_toast%'
|
||||
ORDER BY relname");
|
||||
|
||||
$tableWraps = array();
|
||||
|
||||
// First load the tables (important that this happen before filling out details of tables)
|
||||
$task->log("Reverse Engineering Tables");
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$name = $row['relname'];
|
||||
$task->log(" Adding table '" . $name . "'");
|
||||
$oid = $row['oid'];
|
||||
$table = new Table($name);
|
||||
$database->addTable($table);
|
||||
|
||||
// Create a wrapper to hold these tables and their associated OID
|
||||
$wrap = new stdClass;
|
||||
$wrap->table = $table;
|
||||
$wrap->oid = $oid;
|
||||
$tableWraps[] = $wrap;
|
||||
}
|
||||
|
||||
// Now populate only columns.
|
||||
$task->log("Reverse Engineering Columns");
|
||||
foreach ($tableWraps as $wrap) {
|
||||
$task->log(" Adding columns for table '" . $wrap->table->getName() . "'");
|
||||
$this->addColumns($wrap->table, $wrap->oid, $version);
|
||||
}
|
||||
|
||||
// Now add indexes and constraints.
|
||||
$task->log("Reverse Engineering Indices And Constraints");
|
||||
foreach ($tableWraps as $wrap) {
|
||||
$task->log(" Adding indices and constraints for table '" . $wrap->table->getName() . "'");
|
||||
$this->addForeignKeys($wrap->table, $wrap->oid, $version);
|
||||
$this->addIndexes($wrap->table, $wrap->oid, $version);
|
||||
$this->addPrimaryKey($wrap->table, $wrap->oid, $version);
|
||||
}
|
||||
|
||||
// TODO - Handle Sequences ...
|
||||
|
||||
return count($tableWraps);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds Columns to the specified table.
|
||||
*
|
||||
* @param Table $table The Table model class to add columns to.
|
||||
* @param int $oid The table OID
|
||||
* @param string $version The database version.
|
||||
*/
|
||||
protected function addColumns(Table $table, $oid, $version)
|
||||
{
|
||||
|
||||
// Get the columns, types, etc.
|
||||
// Based on code from pgAdmin3 (http://www.pgadmin.org/)
|
||||
$stmt = $this->dbh->prepare("SELECT
|
||||
att.attname,
|
||||
att.atttypmod,
|
||||
att.atthasdef,
|
||||
att.attnotnull,
|
||||
def.adsrc,
|
||||
CASE WHEN att.attndims > 0 THEN 1 ELSE 0 END AS isarray,
|
||||
CASE
|
||||
WHEN ty.typname = 'bpchar'
|
||||
THEN 'char'
|
||||
WHEN ty.typname = '_bpchar'
|
||||
THEN '_char'
|
||||
ELSE
|
||||
ty.typname
|
||||
END AS typname,
|
||||
ty.typtype
|
||||
FROM pg_attribute att
|
||||
JOIN pg_type ty ON ty.oid=att.atttypid
|
||||
LEFT OUTER JOIN pg_attrdef def ON adrelid=att.attrelid AND adnum=att.attnum
|
||||
WHERE att.attrelid = ? AND att.attnum > 0
|
||||
AND att.attisdropped IS FALSE
|
||||
ORDER BY att.attnum");
|
||||
|
||||
$stmt->bindValue(1, $oid, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
$size = null;
|
||||
$precision = null;
|
||||
$scale = null;
|
||||
|
||||
// Check to ensure that this column isn't an array data type
|
||||
if (((int) $row['isarray']) === 1) {
|
||||
throw new EngineException (sprintf ("Array datatypes are not currently supported [%s.%s]", $this->name, $row['attname']));
|
||||
} // if (((int) $row['isarray']) === 1)
|
||||
|
||||
$name = $row['attname'];
|
||||
|
||||
// If they type is a domain, Process it
|
||||
if (strtolower ($row['typtype']) == 'd') {
|
||||
$arrDomain = $this->processDomain ($row['typname']);
|
||||
$type = $arrDomain['type'];
|
||||
$size = $arrDomain['length'];
|
||||
$precision = $size;
|
||||
$scale = $arrDomain['scale'];
|
||||
$boolHasDefault = (strlen (trim ($row['atthasdef'])) > 0) ? $row['atthasdef'] : $arrDomain['hasdefault'];
|
||||
$default = (strlen (trim ($row['adsrc'])) > 0) ? $row['adsrc'] : $arrDomain['default'];
|
||||
$is_nullable = (strlen (trim ($row['attnotnull'])) > 0) ? $row['attnotnull'] : $arrDomain['notnull'];
|
||||
$is_nullable = (($is_nullable == 't') ? false : true);
|
||||
} else {
|
||||
$type = $row['typname'];
|
||||
$arrLengthPrecision = $this->processLengthScale ($row['atttypmod'], $type);
|
||||
$size = $arrLengthPrecision['length'];
|
||||
$precision = $size;
|
||||
$scale = $arrLengthPrecision['scale'];
|
||||
$boolHasDefault = $row['atthasdef'];
|
||||
$default = $row['adsrc'];
|
||||
$is_nullable = (($row['attnotnull'] == 't') ? false : true);
|
||||
} // else (strtolower ($row['typtype']) == 'd')
|
||||
|
||||
$autoincrement = null;
|
||||
|
||||
// if column has a default
|
||||
if (($boolHasDefault == 't') && (strlen (trim ($default)) > 0)) {
|
||||
if (!preg_match('/^nextval\(/', $default)) {
|
||||
$strDefault= preg_replace ('/::[\W\D]*/', '', $default);
|
||||
$default = str_replace ("'", '', $strDefault);
|
||||
} else {
|
||||
$autoincrement = true;
|
||||
$default = null;
|
||||
}
|
||||
} else {
|
||||
$default = null;
|
||||
}
|
||||
|
||||
$propelType = $this->getMappedPropelType($type);
|
||||
if (!$propelType) {
|
||||
$propelType = Column::DEFAULT_TYPE;
|
||||
$this->warn("Column [" . $table->getName() . "." . $name. "] has a column type (".$type.") that Propel does not support.");
|
||||
}
|
||||
|
||||
$column = new Column($name);
|
||||
$column->setTable($table);
|
||||
$column->setDomainForType($propelType);
|
||||
// We may want to provide an option to include this:
|
||||
// $column->getDomain()->replaceSqlType($type);
|
||||
$column->getDomain()->replaceSize($size);
|
||||
$column->getDomain()->replaceScale($scale);
|
||||
if ($default !== null) {
|
||||
if (in_array($default, array('now()'))) {
|
||||
$type = ColumnDefaultValue::TYPE_EXPR;
|
||||
} else {
|
||||
$type = ColumnDefaultValue::TYPE_VALUE;
|
||||
}
|
||||
$column->getDomain()->setDefaultValue(new ColumnDefaultValue($default, $type));
|
||||
}
|
||||
$column->setAutoIncrement($autoincrement);
|
||||
$column->setNotNull(!$is_nullable);
|
||||
|
||||
$table->addColumn($column);
|
||||
}
|
||||
|
||||
|
||||
} // addColumn()
|
||||
|
||||
private function processLengthScale($intTypmod, $strName)
|
||||
{
|
||||
// Define the return array
|
||||
$arrRetVal = array ('length'=>null, 'scale'=>null);
|
||||
|
||||
// Some datatypes don't have a Typmod
|
||||
if ($intTypmod == -1)
|
||||
{
|
||||
return $arrRetVal;
|
||||
} // if ($intTypmod == -1)
|
||||
|
||||
// Numeric Datatype?
|
||||
if ($strName == $this->getMappedNativeType(PropelTypes::NUMERIC)) {
|
||||
$intLen = ($intTypmod - 4) >> 16;
|
||||
$intPrec = ($intTypmod - 4) & 0xffff;
|
||||
$intLen = sprintf ("%ld", $intLen);
|
||||
if ($intPrec)
|
||||
{
|
||||
$intPrec = sprintf ("%ld", $intPrec);
|
||||
} // if ($intPrec)
|
||||
$arrRetVal['length'] = $intLen;
|
||||
$arrRetVal['scale'] = $intPrec;
|
||||
} // if ($strName == $this->getMappedNativeType(PropelTypes::NUMERIC))
|
||||
elseif ($strName == $this->getMappedNativeType(PropelTypes::TIME) || $strName == 'timetz'
|
||||
|| $strName == $this->getMappedNativeType(PropelTypes::TIMESTAMP) || $strName == 'timestamptz'
|
||||
|| $strName == 'interval' || $strName == 'bit')
|
||||
{
|
||||
$arrRetVal['length'] = sprintf ("%ld", $intTypmod);
|
||||
} // elseif (TIME, TIMESTAMP, INTERVAL, BIT)
|
||||
else
|
||||
{
|
||||
$arrRetVal['length'] = sprintf ("%ld", ($intTypmod - 4));
|
||||
} // else
|
||||
return $arrRetVal;
|
||||
} // private function processLengthScale ($intTypmod, $strName)
|
||||
|
||||
private function processDomain($strDomain)
|
||||
{
|
||||
if (strlen(trim ($strDomain)) < 1) {
|
||||
throw new EngineException ("Invalid domain name [" . $strDomain . "]");
|
||||
}
|
||||
|
||||
$stmt = $this->dbh->prepare("SELECT
|
||||
d.typname as domname,
|
||||
b.typname as basetype,
|
||||
d.typlen,
|
||||
d.typtypmod,
|
||||
d.typnotnull,
|
||||
d.typdefault
|
||||
FROM pg_type d
|
||||
INNER JOIN pg_type b ON b.oid = CASE WHEN d.typndims > 0 then d.typelem ELSE d.typbasetype END
|
||||
WHERE
|
||||
d.typtype = 'd'
|
||||
AND d.typname = ?
|
||||
ORDER BY d.typname");
|
||||
$stmt->bindValue(1, $strDomain);
|
||||
$stmt->execute();
|
||||
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!$row) {
|
||||
throw new EngineException ("Domain [" . $strDomain . "] not found.");
|
||||
}
|
||||
|
||||
$arrDomain = array ();
|
||||
$arrDomain['type'] = $row['basetype'];
|
||||
$arrLengthPrecision = $this->processLengthScale($row['typtypmod'], $row['basetype']);
|
||||
$arrDomain['length'] = $arrLengthPrecision['length'];
|
||||
$arrDomain['scale'] = $arrLengthPrecision['scale'];
|
||||
$arrDomain['notnull'] = $row['typnotnull'];
|
||||
$arrDomain['default'] = $row['typdefault'];
|
||||
$arrDomain['hasdefault'] = (strlen (trim ($row['typdefault'])) > 0) ? 't' : 'f';
|
||||
|
||||
$stmt = null; // cleanup
|
||||
return $arrDomain;
|
||||
} // private function processDomain($strDomain)
|
||||
|
||||
/**
|
||||
* Load foreign keys for this table.
|
||||
*/
|
||||
protected function addForeignKeys(Table $table, $oid, $version)
|
||||
{
|
||||
$database = $table->getDatabase();
|
||||
$stmt = $this->dbh->prepare("SELECT
|
||||
conname,
|
||||
confupdtype,
|
||||
confdeltype,
|
||||
CASE nl.nspname WHEN 'public' THEN cl.relname ELSE nl.nspname||'.'||cl.relname END as fktab,
|
||||
a2.attname as fkcol,
|
||||
CASE nr.nspname WHEN 'public' THEN cr.relname ELSE nr.nspname||'.'||cr.relname END as reftab,
|
||||
a1.attname as refcol
|
||||
FROM pg_constraint ct
|
||||
JOIN pg_class cl ON cl.oid=conrelid
|
||||
JOIN pg_class cr ON cr.oid=confrelid
|
||||
JOIN pg_namespace nl ON nl.oid = cl.relnamespace
|
||||
JOIN pg_namespace nr ON nr.oid = cr.relnamespace
|
||||
LEFT JOIN pg_catalog.pg_attribute a1 ON a1.attrelid = ct.confrelid
|
||||
LEFT JOIN pg_catalog.pg_attribute a2 ON a2.attrelid = ct.conrelid
|
||||
WHERE
|
||||
contype='f'
|
||||
AND conrelid = ?
|
||||
AND a2.attnum = ct.conkey[1]
|
||||
AND a1.attnum = ct.confkey[1]
|
||||
ORDER BY conname");
|
||||
$stmt->bindValue(1, $oid);
|
||||
$stmt->execute();
|
||||
|
||||
$foreignKeys = array(); // local store to avoid duplicates
|
||||
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
$name = $row['conname'];
|
||||
$local_table = $row['fktab'];
|
||||
$local_column = $row['fkcol'];
|
||||
$foreign_table = $row['reftab'];
|
||||
$foreign_column = $row['refcol'];
|
||||
|
||||
// On Update
|
||||
switch ($row['confupdtype']) {
|
||||
case 'c':
|
||||
$onupdate = ForeignKey::CASCADE; break;
|
||||
case 'd':
|
||||
$onupdate = ForeignKey::SETDEFAULT; break;
|
||||
case 'n':
|
||||
$onupdate = ForeignKey::SETNULL; break;
|
||||
case 'r':
|
||||
$onupdate = ForeignKey::RESTRICT; break;
|
||||
default:
|
||||
case 'a':
|
||||
//NOACTION is the postgresql default
|
||||
$onupdate = ForeignKey::NONE; break;
|
||||
}
|
||||
// On Delete
|
||||
switch ($row['confdeltype']) {
|
||||
case 'c':
|
||||
$ondelete = ForeignKey::CASCADE; break;
|
||||
case 'd':
|
||||
$ondelete = ForeignKey::SETDEFAULT; break;
|
||||
case 'n':
|
||||
$ondelete = ForeignKey::SETNULL; break;
|
||||
case 'r':
|
||||
$ondelete = ForeignKey::RESTRICT; break;
|
||||
default:
|
||||
case 'a':
|
||||
//NOACTION is the postgresql default
|
||||
$ondelete = ForeignKey::NONE; break;
|
||||
}
|
||||
|
||||
$foreignTable = $database->getTable($foreign_table);
|
||||
$foreignColumn = $foreignTable->getColumn($foreign_column);
|
||||
|
||||
$localTable = $database->getTable($local_table);
|
||||
$localColumn = $localTable->getColumn($local_column);
|
||||
|
||||
if (!isset($foreignKeys[$name])) {
|
||||
$fk = new ForeignKey($name);
|
||||
$fk->setForeignTableName($foreignTable->getName());
|
||||
$fk->setOnDelete($ondelete);
|
||||
$fk->setOnUpdate($onupdate);
|
||||
$table->addForeignKey($fk);
|
||||
$foreignKeys[$name] = $fk;
|
||||
}
|
||||
|
||||
$foreignKeys[$name]->addReference($localColumn, $foreignColumn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load indexes for this table
|
||||
*/
|
||||
protected function addIndexes(Table $table, $oid, $version)
|
||||
{
|
||||
$stmt = $this->dbh->prepare("SELECT
|
||||
DISTINCT ON(cls.relname)
|
||||
cls.relname as idxname,
|
||||
indkey,
|
||||
indisunique
|
||||
FROM pg_index idx
|
||||
JOIN pg_class cls ON cls.oid=indexrelid
|
||||
WHERE indrelid = ? AND NOT indisprimary
|
||||
ORDER BY cls.relname");
|
||||
|
||||
$stmt->bindValue(1, $oid);
|
||||
$stmt->execute();
|
||||
|
||||
$stmt2 = $this->dbh->prepare("SELECT a.attname
|
||||
FROM pg_catalog.pg_class c JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
|
||||
WHERE c.oid = ? AND a.attnum = ? AND NOT a.attisdropped
|
||||
ORDER BY a.attnum");
|
||||
|
||||
$indexes = array();
|
||||
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$name = $row["idxname"];
|
||||
$unique = ($row["indisunique"] == 't') ? true : false;
|
||||
if (!isset($indexes[$name])) {
|
||||
if ($unique) {
|
||||
$indexes[$name] = new Unique($name);
|
||||
} else {
|
||||
$indexes[$name] = new Index($name);
|
||||
}
|
||||
$table->addIndex($indexes[$name]);
|
||||
}
|
||||
|
||||
$arrColumns = explode (' ', $row['indkey']);
|
||||
foreach ($arrColumns as $intColNum)
|
||||
{
|
||||
$stmt2->bindValue(1, $oid);
|
||||
$stmt2->bindValue(2, $intColNum);
|
||||
$stmt2->execute();
|
||||
|
||||
$row2 = $stmt2->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
$indexes[$name]->addColumn($table->getColumn($row2['attname']));
|
||||
|
||||
} // foreach ($arrColumns as $intColNum)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the primary key for this table.
|
||||
*/
|
||||
protected function addPrimaryKey(Table $table, $oid, $version)
|
||||
{
|
||||
|
||||
$stmt = $this->dbh->prepare("SELECT
|
||||
DISTINCT ON(cls.relname)
|
||||
cls.relname as idxname,
|
||||
indkey,
|
||||
indisunique
|
||||
FROM pg_index idx
|
||||
JOIN pg_class cls ON cls.oid=indexrelid
|
||||
WHERE indrelid = ? AND indisprimary
|
||||
ORDER BY cls.relname");
|
||||
$stmt->bindValue(1, $oid);
|
||||
$stmt->execute();
|
||||
|
||||
// Loop through the returned results, grouping the same key_name together
|
||||
// adding each column for that key.
|
||||
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$arrColumns = explode (' ', $row['indkey']);
|
||||
foreach ($arrColumns as $intColNum) {
|
||||
$stmt2 = $this->dbh->prepare("SELECT a.attname
|
||||
FROM pg_catalog.pg_class c JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
|
||||
WHERE c.oid = ? AND a.attnum = ? AND NOT a.attisdropped
|
||||
ORDER BY a.attnum");
|
||||
$stmt2->bindValue(1, $oid);
|
||||
$stmt2->bindValue(2, $intColNum);
|
||||
$stmt2->execute();
|
||||
|
||||
$row2 = $stmt2->fetch(PDO::FETCH_ASSOC);
|
||||
$table->getColumn($row2['attname'])->setPrimaryKey(true);
|
||||
|
||||
} // foreach ($arrColumns as $intColNum)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the sequences for this database.
|
||||
*
|
||||
* @return void
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected function addSequences(Database $database)
|
||||
{
|
||||
/*
|
||||
-- WE DON'T HAVE ANY USE FOR THESE YET IN REVERSE ENGINEERING ...
|
||||
$this->sequences = array();
|
||||
$result = pg_query($this->conn->getResource(), "SELECT c.oid,
|
||||
case when n.nspname='public' then c.relname else n.nspname||'.'||c.relname end as relname
|
||||
FROM pg_class c join pg_namespace n on (c.relnamespace=n.oid)
|
||||
WHERE c.relkind = 'S'
|
||||
AND n.nspname NOT IN ('information_schema','pg_catalog')
|
||||
AND n.nspname NOT LIKE 'pg_temp%'
|
||||
AND n.nspname NOT LIKE 'pg_toast%'
|
||||
ORDER BY relname");
|
||||
|
||||
if (!$result) {
|
||||
throw new SQLException("Could not list sequences", pg_last_error($this->dblink));
|
||||
}
|
||||
|
||||
while ($row = pg_fetch_assoc($result)) {
|
||||
// FIXME -- decide what info we need for sequences & then create a SequenceInfo object (if needed)
|
||||
$obj = new stdClass;
|
||||
$obj->name = $row['relname'];
|
||||
$obj->oid = $row['oid'];
|
||||
$this->sequences[strtoupper($row['relname'])] = $obj;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Propel package.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
require_once 'reverse/BaseSchemaParser.php';
|
||||
|
||||
/**
|
||||
* SQLite database schema parser.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1612 $
|
||||
* @package propel.generator.reverse.sqlite
|
||||
*/
|
||||
class SqliteSchemaParser extends BaseSchemaParser
|
||||
{
|
||||
|
||||
/**
|
||||
* Map Sqlite native types to Propel types.
|
||||
*
|
||||
* There really aren't any SQLite native types, so we're just
|
||||
* using the MySQL ones here.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $sqliteTypeMap = array(
|
||||
'tinyint' => PropelTypes::TINYINT,
|
||||
'smallint' => PropelTypes::SMALLINT,
|
||||
'mediumint' => PropelTypes::SMALLINT,
|
||||
'int' => PropelTypes::INTEGER,
|
||||
'integer' => PropelTypes::INTEGER,
|
||||
'bigint' => PropelTypes::BIGINT,
|
||||
'int24' => PropelTypes::BIGINT,
|
||||
'real' => PropelTypes::REAL,
|
||||
'float' => PropelTypes::FLOAT,
|
||||
'decimal' => PropelTypes::DECIMAL,
|
||||
'numeric' => PropelTypes::NUMERIC,
|
||||
'double' => PropelTypes::DOUBLE,
|
||||
'char' => PropelTypes::CHAR,
|
||||
'varchar' => PropelTypes::VARCHAR,
|
||||
'date' => PropelTypes::DATE,
|
||||
'time' => PropelTypes::TIME,
|
||||
'year' => PropelTypes::INTEGER,
|
||||
'datetime' => PropelTypes::TIMESTAMP,
|
||||
'timestamp' => PropelTypes::TIMESTAMP,
|
||||
'tinyblob' => PropelTypes::BINARY,
|
||||
'blob' => PropelTypes::BLOB,
|
||||
'mediumblob' => PropelTypes::BLOB,
|
||||
'longblob' => PropelTypes::BLOB,
|
||||
'longtext' => PropelTypes::CLOB,
|
||||
'tinytext' => PropelTypes::VARCHAR,
|
||||
'mediumtext' => PropelTypes::LONGVARCHAR,
|
||||
'text' => PropelTypes::LONGVARCHAR,
|
||||
'enum' => PropelTypes::CHAR,
|
||||
'set' => PropelTypes::CHAR,
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets a type mapping from native types to Propel types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTypeMapping()
|
||||
{
|
||||
return self::$sqliteTypeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function parse(Database $database, PDOTask $task = null)
|
||||
{
|
||||
$stmt = $this->dbh->query("SELECT name FROM sqlite_master WHERE type='table' UNION ALL SELECT name FROM sqlite_temp_master WHERE type='table' ORDER BY name;");
|
||||
|
||||
// First load the tables (important that this happen before filling out details of tables)
|
||||
$tables = array();
|
||||
while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
|
||||
$name = $row[0];
|
||||
$table = new Table($name);
|
||||
$database->addTable($table);
|
||||
$tables[] = $table;
|
||||
}
|
||||
|
||||
// Now populate only columns.
|
||||
foreach ($tables as $table) {
|
||||
$this->addColumns($table);
|
||||
}
|
||||
|
||||
// Now add indexes and constraints.
|
||||
foreach ($tables as $table) {
|
||||
$this->addIndexes($table);
|
||||
}
|
||||
|
||||
return count($tables);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds Columns to the specified table.
|
||||
*
|
||||
* @param Table $table The Table model class to add columns to.
|
||||
* @param int $oid The table OID
|
||||
* @param string $version The database version.
|
||||
*/
|
||||
protected function addColumns(Table $table)
|
||||
{
|
||||
$stmt = $this->dbh->query("PRAGMA table_info('" . $table->getName() . "')");
|
||||
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
$name = $row['name'];
|
||||
|
||||
$fulltype = $row['type'];
|
||||
$size = null;
|
||||
$precision = null;
|
||||
$scale = null;
|
||||
|
||||
if (preg_match('/^([^\(]+)\(\s*(\d+)\s*,\s*(\d+)\s*\)$/', $fulltype, $matches)) {
|
||||
$type = $matches[1];
|
||||
$precision = $matches[2];
|
||||
$scale = $matches[3]; // aka precision
|
||||
} elseif (preg_match('/^([^\(]+)\(\s*(\d+)\s*\)$/', $fulltype, $matches)) {
|
||||
$type = $matches[1];
|
||||
$size = $matches[2];
|
||||
} else {
|
||||
$type = $fulltype;
|
||||
}
|
||||
// If column is primary key and of type INTEGER, it is auto increment
|
||||
// See: http://sqlite.org/faq.html#q1
|
||||
$autoincrement = ($row['pk'] == 1 && strtolower($type) == 'integer');
|
||||
$not_null = $row['notnull'];
|
||||
$default = $row['dflt_value'];
|
||||
|
||||
|
||||
$propelType = $this->getMappedPropelType($type);
|
||||
if (!$propelType) {
|
||||
$propelType = Column::DEFAULT_TYPE;
|
||||
$this->warn("Column [" . $table->getName() . "." . $name. "] has a column type (".$type.") that Propel does not support.");
|
||||
}
|
||||
|
||||
$column = new Column($name);
|
||||
$column->setTable($table);
|
||||
$column->setDomainForType($propelType);
|
||||
// We may want to provide an option to include this:
|
||||
// $column->getDomain()->replaceSqlType($type);
|
||||
$column->getDomain()->replaceSize($size);
|
||||
$column->getDomain()->replaceScale($scale);
|
||||
if ($default !== null) {
|
||||
$column->getDomain()->setDefaultValue(new ColumnDefaultValue($default, ColumnDefaultValue::TYPE_VALUE));
|
||||
}
|
||||
$column->setAutoIncrement($autoincrement);
|
||||
$column->setNotNull($not_null);
|
||||
|
||||
|
||||
if (($row['pk'] == 1) || (strtolower($type) == 'integer')) {
|
||||
$column->setPrimaryKey(true);
|
||||
}
|
||||
|
||||
$table->addColumn($column);
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // addColumn()
|
||||
|
||||
/**
|
||||
* Load indexes for this table
|
||||
*/
|
||||
protected function addIndexes(Table $table)
|
||||
{
|
||||
$stmt = $this->dbh->query("PRAGMA index_list('" . $table->getName() . "')");
|
||||
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
$name = $row['name'];
|
||||
$index = new Index($name);
|
||||
|
||||
$stmt2 = $this->dbh->query("PRAGMA index_info('".$name."')");
|
||||
while ($row2 = $stmt2->fetch(PDO::FETCH_ASSOC)) {
|
||||
$colname = $row2['name'];
|
||||
$index->addColumn($table->getColumn($colname));
|
||||
}
|
||||
|
||||
$table->addIndex($index);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue