summaryrefslogtreecommitdiff
path: root/framework/Data/ActiveRecord/Vendor/TPgsqlMetaDataInspector.php
diff options
context:
space:
mode:
authorwei <>2006-11-26 22:15:58 +0000
committerwei <>2006-11-26 22:15:58 +0000
commita8b3ebe8f62c3888b216d827c1c5dcba8a47d4e1 (patch)
tree5eef79dbc5e2f506047fa463cb427a40a7bd8441 /framework/Data/ActiveRecord/Vendor/TPgsqlMetaDataInspector.php
parent6773dfe453682d2b39a26fbabef8e706bf6bb412 (diff)
Adding active record implementation.
Diffstat (limited to 'framework/Data/ActiveRecord/Vendor/TPgsqlMetaDataInspector.php')
-rw-r--r--framework/Data/ActiveRecord/Vendor/TPgsqlMetaDataInspector.php223
1 files changed, 223 insertions, 0 deletions
diff --git a/framework/Data/ActiveRecord/Vendor/TPgsqlMetaDataInspector.php b/framework/Data/ActiveRecord/Vendor/TPgsqlMetaDataInspector.php
new file mode 100644
index 00000000..df31b9c0
--- /dev/null
+++ b/framework/Data/ActiveRecord/Vendor/TPgsqlMetaDataInspector.php
@@ -0,0 +1,223 @@
+<?php
+/**
+ * TPgsqlMetaDataInspector class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Data.ActiveRecord.Vendor
+ */
+
+Prado::using('System.Data.ActiveRecord.Vendor.TDbMetaDataInspector');
+Prado::using('System.Data.ActiveRecord.Vendor.TPgsqlColumnMetaData');
+Prado::using('System.Data.ActiveRecord.Vendor.TPgsqlMetaData');
+
+/**
+ * Table meta data inspector for Postgres database 7.3 or later.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Data.ActiveRecord.Vendor
+ * @since 3.1
+ */
+class TPgsqlMetaDataInspector extends TDbMetaDataInspector
+{
+ private $_schema = 'public';
+
+ /**
+ * @param string default schema.
+ */
+ public function setDefaultSchema($schema)
+ {
+ $this->_schema=$schema;
+ }
+
+ /**
+ * @return string default schema.
+ */
+ public function getDefaultSchema()
+ {
+ return $this->_schema;
+ }
+
+ /**
+ * Create a new instance of meta data.
+ * @param string table name
+ * @param array column meta data
+ * @param array primary key meta data
+ * @param array foreign key meta data.
+ * @return TDbMetaData table meta data.
+ */
+ protected function createMetaData($table, $columns, $primary, $foreign)
+ {
+ foreach($primary as $column)
+ $columns[$column]->setIsPrimaryKey(true);
+ return new TPgsqlMetaData($table,$columns,$primary,$foreign,$this->getIsView($table));
+ }
+
+ protected function getIsView($table)
+ {
+ $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;
+ $conn=$this->getDbConnection();
+ $conn->setActive(true);
+ $command=$conn->createCommand($sql);
+ $command->bindValue(':schema',$this->getDefaultSchema());
+ $command->bindValue(':table', $table);
+ return intval($command->queryScalar()) === 1;
+ }
+
+ /**
+ * Get the column definitions for given table.
+ * @param string table name.
+ * @return array column name value pairs of column meta data.
+ */
+ protected function getColumnDefinitions($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;
+ $conn = $this->getDbConnection();
+ $conn->setActive(true);
+ $command = $conn->createCommand($sql);
+ $command->bindValue(':table', $table);
+ $command->bindValue(':schema', $this->getDefaultSchema());
+ $cols = array();
+ foreach($command->query() as $col)
+ $cols[$col['attname']] = $this->getColumnMetaData($col);
+ return $cols;
+ }
+
+ /**
+ * Returns the column details.
+ * @param array column details.
+ * @return TPgsqlColumnMetaData column meta data.
+ */
+ protected function getColumnMetaData($col)
+ {
+ $name = '"'.$col['attname'].'"'; //quote the column names!
+ $type = $col['type'];
+
+ // A specific constant in the 7.0 source, the length is offset by 4.
+ $length = $col['atttypmod'] > 0 ? $col['atttypmod'] - 4 : -1;
+ $notNull = $col['attnotnull'];
+ $serial = $col['attisserial'] ? $this->getSerialName($col['adsrc']) : null;
+ $default = $serial === null && $col['atthasdef'] ? $col['adsrc'] : null;
+ return new TPgsqlColumnMetaData($name,$type,$length,$notNull,$serial,$default);
+ }
+
+ /**
+ * @return string serial name if found, null otherwise.
+ */
+ protected function getSerialName($src)
+ {
+ $matches = array();
+ if(preg_match('/nextval\(\'([^\']+)\'::regclass\)/i',$src,$matches))
+ return $matches[1];
+ }
+
+ /**
+ * Gets the primary and foreign key details for the given table.
+ * @param string table name.
+ * @return array key value pairs with keys 'primary' and 'foreign'.
+ */
+ protected function getConstraintKeys($table)
+ {
+ $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', $table);
+ $command->bindValue(':schema', $this->getDefaultSchema());
+ $keys['primary'] = array();
+ $keys['foreign'] = array();
+ foreach($command->query() as $row)
+ {
+ if($row['contype']==='p')
+ $keys['primary'] = $this->getPrimaryKeys($row['consrc']);
+ else if($row['contype'] === 'f')
+ {
+ $fkey = $this->getForeignKeys($row['consrc']);
+ if($fkey!==null)
+ $keys['foreign'][] = $fkey;
+ }
+ }
+ return $keys;
+ }
+
+ /**
+ * 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' => $matches[2], 'keys' => $fkeys);
+ }
+ }
+}
+
+?> \ No newline at end of file