/** * Optimize table column types, based on hints * @param string $table name of the table * @param string $columnName name of the column * @param string $datatype */ public static function optimize($table, $columnName, $datatype, $length = null) { try { $databaseColumnType = DatabaseCompatibilityUtil::mapHintTypeIntoDatabaseColumnType($datatype, $length); if (isset(self::$optimizedTableColumns[$table])) { $fields = self::$optimizedTableColumns[$table]; // It is possible that field is created outside optimizer, so in this case reload fields from database if (!in_array($columnName, array_keys($fields))) { $fields = R::$writer->getColumns($table); } } else { $fields = R::$writer->getColumns($table); } if (in_array($columnName, array_keys($fields))) { $columnType = $fields[$columnName]; if (strtolower($columnType) != strtolower($databaseColumnType)) { if (strtolower($datatype) == 'string' && isset($length) && $length > 0) { $maxLength = R::getCell("SELECT MAX(LENGTH({$columnName})) FROM {$table}"); if ($maxLength <= $length) { R::exec("alter table {$table} change {$columnName} {$columnName} " . $databaseColumnType); } } else { R::exec("alter table {$table} change {$columnName} {$columnName} " . $databaseColumnType); } } } else { R::exec("alter table {$table} add {$columnName} " . $databaseColumnType); } } catch (RedBean_Exception_SQL $e) { //42S02 - Table does not exist. if (!in_array($e->getSQLState(), array('42S02'))) { throw $e; } else { R::$writer->createTable($table); R::exec("alter table {$table} add {$columnName} " . $databaseColumnType); } } if (isset($fields)) { self::$optimizedTableColumns[$table] = $fields; } else { self::$optimizedTableColumns[$table] = R::$writer->getColumns($table); } self::$optimizedTableColumns[$table][$columnName] = $databaseColumnType; }
public static function resolveColumnMetadataByHintType($name, $hintType = 'string', $length = 255, $unsigned = null, $notNull = 'NULL', $default = 'DEFAULT NULL', $collation = null, $resolveName = true) { // TODO: @Shoaibi: Critical: write tests for: integer, smallint, tinyint, blob, date, datetime, double, string, text, email, url // with and without column ending with _id, check collation, unsigned, type, default if ($resolveName) { $name = static::resolve($name); } // map reasonable default values $defaults = array('hintType' => 'string', 'length' => 255, 'notNull' => 'NULL', 'default' => 'DEFAULT NULL', 'unsigned' => 'eval:DatabaseCompatibilityUtil::resolveUnsignedByHintType($hintType, ' . RedBeanModelMemberRulesToColumnAdapter::ASSUME_SIGNED . ", '{$name}');", 'collation' => 'eval:DatabaseCompatibilityUtil::resolveCollationByHintType($hintType);'); foreach ($defaults as $key => $defaultValue) { if (!isset(${$key})) { MetadataUtil::resolveEvaluateSubString($defaultValue, 'hintType', $hintType); ${$key} = $defaultValue; } } // field is set to be NOT NULL in db, its default can't be 'NULL', unsetting variable. // Not Coding Standard if ($notNull !== 'NULL') { $default = null; } // resolve hint type to db type. $type = DatabaseCompatibilityUtil::mapHintTypeIntoDatabaseColumnType($hintType, $length); $column = compact('name', 'type', 'unsigned', 'notNull', 'collation', 'default'); return $column; }
public function testMapHintTypeIntoDatabaseColumnType() { if (RedBeanDatabase::getDatabaseType() == 'mysql') { $databaseColumnType = DatabaseCompatibilityUtil::mapHintTypeIntoDatabaseColumnType('blob'); $this->assertEquals('BLOB', $databaseColumnType); $databaseColumnType = DatabaseCompatibilityUtil::mapHintTypeIntoDatabaseColumnType('longblob'); $this->assertEquals('LONGBLOB', $databaseColumnType); $databaseColumnType = DatabaseCompatibilityUtil::mapHintTypeIntoDatabaseColumnType('boolean'); $this->assertEquals('TINYINT(1)', $databaseColumnType); $databaseColumnType = DatabaseCompatibilityUtil::mapHintTypeIntoDatabaseColumnType('date'); $this->assertEquals('DATE', $databaseColumnType); $databaseColumnType = DatabaseCompatibilityUtil::mapHintTypeIntoDatabaseColumnType('datetime'); $this->assertEquals('DATETIME', $databaseColumnType); $databaseColumnType = DatabaseCompatibilityUtil::mapHintTypeIntoDatabaseColumnType('string'); $this->assertEquals('VARCHAR(255)', $databaseColumnType); $databaseColumnType = DatabaseCompatibilityUtil::mapHintTypeIntoDatabaseColumnType('text'); $this->assertEquals('TEXT', $databaseColumnType); $databaseColumnType = DatabaseCompatibilityUtil::mapHintTypeIntoDatabaseColumnType('longtext'); $this->assertEquals('LONGTEXT', $databaseColumnType); $databaseColumnType = DatabaseCompatibilityUtil::mapHintTypeIntoDatabaseColumnType('id'); $this->assertEquals('INT(11) UNSIGNED', $databaseColumnType); try { $databaseColumnType = DatabaseCompatibilityUtil::mapHintTypeIntoDatabaseColumnType('invalidType'); $this->fail(); } catch (NotSupportedException $e) { // Do nothing } } }