2012-10-19 13:20:57 -02:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Data;
|
2015-09-15 10:49:41 +02:00
|
|
|
|
using System.Globalization;
|
2012-10-19 13:20:57 -02:00
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text;
|
2016-04-12 15:11:07 +02:00
|
|
|
|
using NPoco;
|
2012-10-19 13:20:57 -02:00
|
|
|
|
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
2012-12-07 13:48:38 -01:00
|
|
|
|
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
2013-12-18 17:22:00 +11:00
|
|
|
|
using Umbraco.Core.Persistence.Querying;
|
2012-10-19 13:20:57 -02:00
|
|
|
|
|
|
|
|
|
|
namespace Umbraco.Core.Persistence.SqlSyntax
|
|
|
|
|
|
{
|
2012-10-30 15:03:58 -01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Represents the Base Sql Syntax provider implementation.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// All Sql Syntax provider implementations should derive from this abstract class.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <typeparam name="TSyntax"></typeparam>
|
2013-03-09 10:43:34 -01:00
|
|
|
|
public abstract class SqlSyntaxProviderBase<TSyntax> : ISqlSyntaxProvider
|
2012-10-19 13:20:57 -02:00
|
|
|
|
where TSyntax : ISqlSyntaxProvider
|
|
|
|
|
|
{
|
2012-11-30 15:01:52 -01:00
|
|
|
|
protected SqlSyntaxProviderBase()
|
|
|
|
|
|
{
|
2012-12-19 15:23:05 -01:00
|
|
|
|
ClauseOrder = new List<Func<ColumnDefinition, string>>
|
2012-11-30 15:01:52 -01:00
|
|
|
|
{
|
|
|
|
|
|
FormatString,
|
|
|
|
|
|
FormatType,
|
|
|
|
|
|
FormatNullable,
|
2012-12-19 15:23:05 -01:00
|
|
|
|
FormatConstraint,
|
2012-11-30 15:01:52 -01:00
|
|
|
|
FormatDefaultValue,
|
|
|
|
|
|
FormatPrimaryKey,
|
|
|
|
|
|
FormatIdentity
|
|
|
|
|
|
};
|
2015-10-14 12:07:50 +02:00
|
|
|
|
|
|
|
|
|
|
//defaults for all providers
|
|
|
|
|
|
StringLengthColumnDefinitionFormat = StringLengthUnicodeColumnDefinitionFormat;
|
|
|
|
|
|
StringColumnDefinition = string.Format(StringLengthColumnDefinitionFormat, DefaultStringLength);
|
|
|
|
|
|
DecimalColumnDefinition = string.Format(DecimalColumnDefinitionFormat, DefaultDecimalPrecision, DefaultDecimalScale);
|
|
|
|
|
|
|
|
|
|
|
|
InitColumnTypeMap();
|
2012-11-30 15:01:52 -01:00
|
|
|
|
}
|
|
|
|
|
|
|
2014-09-24 13:51:16 +10:00
|
|
|
|
public string GetWildcardPlaceholder()
|
|
|
|
|
|
{
|
|
|
|
|
|
return "%";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-10-19 13:20:57 -02:00
|
|
|
|
public string StringLengthNonUnicodeColumnDefinitionFormat = "VARCHAR({0})";
|
|
|
|
|
|
public string StringLengthUnicodeColumnDefinitionFormat = "NVARCHAR({0})";
|
2015-10-14 12:07:50 +02:00
|
|
|
|
public string DecimalColumnDefinitionFormat = "DECIMAL({0},{1})";
|
2012-10-19 13:20:57 -02:00
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
public string DefaultValueFormat = "DEFAULT ({0})";
|
2012-10-19 13:20:57 -02:00
|
|
|
|
public int DefaultStringLength = 255;
|
2015-10-14 12:07:50 +02:00
|
|
|
|
public int DefaultDecimalPrecision = 20;
|
|
|
|
|
|
public int DefaultDecimalScale = 9;
|
2012-10-19 13:20:57 -02:00
|
|
|
|
|
|
|
|
|
|
//Set by Constructor
|
|
|
|
|
|
public string StringColumnDefinition;
|
|
|
|
|
|
public string StringLengthColumnDefinitionFormat;
|
|
|
|
|
|
|
|
|
|
|
|
public string AutoIncrementDefinition = "AUTOINCREMENT";
|
|
|
|
|
|
public string IntColumnDefinition = "INTEGER";
|
|
|
|
|
|
public string LongColumnDefinition = "BIGINT";
|
|
|
|
|
|
public string GuidColumnDefinition = "GUID";
|
|
|
|
|
|
public string BoolColumnDefinition = "BOOL";
|
|
|
|
|
|
public string RealColumnDefinition = "DOUBLE";
|
2015-10-14 12:07:50 +02:00
|
|
|
|
public string DecimalColumnDefinition;
|
2012-10-19 13:20:57 -02:00
|
|
|
|
public string BlobColumnDefinition = "BLOB";
|
|
|
|
|
|
public string DateTimeColumnDefinition = "DATETIME";
|
|
|
|
|
|
public string TimeColumnDefinition = "DATETIME";
|
|
|
|
|
|
|
2016-05-18 10:55:19 +02:00
|
|
|
|
protected IList<Func<ColumnDefinition, string>> ClauseOrder { get; }
|
2012-11-30 15:01:52 -01:00
|
|
|
|
|
2015-12-22 18:00:11 +01:00
|
|
|
|
protected DbTypes DbTypeMap = new DbTypes();
|
2012-10-19 13:20:57 -02:00
|
|
|
|
protected void InitColumnTypeMap()
|
|
|
|
|
|
{
|
|
|
|
|
|
DbTypeMap.Set<string>(DbType.String, StringColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<char>(DbType.StringFixedLength, StringColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<char?>(DbType.StringFixedLength, StringColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<char[]>(DbType.String, StringColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<bool>(DbType.Boolean, BoolColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<bool?>(DbType.Boolean, BoolColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<Guid>(DbType.Guid, GuidColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<Guid?>(DbType.Guid, GuidColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<DateTime>(DbType.DateTime, DateTimeColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<DateTime?>(DbType.DateTime, DateTimeColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<TimeSpan>(DbType.Time, TimeColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<TimeSpan?>(DbType.Time, TimeColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<DateTimeOffset>(DbType.Time, TimeColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<DateTimeOffset?>(DbType.Time, TimeColumnDefinition);
|
|
|
|
|
|
|
|
|
|
|
|
DbTypeMap.Set<byte>(DbType.Byte, IntColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<byte?>(DbType.Byte, IntColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<sbyte>(DbType.SByte, IntColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<sbyte?>(DbType.SByte, IntColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<short>(DbType.Int16, IntColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<short?>(DbType.Int16, IntColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<ushort>(DbType.UInt16, IntColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<ushort?>(DbType.UInt16, IntColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<int>(DbType.Int32, IntColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<int?>(DbType.Int32, IntColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<uint>(DbType.UInt32, IntColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<uint?>(DbType.UInt32, IntColumnDefinition);
|
|
|
|
|
|
|
|
|
|
|
|
DbTypeMap.Set<long>(DbType.Int64, LongColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<long?>(DbType.Int64, LongColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<ulong>(DbType.UInt64, LongColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<ulong?>(DbType.UInt64, LongColumnDefinition);
|
|
|
|
|
|
|
|
|
|
|
|
DbTypeMap.Set<float>(DbType.Single, RealColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<float?>(DbType.Single, RealColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<double>(DbType.Double, RealColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<double?>(DbType.Double, RealColumnDefinition);
|
|
|
|
|
|
|
|
|
|
|
|
DbTypeMap.Set<decimal>(DbType.Decimal, DecimalColumnDefinition);
|
|
|
|
|
|
DbTypeMap.Set<decimal?>(DbType.Decimal, DecimalColumnDefinition);
|
|
|
|
|
|
|
|
|
|
|
|
DbTypeMap.Set<byte[]>(DbType.Binary, BlobColumnDefinition);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2014-02-17 21:38:13 +11:00
|
|
|
|
public virtual string EscapeString(string val)
|
|
|
|
|
|
{
|
2016-04-12 15:11:07 +02:00
|
|
|
|
return NPocoDatabaseExtensions.EscapeAtSymbols(val.Replace("'", "''"));
|
2014-02-17 21:38:13 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
2014-09-24 13:51:16 +10:00
|
|
|
|
public virtual string GetStringColumnEqualComparison(string column, int paramIndex, TextColumnType columnType)
|
|
|
|
|
|
{
|
|
|
|
|
|
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
|
2016-11-03 10:31:44 +01:00
|
|
|
|
return $"upper({column}) = upper(@{paramIndex})";
|
2014-09-24 13:51:16 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public virtual string GetStringColumnWildcardComparison(string column, int paramIndex, TextColumnType columnType)
|
|
|
|
|
|
{
|
|
|
|
|
|
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
|
2016-11-03 10:31:44 +01:00
|
|
|
|
return $"upper({column}) LIKE upper(@{paramIndex})";
|
2014-09-24 13:51:16 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Obsolete("Use the overload with the parameter index instead")]
|
2013-12-18 17:22:00 +11:00
|
|
|
|
public virtual string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType)
|
|
|
|
|
|
{
|
|
|
|
|
|
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
|
2016-11-03 10:31:44 +01:00
|
|
|
|
return $"upper({column}) = '{value.ToUpper()}'";
|
2013-12-18 17:22:00 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
2014-09-24 13:51:16 +10:00
|
|
|
|
[Obsolete("Use the overload with the parameter index instead")]
|
2013-12-18 17:22:00 +11:00
|
|
|
|
public virtual string GetStringColumnStartsWithComparison(string column, string value, TextColumnType columnType)
|
|
|
|
|
|
{
|
|
|
|
|
|
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
|
2016-11-03 10:31:44 +01:00
|
|
|
|
return $"upper({column}) LIKE '{value.ToUpper()}%'";
|
2013-12-18 17:22:00 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
2014-09-24 13:51:16 +10:00
|
|
|
|
[Obsolete("Use the overload with the parameter index instead")]
|
2013-12-18 17:22:00 +11:00
|
|
|
|
public virtual string GetStringColumnEndsWithComparison(string column, string value, TextColumnType columnType)
|
|
|
|
|
|
{
|
|
|
|
|
|
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
|
2016-11-03 10:31:44 +01:00
|
|
|
|
return $"upper({column}) LIKE '%{value.ToUpper()}'";
|
2013-12-18 17:22:00 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
2014-09-24 13:51:16 +10:00
|
|
|
|
[Obsolete("Use the overload with the parameter index instead")]
|
2013-12-18 17:22:00 +11:00
|
|
|
|
public virtual string GetStringColumnContainsComparison(string column, string value, TextColumnType columnType)
|
|
|
|
|
|
{
|
|
|
|
|
|
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
|
2016-11-03 10:31:44 +01:00
|
|
|
|
return $"upper({column}) LIKE '%{value.ToUpper()}%'";
|
2013-12-18 17:22:00 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
2014-09-24 13:51:16 +10:00
|
|
|
|
[Obsolete("Use the overload with the parameter index instead")]
|
2013-12-19 18:33:25 +11:00
|
|
|
|
public virtual string GetStringColumnWildcardComparison(string column, string value, TextColumnType columnType)
|
|
|
|
|
|
{
|
|
|
|
|
|
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
|
2016-11-03 10:31:44 +01:00
|
|
|
|
return $"upper({column}) LIKE '{value.ToUpper()}'";
|
2013-12-19 18:33:25 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-18 10:55:19 +02:00
|
|
|
|
public virtual string GetConcat(params string[] args)
|
|
|
|
|
|
{
|
|
|
|
|
|
return "concat(" + string.Join(",", args) + ")";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-10-19 13:20:57 -02:00
|
|
|
|
public virtual string GetQuotedTableName(string tableName)
|
|
|
|
|
|
{
|
2016-11-03 10:31:44 +01:00
|
|
|
|
return $"\"{tableName}\"";
|
2012-10-19 13:20:57 -02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public virtual string GetQuotedColumnName(string columnName)
|
|
|
|
|
|
{
|
2016-11-03 10:31:44 +01:00
|
|
|
|
return $"\"{columnName}\"";
|
2012-10-19 13:20:57 -02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public virtual string GetQuotedName(string name)
|
|
|
|
|
|
{
|
2016-11-03 10:31:44 +01:00
|
|
|
|
return $"\"{name}\"";
|
2012-10-19 13:20:57 -02:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-10-19 19:07:17 -02:00
|
|
|
|
public virtual string GetQuotedValue(string value)
|
|
|
|
|
|
{
|
2016-11-03 10:31:44 +01:00
|
|
|
|
return $"'{value}'";
|
2012-10-19 19:07:17 -02:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-10-19 13:20:57 -02:00
|
|
|
|
public virtual string GetIndexType(IndexTypes indexTypes)
|
|
|
|
|
|
{
|
|
|
|
|
|
string indexType;
|
|
|
|
|
|
|
|
|
|
|
|
if (indexTypes == IndexTypes.Clustered)
|
|
|
|
|
|
{
|
|
|
|
|
|
indexType = "CLUSTERED";
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
indexType = indexTypes == IndexTypes.NonClustered
|
|
|
|
|
|
? "NONCLUSTERED"
|
|
|
|
|
|
: "UNIQUE NONCLUSTERED";
|
|
|
|
|
|
}
|
|
|
|
|
|
return indexType;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-10-19 19:07:17 -02:00
|
|
|
|
public virtual string GetSpecialDbType(SpecialDbTypes dbTypes)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (dbTypes == SpecialDbTypes.NCHAR)
|
|
|
|
|
|
{
|
|
|
|
|
|
return "NCHAR";
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (dbTypes == SpecialDbTypes.NTEXT)
|
|
|
|
|
|
return "NTEXT";
|
|
|
|
|
|
|
|
|
|
|
|
return "NVARCHAR";
|
|
|
|
|
|
}
|
2013-02-25 13:14:26 -01:00
|
|
|
|
|
2016-12-16 14:18:37 +01:00
|
|
|
|
public virtual bool? SupportsCaseInsensitiveQueries(IDatabase db)
|
2013-02-25 13:14:26 -01:00
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2012-10-19 19:07:17 -02:00
|
|
|
|
|
2016-12-16 14:18:37 +01:00
|
|
|
|
public virtual IEnumerable<string> GetTablesInSchema(IDatabase db)
|
2013-01-25 15:05:42 -01:00
|
|
|
|
{
|
|
|
|
|
|
return new List<string>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-12-16 14:18:37 +01:00
|
|
|
|
public virtual IEnumerable<ColumnInfo> GetColumnsInSchema(IDatabase db)
|
2013-01-25 15:05:42 -01:00
|
|
|
|
{
|
|
|
|
|
|
return new List<ColumnInfo>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-12-16 14:18:37 +01:00
|
|
|
|
public virtual IEnumerable<Tuple<string, string>> GetConstraintsPerTable(IDatabase db)
|
2013-01-25 15:05:42 -01:00
|
|
|
|
{
|
|
|
|
|
|
return new List<Tuple<string, string>>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-12-16 14:18:37 +01:00
|
|
|
|
public virtual IEnumerable<Tuple<string, string, string>> GetConstraintsPerColumn(IDatabase db)
|
2013-01-25 15:05:42 -01:00
|
|
|
|
{
|
|
|
|
|
|
return new List<Tuple<string, string, string>>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-12-16 14:18:37 +01:00
|
|
|
|
public abstract IEnumerable<Tuple<string, string, string, bool>> GetDefinedIndexes(IDatabase db);
|
2014-03-12 17:17:52 +11:00
|
|
|
|
|
2016-12-16 14:18:37 +01:00
|
|
|
|
public virtual bool DoesTableExist(IDatabase db, string tableName)
|
2012-10-19 13:20:57 -02:00
|
|
|
|
{
|
2012-12-19 15:23:05 -01:00
|
|
|
|
return false;
|
2012-10-19 19:07:17 -02:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-12-26 14:44:42 -01:00
|
|
|
|
public virtual bool SupportsClustered()
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-12-27 18:52:47 -01:00
|
|
|
|
public virtual bool SupportsIdentityInsert()
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-09-11 11:49:37 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// This is used ONLY if we need to format datetime without using SQL parameters (i.e. during migrations)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="date"></param>
|
|
|
|
|
|
/// <param name="includeTime"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// MSSQL has a DateTime standard that is unambiguous and works on all servers:
|
|
|
|
|
|
/// YYYYMMDD HH:mm:ss
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public virtual string FormatDateTime(DateTime date, bool includeTime = true)
|
|
|
|
|
|
{
|
2015-09-15 10:49:41 +02:00
|
|
|
|
// need CultureInfo.InvariantCulture because ":" here is the "time separator" and
|
|
|
|
|
|
// may be converted to something else in different cultures (eg "." in DK).
|
2015-09-15 10:52:32 +02:00
|
|
|
|
return date.ToString(includeTime ? "yyyyMMdd HH:mm:ss" : "yyyyMMdd", CultureInfo.InvariantCulture);
|
2015-09-11 11:49:37 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
public virtual string Format(TableDefinition table)
|
2012-10-19 19:07:17 -02:00
|
|
|
|
{
|
2012-12-20 11:36:20 -01:00
|
|
|
|
var statement = string.Format(CreateTable, GetQuotedTableName(table.Name), Format(table.Columns));
|
2012-10-19 13:20:57 -02:00
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
return statement;
|
2012-10-19 13:20:57 -02:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
public virtual List<string> Format(IEnumerable<IndexDefinition> indexes)
|
2012-10-19 13:20:57 -02:00
|
|
|
|
{
|
2012-12-19 15:23:05 -01:00
|
|
|
|
return indexes.Select(Format).ToList();
|
2012-10-19 13:20:57 -02:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
public virtual string Format(IndexDefinition index)
|
2012-10-30 15:03:58 -01:00
|
|
|
|
{
|
2016-11-03 10:31:44 +01:00
|
|
|
|
var name = string.IsNullOrEmpty(index.Name)
|
|
|
|
|
|
? $"IX_{index.TableName}_{index.ColumnName}"
|
|
|
|
|
|
: index.Name;
|
2012-10-30 15:03:58 -01:00
|
|
|
|
|
2016-11-03 10:31:44 +01:00
|
|
|
|
var columns = index.Columns.Any()
|
|
|
|
|
|
? string.Join(",", index.Columns.Select(x => GetQuotedColumnName(x.Name)))
|
|
|
|
|
|
: GetQuotedColumnName(index.ColumnName);
|
2012-10-30 15:03:58 -01:00
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
return string.Format(CreateIndex, GetIndexType(index.IndexType), " ", GetQuotedName(name),
|
|
|
|
|
|
GetQuotedTableName(index.TableName), columns);
|
2012-10-30 15:03:58 -01:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
public virtual List<string> Format(IEnumerable<ForeignKeyDefinition> foreignKeys)
|
2012-10-19 13:20:57 -02:00
|
|
|
|
{
|
2012-12-19 15:23:05 -01:00
|
|
|
|
return foreignKeys.Select(Format).ToList();
|
2012-10-19 13:20:57 -02:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
public virtual string Format(ForeignKeyDefinition foreignKey)
|
2012-10-19 13:20:57 -02:00
|
|
|
|
{
|
2016-11-03 10:31:44 +01:00
|
|
|
|
var constraintName = string.IsNullOrEmpty(foreignKey.Name)
|
|
|
|
|
|
? $"FK_{foreignKey.ForeignTable}_{foreignKey.PrimaryTable}_{foreignKey.PrimaryColumns.First()}"
|
|
|
|
|
|
: foreignKey.Name;
|
2012-12-19 15:23:05 -01:00
|
|
|
|
|
|
|
|
|
|
return string.Format(CreateForeignKeyConstraint,
|
|
|
|
|
|
GetQuotedTableName(foreignKey.ForeignTable),
|
|
|
|
|
|
GetQuotedName(constraintName),
|
|
|
|
|
|
GetQuotedColumnName(foreignKey.ForeignColumns.First()),
|
|
|
|
|
|
GetQuotedTableName(foreignKey.PrimaryTable),
|
|
|
|
|
|
GetQuotedColumnName(foreignKey.PrimaryColumns.First()),
|
2016-02-26 14:30:32 +00:00
|
|
|
|
FormatCascade("DELETE", foreignKey.OnDelete),
|
2012-12-20 11:36:20 -01:00
|
|
|
|
FormatCascade("UPDATE", foreignKey.OnUpdate));
|
2012-12-19 15:23:05 -01:00
|
|
|
|
}
|
2012-10-19 13:20:57 -02:00
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
public virtual string Format(IEnumerable<ColumnDefinition> columns)
|
|
|
|
|
|
{
|
|
|
|
|
|
var sb = new StringBuilder();
|
|
|
|
|
|
foreach (var column in columns)
|
|
|
|
|
|
{
|
2016-02-26 14:30:32 +00:00
|
|
|
|
sb.Append(Format(column) + ",\n");
|
2012-12-19 15:23:05 -01:00
|
|
|
|
}
|
|
|
|
|
|
return sb.ToString().TrimEnd(",\n");
|
2012-10-19 13:20:57 -02:00
|
|
|
|
}
|
2012-11-30 15:01:52 -01:00
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
public virtual string Format(ColumnDefinition column)
|
2012-11-30 15:01:52 -01:00
|
|
|
|
{
|
2016-11-03 10:31:44 +01:00
|
|
|
|
return string.Join(" ", ClauseOrder
|
|
|
|
|
|
.Select(action => action(column))
|
|
|
|
|
|
.Where(clause => string.IsNullOrEmpty(clause) == false));
|
2012-11-30 15:01:52 -01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-11-21 14:19:16 +01:00
|
|
|
|
public virtual string Format(ColumnDefinition column, string tableName, out IEnumerable<string> sqls)
|
|
|
|
|
|
{
|
|
|
|
|
|
var sql = new StringBuilder();
|
|
|
|
|
|
sql.Append(FormatString(column));
|
|
|
|
|
|
sql.Append(" ");
|
|
|
|
|
|
sql.Append(FormatType(column));
|
|
|
|
|
|
sql.Append(" ");
|
|
|
|
|
|
sql.Append("NULL"); // always nullable
|
|
|
|
|
|
sql.Append(" ");
|
|
|
|
|
|
sql.Append(FormatConstraint(column));
|
|
|
|
|
|
sql.Append(" ");
|
|
|
|
|
|
sql.Append(FormatDefaultValue(column));
|
|
|
|
|
|
sql.Append(" ");
|
|
|
|
|
|
sql.Append(FormatPrimaryKey(column));
|
|
|
|
|
|
sql.Append(" ");
|
|
|
|
|
|
sql.Append(FormatIdentity(column));
|
|
|
|
|
|
|
|
|
|
|
|
var isNullable = column.IsNullable;
|
|
|
|
|
|
|
|
|
|
|
|
//var constraint = FormatConstraint(column)?.TrimStart("CONSTRAINT ");
|
|
|
|
|
|
//var hasConstraint = !string.IsNullOrWhiteSpace(constraint);
|
|
|
|
|
|
|
|
|
|
|
|
//var defaultValue = FormatDefaultValue(column);
|
|
|
|
|
|
//var hasDefaultValue = !string.IsNullOrWhiteSpace(defaultValue);
|
|
|
|
|
|
|
|
|
|
|
|
if (isNullable /*&& !hasConstraint && !hasDefaultValue*/)
|
|
|
|
|
|
{
|
|
|
|
|
|
sqls = Enumerable.Empty<string>();
|
|
|
|
|
|
return sql.ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var msql = new List<string>();
|
|
|
|
|
|
sqls = msql;
|
|
|
|
|
|
|
|
|
|
|
|
var alterSql = new StringBuilder();
|
|
|
|
|
|
alterSql.Append(FormatString(column));
|
|
|
|
|
|
alterSql.Append(" ");
|
|
|
|
|
|
alterSql.Append(FormatType(column));
|
|
|
|
|
|
alterSql.Append(" ");
|
|
|
|
|
|
alterSql.Append(FormatNullable(column));
|
|
|
|
|
|
//alterSql.Append(" ");
|
|
|
|
|
|
//alterSql.Append(FormatPrimaryKey(column));
|
|
|
|
|
|
//alterSql.Append(" ");
|
|
|
|
|
|
//alterSql.Append(FormatIdentity(column));
|
|
|
|
|
|
msql.Add(string.Format(AlterColumn, tableName, alterSql));
|
|
|
|
|
|
|
|
|
|
|
|
//if (hasConstraint)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// var dropConstraintSql = string.Format(DeleteConstraint, tableName, constraint);
|
|
|
|
|
|
// msql.Add(dropConstraintSql);
|
|
|
|
|
|
// var constraintType = hasDefaultValue ? defaultValue : "";
|
|
|
|
|
|
// var createConstraintSql = string.Format(CreateConstraint, tableName, constraint, constraintType, FormatString(column));
|
|
|
|
|
|
// msql.Add(createConstraintSql);
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
return sql.ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-12-20 11:36:20 -01:00
|
|
|
|
public virtual string FormatPrimaryKey(TableDefinition table)
|
|
|
|
|
|
{
|
|
|
|
|
|
var columnDefinition = table.Columns.FirstOrDefault(x => x.IsPrimaryKey);
|
|
|
|
|
|
if (columnDefinition == null)
|
|
|
|
|
|
return string.Empty;
|
|
|
|
|
|
|
2016-11-03 10:31:44 +01:00
|
|
|
|
var constraintName = string.IsNullOrEmpty(columnDefinition.PrimaryKeyName)
|
|
|
|
|
|
? $"PK_{table.Name}"
|
|
|
|
|
|
: columnDefinition.PrimaryKeyName;
|
2012-12-20 11:36:20 -01:00
|
|
|
|
|
2016-11-03 10:31:44 +01:00
|
|
|
|
var columns = string.IsNullOrEmpty(columnDefinition.PrimaryKeyColumns)
|
|
|
|
|
|
? GetQuotedColumnName(columnDefinition.Name)
|
|
|
|
|
|
: string.Join(", ", columnDefinition.PrimaryKeyColumns
|
|
|
|
|
|
.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
|
|
|
|
|
|
.Select(GetQuotedColumnName));
|
2012-12-20 11:36:20 -01:00
|
|
|
|
|
2016-11-03 10:31:44 +01:00
|
|
|
|
var primaryKeyPart = string.Concat("PRIMARY KEY", columnDefinition.IsIndexed ? " CLUSTERED" : " NONCLUSTERED");
|
2012-12-20 11:36:20 -01:00
|
|
|
|
|
|
|
|
|
|
return string.Format(CreateConstraint,
|
|
|
|
|
|
GetQuotedTableName(table.Name),
|
|
|
|
|
|
GetQuotedName(constraintName),
|
|
|
|
|
|
primaryKeyPart,
|
|
|
|
|
|
columns);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public virtual string FormatColumnRename(string tableName, string oldName, string newName)
|
|
|
|
|
|
{
|
|
|
|
|
|
return string.Format(RenameColumn,
|
|
|
|
|
|
GetQuotedTableName(tableName),
|
|
|
|
|
|
GetQuotedColumnName(oldName),
|
|
|
|
|
|
GetQuotedColumnName(newName));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public virtual string FormatTableRename(string oldName, string newName)
|
|
|
|
|
|
{
|
|
|
|
|
|
return string.Format(RenameTable, GetQuotedTableName(oldName), GetQuotedTableName(newName));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual string FormatCascade(string onWhat, Rule rule)
|
|
|
|
|
|
{
|
2016-11-03 10:31:44 +01:00
|
|
|
|
var action = "NO ACTION";
|
2012-12-20 11:36:20 -01:00
|
|
|
|
switch (rule)
|
|
|
|
|
|
{
|
|
|
|
|
|
case Rule.None:
|
|
|
|
|
|
return "";
|
|
|
|
|
|
case Rule.Cascade:
|
|
|
|
|
|
action = "CASCADE";
|
|
|
|
|
|
break;
|
|
|
|
|
|
case Rule.SetNull:
|
|
|
|
|
|
action = "SET NULL";
|
|
|
|
|
|
break;
|
|
|
|
|
|
case Rule.SetDefault:
|
|
|
|
|
|
action = "SET DEFAULT";
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-11-03 10:31:44 +01:00
|
|
|
|
return $" ON {onWhat} {action}";
|
2012-12-20 11:36:20 -01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual string FormatString(ColumnDefinition column)
|
2012-11-30 15:01:52 -01:00
|
|
|
|
{
|
|
|
|
|
|
return GetQuotedColumnName(column.Name);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
protected virtual string FormatType(ColumnDefinition column)
|
2012-11-30 15:01:52 -01:00
|
|
|
|
{
|
2012-12-19 15:23:05 -01:00
|
|
|
|
if (column.Type.HasValue == false && string.IsNullOrEmpty(column.CustomType) == false)
|
2012-11-30 15:01:52 -01:00
|
|
|
|
return column.CustomType;
|
|
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
if (column.HasSpecialDbType)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (column.Size != default(int))
|
|
|
|
|
|
{
|
2016-11-03 10:31:44 +01:00
|
|
|
|
return $"{GetSpecialDbType(column.DbType)}({column.Size})";
|
2012-12-19 15:23:05 -01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return GetSpecialDbType(column.DbType);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-11-03 10:31:44 +01:00
|
|
|
|
var type = column.Type.HasValue
|
2012-12-19 15:23:05 -01:00
|
|
|
|
? DbTypeMap.ColumnDbTypeMap.First(x => x.Value == column.Type.Value).Key
|
|
|
|
|
|
: column.PropertyType;
|
|
|
|
|
|
|
2016-02-26 14:30:32 +00:00
|
|
|
|
if (type == typeof(string))
|
2012-12-19 15:23:05 -01:00
|
|
|
|
{
|
|
|
|
|
|
var valueOrDefault = column.Size != default(int) ? column.Size : DefaultStringLength;
|
|
|
|
|
|
return string.Format(StringLengthColumnDefinitionFormat, valueOrDefault);
|
|
|
|
|
|
}
|
2012-11-30 15:01:52 -01:00
|
|
|
|
|
2015-10-14 12:07:50 +02:00
|
|
|
|
if (type == typeof(decimal))
|
|
|
|
|
|
{
|
|
|
|
|
|
var precision = column.Size != default(int) ? column.Size : DefaultDecimalPrecision;
|
|
|
|
|
|
var scale = column.Precision != default(int) ? column.Precision : DefaultDecimalScale;
|
|
|
|
|
|
return string.Format(DecimalColumnDefinitionFormat, precision, scale);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-11-03 10:31:44 +01:00
|
|
|
|
var definition = DbTypeMap.ColumnTypeMap.First(x => x.Key == type).Value;
|
|
|
|
|
|
var dbTypeDefinition = column.Size != default(int)
|
|
|
|
|
|
? $"{definition}({column.Size})"
|
|
|
|
|
|
: definition;
|
2012-11-30 15:01:52 -01:00
|
|
|
|
//NOTE Percision is left out
|
|
|
|
|
|
return dbTypeDefinition;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
protected virtual string FormatNullable(ColumnDefinition column)
|
|
|
|
|
|
{
|
|
|
|
|
|
return column.IsNullable ? "NULL" : "NOT NULL";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual string FormatConstraint(ColumnDefinition column)
|
2012-11-30 15:01:52 -01:00
|
|
|
|
{
|
2012-12-19 15:23:05 -01:00
|
|
|
|
if (string.IsNullOrEmpty(column.ConstraintName) && column.DefaultValue == null)
|
|
|
|
|
|
return string.Empty;
|
|
|
|
|
|
|
2016-11-03 10:31:44 +01:00
|
|
|
|
return
|
|
|
|
|
|
$"CONSTRAINT {(string.IsNullOrEmpty(column.ConstraintName) ? GetQuotedName($"DF_{column.TableName}_{column.Name}") : column.ConstraintName)}";
|
2012-11-30 15:01:52 -01:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
protected virtual string FormatDefaultValue(ColumnDefinition column)
|
2012-11-30 15:01:52 -01:00
|
|
|
|
{
|
|
|
|
|
|
if (column.DefaultValue == null)
|
|
|
|
|
|
return string.Empty;
|
|
|
|
|
|
|
2015-09-14 10:33:37 +02:00
|
|
|
|
//hack - probably not needed with latest changes
|
2013-01-02 11:49:57 -01:00
|
|
|
|
if (column.DefaultValue.ToString().ToLower().Equals("getdate()".ToLower()))
|
2015-09-14 10:33:37 +02:00
|
|
|
|
column.DefaultValue = SystemMethods.CurrentDateTime;
|
2013-01-02 11:49:57 -01:00
|
|
|
|
|
|
|
|
|
|
// see if this is for a system method
|
|
|
|
|
|
if (column.DefaultValue is SystemMethods)
|
2012-11-30 15:01:52 -01:00
|
|
|
|
{
|
2016-11-03 10:31:44 +01:00
|
|
|
|
var method = FormatSystemMethods((SystemMethods)column.DefaultValue);
|
|
|
|
|
|
return string.IsNullOrEmpty(method) ? string.Empty : string.Format(DefaultValueFormat, method);
|
2012-11-30 15:01:52 -01:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
return string.Format(DefaultValueFormat, GetQuotedValue(column.DefaultValue.ToString()));
|
2012-11-30 15:01:52 -01:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
protected virtual string FormatPrimaryKey(ColumnDefinition column)
|
2012-11-30 15:01:52 -01:00
|
|
|
|
{
|
|
|
|
|
|
return string.Empty;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected abstract string FormatSystemMethods(SystemMethods systemMethod);
|
|
|
|
|
|
|
2012-12-19 15:23:05 -01:00
|
|
|
|
protected abstract string FormatIdentity(ColumnDefinition column);
|
2012-11-30 15:01:52 -01:00
|
|
|
|
|
2017-09-22 18:48:58 +02:00
|
|
|
|
public abstract Sql<ISqlContext> SelectTop(Sql<ISqlContext> sql, int top);
|
2016-08-02 12:11:35 +02:00
|
|
|
|
|
2017-09-22 18:48:58 +02:00
|
|
|
|
public virtual string DeleteDefaultConstraint => throw new NotSupportedException("Default constraints are not supported");
|
2012-12-20 11:36:20 -01:00
|
|
|
|
|
2016-11-03 10:31:44 +01:00
|
|
|
|
public virtual string CreateTable => "CREATE TABLE {0} ({1})";
|
|
|
|
|
|
public virtual string DropTable => "DROP TABLE {0}";
|
2012-11-30 15:01:52 -01:00
|
|
|
|
|
2018-05-18 17:19:48 +02:00
|
|
|
|
public virtual string AddColumn => "ALTER TABLE {0} ADD {1}";
|
2016-11-03 10:31:44 +01:00
|
|
|
|
public virtual string DropColumn => "ALTER TABLE {0} DROP COLUMN {1}";
|
|
|
|
|
|
public virtual string AlterColumn => "ALTER TABLE {0} ALTER COLUMN {1}";
|
|
|
|
|
|
public virtual string RenameColumn => "ALTER TABLE {0} RENAME COLUMN {1} TO {2}";
|
2012-11-30 15:01:52 -01:00
|
|
|
|
|
2016-11-03 10:31:44 +01:00
|
|
|
|
public virtual string RenameTable => "RENAME TABLE {0} TO {1}";
|
2012-11-30 15:01:52 -01:00
|
|
|
|
|
2016-11-03 10:31:44 +01:00
|
|
|
|
public virtual string CreateSchema => "CREATE SCHEMA {0}";
|
|
|
|
|
|
public virtual string AlterSchema => "ALTER SCHEMA {0} TRANSFER {1}.{2}";
|
|
|
|
|
|
public virtual string DropSchema => "DROP SCHEMA {0}";
|
2012-11-30 15:01:52 -01:00
|
|
|
|
|
2016-11-03 10:31:44 +01:00
|
|
|
|
public virtual string CreateIndex => "CREATE {0}{1}INDEX {2} ON {3} ({4})";
|
|
|
|
|
|
public virtual string DropIndex => "DROP INDEX {0}";
|
2012-11-30 15:01:52 -01:00
|
|
|
|
|
2016-11-03 10:31:44 +01:00
|
|
|
|
public virtual string InsertData => "INSERT INTO {0} ({1}) VALUES ({2})";
|
|
|
|
|
|
public virtual string UpdateData => "UPDATE {0} SET {1} WHERE {2}";
|
|
|
|
|
|
public virtual string DeleteData => "DELETE FROM {0} WHERE {1}";
|
|
|
|
|
|
public virtual string TruncateTable => "TRUNCATE TABLE {0}";
|
2012-11-30 15:01:52 -01:00
|
|
|
|
|
2016-11-03 10:31:44 +01:00
|
|
|
|
public virtual string CreateConstraint => "ALTER TABLE {0} ADD CONSTRAINT {1} {2} ({3})";
|
|
|
|
|
|
public virtual string DeleteConstraint => "ALTER TABLE {0} DROP CONSTRAINT {1}";
|
|
|
|
|
|
public virtual string CreateForeignKeyConstraint => "ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4}){5}{6}";
|
2016-02-26 14:30:32 +00:00
|
|
|
|
|
2016-11-03 10:31:44 +01:00
|
|
|
|
public virtual string ConvertIntegerToOrderableString => "REPLACE(STR({0}, 8), SPACE(1), '0')";
|
|
|
|
|
|
public virtual string ConvertDateToOrderableString => "CONVERT(nvarchar, {0}, 102)";
|
|
|
|
|
|
public virtual string ConvertDecimalToOrderableString => "REPLACE(STR({0}, 20, 9), SPACE(1), '0')";
|
2012-10-19 13:20:57 -02:00
|
|
|
|
}
|
2017-07-20 11:21:28 +02:00
|
|
|
|
}
|