From 58133573b39d5784157dfa970c3d5a9dd15ee148 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Tue, 30 Jun 2020 00:31:06 +0900 Subject: [PATCH] Implement addColumn() and modifyColumn() --- common/framework/db.php | 86 ++++++++++++++++++-- common/framework/parsers/dbtableparser.php | 95 +++++++++++++++------- 2 files changed, 148 insertions(+), 33 deletions(-) diff --git a/common/framework/db.php b/common/framework/db.php index 2a221b79e..60705b3e2 100644 --- a/common/framework/db.php +++ b/common/framework/db.php @@ -648,12 +648,14 @@ class DB */ public function createTable(string $filename = '', string $content = ''): \BaseObject { + // Get the table definition from DBTableParser. $table = Parsers\DBTableParser::loadXML($filename, $content); if (!$table) { return $this->setError(-1, 'Table creation failed.'); } + // Generate the CREATE TABLE query and execute it. $query_string = $table->getCreateQuery($this->_prefix, $this->_charset, $this->_engine); $stmt = $this->_query($query_string); return $stmt ? new \BaseObject : $this->getError(); @@ -699,24 +701,98 @@ class DB */ public function addColumn(string $table_name, string $column_name, string $type = 'number', $size = null, $default = null, $notnull = false, $after_column = null): \BaseObject { - // TODO - return new \BaseObject; + // Normalize the type and size. + list($type, $xetype, $size) = Parsers\DBTableParser::getTypeAndSize($type, strval($size)); + + // Compose the ADD COLUMN query. + $query = sprintf("ALTER TABLE `%s` ADD COLUMN `%s` ", $this->addQuotes($this->_prefix . $table_name), $this->addQuotes($column_name)); + $query .= $size ? sprintf('%s(%s)', $type, $size) : $type; + $query .= $notnull ? ' NOT NULL' : ''; + + // Add the default value according to the type. + if (isset($default)) + { + if (contains('int', $type, false) && is_numeric($default)) + { + $query .= sprintf(" DEFAULT %s", $default); + } + else + { + $query .= sprintf(" DEFAULT '%s'", $this->addQuotes($default)); + } + } + + // Add position information. + if ($after_column === 'FIRST') + { + $query .= ' FIRST'; + } + elseif ($after_column) + { + $query .= sprintf(' AFTER `%s`', $this->addQuotes($after_column)); + } + + // Execute the query and return the result. + $stmt = $this->_query($query); + return $stmt ? new \BaseObject : $this->getError(); } /** * Modify a column. * * @param string $table_name + * @param string $column_name * @param string $type * @param string $size * @param mixed $default * @param bool $notnull + * @param string $after_column + * @param string $new_name * @return BaseObject */ - public function modifyColumn(string $table_name, string $column_name, string $type = 'number', $size = null, $default = null, $notnull = false): \BaseObject + public function modifyColumn(string $table_name, string $column_name, string $type = 'number', $size = null, $default = null, $notnull = false, $after_column = null, $new_name = null): \BaseObject { - // TODO - return new \BaseObject; + // Normalize the type and size. + list($type, $xetype, $size) = Parsers\DBTableParser::getTypeAndSize($type, strval($size)); + + // Compose the MODIFY COLUMN query. + if ($new_name && $new_name !== $column_name) + { + $query = sprintf("ALTER TABLE `%s` CHANGE `%s` `%s` ", $this->addQuotes($this->_prefix . $table_name), $this->addQuotes($column_name), $this->addQuotes($new_name)); + } + else + { + $query = sprintf("ALTER TABLE `%s` MODIFY `%s` ", $this->addQuotes($this->_prefix . $table_name), $this->addQuotes($column_name)); + } + $query .= $size ? sprintf('%s(%s)', $type, $size) : $type; + $query .= $notnull ? ' NOT NULL' : ''; + + // Add the default value according to the type. + if (isset($default)) + { + if (contains('int', $type, false) && is_numeric($default)) + { + $query .= sprintf(" DEFAULT %s", $default); + } + else + { + $query .= sprintf(" DEFAULT '%s'", $this->addQuotes($default)); + } + } + + // Add position information. + if ($after_column === 'FIRST') + { + $query .= ' FIRST'; + } + elseif ($after_column) + { + $query .= sprintf(' AFTER `%s`', $this->addQuotes($after_column)); + } + + // Execute the query and return the result. + $stmt = $this->_query($query); + return $stmt ? new \BaseObject : $this->getError(); } /** diff --git a/common/framework/parsers/dbtableparser.php b/common/framework/parsers/dbtableparser.php index 71475e09b..f91f6a1e8 100644 --- a/common/framework/parsers/dbtableparser.php +++ b/common/framework/parsers/dbtableparser.php @@ -23,6 +23,7 @@ class DBTableParser extends BaseParser protected static $_nosize_types = array( 'bigint' => true, 'int' => true, + 'integer' => true, ); /** @@ -66,34 +67,7 @@ class DBTableParser extends BaseParser // Get the column name and type. $column = new DBTable\Column; $column->name = strval($column_info['name']); - $column->type = strval($column_info['type']); - - // Map XE-compatible types to database native types. - if (isset(self::$_xe_types[$column->type])) - { - $column->xetype = $column->type; - $column->type = self::$_xe_types[$column->type]; - } - else - { - $column->xetype = $column->type; - } - - // Get the size. - if (preg_match('/^([a-z0-9_]+)\(([0-9,\s]+)\)$/i', $column->type, $matches)) - { - $column->type = $matches[1]; - $column->size = $matches[2]; - } - if (isset($column_info['size'])) - { - $column->size = strval($column_info['size']); - } - $column->size = implode(',', array_map('trim', explode(',', $column->size))) ?: null; - if (isset(self::$_nosize_types[$column->type])) - { - $column->size = null; - } + list($column->type, $column->xetype, $column->size) = self::getTypeAndSize(strval($column_info['type']), strval($column_info['size'])); // Get all attributes. $attribs = self::_getAttributes($column_info); @@ -206,4 +180,69 @@ class DBTableParser extends BaseParser // Return the complete table definition. return $table; } + + /** + * Get column type and size. + * + * @param string $type + * @param string $size + * @return array + */ + public static function getTypeAndSize(string $type, string $size): array + { + // Map XE-compatible types to database native types. + if (isset(self::$_xe_types[$type])) + { + $xetype = $type; + $type = self::$_xe_types[$type]; + } + else + { + $xetype = $type; + } + + // Extract and normalize the size. + if (preg_match('/^([a-z0-9_]+)\(([0-9,\s]+)\)$/i', $type, $matches)) + { + $type = $matches[1]; + $size = $matches[2]; + } + $size = implode(',', array_map('trim', explode(',', $size))) ?: null; + if (isset(self::$_nosize_types[$type])) + { + $size = null; + } + + // Return a complete array. + return [$type, $xetype, $size]; + } + + /** + * Get the XE-compatible type from a real database type. + * + * @param string $type + * @param string $size + * @return string + */ + public static function getXEType(string $type, string $size): string + { + switch ($type) + { + case 'bigint': + return 'bignumber'; + case 'int': + case 'integer': + return 'number'; + case 'longtext': + return 'bigtext'; + case 'char': + case 'varchar': + if ($size == 14) + { + return 'date'; + } + default: + return $type; + } + } }