using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using Umbraco.Core.Persistence.DatabaseAnnotations; using Umbraco.Core.Persistence.DatabaseModelDefinitions; namespace Umbraco.Core.Persistence.SqlSyntax { /// /// Represents the Base Sql Syntax provider implementation. /// /// /// All Sql Syntax provider implementations should derive from this abstract class. /// /// internal abstract class SqlSyntaxProviderBase : ISqlSyntaxProvider where TSyntax : ISqlSyntaxProvider { protected SqlSyntaxProviderBase() { ClauseOrder = new List> { FormatString, FormatType, FormatNullable, FormatConstraint, FormatDefaultValue, FormatPrimaryKey, FormatIdentity }; } public string StringLengthNonUnicodeColumnDefinitionFormat = "VARCHAR({0})"; public string StringLengthUnicodeColumnDefinitionFormat = "NVARCHAR({0})"; public string DefaultValueFormat = "DEFAULT ({0})"; public int DefaultStringLength = 255; //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"; public string DecimalColumnDefinition = "DECIMAL"; public string BlobColumnDefinition = "BLOB"; public string DateTimeColumnDefinition = "DATETIME"; public string TimeColumnDefinition = "DATETIME"; protected IList> ClauseOrder { get; set; } protected DbTypes DbTypeMap = new DbTypes(); protected void InitColumnTypeMap() { DbTypeMap.Set(DbType.String, StringColumnDefinition); DbTypeMap.Set(DbType.StringFixedLength, StringColumnDefinition); DbTypeMap.Set(DbType.StringFixedLength, StringColumnDefinition); DbTypeMap.Set(DbType.String, StringColumnDefinition); DbTypeMap.Set(DbType.Boolean, BoolColumnDefinition); DbTypeMap.Set(DbType.Boolean, BoolColumnDefinition); DbTypeMap.Set(DbType.Guid, GuidColumnDefinition); DbTypeMap.Set(DbType.Guid, GuidColumnDefinition); DbTypeMap.Set(DbType.DateTime, DateTimeColumnDefinition); DbTypeMap.Set(DbType.DateTime, DateTimeColumnDefinition); DbTypeMap.Set(DbType.Time, TimeColumnDefinition); DbTypeMap.Set(DbType.Time, TimeColumnDefinition); DbTypeMap.Set(DbType.Time, TimeColumnDefinition); DbTypeMap.Set(DbType.Time, TimeColumnDefinition); DbTypeMap.Set(DbType.Byte, IntColumnDefinition); DbTypeMap.Set(DbType.Byte, IntColumnDefinition); DbTypeMap.Set(DbType.SByte, IntColumnDefinition); DbTypeMap.Set(DbType.SByte, IntColumnDefinition); DbTypeMap.Set(DbType.Int16, IntColumnDefinition); DbTypeMap.Set(DbType.Int16, IntColumnDefinition); DbTypeMap.Set(DbType.UInt16, IntColumnDefinition); DbTypeMap.Set(DbType.UInt16, IntColumnDefinition); DbTypeMap.Set(DbType.Int32, IntColumnDefinition); DbTypeMap.Set(DbType.Int32, IntColumnDefinition); DbTypeMap.Set(DbType.UInt32, IntColumnDefinition); DbTypeMap.Set(DbType.UInt32, IntColumnDefinition); DbTypeMap.Set(DbType.Int64, LongColumnDefinition); DbTypeMap.Set(DbType.Int64, LongColumnDefinition); DbTypeMap.Set(DbType.UInt64, LongColumnDefinition); DbTypeMap.Set(DbType.UInt64, LongColumnDefinition); DbTypeMap.Set(DbType.Single, RealColumnDefinition); DbTypeMap.Set(DbType.Single, RealColumnDefinition); DbTypeMap.Set(DbType.Double, RealColumnDefinition); DbTypeMap.Set(DbType.Double, RealColumnDefinition); DbTypeMap.Set(DbType.Decimal, DecimalColumnDefinition); DbTypeMap.Set(DbType.Decimal, DecimalColumnDefinition); DbTypeMap.Set(DbType.Binary, BlobColumnDefinition); } public virtual string GetQuotedTableName(string tableName) { return string.Format("\"{0}\"", tableName); } public virtual string GetQuotedColumnName(string columnName) { return string.Format("\"{0}\"", columnName); } public virtual string GetQuotedName(string name) { return string.Format("\"{0}\"", name); } public virtual string GetQuotedValue(string value) { return string.Format("'{0}'", value); } public virtual string GetIndexType(IndexTypes indexTypes) { string indexType; if (indexTypes == IndexTypes.Clustered) { indexType = "CLUSTERED"; } else { indexType = indexTypes == IndexTypes.NonClustered ? "NONCLUSTERED" : "UNIQUE NONCLUSTERED"; } return indexType; } public virtual string GetSpecialDbType(SpecialDbTypes dbTypes) { if (dbTypes == SpecialDbTypes.NCHAR) { return "NCHAR"; } else if (dbTypes == SpecialDbTypes.NTEXT) return "NTEXT"; return "NVARCHAR"; } public virtual bool DoesTableExist(Database db, string tableName) { return false; } public virtual string Format(TableDefinition table) { var statement = string.Format(CreateTable, table.Name, Format(table.Columns)); return statement; } public virtual string FormatPrimaryKey(TableDefinition table) { var columnDefinition = table.Columns.FirstOrDefault(x => x.IsPrimaryKey); if (columnDefinition == null) return string.Empty; string constraintName = string.IsNullOrEmpty(columnDefinition.PrimaryKeyName) ? string.Format("PK_{0}", table.Name) : columnDefinition.PrimaryKeyName; string columns = string.IsNullOrEmpty(columnDefinition.PrimaryKeyColumns) ? GetQuotedColumnName(columnDefinition.Name) : columnDefinition.PrimaryKeyColumns; string primaryKeyPart = string.Concat("PRIMARY KEY", columnDefinition.IsIndexed ? " CLUSTERED" : " NONCLUSTERED"); return string.Format(CreateConstraint, GetQuotedTableName(table.Name), GetQuotedName(constraintName), primaryKeyPart, columns); } public virtual List Format(IEnumerable indexes) { return indexes.Select(Format).ToList(); } public virtual string Format(IndexDefinition index) { string name = string.IsNullOrEmpty(index.Name) ? string.Format("IX_{0}_{1}", index.TableName, index.ColumnName) : index.Name; string columns = index.Columns.Any() ? string.Join(",", index.Columns.Select(x => GetQuotedColumnName(x.Name))) : GetQuotedColumnName(index.ColumnName); return string.Format(CreateIndex, GetIndexType(index.IndexType), " ", GetQuotedName(name), GetQuotedTableName(index.TableName), columns); } public virtual List Format(IEnumerable foreignKeys) { return foreignKeys.Select(Format).ToList(); } public virtual string Format(ForeignKeyDefinition foreignKey) { string constraintName = string.IsNullOrEmpty(foreignKey.Name) ? string.Format("FK_{0}_{1}_{2}", foreignKey.ForeignTable, foreignKey.PrimaryTable, foreignKey.PrimaryColumns.First()) : foreignKey.Name; return string.Format(CreateForeignKeyConstraint, GetQuotedTableName(foreignKey.ForeignTable), GetQuotedName(constraintName), GetQuotedColumnName(foreignKey.ForeignColumns.First()), GetQuotedTableName(foreignKey.PrimaryTable), GetQuotedColumnName(foreignKey.PrimaryColumns.First()), "", ""); } public virtual string Format(IEnumerable columns) { var sb = new StringBuilder(); foreach (var column in columns) { sb.Append(Format(column) +",\n"); } return sb.ToString().TrimEnd(",\n"); } public virtual string Format(ColumnDefinition column) { var clauses = new List(); foreach (var action in ClauseOrder) { string clause = action(column); if (!string.IsNullOrEmpty(clause)) clauses.Add(clause); } return string.Join(" ", clauses.ToArray()); } public virtual string FormatString(ColumnDefinition column) { return GetQuotedColumnName(column.Name); } protected virtual string FormatType(ColumnDefinition column) { if (column.Type.HasValue == false && string.IsNullOrEmpty(column.CustomType) == false) return column.CustomType; if (column.HasSpecialDbType) { if (column.Size != default(int)) { return string.Format("{0}({1})", GetSpecialDbType(column.DbType), column.Size); } return GetSpecialDbType(column.DbType); } Type type = column.Type.HasValue ? DbTypeMap.ColumnDbTypeMap.First(x => x.Value == column.Type.Value).Key : column.PropertyType; if (type == typeof (string)) { var valueOrDefault = column.Size != default(int) ? column.Size : DefaultStringLength; return string.Format(StringLengthColumnDefinitionFormat, valueOrDefault); } string definition = DbTypeMap.ColumnTypeMap.First(x => x.Key == type).Value; string dbTypeDefinition = column.Size != default(int) ? string.Format("{0}({1})", definition, column.Size) : definition; //NOTE Percision is left out return dbTypeDefinition; } protected virtual string FormatNullable(ColumnDefinition column) { return column.IsNullable ? "NULL" : "NOT NULL"; } protected virtual string FormatConstraint(ColumnDefinition column) { if (string.IsNullOrEmpty(column.ConstraintName) && column.DefaultValue == null) return string.Empty; return string.Format("CONSTRAINT {0}", string.IsNullOrEmpty(column.ConstraintName) ? GetQuotedName(string.Format("DF_{0}_{1}", column.TableName, column.Name)) : column.ConstraintName); } protected virtual string FormatDefaultValue(ColumnDefinition column) { if (column.DefaultValue == null) return string.Empty; // see if this is for a system method if (column.DefaultValue is SystemMethods) { string method = FormatSystemMethods((SystemMethods)column.DefaultValue); if (string.IsNullOrEmpty(method)) return string.Empty; return string.Format(DefaultValueFormat, method); } return string.Format(DefaultValueFormat, GetQuotedValue(column.DefaultValue.ToString())); } protected virtual string FormatPrimaryKey(ColumnDefinition column) { return string.Empty; } protected abstract string FormatSystemMethods(SystemMethods systemMethod); protected abstract string FormatIdentity(ColumnDefinition column); public virtual string CreateTable { get { return "CREATE TABLE {0} ({1})"; } } public virtual string DropTable { get { return "DROP TABLE {0}"; } } public virtual string AddColumn { get { return "ALTER TABLE {0} ADD COLUMN {1}"; } } public virtual string DropColumn { get { return "ALTER TABLE {0} DROP COLUMN {1}"; } } public virtual string AlterColumn { get { return "ALTER TABLE {0} ALTER COLUMN {1}"; } } public virtual string RenameColumn { get { return "ALTER TABLE {0} RENAME COLUMN {1} TO {2}"; } } public virtual string RenameTable { get { return "RENAME TABLE {0} TO {1}"; } } public virtual string CreateSchema { get { return "CREATE SCHEMA {0}"; } } public virtual string AlterSchema { get { return "ALTER SCHEMA {0} TRANSFER {1}.{2}"; } } public virtual string DropSchema { get { return "DROP SCHEMA {0}"; } } public virtual string CreateIndex { get { return "CREATE {0}{1}INDEX {2} ON {3} ({4})"; } } public virtual string DropIndex { get { return "DROP INDEX {0}"; } } public virtual string InsertData { get { return "INSERT INTO {0} ({1}) VALUES ({2})"; } } public virtual string UpdateData { get { return "UPDATE {0} SET {1} WHERE {2}"; } } public virtual string DeleteData { get { return "DELETE FROM {0} WHERE {1}"; } } public virtual string CreateConstraint { get { return "ALTER TABLE {0} ADD CONSTRAINT {1} {2} ({3})"; } } public virtual string DeleteConstraint { get { return "ALTER TABLE {0} DROP CONSTRAINT {1}"; } } public virtual string CreateForeignKeyConstraint { get { return "ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4}){5}{6}"; } } } }