Skip to content

Commit

Permalink
Merge in pull request 285 from concept-hf:firebird-support
Browse files Browse the repository at this point in the history
  • Loading branch information
daniellee committed Aug 29, 2012
2 parents 3e41e87 + fc153fd commit 1ef1477
Show file tree
Hide file tree
Showing 25 changed files with 4,175 additions and 14 deletions.
Binary file added lib/FirebirdSql.Data.FirebirdClient.dll
Binary file not shown.
2 changes: 1 addition & 1 deletion rakefile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

desc "build the console app for target .NET Framework version ${v}"
task "console-#{v}-#{p}" => [:release, "compile-console-#{v}-#{p}", "dist/console-#{v}-#{p}"] do
cp_r FileList['lib/Postgres/*', 'lib/MySql.Data.dll', 'lib/Oracle.DataAccess.dll', 'lib/System.Data.SQLite.dll', 'lib/SQLServerCE4/Private/*'], "dist/console-#{v}-#{p}"
cp_r FileList['lib/Postgres/*', 'lib/MySql.Data.dll', 'lib/Oracle.DataAccess.dll', 'lib/System.Data.SQLite.dll', 'lib/SQLServerCE4/Private/*', 'lib/FirebirdSql.Data.FirebirdClient.dll'], "dist/console-#{v}-#{p}"
cp_r FileList['src/FluentMigrator.Console/bin/Release/*'].exclude('src/FluentMigrator.Console/bin/Release/SQLServerCENative'), "dist/console-#{v}-#{p}"
cp_r FileList['src/FluentMigrator.Nant/bin/Release/FluentMigrator.Nant.*'], "dist/console-#{v}-#{p}"
cp_r FileList['src/FluentMigrator.MSBuild/bin/Release/FluentMigrator.MSBuild.*'], "dist/console-#{v}-#{p}"
Expand Down
13 changes: 13 additions & 0 deletions src/FluentMigrator.Runner/FluentMigrator.Runner.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@
<Compile Include="Extensions\TagsExtensions.cs" />
<Compile Include="Generators\Base\ColumnBase.cs" />
<Compile Include="Extensions\CompatabilityModeExtension.cs" />
<Compile Include="Generators\Firebird\FirebirdColumn.cs" />
<Compile Include="Generators\Firebird\FirebirdGenerator.cs" />
<Compile Include="Generators\Firebird\FirebirdTruncator.cs" />
<Compile Include="Processors\Firebird\FirebirdProcessedExpression.cs" />
<Compile Include="Generators\Firebird\FirebirdQuoter.cs" />
<Compile Include="Generators\Firebird\FirebirdTypeMap.cs" />
<Compile Include="Generators\Generic\GenericQuoter.cs" />
<Compile Include="Generators\Generic\GenericGenerator.cs" />
<Compile Include="Generators\IColumn.cs" />
Expand Down Expand Up @@ -192,6 +198,13 @@
<Compile Include="Initialization\UndeterminableConnectionException.cs" />
<Compile Include="IProfileLoader.cs" />
<Compile Include="IVersionLoader.cs" />
<Compile Include="Processors\Firebird\FirebirdDbFactory.cs" />
<Compile Include="Processors\Firebird\FirebirdOptions.cs" />
<Compile Include="Processors\Firebird\FirebirdProcessor.cs" />
<Compile Include="Processors\Firebird\FirebirdProcessorFactory.cs" />
<Compile Include="Processors\Firebird\FirebirdSchemaInfo.cs" />
<Compile Include="Processors\Firebird\FirebirdSchemaProvider.cs" />
<Compile Include="Processors\Firebird\FirebirdTableSchema.cs" />
<Compile Include="Processors\Jet\JetProcessor.cs" />
<Compile Include="Processors\Jet\JetProcessorFactory.cs" />
<Compile Include="Processors\MigrationProcessorFactory.cs" />
Expand Down
71 changes: 71 additions & 0 deletions src/FluentMigrator.Runner/Generators/Firebird/FirebirdColumn.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FluentMigrator.Model;
using FluentMigrator.Runner.Generators.Base;
using FluentMigrator.Runner.Processors.Firebird;

