Merge pull request #5358 from oldrev/feature/postgresql

Feature: PostgreSQL Support
This commit is contained in:
Sébastien Ros
2015-06-18 12:35:03 -07:00
24 changed files with 6731 additions and 9 deletions

View File

@@ -59,6 +59,7 @@ namespace Orchard.Tests.ContentManagement {
builder.RegisterInstance(new ShellSettings { Name = ShellSettings.DefaultName, DataProvider = "SqlCe" });
builder.RegisterType<SqlCeStatementProvider>().As<ISqlStatementProvider>();
builder.RegisterType<MySqlStatementProvider>().As<ISqlStatementProvider>();
builder.RegisterType<PostgreSqlStatementProvider>().As<ISqlStatementProvider>();
builder.RegisterType<AlphaPartHandler>().As<IContentHandler>();
builder.RegisterType<BetaPartHandler>().As<IContentHandler>();

View File

@@ -36,7 +36,7 @@ namespace Orchard.Setup.Commands {
[OrchardSwitch]
public string Recipe { get; set; }
[CommandHelp("setup /SiteName:<siteName> /AdminUsername:<username> /AdminPassword:<password> /DatabaseProvider:<SqlCe|SQLServer|MySql> " +
[CommandHelp("setup /SiteName:<siteName> /AdminUsername:<username> /AdminPassword:<password> /DatabaseProvider:<SqlCe|SQLServer|MySql|PostgreSql> " +
"/DatabaseConnectionString:<connection_string> /DatabaseTablePrefix:<table_prefix> /EnabledFeatures:<feature1,feature2,...> " +
"/Recipe:<recipe>" +
"\r\n\tRun first time setup for the site or for a given tenant")]

View File

@@ -129,6 +129,10 @@ namespace Orchard.Setup.Controllers {
providerName = "MySql";
break;
case SetupDatabaseType.PostgreSql:
providerName = "PostgreSql";
break;
default:
throw new ApplicationException("Unknown database type: " + model.DatabaseProvider);
}

View File

@@ -9,6 +9,7 @@ namespace Orchard.Setup.Controllers
{
Builtin,
SqlServer,
MySql
MySql,
PostgreSql,
}
}

View File

@@ -141,6 +141,9 @@ namespace Orchard.Setup.Services {
throw new OrchardException(T("A previous Orchard installation was detected in this database with this table prefix."));
}
// Make a workaround to avoid the Transaction issue for PostgreSQL
environment.Resolve<ITransactionManager>().RequireNew();
var reportsCoordinator = environment.Resolve<IReportsCoordinator>();
reportsCoordinator.Register("Data Migration", "Setup", "Orchard installation");

View File

@@ -43,6 +43,10 @@ if (!Model.DatabaseIsPreconfigured) {
@Html.RadioButtonFor(svm => svm.DatabaseProvider, Orchard.Setup.Controllers.SetupDatabaseType.MySql.ToString(), new { id = "mysql" })
<label for="mysql" class="forcheckbox">@T("Use an existing MySql database")</label>
</div>
<div>
@Html.RadioButtonFor(svm => svm.DatabaseProvider, Orchard.Setup.Controllers.SetupDatabaseType.PostgreSql.ToString(), new { id = "postgresql" })
<label for="postgresql" class="forcheckbox">@T("Use an existing PostgreSQL database")</label>
</div>
<div data-controllerid="builtin" data-defaultstate="hidden">
<label for="DatabaseConnectionString">@T("Connection string")</label>
@Html.EditorFor(svm => svm.DatabaseConnectionString)
@@ -55,6 +59,10 @@ if (!Model.DatabaseIsPreconfigured) {
@T("Data Source=serverName;Database=dbName;User Id=userName;Password=password")
</span>
<span data-controllerid="postgresql" class="hint databaseTypeHint">
@T("Server=serverName;Port=5432;Encoding=UNICODE;Database=dbName;User Id=userName;Password=password")
</span>
<br /><br />
<label for="DatabaseTablePrefix">@T("Database Table Prefix")</label>
@Html.EditorFor(svm => svm.DatabaseTablePrefix)

View File

@@ -59,6 +59,10 @@
<HintPath>..\..\lib\aspnetmvc\Microsoft.Web.Infrastructure.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\npgsql\Mono.Security.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..\..\lib\newtonsoft.json\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
@@ -68,6 +72,10 @@
<HintPath>..\..\lib\mysql\MySql.Data.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Npgsql, Version=2.2.3.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\npgsql\Npgsql.dll</HintPath>
</Reference>
<Reference Include="NuGet.Core, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\lib\nuget\NuGet.Core.dll</HintPath>
<Private>True</Private>
@@ -280,4 +288,4 @@
<CopyAreaManifests ManifestPath="$(AreasManifestDir)" CrossCopy="false" RenameViews="true" />
-->
</Target>
</Project>
</Project>

View File

@@ -79,9 +79,15 @@ namespace Orchard.Data.Migration.Interpreters {
builder.Append(", ");
}
var primaryKeysQuoted = new List<string>(primaryKeys.Length);
foreach (string pk in primaryKeys) {
primaryKeysQuoted.Add(_dialectLazy.Value.QuoteForColumnName(pk));
}
builder.Append(_dialectLazy.Value.PrimaryKeyString)
.Append(" ( ")
.Append(String.Join(", ", primaryKeys.ToArray()))
.Append(String.Join(", ", primaryKeysQuoted.ToArray()))
.Append(" )");
}
@@ -358,7 +364,7 @@ namespace Orchard.Data.Migration.Interpreters {
return false;
}
public static string ConvertToSqlValue(object value) {
public string ConvertToSqlValue(object value) {
if ( value == null ) {
return "null";
}
@@ -372,7 +378,7 @@ namespace Orchard.Data.Migration.Interpreters {
case TypeCode.Char:
return String.Concat("'", Convert.ToString(value).Replace("'", "''"), "'");
case TypeCode.Boolean:
return (bool) value ? "1" : "0";
return this._dialectLazy.Value.ToBooleanValueString((bool)value);
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.UInt16:

View File

@@ -10,8 +10,10 @@ namespace Orchard.Data.Migration.Interpreters {
public class MySqlCommandInterpreter : ICommandInterpreter<AlterColumnCommand> {
private readonly Lazy<Dialect> _dialectLazy;
private readonly ShellSettings _shellSettings;
private readonly DefaultDataMigrationInterpreter _dataMigrationInterpreter;
public MySqlCommandInterpreter() {
public MySqlCommandInterpreter(DefaultDataMigrationInterpreter dataMigrationInterpreter) {
_dataMigrationInterpreter = dataMigrationInterpreter;
T = NullLocalizer.Instance;
}
@@ -47,7 +49,7 @@ namespace Orchard.Data.Migration.Interpreters {
// [default value]
if (command.Default != null) {
builder.Append(" set default ").Append(DefaultDataMigrationInterpreter.ConvertToSqlValue(command.Default)).Append(" ");
builder.Append(" set default ").Append(_dataMigrationInterpreter.ConvertToSqlValue(command.Default)).Append(" ");
}
return new [] {

View File

@@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Reflection;
using FluentNHibernate.Cfg.Db;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.SqlTypes;
namespace Orchard.Data.Providers {
public class PostgreSqlDataServicesProvider : AbstractDataServicesProvider {
private readonly string _dataFolder;
private readonly string _connectionString;
public PostgreSqlDataServicesProvider(string dataFolder, string connectionString) {
_dataFolder = dataFolder;
_connectionString = connectionString;
}
public static string ProviderName {
get { return "PostgreSql"; }
}
public override IPersistenceConfigurer GetPersistenceConfigurer(bool createDatabase) {
var persistence = PostgreSql82Configuration.PostgreSql82;
if (string.IsNullOrEmpty(_connectionString)) {
throw new ArgumentException("The connection string is empty");
}
persistence = persistence.ConnectionString(_connectionString);
return persistence;
}
sealed class PostgreSql82DialectFixed : PostgreSQL82Dialect {
// Works around a bug in NHibernate PostgreSQL82 dialect which overrides the
// GetIdentityColumnString method but fails to override the IdentityColumnString,
// which eventually leads to exception being thrown.
public override string IdentityColumnString {
get { return "serial"; }
}
// Avoid to quote any identifiers for PostgreSQL. Doing that will fold all of them into
// lower case which will then make it easier to issue queries. When an identifier (e.g.
// a table name) is enclosed in quotes when creating it you have to always use quotes
// _and_ the correct case when referring to it thereafter.
protected override string Quote(string name) {
return name;
}
// PostgreSQL does not accept the default Dialect's 0 or 1 value for boolean columns.
public override string ToBooleanValueString(bool value) {
return value ? "'t'" : "'f'";
}
public override string QuoteForColumnName(string columnName) {
return columnName;
}
public override string QuoteForTableName(string tableName) {
return tableName;
}
}
sealed class PostgreSql82Configuration : PersistenceConfiguration<PostgreSql82Configuration> {
public static PostgreSql82Configuration PostgreSql82 {
get { return new PostgreSql82Configuration().Dialect<PostgreSql82DialectFixed>(); }
}
}
}
public class PostgreSqlNamingStrategy : INamingStrategy {
public string ClassToTableName(string className) {
return DoubleQuote(className);
}
public string PropertyToColumnName(string propertyName) {
return DoubleQuote(propertyName);
}
public string TableName(string tableName) {
return DoubleQuote(tableName);
}
public string ColumnName(string columnName) {
return DoubleQuote(columnName);
}
public string PropertyToTableName(string className,
string propertyName) {
return DoubleQuote(propertyName);
}
public string LogicalColumnName(string columnName,
string propertyName) {
return String.IsNullOrWhiteSpace(columnName) ?
DoubleQuote(propertyName) :
DoubleQuote(columnName);
}
private static string DoubleQuote(string raw) {
// In some cases the identifier is single-quoted.
// We simply remove the single quotes:
raw = raw.Replace("`", "");
return String.Format("\"{0}\"", raw);
}
}
}

View File

@@ -0,0 +1,16 @@
namespace Orchard.Data.Providers {
public class PostgreSqlStatementProvider : ISqlStatementProvider {
public string DataProvider {
get { return "PostgreSql"; }
}
public string GetStatement(string command) {
switch (command) {
case "random":
return "random()";
}
return null;
}
}
}

View File

@@ -197,6 +197,8 @@
<Compile Include="Data\Providers\SqlCeStatementProvider.cs" />
<Compile Include="Data\Providers\ISqlStatementProvider.cs" />
<Compile Include="Data\Providers\SqlServerStatementProvider.cs" />
<Compile Include="Data\Providers\PostgreSqlStatementProvider.cs" />
<Compile Include="Data\Providers\PostgreSqlDataServicesProvider.cs" />
<Compile Include="DisplayManagement\Arguments.cs" />
<Compile Include="Data\Bags\SConvert.cs" />
<Compile Include="Data\Bags\Serialization\IBagSerializer.cs" />
@@ -1025,4 +1027,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>