2018-06-29 19:52:40 +02:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using Umbraco.Core.Persistence.DatabaseModelDefinitions ;
namespace Umbraco.Core.Persistence.SqlSyntax
{
/// <summary>
/// Represents an SqlSyntaxProvider for Sql Server.
/// </summary>
2018-11-22 14:05:51 +00:00
[SqlSyntaxProvider(Constants.DatabaseProviders.SqlServer)]
2018-06-29 19:52:40 +02:00
public class SqlServerSyntaxProvider : MicrosoftSqlSyntaxProviderBase < SqlServerSyntaxProvider >
{
2018-11-22 14:05:51 +00:00
/// <summary>
/// Gets/sets the version of the current SQL server instance
/// </summary>
internal SqlServerVersionName GetVersionName ( Database database )
2018-06-29 19:52:40 +02:00
{
2018-11-22 14:05:51 +00:00
if ( _versionName . HasValue )
return _versionName . Value ;
2018-06-29 19:52:40 +02:00
try
{
2018-11-22 14:05:51 +00:00
var version = database . ExecuteScalar < string >( "SELECT SERVERPROPERTY('productversion')" );
var firstPart = version . Split ( '.' )[ 0 ];
switch ( firstPart )
2018-09-19 18:51:27 +02:00
{
2018-11-22 14:05:51 +00:00
case "13" :
_versionName = SqlServerVersionName . V2016 ;
break ;
case "12" :
_versionName = SqlServerVersionName . V2014 ;
break ;
case "11" :
_versionName = SqlServerVersionName . V2012 ;
break ;
case "10" :
_versionName = SqlServerVersionName . V2008 ;
break ;
case "9" :
_versionName = SqlServerVersionName . V2005 ;
break ;
case "8" :
_versionName = SqlServerVersionName . V2000 ;
break ;
case "7" :
_versionName = SqlServerVersionName . V7 ;
break ;
default :
_versionName = SqlServerVersionName . Other ;
break ;
2018-09-19 18:51:27 +02:00
}
}
2018-11-22 14:05:51 +00:00
catch ( Exception )
{
_versionName = SqlServerVersionName . Invalid ;
}
return _versionName . Value ;
2018-09-19 18:51:27 +02:00
}
2018-11-22 14:05:51 +00:00
private SqlServerVersionName ? _versionName ;
2018-06-29 19:52:40 +02:00
/// <summary>
/// SQL Server stores default values assigned to columns as constraints, it also stores them with named values, this is the only
/// server type that does this, therefore this method doesn't exist on any other syntax provider
/// </summary>
/// <returns></returns>
2018-11-22 14:05:51 +00:00
public IEnumerable < Tuple < string , string , string , string >> GetDefaultConstraintsPerColumn ( Database db )
2018-06-29 19:52:40 +02:00
{
2018-08-26 23:13:08 +02:00
var items = db . Fetch < dynamic >( "SELECT TableName = t.Name, ColumnName = c.Name, dc.Name, dc.[Definition] FROM sys.tables t INNER JOIN sys.default_constraints dc ON t.object_id = dc.parent_object_id INNER JOIN sys.columns c ON dc.parent_object_id = c.object_id AND c.column_id = dc.parent_column_id INNER JOIN sys.schemas as s on t.[schema_id] = s.[schema_id] WHERE s.name = (SELECT SCHEMA_NAME())" );
2018-06-29 19:52:40 +02:00
return items . Select ( x => new Tuple < string , string , string , string >( x . TableName , x . ColumnName , x . Name , x . Definition ));
}
2018-11-22 14:05:51 +00:00
public override IEnumerable < string > GetTablesInSchema ( Database db )
2018-06-29 19:52:40 +02:00
{
2018-08-26 23:13:08 +02:00
var items = db . Fetch < dynamic >( "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())" );
2018-06-29 19:52:40 +02:00
return items . Select ( x => x . TABLE_NAME ). Cast < string >(). ToList ();
}
2018-11-22 14:05:51 +00:00
public override IEnumerable < ColumnInfo > GetColumnsInSchema ( Database db )
2018-06-29 19:52:40 +02:00
{
2018-08-26 23:13:08 +02:00
var items = db . Fetch < dynamic >( "SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())" );
2018-06-29 19:52:40 +02:00
return
items . Select (
item =>
new ColumnInfo ( item . TABLE_NAME , item . COLUMN_NAME , item . ORDINAL_POSITION , item . COLUMN_DEFAULT ,
item . IS_NULLABLE , item . DATA_TYPE )). ToList ();
}
2018-08-20 15:16:58 +10:00
/// <inheritdoc />
2018-11-22 14:05:51 +00:00
public override IEnumerable < Tuple < string , string >> GetConstraintsPerTable ( Database db )
2018-06-29 19:52:40 +02:00
{
var items =
db . Fetch < dynamic >(
2018-08-26 23:13:08 +02:00
"SELECT TABLE_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())" );
2018-06-29 19:52:40 +02:00
return items . Select ( item => new Tuple < string , string >( item . TABLE_NAME , item . CONSTRAINT_NAME )). ToList ();
}
2018-08-20 15:16:58 +10:00
/// <inheritdoc />
2018-11-22 14:05:51 +00:00
public override IEnumerable < Tuple < string , string , string >> GetConstraintsPerColumn ( Database db )
2018-06-29 19:52:40 +02:00
{
var items =
db . Fetch < dynamic >(
2018-08-26 23:13:08 +02:00
"SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())" );
2018-06-29 19:52:40 +02:00
return items . Select ( item => new Tuple < string , string , string >( item . TABLE_NAME , item . COLUMN_NAME , item . CONSTRAINT_NAME )). ToList ();
}
2018-08-20 15:16:58 +10:00
/// <inheritdoc />
2018-11-22 14:05:51 +00:00
public override IEnumerable < Tuple < string , string , string , bool >> GetDefinedIndexes ( Database db )
2018-06-29 19:52:40 +02:00
{
var items =
db . Fetch < dynamic >(
@"select T.name as TABLE_NAME, I.name as INDEX_NAME, AC.Name as COLUMN_NAME,
CASE WHEN I.is_unique_constraint = 1 OR I.is_unique = 1 THEN 1 ELSE 0 END AS [UNIQUE]
2018-11-22 14:05:51 +00:00
from sys.tables as T inner join sys.indexes as I on T.[object_id] = I.[object_id]
inner join sys.index_columns as IC on IC.[object_id] = I.[object_id] and IC.[index_id] = I.[index_id]
inner join sys.all_columns as AC on IC.[object_id] = AC.[object_id] and IC.[column_id] = AC.[column_id]
2018-08-26 23:13:08 +02:00
inner join sys.schemas as S on T.[schema_id] = S.[schema_id]
WHERE S.name = (SELECT SCHEMA_NAME()) AND I.is_primary_key = 0
2018-06-29 19:52:40 +02:00
order by T.name, I.name" );
return items . Select ( item => new Tuple < string , string , string , bool >( item . TABLE_NAME , item . INDEX_NAME , item . COLUMN_NAME ,
item . UNIQUE == 1 )). ToList ();
}
2018-11-22 14:05:51 +00:00
public override bool DoesTableExist ( Database db , string tableName )
2018-06-29 19:52:40 +02:00
{
var result =
2018-08-26 23:13:08 +02:00
db . ExecuteScalar < long >( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @TableName AND TABLE_SCHEMA = (SELECT SCHEMA_NAME())" ,
2018-06-29 19:52:40 +02:00
new { TableName = tableName });
return result > 0 ;
}
public override string FormatColumnRename ( string tableName , string oldName , string newName )
{
return string . Format ( RenameColumn , tableName , oldName , newName );
}
public override string FormatTableRename ( string oldName , string newName )
{
return string . Format ( RenameTable , oldName , newName );
}
protected override string FormatIdentity ( ColumnDefinition column )
{
return column . IsIdentity ? GetIdentityString ( column ) : string . Empty ;
}
2018-11-22 14:05:51 +00:00
public override Sql SelectTop ( Sql sql , int top )
2018-06-29 19:52:40 +02:00
{
2018-11-22 14:05:51 +00:00
return new Sql ( sql . SQL . Insert ( sql . SQL . IndexOf ( ' ' ), " TOP " + top ), sql . Arguments );
2018-06-29 19:52:40 +02:00
}
private static string GetIdentityString ( ColumnDefinition column )
{
return "IDENTITY(1,1)" ;
}
protected override string FormatSystemMethods ( SystemMethods systemMethod )
{
switch ( systemMethod )
{
case SystemMethods . NewGuid :
return "NEWID()" ;
case SystemMethods . CurrentDateTime :
return "GETDATE()" ;
//case SystemMethods.NewSequentialId:
// return "NEWSEQUENTIALID()";
//case SystemMethods.CurrentUTCDateTime:
// return "GETUTCDATE()";
}
return null ;
}
2018-11-22 14:05:51 +00:00
public override string DeleteDefaultConstraint
{
get { return "ALTER TABLE [{0}] DROP CONSTRAINT [DF_{0}_{1}]" ; }
}
2018-06-29 19:52:40 +02:00
2018-11-22 14:05:51 +00:00
public override string DropIndex { get { return "DROP INDEX {0} ON {1}" ; } }
public override string RenameColumn { get { return "sp_rename '{0}.{1}', '{2}', 'COLUMN'" ; } }
2018-06-29 19:52:40 +02:00
}
}