Skip to content

Commit

Permalink
Merge df0708f into 9b6b0f8
Browse files Browse the repository at this point in the history
  • Loading branch information
othercorey committed Nov 21, 2019
2 parents 9b6b0f8 + df0708f commit f016356
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 32 deletions.
82 changes: 60 additions & 22 deletions src/Database/Schema/SqlserverSchema.php
Expand Up @@ -91,7 +91,12 @@ protected function _convertColumn(
return ['type' => $col, 'length' => null];
}
if (strpos($col, 'datetime') !== false) {
return ['type' => TableSchema::TYPE_TIMESTAMP, 'length' => null];
$typeName = TableSchema::TYPE_DATETIME;
if ($scale > 0) {
$typeName = TableSchema::TYPE_DATETIME_FRACTIONAL;
}

return ['type' => $typeName, 'length' => null, 'precision' => $scale];
}

if ($col === 'char') {
Expand Down Expand Up @@ -168,23 +173,18 @@ public function convertColumnDescription(TableSchema $schema, array $row): void
{
$field = $this->_convertColumn(
$row['type'],
$row['char_length'] != null ? (int)$row['char_length'] : null,
$row['precision'] != null ? (int)$row['precision'] : null,
$row['scale'] != null ? (int)$row['scale'] : null
$row['char_length'] !== null ? (int)$row['char_length'] : null,
$row['precision'] !== null ? (int)$row['precision'] : null,
$row['scale'] !== null ? (int)$row['scale'] : null
);
if (!empty($row['default'])) {
$row['default'] = trim($row['default'], '()');
}

if (!empty($row['autoincrement'])) {
$field['autoIncrement'] = true;
}
if ($field['type'] === TableSchema::TYPE_BOOLEAN) {
$row['default'] = (int)$row['default'];
}

$field += [
'null' => $row['null'] === '1',
'default' => $this->_defaultValue($row['default']),
'default' => $this->_defaultValue($field['type'], $row['default']),
'collate' => $row['collation_name'],
];
$schema->addColumn($row['name'], $field);
Expand All @@ -193,20 +193,35 @@ public function convertColumnDescription(TableSchema $schema, array $row): void
/**
* Manipulate the default value.
*
* Sqlite includes quotes and bared NULLs in default values.
* We need to remove those.
* Removes () wrapping default values, extracts strings from
* N'' wrappers and collation text and converts NULL strings.
*
* @param string|int|null $default The default value.
* @param string $type The schema type
* @param string|null $default The default value.
* @return string|int|null
*/
protected function _defaultValue($default)
protected function _defaultValue($type, $default)
{
if ($default === null) {
return $default;
}

// remove () surrounding value (NULL) but leave () at the end of functions
// integers might have two ((0)) wrapping value
if (preg_match('/^\(+(.*?(\(\))?)\)+$/', $default, $matches)) {
$default = $matches[1];
}

if ($default === 'NULL') {
return null;
}

if ($type === TableSchema::TYPE_BOOLEAN) {
return (int)$default;
}

// Remove quotes
if (is_string($default) && preg_match("/^N?'(.*)'/", $default, $matches)) {
if (preg_match("/^\(?N?'(.*)'\)?/", $default, $matches)) {
return str_replace("''", "'", $matches[1]);
}

Expand Down Expand Up @@ -365,8 +380,10 @@ public function columnSql(TableSchema $schema, string $name): string
TableSchema::TYPE_DECIMAL => ' DECIMAL',
TableSchema::TYPE_DATE => ' DATE',
TableSchema::TYPE_TIME => ' TIME',
TableSchema::TYPE_DATETIME => ' DATETIME',
TableSchema::TYPE_TIMESTAMP => ' DATETIME',
TableSchema::TYPE_DATETIME => ' DATETIME2',
TableSchema::TYPE_DATETIME_FRACTIONAL => ' DATETIME2',
TableSchema::TYPE_TIMESTAMP => ' DATETIME2',
TableSchema::TYPE_TIMESTAMP_FRACTIONAL => ' DATETIME2',
TableSchema::TYPE_UUID => ' UNIQUEIDENTIFIER',
TableSchema::TYPE_JSON => ' NVARCHAR(MAX)',
];
Expand Down Expand Up @@ -424,7 +441,14 @@ public function columnSql(TableSchema $schema, string $name): string
$out .= ' COLLATE ' . $data['collate'];
}

if ($data['type'] === TableSchema::TYPE_FLOAT && isset($data['precision'])) {
$precisionTypes = [
TableSchema::TYPE_FLOAT,
TableSchema::TYPE_DATETIME,
TableSchema::TYPE_DATETIME_FRACTIONAL,
TableSchema::TYPE_TIMESTAMP,
TableSchema::TYPE_TIMESTAMP_FRACTIONAL,
];
if (in_array($data['type'], $precisionTypes, true) && isset($data['precision'])) {
$out .= '(' . (int)$data['precision'] . ')';
}

Expand All @@ -442,12 +466,26 @@ public function columnSql(TableSchema $schema, string $name): string
$out .= ' NOT NULL';
}

$dateTimeTypes = [
TableSchema::TYPE_DATETIME,
TableSchema::TYPE_DATETIME_FRACTIONAL,
TableSchema::TYPE_TIMESTAMP,
TableSchema::TYPE_TIMESTAMP_FRACTIONAL,
];
$dateTimeDefaults = [
'current_timestamp',
'getdate()',
'getutcdate()',
'sysdatetime()',
'sysutcdatetime()',
'sysdatetimeoffset()',
];
if (
isset($data['default']) &&
in_array($data['type'], [TableSchema::TYPE_TIMESTAMP, TableSchema::TYPE_DATETIME]) &&
strtolower($data['default']) === 'current_timestamp'
in_array($data['type'], $dateTimeTypes, true) &&
in_array(strtolower($data['default']), $dateTimeDefaults, true)
) {
$out .= ' DEFAULT CURRENT_TIMESTAMP';
$out .= ' DEFAULT ' . strtoupper($data['default']);
} elseif (isset($data['default'])) {
$default = is_bool($data['default'])
? (int)$data['default']
Expand Down
110 changes: 100 additions & 10 deletions tests/TestCase/Database/Schema/SqlserverSchemaTest.php
Expand Up @@ -71,6 +71,10 @@ protected function _createTables($connection)
published BIT DEFAULT 0,
views SMALLINT DEFAULT 0,
created DATETIME,
created2 DATETIME2,
created2_with_default DATETIME2 DEFAULT SYSDATETIME(),
created2_with_precision DATETIME2(3),
created2_without_precision DATETIME2(0),
field1 VARCHAR(10) DEFAULT NULL,
field2 VARCHAR(10) DEFAULT 'NULL',
field3 VARCHAR(10) DEFAULT 'O''hare',
Expand All @@ -94,8 +98,22 @@ public static function convertColumnProvider()
'DATETIME',
null,
null,
3,
['type' => 'datetimefractional', 'length' => null, 'precision' => 3],
],
[
'DATETIME2',
null,
null,
7,
['type' => 'datetimefractional', 'length' => null, 'precision' => 7],
],
[
'DATETIME2',
null,
null,
['type' => 'timestamp', 'length' => null],
0,
['type' => 'datetime', 'length' => null, 'precision' => 0],
],
[
'DATE',
Expand Down Expand Up @@ -398,11 +416,43 @@ public function testDescribeTable()
'comment' => null,
],
'created' => [
'type' => 'timestamp',
'type' => 'datetimefractional',
'null' => true,
'default' => null,
'length' => null,
'precision' => null,
'precision' => 3,
'comment' => null,
],
'created2' => [
'type' => 'datetimefractional',
'null' => true,
'default' => null,
'length' => null,
'precision' => 7,
'comment' => null,
],
'created2_with_default' => [
'type' => 'datetimefractional',
'null' => true,
'default' => 'sysdatetime()',
'length' => null,
'precision' => 7,
'comment' => null,
],
'created2_with_precision' => [
'type' => 'datetimefractional',
'null' => true,
'default' => null,
'length' => null,
'precision' => 3,
'comment' => null,
],
'created2_without_precision' => [
'type' => 'datetime',
'null' => true,
'default' => null,
'length' => null,
'precision' => 0,
'comment' => null,
],
'field1' => [
Expand Down Expand Up @@ -701,27 +751,52 @@ public static function columnSqlProvider()
[
'created',
['type' => 'datetime'],
'[created] DATETIME',
'[created] DATETIME2',
],
[
'open_date',
['type' => 'datetime', 'null' => false, 'default' => '2016-12-07 23:04:00'],
'[open_date] DATETIME NOT NULL DEFAULT \'2016-12-07 23:04:00\'',
'[open_date] DATETIME2 NOT NULL DEFAULT \'2016-12-07 23:04:00\'',
],
[
'open_date',
['type' => 'datetime', 'null' => false, 'default' => 'current_timestamp'],
'[open_date] DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP',
'[open_date] DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP',
],
[
'open_date',
['type' => 'datetime', 'null' => false, 'default' => 'getdate()'],
'[open_date] DATETIME2 NOT NULL DEFAULT GETDATE()',
],
[
'open_date',
['type' => 'datetime', 'null' => false, 'default' => 'getutcdate()'],
'[open_date] DATETIME2 NOT NULL DEFAULT GETUTCDATE()',
],
[
'open_date',
['type' => 'datetime', 'null' => false, 'default' => 'sysdatetime()'],
'[open_date] DATETIME2 NOT NULL DEFAULT SYSDATETIME()',
],
[
'open_date',
['type' => 'datetime', 'null' => false, 'default' => 'sysutcdatetime()'],
'[open_date] DATETIME2 NOT NULL DEFAULT SYSUTCDATETIME()',
],
[
'open_date',
['type' => 'datetime', 'null' => false, 'default' => 'sysdatetimeoffset()'],
'[open_date] DATETIME2 NOT NULL DEFAULT SYSDATETIMEOFFSET()',
],
[
'null_date',
['type' => 'datetime', 'null' => true, 'default' => 'current_timestamp'],
'[null_date] DATETIME DEFAULT CURRENT_TIMESTAMP',
'[null_date] DATETIME2 DEFAULT CURRENT_TIMESTAMP',
],
[
'null_date',
['type' => 'datetime', 'null' => true],
'[null_date] DATETIME DEFAULT NULL',
'[null_date] DATETIME2 DEFAULT NULL',
],
// Date & Time
[
Expand All @@ -738,7 +813,7 @@ public static function columnSqlProvider()
[
'created',
['type' => 'timestamp', 'null' => true],
'[created] DATETIME DEFAULT NULL',
'[created] DATETIME2 DEFAULT NULL',
],
];
}
Expand Down Expand Up @@ -962,6 +1037,18 @@ public function testCreateSql()
'null' => false,
])
->addColumn('created', 'datetime')
->addColumn('created_with_default', [
'type' => 'datetime',
'default' => 'sysdatetime()',
])
->addColumn('created_with_precision', [
'type' => 'datetime',
'precision' => 3,
])
->addColumn('created_without_precision', [
'type' => 'datetime',
'precision' => 0,
])
->addConstraint('primary', [
'type' => 'primary',
'columns' => ['id'],
Expand All @@ -978,7 +1065,10 @@ public function testCreateSql()
[body] NVARCHAR(MAX),
[data] NVARCHAR(MAX),
[hash] NCHAR(40) COLLATE Latin1_General_BIN NOT NULL,
[created] DATETIME,
[created] DATETIME2,
[created_with_default] DATETIME2 DEFAULT SYSDATETIME(),
[created_with_precision] DATETIME2(3),
[created_without_precision] DATETIME2(0),
PRIMARY KEY ([id])
)
SQL;
Expand Down
18 changes: 18 additions & 0 deletions tests/TestCase/ORM/TableTest.php
Expand Up @@ -119,6 +119,24 @@ public function setUp(): void
'Users__updated' => 'timestampfractional',
'updated' => 'timestampfractional',
]);
} elseif (strpos($config['driver'], 'Sqlserver') !== false) {
$this->usersTypeMap = new TypeMap([
'Users.id' => 'integer',
'id' => 'integer',
'Users__id' => 'integer',
'Users.username' => 'string',
'Users__username' => 'string',
'username' => 'string',
'Users.password' => 'string',
'Users__password' => 'string',
'password' => 'string',
'Users.created' => 'datetimefractional',
'Users__created' => 'datetimefractional',
'created' => 'datetimefractional',
'Users.updated' => 'datetimefractional',
'Users__updated' => 'datetimefractional',
'updated' => 'datetimefractional',
]);
}

$this->articlesTypeMap = new TypeMap([
Expand Down

0 comments on commit f016356

Please sign in to comment.