Browse Source

New attemp

bizley-patch-1
DarkDef 3 years ago
parent
commit
4fba562cd0
  1. 37
      framework/db/ColumnSchemaBuilder.php
  2. 77
      framework/db/mssql/ColumnSchemaBuilder.php
  3. 41
      framework/db/mssql/QueryBuilder.php
  4. 8
      framework/db/mssql/Schema.php
  5. 38
      tests/framework/db/mssql/QueryBuilderTest.php

37
framework/db/ColumnSchemaBuilder.php

@ -331,35 +331,46 @@ class ColumnSchemaBuilder extends BaseObject
}
/**
* Builds the default value specification for the column.
* @return string string with default value of column.
* Return the default value for the column.
* @return string|null string with default value of column.
*/
protected function buildDefaultString()
protected function buildDefaultValue()
{
if ($this->default === null) {
return $this->isNotNull === false ? ' DEFAULT NULL' : '';
return $this->isNotNull === false ? 'NULL' : null;
}
$string = ' DEFAULT ';
switch (gettype($this->default)) {
case 'integer':
$string .= (string) $this->default;
break;
case 'double':
// ensure type cast always has . as decimal separator in all locales
$string .= StringHelper::floatToString($this->default);
$defaultValue = StringHelper::floatToString($this->default);
break;
case 'boolean':
$string .= $this->default ? 'TRUE' : 'FALSE';
$defaultValue = $this->default ? 'TRUE' : 'FALSE';
break;
case 'integer':
case 'object':
$string .= (string) $this->default;
$defaultValue = (string) $this->default;
break;
default:
$string .= "'{$this->default}'";
$defaultValue = "'{$this->default}'";
}
return $defaultValue;
}
/**
* Builds the default value specification for the column.
* @return string string with default value of column.
*/
protected function buildDefaultString()
{
$defaultValue = $this->buildDefaultValue();
if ($defaultValue === null) {
return '';
}
return $string;
return ' DEFAULT ' . $defaultValue;
}
/**

77
framework/db/mssql/ColumnSchemaBuilder.php

@ -0,0 +1,77 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db\mssql;
use yii\db\ColumnSchemaBuilder as AbstractColumnSchemaBuilder;
use yii\db\Expression;
/**
* ColumnSchemaBuilder is the schema builder for MySQL databases.
*
* @author Chris Harris <chris@buckshotsoftware.com>
* @since 2.0.8
*/
class ColumnSchemaBuilder extends AbstractColumnSchemaBuilder
{
protected $format = '{type}{length}{notnull}{unique}{default}{check}{append}';
/**
* Builds the full string for the column's schema.
* @return string
*/
public function __toString()
{
switch ($this->getTypeCategory()) {
case self::CATEGORY_PK:
$format = '{type}{check}{comment}{append}';
break;
default:
$format = $this->format;
}
return $this->buildCompleteString($format);
}
/**
* Changes default format string for MSSQL ALTER COMMAND
*/
public function isAlterColumn()
{
$this->format = '{type}{length}{notnull}{append}';
}
/**
* Getting the `Default` value for constraint
* @return string|Expression|null
*/
public function getDefaultValue()
{
if ($this->default instanceof Expression) {
return $this->default;
}
return $this->buildDefaultValue();
}
/**
* Get the `Check` value for constraint
* @return string|null
*/
public function getCheckValue()
{
return $this->check !== null ? "{$this->check}" : null;
}
/**
* @return bool
*/
public function isUnique()
{
return $this->isUnique;
}
}

41
framework/db/mssql/QueryBuilder.php