namespace FluentMigrator.Runner.Generators.Firebird
{
internal class FirebirdColumn : ColumnBase
{
protected FirebirdOptions FBOptions { get; private set; }

public FirebirdColumn(FirebirdOptions fbOptions) : base(new FirebirdTypeMap(), new FirebirdQuoter())
{
if (fbOptions == null)
throw new ArgumentNullException("fbOptions");
FBOptions = fbOptions;

//In firebird DEFAULT clause precedes NULLABLE clause
ClauseOrder = new List<Func<ColumnDefinition, string>> { FormatString, FormatType, FormatDefaultValue, FormatNullable, FormatPrimaryKey, FormatIdentity };
}

protected override string FormatIdentity(ColumnDefinition column)
{
//Identity not supported
return string.Empty;
}

protected override string FormatSystemMethods(SystemMethods systemMethod)
{
switch (systemMethod)
{
case SystemMethods.NewGuid:
return "gen_uuid()";
case SystemMethods.CurrentDateTime:
return "CURRENT_TIMESTAMP";
}

throw new NotImplementedException();
}

protected override string GetPrimaryKeyConstraintName(IEnumerable<ColumnDefinition> primaryKeyColumns, string tableName)
{
string primaryKeyName = primaryKeyColumns.Select(x => x.PrimaryKeyName).FirstOrDefault();

if (string.IsNullOrEmpty(primaryKeyName))
{
return string.Empty;
}
else if (primaryKeyName.Length > FirebirdOptions.MaxNameLength)
{
if (!FBOptions.TruncateLongNames)
throw new ArgumentException(String.Format("Name too long: {0}", primaryKeyName));
primaryKeyName = primaryKeyName.Substring(0, Math.Min(FirebirdOptions.MaxNameLength, primaryKeyName.Length));
}

return string.Format("CONSTRAINT {0} ", Quoter.QuoteIndexName(primaryKeyName));
}

public virtual string GenerateForTypeAlter(ColumnDefinition column)
{
return FormatType(column);
}

public virtual string GenerateForDefaultAlter(ColumnDefinition column)
{
return FormatDefaultValue(column);
}
}
}
269 changes: 269 additions & 0 deletions src/FluentMigrator.Runner/Generators/Firebird/FirebirdGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FluentMigrator.Expressions;
using FluentMigrator.Model;
using FluentMigrator.Runner.Generators.Generic;
using FluentMigrator.Runner.Processors.Firebird;

