From 7565ffb1d48adb6e3289b3e0316350dbe6078811 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 28 Oct 2008 14:37:40 +0000 Subject: [PATCH] - added dibi-field-type autodetection - added DibiColumnInfo::getVendorInfo() --- dibi/dibi.php | 1 + dibi/drivers/mssql.php | 3 +- dibi/drivers/mysql.php | 8 ++-- dibi/drivers/mysqli.php | 20 ++++++---- dibi/drivers/pdo.php | 6 ++- dibi/drivers/postgre.php | 8 ++-- dibi/drivers/sqlite.php | 1 + dibi/libs/DibiDatabaseInfo.php | 72 +++++++++++++++++++++++++++------- dibi/libs/DibiResult.php | 50 +++++++++++++++-------- 9 files changed, 119 insertions(+), 50 deletions(-) diff --git a/dibi/dibi.php b/dibi/dibi.php index e8d23cec..cedcba2c 100644 --- a/dibi/dibi.php +++ b/dibi/dibi.php @@ -101,6 +101,7 @@ class dibi FIELD_FLOAT = 'f', FIELD_DATE = 'd', FIELD_DATETIME = 't', + FIELD_TIME = 't', // special IDENTIFIER = 'n'; diff --git a/dibi/drivers/mssql.php b/dibi/drivers/mssql.php index f4811e53..2c190355 100644 --- a/dibi/drivers/mssql.php +++ b/dibi/drivers/mssql.php @@ -346,9 +346,8 @@ class DibiMsSqlDriver extends DibiObject implements IDibiDriver 'name' => $row['name'], 'fullname' => $row['column_source'] ? $row['column_source'] . '.' . $row['name'] : $row['name'], 'table' => $row['column_source'], - 'type' => NULL, 'nativetype' => $row['type'], - ) + $row; + ); } return $res; } diff --git a/dibi/drivers/mysql.php b/dibi/drivers/mysql.php index e94b5b7f..458f42fa 100644 --- a/dibi/drivers/mysql.php +++ b/dibi/drivers/mysql.php @@ -409,12 +409,12 @@ class DibiMySqlDriver extends DibiObject implements IDibiDriver for ($i = 0; $i < $count; $i++) { $row = (array) mysql_fetch_field($this->resultSet, $i); $res[] = array( + 'name' => $row['name'], + 'table' => $row['table'], 'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'], - 'type' => NULL, 'nativetype' => strtoupper($row['type']), - 'nullable' => !($row['not_null']), - 'default' => $row['def'], - ) + $row; + 'vendor' => $row, + ); } return $res; } diff --git a/dibi/drivers/mysqli.php b/dibi/drivers/mysqli.php index 7f563ad8..d1d5cbf3 100644 --- a/dibi/drivers/mysqli.php +++ b/dibi/drivers/mysqli.php @@ -386,21 +386,27 @@ class DibiMySqliDriver extends DibiObject implements IDibiDriver */ public function getColumnsMeta() { + static $types; + if (empty($types)) { + $consts = get_defined_constants(TRUE); + foreach ($consts['mysqli'] as $key => $value) { + if (strncmp($key, 'MYSQLI_TYPE_', 12) === 0) { + $types[$value] = substr($key, 12); + } + } + } + $count = mysqli_num_fields($this->resultSet); $res = array(); for ($i = 0; $i < $count; $i++) { $row = (array) mysqli_fetch_field_direct($this->resultSet, $i); $res[] = array( 'name' => $row['name'], - 'column' => $row['orgname'], - 'alias' => $row['table'], 'table' => $row['orgtable'], 'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'], - 'type' => NULL, - 'nativetype' => $row['type'], - 'nullable' => !($row['flags'] & MYSQLI_NOT_NULL_FLAG), - 'default' => $row['def'], - ) + $row; + 'nativetype' => $types[$row['type']], + 'vendor' => $row, + ); } return $res; } diff --git a/dibi/drivers/pdo.php b/dibi/drivers/pdo.php index ed055aa7..24893562 100644 --- a/dibi/drivers/pdo.php +++ b/dibi/drivers/pdo.php @@ -400,10 +400,12 @@ class DibiPdoDriver extends DibiObject implements IDibiDriver throw new DibiDriverException('Driver does not support meta data.'); } $res[] = array( - 'type' => NULL, + 'name' => $row['name'], + 'table' => $row['table'], 'nativetype' => $row['native_type'], 'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'], - ) + $row; + 'vendor' => $row, + ); } return $res; } diff --git a/dibi/drivers/postgre.php b/dibi/drivers/postgre.php index 93074a8d..59dbda8d 100644 --- a/dibi/drivers/postgre.php +++ b/dibi/drivers/postgre.php @@ -456,14 +456,14 @@ class DibiPostgreDriver extends DibiObject implements IDibiDriver $this->query(" SELECT indkey FROM pg_index, pg_class - WHERE pg_class.relname = '$_table' AND pg_class.oid = pg_index.indrelid AND pg_index.indisprimary + WHERE pg_class.relname = $_table AND pg_class.oid = pg_index.indrelid AND pg_index.indisprimary "); $primary = (int) pg_fetch_object($this->resultSet)->indkey; $this->query(" SELECT * FROM information_schema.columns - WHERE table_name = '$_table' AND table_schema = current_schema() + WHERE table_name = $_table AND table_schema = current_schema() ORDER BY ordinal_position "); $res = array(); @@ -472,13 +472,13 @@ class DibiPostgreDriver extends DibiObject implements IDibiDriver $res[] = array( 'name' => $row['column_name'], 'table' => $table, - 'type' => NULL, 'nativetype' => strtoupper($row['udt_name']), 'size' => $size ? $size : NULL, 'nullable' => $row['is_nullable'] === 'YES', 'default' => $row['column_default'], 'autoincrement' => (int) $row['ordinal_position'] === $primary && substr($row['column_default'], 0, 7) === 'nextval', - ) + $row; + 'vendor' => $row, + ); } $this->free(); return $res; diff --git a/dibi/drivers/sqlite.php b/dibi/drivers/sqlite.php index b4c5714f..a2970cfe 100644 --- a/dibi/drivers/sqlite.php +++ b/dibi/drivers/sqlite.php @@ -369,6 +369,7 @@ class DibiSqliteDriver extends DibiObject implements IDibiDriver 'name' => isset($pair[1]) ? $pair[1] : $pair[0], 'table' => isset($pair[1]) ? $pair[0] : NULL, 'fullname' => $name, + 'nativetype' => NULL, ); } return $res; diff --git a/dibi/libs/DibiDatabaseInfo.php b/dibi/libs/DibiDatabaseInfo.php index ebb497a4..f688ff82 100644 --- a/dibi/libs/DibiDatabaseInfo.php +++ b/dibi/libs/DibiDatabaseInfo.php @@ -138,8 +138,11 @@ class DibiTableInfo extends DibiObject /** @var IDibiDriver */ private $driver; - /** @var array */ - private $info; + /** @var string */ + private $name; + + /** @var bool */ + private $view; /** @var array */ private $columns; @@ -158,7 +161,8 @@ class DibiTableInfo extends DibiObject public function __construct(IDibiDriver $driver, array $info) { $this->driver = $driver; - $this->info = $info; + $this->name = $info['name']; + $this->view = !empty($info['view']); } @@ -168,7 +172,7 @@ class DibiTableInfo extends DibiObject */ public function getName() { - return $this->info['name']; + return $this->name; } @@ -178,7 +182,7 @@ class DibiTableInfo extends DibiObject */ public function isView() { - return !empty($this->info['view']); + return $this->view; } @@ -279,7 +283,7 @@ class DibiTableInfo extends DibiObject { if ($this->columns === NULL) { $this->columns = array(); - foreach ($this->driver->getColumns($this->info['name']) as $info) { + foreach ($this->driver->getColumns($this->name) as $info) { $this->columns[strtolower($info['name'])] = new DibiColumnInfo($this->driver, $info); } } @@ -295,7 +299,7 @@ class DibiTableInfo extends DibiObject if ($this->indexes === NULL) { $this->initColumns(); $this->indexes = array(); - foreach ($this->driver->getIndexes($this->info['name']) as $info) { + foreach ($this->driver->getIndexes($this->name) as $info) { foreach ($info['columns'] as $key => $name) { $info['columns'][$key] = $this->columns[strtolower($name)]; } @@ -328,18 +332,25 @@ class DibiTableInfo extends DibiObject */ class DibiColumnInfo extends DibiObject { + /** @var array */ + private static $types; + /** @var IDibiDriver */ private $driver; - /** @var array (name, table, fullname, type, nativetype, size, nullable, default, autoincrement) */ + /** @var array (name, nativetype, [table], [fullname], [size], [nullable], [default], [autoincrement], [vendor]) */ private $info; + /** @var string */ + private $type; + public function __construct(IDibiDriver $driver, array $info) { $this->driver = $driver; $this->info = $info; + $this->type = self::detectType($this->info['nativetype']); } @@ -382,7 +393,7 @@ class DibiColumnInfo extends DibiObject */ public function getType() { - return isset($this->info['type']) ? $this->info['type'] : NULL; + return $this->type; } @@ -392,7 +403,7 @@ class DibiColumnInfo extends DibiObject */ public function getNativeType() { - return isset($this->info['nativetype']) ? $this->info['nativetype'] : NULL; + return $this->info['nativetype']; } @@ -412,7 +423,7 @@ class DibiColumnInfo extends DibiObject */ public function isNullable() { - return !empty($this->info['nullable']); + return isset($this->info['nullable']) ? (bool) $this->info['nullable'] : NULL; } @@ -422,7 +433,7 @@ class DibiColumnInfo extends DibiObject */ public function isAutoIncrement() { - return !empty($this->info['autoincrement']); + return isset($this->info['autoincrement']) ? (bool) $this->info['autoincrement'] : NULL; } @@ -441,9 +452,39 @@ class DibiColumnInfo extends DibiObject * @param string * @return mixed */ - public function getInfo($key) + public function getVendorInfo($key) { - return isset($this->info[$key]) ? $this->info[$key] : NULL; + return isset($this->info['vendor'][$key]) ? $this->info['vendor'][$key] : NULL; + } + + + + /** + * Heuristic type detection. + * @param string + * @return string + */ + public static function detectType($type) + { + static $patterns = array( + 'BYTE|COUNTER|SERIAL|INT|LONG' => dibi::FIELD_INTEGER, + 'CURRENCY|REAL|MONEY|FLOAT|DOUBLE|DECIMAL|NUMERIC' => dibi::FIELD_FLOAT, + '^TIME$' => dibi::FIELD_TIME, + 'TIME' => dibi::FIELD_DATETIME, // DATETIME, TIMESTAMP + 'YEAR|DATE' => dibi::FIELD_DATE, + 'BYTEA|BLOB|BIN' => dibi::FIELD_BINARY, + 'BOOL|BIT' => dibi::FIELD_BOOL, + ); + + if (!isset(self::$types[$type])) { + self::$types[$type] = dibi::FIELD_TEXT; + foreach ($patterns as $s => $val) { + if (preg_match("#$s#i", $type)) { + return self::$types[$type] = $val; + } + } + } + return self::$types[$type]; } } @@ -454,6 +495,7 @@ class DibiColumnInfo extends DibiObject /** * Reflection metadata class for a foreign key. * @package dibi + * @todo */ class DibiForeignKeyInfo extends DibiObject { @@ -502,7 +544,7 @@ class DibiForeignKeyInfo extends DibiObject */ class DibiIndexInfo extends DibiObject { - /** @var array (name, columns, unique, primary) */ + /** @var array (name, columns, [unique], [primary]) */ private $info; diff --git a/dibi/libs/DibiResult.php b/dibi/libs/DibiResult.php index 4bc7c4aa..c077cc55 100644 --- a/dibi/libs/DibiResult.php +++ b/dibi/libs/DibiResult.php @@ -58,7 +58,7 @@ class DibiResult extends DibiObject implements IDataSource * Cache for $driver->getColumnsMeta(). * @var array */ - private $metaCache; + private $meta; /** * Already fetched? Used for allowance for first seek(0). @@ -164,12 +164,8 @@ class DibiResult extends DibiObject implements IDataSource final public function setWithTables($val) { if ($val) { - if ($this->metaCache === NULL) { - $this->metaCache = $this->getDriver()->getColumnsMeta(); - } - $cols = array(); - foreach ($this->metaCache as $info) { + foreach ($this->getMeta() as $info) { $name = $info['fullname']; if (isset($cols[$name])) { $fix = 1; @@ -446,6 +442,19 @@ class DibiResult extends DibiObject implements IDataSource + /** + * Autodetect column types. + * @return void + */ + final public function detectTypes() + { + foreach ($this->getMeta() as $info) { + $this->xlat[$info['name']] = array('type' => $info['type'], 'format' => NULL); + } + } + + + /** * Define multiple columns types (for internal usage). * @param array @@ -508,18 +517,14 @@ class DibiResult extends DibiObject implements IDataSource /** - * Gets an array of meta informations about column. + * Gets an array of meta informations about columns. * * @return array of DibiColumnInfo */ final public function getColumns() { - if ($this->metaCache === NULL) { - $this->metaCache = $this->getDriver()->getColumnsMeta(); - } - $cols = array(); - foreach ($this->metaCache as $info) { + foreach ($this->getMeta() as $info) { $cols[] = new DibiColumnInfo($this->driver, $info); } return $cols; @@ -533,11 +538,8 @@ class DibiResult extends DibiObject implements IDataSource */ public function getColumnNames($withTables = FALSE) { - if ($this->metaCache === NULL) { - $this->metaCache = $this->getDriver()->getColumnsMeta(); - } $cols = array(); - foreach ($this->metaCache as $info) { + foreach ($this->getMeta() as $info) { $cols[] = $info[$withTables ? 'fullname' : 'name']; } return $cols; @@ -623,6 +625,22 @@ class DibiResult extends DibiObject implements IDataSource } + + /** + * Meta lazy initialization. + * @return array + */ + private function getMeta() + { + if ($this->meta === NULL) { + $this->meta = $this->getDriver()->getColumnsMeta(); + foreach ($this->meta as & $row) { + $row['type'] = DibiColumnInfo::detectType($row['nativetype']); + } + } + return $this->meta; + } + }