@ -174,32 +174,28 @@ class QueryBuilder extends \yii\db\QueryBuilder
*/
public function alterColumn($table, $column, $type)
{
$sqlAfter = [];
$sqlAfter[] = $this->dropConstraintsForColumn($table, $column, 'D');
$columnName = $this->db->quoteColumnName($column);
$tableName = $this->db->quoteTableName($table);
if ($type instanceof \yii\db\mssql\ColumnSchemaBuilder) {
$type->isAlterColumn();
$constraintBase = preg_replace('/[^a-z0-9_]/i', '', $table . '_' . $column);
$columnName = $this->db->quoteColumnName($column);
$tableName = $this->db->quoteTableName($table);
$constraintBase = preg_replace('/[^a-z0-9_]/i', '', $table . '_' . $column);
$type = $this->getColumnType($type);
if (preg_match('/\s+DEFAULT\s+(["\']?\w*["\']?)/i', $type, $matches)) {
$value = strtolower($matches[1]) === 'null' ? null : $matches[1];
$type = preg_replace('/\s+DEFAULT\s+(["\']?\w*["\']?)/i', '', $type);
$sqlAfter[] = $this->dropConstraintsForColumn($table, $column, 'D');
$sqlAfter[] = $this->addDefaultValue("DF_{$constraintBase}", $table, $column, $value);
} else {
$sqlAfter[] = $this->dropConstraintsForColumn($table, $column, 'D');
}
$defaultValue = $type->getDefaultValue();
if ($defaultValue !== null) {
$sqlAfter[] = $this->addDefaultValue("DF_{$constraintBase}", $table, $column, $defaultValue instanceof Expression ? $defaultValue : new Expression($defaultValue));
}
if (preg_match('/\s+CHECK\s+\((.+)\)/i', $type, $matches)) {
$type = preg_replace('/\s+CHECK\s+\((.+)\)/i', '', $type);
$sqlAfter[] = "ALTER TABLE {$tableName} ADD CONSTRAINT " . $this->db->quoteColumnName("CK_{$constraintBase}") . " CHECK ({$matches[1]})";
}
$checkValue = $type->getCheckValue();
if ($checkValue !== null) {
$sqlAfter[] = "ALTER TABLE {$tableName} ADD CONSTRAINT " . $this->db->quoteColumnName("CK_{$constraintBase}") . " CHECK ({$checkValue})";
}
$type = preg_replace('/\s+UNIQUE/i', '', $type, -1, $count);
if ($count) {
$sqlAfter[] = "ALTER TABLE {$tableName} ADD CONSTRAINT " . $this->db->quoteColumnName("UQ_{$constraintBase}") . " UNIQUE ({$columnName})";
if ($type->isUnique()) {
$sqlAfter[] = "ALTER TABLE {$tableName} ADD CONSTRAINT " . $this->db->quoteColumnName("UQ_{$constraintBase}") . " UNIQUE ({$columnName})";
}
}
return 'ALTER TABLE ' . $this->db->quoteTableName($table) . ' ALTER COLUMN '
@ -214,7 +210,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
public function addDefaultValue($name, $table, $column, $value)
{
return 'ALTER TABLE ' . $this->db->quoteTableName($table) . ' ADD CONSTRAINT '
. $this->db->quoteColumnName($name) . ' DEFAULT ' . ($value === null ? 'NULL' : $this->db->quoteValue($value)) . ' FOR '
. $this->db->quoteColumnName($name) . ' DEFAULT ' . $this->db->quoteValue($value) . ' FOR '
. $this->db->quoteColumnName($column);
}
@ -662,5 +658,4 @@ END";
return $this->dropConstraintsForColumn($table, $column) . "\nALTER TABLE " . $this->db->quoteTableName($table)
. " DROP COLUMN " . $this->db->quoteColumnName($column);
}
}

8
framework/db/mssql/Schema.php

@ -804,4 +804,12 @@ SQL;
return $result;
}
/**
* {@inheritdoc}
*/
public function createColumnSchemaBuilder($type, $length = null)
{
return new ColumnSchemaBuilder($type, $length, $this->db);
}
}

38
tests/framework/db/mssql/QueryBuilderTest.php