namespace FluentMigrator.Runner.Generators.Firebird
{

public class FirebirdGenerator : GenericGenerator
{
protected readonly FirebirdTruncator truncator;
protected Processors.Firebird.FirebirdOptions FBOptions { get; private set; }

public FirebirdGenerator(Processors.Firebird.FirebirdOptions fbOptions) : base(new FirebirdColumn(fbOptions), new FirebirdQuoter())
{
if (fbOptions == null)
throw new ArgumentNullException("fbOptions");

FBOptions = fbOptions;
truncator = new FirebirdTruncator(FBOptions.TruncateLongNames);
}

//It's kind of a hack to mess with system tables, but this is the cleanest and time-tested method to alter the nullable constraint.
// It's even mentioned in the firebird official FAQ.
// Currently the only drawback is that the integrity is not checked by the engine, you have to ensure it manually
public string AlterColumnSetNullable { get { return "UPDATE RDB$RELATION_FIELDS SET RDB$NULL_FLAG = {0} WHERE RDB$RELATION_NAME = {1} AND RDB$FIELD_NAME = {2}"; } }

public string AlterColumnSetType { get { return "ALTER TABLE {0} ALTER COLUMN {1} TYPE {2}"; } }

#region SQL Generation overrides

public override string AddColumn { get { return "ALTER TABLE {0} ADD {1}"; } }
public override string DropColumn { get { return "ALTER TABLE {0} DROP {1}"; } }
public override string RenameColumn { get { return "ALTER TABLE {0} ALTER COLUMN {1} TO {2}"; } }

public override string Generate(AlterDefaultConstraintExpression expression)
{
truncator.Truncate(expression);
return String.Format("ALTER TABLE {0} ALTER COLUMN {1} SET DEFAULT {2}",
Quoter.QuoteTableName(expression.TableName),
Quoter.QuoteColumnName(expression.ColumnName),
Quoter.QuoteValue(expression.DefaultValue)
);
}

public override string Generate(DeleteDefaultConstraintExpression expression)
{
truncator.Truncate(expression);
return String.Format("ALTER TABLE {0} ALTER COLUMN {1} DROP DEFAULT",
Quoter.QuoteTableName(expression.TableName),
Quoter.QuoteColumnName(expression.ColumnName)
);
}

public override string Generate(CreateIndexExpression expression)
{
//Firebird doesn't have particular asc or desc order per column, only per the whole index
// CREATE [UNIQUE] [ASC[ENDING] | [DESC[ENDING]] INDEX indexname
// ON tablename { (<col> [, <col> ...]) | COMPUTED BY (expression) }
// <col> ::= a column not of type ARRAY, BLOB or COMPUTED BY
//
// Assuming the first column's direction for the index's direction.

truncator.Truncate(expression);

StringBuilder indexColumns = new StringBuilder("");
Direction indexDirection = Direction.Ascending;
int columnCount = expression.Index.Columns.Count;
for (int i = 0; i < columnCount; i++)
{
IndexColumnDefinition columnDef = expression.Index.Columns.ElementAt(i);

if (i > 0)
indexColumns.Append(", ");
else indexDirection = columnDef.Direction;

indexColumns.Append(Quoter.QuoteColumnName(columnDef.Name));

}

return String.Format(CreateIndex
, GetUniqueString(expression)
, indexDirection == Direction.Ascending ? "ASC " : "DESC "
, Quoter.QuoteIndexName(expression.Index.Name)
, Quoter.QuoteTableName(expression.Index.TableName)
, indexColumns.ToString());
}

public override string Generate(AlterColumnExpression expression)
{
truncator.Truncate(expression);
return compatabilityMode.HandleCompatabilty("Alter column is not supported as expected");
}


public override string Generate(CreateSequenceExpression expression)
{
truncator.Truncate(expression);
return String.Format("CREATE SEQUENCE {0}", Quoter.QuoteSequenceName(expression.Sequence.Name));
}

public override string Generate(DeleteSequenceExpression expression)
{
truncator.Truncate(expression);
return String.Format("DROP SEQUENCE {0}", Quoter.QuoteSequenceName(expression.SequenceName));
}

public string GenerateAlterSequence(SequenceDefinition sequence)
{
truncator.Truncate(sequence);
if (sequence.StartWith != null)
return String.Format("ALTER SEQUENCE {0} RESTART WITH {1}", Quoter.QuoteSequenceName(sequence.Name), sequence.StartWith.ToString());

return String.Empty;
}

#endregion


#region Name truncation overrides

public override string Generate(CreateTableExpression expression)
{
truncator.Truncate(expression);
return base.Generate(expression);
}

public override string Generate(DeleteTableExpression expression)
{
truncator.Truncate(expression);
return base.Generate(expression);
}

public override string Generate(RenameTableExpression expression)
{
truncator.Truncate(expression);
return compatabilityMode.HandleCompatabilty("Rename table is not supported");
}

public override string Generate(CreateColumnExpression expression)
{
truncator.Truncate(expression);
return base.Generate(expression);
}

public override string Generate(DeleteColumnExpression expression)
{
truncator.Truncate(expression);
return base.Generate(expression);
}

public override string Generate(RenameColumnExpression expression)
{
truncator.Truncate(expression);
return base.Generate(expression);
}

public override string Generate(DeleteIndexExpression expression)
{
truncator.Truncate(expression);
return base.Generate(expression);
}

public override string Generate(CreateConstraintExpression expression)
{
truncator.Truncate(expression);
return base.Generate(expression);
}

public override string Generate(DeleteConstraintExpression expression)
{
truncator.Truncate(expression);
return base.Generate(expression);
}

public override string Generate(CreateForeignKeyExpression expression)
{
truncator.Truncate(expression);
return base.Generate(expression);
}

public override string GenerateForeignKeyName(CreateForeignKeyExpression expression)
{
truncator.Truncate(expression);
return truncator.Truncate(base.GenerateForeignKeyName(expression));
}

public override string Generate(DeleteForeignKeyExpression expression)
{
truncator.Truncate(expression);
return base.Generate(expression);
}

public override string Generate(InsertDataExpression expression)
{
truncator.Truncate(expression);
return base.Generate(expression);
}

public override string Generate(UpdateDataExpression expression)
{
truncator.Truncate(expression);
return base.Generate(expression);
}

public override string Generate(DeleteDataExpression expression)
{
truncator.Truncate(expression);
return base.Generate(expression);
}

#endregion


#region Alter column generators

public virtual string GenerateSetNull(ColumnDefinition column)
{
truncator.Truncate(column);
return String.Format(AlterColumnSetNullable,
column.IsNullable ? "1" : "NULL",
Quoter.QuoteValue(column.TableName),
Quoter.QuoteValue(column.Name)
);
}

public virtual string GenerateSetType(ColumnDefinition column)
{
truncator.Truncate(column);
return String.Format(AlterColumnSetType,
Quoter.QuoteTableName(column.TableName),
Quoter.QuoteColumnName(column.Name),
(Column as FirebirdColumn).GenerateForTypeAlter(column)
);
}

#endregion


#region Helpers

public static bool ColumnTypesMatch(ColumnDefinition col1, ColumnDefinition col2)
{
FirebirdColumn column = new FirebirdColumn(new FirebirdOptions());
string colDef1 = column.GenerateForTypeAlter(col1);
string colDef2 = column.GenerateForTypeAlter(col2);
return colDef1 == colDef2;
}

public static bool DefaultValuesMatch(ColumnDefinition col1, ColumnDefinition col2)
{
if (col1.DefaultValue is ColumnDefinition.UndefinedDefaultValue && col2.DefaultValue is ColumnDefinition.UndefinedDefaultValue)
return true;
if (col1.DefaultValue is ColumnDefinition.UndefinedDefaultValue || col2.DefaultValue is ColumnDefinition.UndefinedDefaultValue)
return true;
FirebirdColumn column = new FirebirdColumn(new FirebirdOptions());
string col1Value = column.GenerateForDefaultAlter(col1);
string col2Value = column.GenerateForDefaultAlter(col2);
return col1Value != col2Value;
}

#endregion

}
}
15 changes: 15 additions & 0 deletions src/FluentMigrator.Runner/Generators/Firebird/FirebirdQuoter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using FluentMigrator.Runner.Generators.Generic;

namespace FluentMigrator.Runner.Generators.Firebird
{
public class FirebirdQuoter : GenericQuoter
{
public override string OpenQuote { get { return "\""; } }
public override string CloseQuote { get { return "\""; } }

public override string FormatDateTime(System.DateTime value)
{
return ValueQuote + (value).ToString("yyyy-MM-dd HH:mm:ss") + ValueQuote;
}
}
}
Loading

0 comments on commit 1ef1477

Please sign in to comment.