@ -552,7 +552,7 @@ WHILE 1=1 BEGIN
IF @constraintName IS NULL BREAK
EXEC (N'ALTER TABLE ' + @tableName + ' DROP CONSTRAINT [' + @constraintName + ']')
END
ALTER TABLE [foo1] ADD CONSTRAINT [DF_foo1_bar] DEFAULT '''''' FOR [bar]";
ALTER TABLE [foo1] ADD CONSTRAINT [DF_foo1_bar] DEFAULT '' FOR [bar]";
$sql = $qb->alterColumn('foo1', 'bar', $this->string(255)->defaultValue(''));
$this->assertEquals($expected, $sql);
@ -579,7 +579,7 @@ WHILE 1=1 BEGIN
IF @constraintName IS NULL BREAK
EXEC (N'ALTER TABLE ' + @tableName + ' DROP CONSTRAINT [' + @constraintName + ']')
END
ALTER TABLE [foo1] ADD CONSTRAINT [DF_foo1_bar] DEFAULT '''AbCdE''' FOR [bar]";
ALTER TABLE [foo1] ADD CONSTRAINT [DF_foo1_bar] DEFAULT 'AbCdE' FOR [bar]";
$sql = $qb->alterColumn('foo1', 'bar', $this->string(255)->defaultValue('AbCdE'));
$this->assertEquals($expected, $sql);
@ -606,7 +606,7 @@ WHILE 1=1 BEGIN
IF @constraintName IS NULL BREAK
EXEC (N'ALTER TABLE ' + @tableName + ' DROP CONSTRAINT [' + @constraintName + ']')
END
ALTER TABLE [foo1] ADD CONSTRAINT [DF_foo1_bar] DEFAULT 'CURRENT_TIMESTAMP' FOR [bar]";
ALTER TABLE [foo1] ADD CONSTRAINT [DF_foo1_bar] DEFAULT CURRENT_TIMESTAMP FOR [bar]";
$sql = $qb->alterColumn('foo1', 'bar', $this->timestamp()->defaultExpression('CURRENT_TIMESTAMP'));
$this->assertEquals($expected, $sql);
@ -688,6 +688,38 @@ ALTER TABLE [foo1] ADD CONSTRAINT [DF_foo1_bar] DEFAULT NULL FOR [bar]";
$this->assertEquals($expected, $sql);
}
public function testAlterColumnWithExpression()
{
$qb = $this->getQueryBuilder();
$expected = "ALTER TABLE [foo1] ALTER COLUMN [bar] int NULL
DECLARE @tableName VARCHAR(MAX) = '[foo1]'
DECLARE @columnName VARCHAR(MAX) = 'bar'
WHILE 1=1 BEGIN
DECLARE @constraintName NVARCHAR(128)
SET @constraintName = (SELECT TOP 1 OBJECT_NAME(cons.[object_id])
FROM (
SELECT sc.[constid] object_id
FROM [sys].[sysconstraints] sc
JOIN [sys].[columns] c ON c.[object_id]=sc.[id] AND c.[column_id]=sc.[colid] AND c.[name]=@columnName
WHERE sc.[id] = OBJECT_ID(@tableName)
UNION
SELECT object_id(i.[name]) FROM [sys].[indexes] i
JOIN [sys].[columns] c ON c.[object_id]=i.[object_id] AND c.[name]=@columnName
JOIN [sys].[index_columns] ic ON ic.[object_id]=i.[object_id] AND i.[index_id]=ic.[index_id] AND c.[column_id]=ic.[column_id]
WHERE i.[is_unique_constraint]=1 and i.[object_id]=OBJECT_ID(@tableName)
) cons
JOIN [sys].[objects] so ON so.[object_id]=cons.[object_id]
WHERE so.[type]='D')
IF @constraintName IS NULL BREAK
EXEC (N'ALTER TABLE ' + @tableName + ' DROP CONSTRAINT [' + @constraintName + ']')
END
ALTER TABLE [foo1] ADD CONSTRAINT [DF_foo1_bar] DEFAULT CAST(GETDATE() AS INT) FOR [bar]";
$sql = $qb->alterColumn('foo1', 'bar', $this->integer()->null()->defaultValue(new Expression('CAST(GETDATE() AS INT)')));
$this->assertEquals($expected, $sql);
}
public function testAlterColumnWithCheckConstraintOnDb()
{
$connection = $this->getConnection();

Loading…
Cancel
Save