Permalink
Browse files

Merge branch 'hotfix/4.0.3'

  • Loading branch information...
roji committed Sep 8, 2018
2 parents c2d4659 + 24e24e1 commit 27fc3fc266c61e66f235947dba686b716904b056
Showing with 339 additions and 143 deletions.
  1. +1 −1 .appveyor.yml
  2. +0 −10 NuGet.Config
  3. +21 −1 doc/types/nts.md
  4. +2 −4 src/Npgsql.NetTopologySuite/Npgsql.NetTopologySuite.csproj
  5. +4 −2 src/Npgsql.NetTopologySuite/NpgsqlNetTopologySuiteExtensions.cs
  6. +2 −0 src/Npgsql/ConnectorPool.cs
  7. +1 −1 src/Npgsql/Npgsql.csproj
  8. +10 −4 src/Npgsql/NpgsqlConnection.cs
  9. +3 −2 src/Npgsql/NpgsqlDefaultDataReader.cs
  10. +3 −4 src/Npgsql/NpgsqlParameter`.cs
  11. +4 −6 src/Npgsql/NpgsqlReadBuffer.cs
  12. +3 −2 src/Npgsql/NpgsqlSequentialDataReader.cs
  13. +7 −0 src/Npgsql/NpgsqlTypes/NpgsqlDbType.cs
  14. +3 −3 src/Npgsql/NpgsqlWriteBuffer.cs
  15. +0 −14 src/Npgsql/PGUtil.cs
  16. +3 −2 src/Npgsql/PoolManager.cs
  17. +4 −0 src/Npgsql/PostgresDatabaseInfo.cs
  18. +4 −2 src/Npgsql/PostgresException.cs
  19. +4 −6 src/Npgsql/TypeHandlers/NumericHandlers/MoneyHandler.cs
  20. +1 −0 src/Npgsql/TypeHandlers/NumericHandlers/UInt32Handler.cs
  21. +3 −5 src/Npgsql/TypeMapping/ConnectorTypeMapper.cs
  22. +4 −7 src/Npgsql/TypeMapping/GlobalTypeMapper.cs
  23. +30 −14 src/Npgsql/TypeMapping/INpgsqlTypeMapper.cs
  24. +17 −8 src/Npgsql/TypeMapping/TypeMapperBase.cs
  25. +1 −1 src/VSIX/Properties/AssemblyInfo.cs
  26. +1 −1 src/VSIX/source.extension.vsixmanifest
  27. +36 −8 test/Npgsql.PluginTests/NetTopologySuiteTests.cs
  28. +0 −2 test/Npgsql.PluginTests/Npgsql.PluginTests.csproj
  29. +57 −0 test/Npgsql.Tests/BugTests.cs
  30. +1 −1 test/Npgsql.Tests/CommandTests.cs
  31. +1 −1 test/Npgsql.Tests/NotificationTests.cs
  32. +2 −1 test/Npgsql.Tests/ReaderTests.cs
  33. +7 −4 test/Npgsql.Tests/Types/MiscTypeTests.cs
  34. +99 −0 test/Npgsql.Tests/Types/MoneyTests.cs
  35. +0 −26 test/Npgsql.Tests/Types/NumericTypeTests.cs
View
@@ -1,5 +1,5 @@
image: Visual Studio 2017
version: 4.0.2-{build}
version: 4.0.3-{build}
environment:
global:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
View

This file was deleted.

Oops, something went wrong.
View
@@ -29,10 +29,30 @@ using Npgsql;
// Place this at the beginning of your program to use NetTopologySuite everywhere (recommended)
NpgsqlConnection.GlobalTypeMapper.UseNetTopologySuite();
// Or to temporarily use NetTopologySuite on a single connection only:
// Or to temporarily use NetTopologySuite on a single connection only
conn.TypeMapper.UseNetTopologySuite();
```
By default the plugin handles only ordinates provided by the `DefaultCoordinateSequenceFactory` of `GeometryServiceProvider.Instance`. If `GeometryServiceProvider` is initialized automatically the X and Y ordinates are handled. To change the behavior specify the `handleOrdinates` parameter like in the following example:
```c#
conn.TypeMapper.UseNetTopologySuite(handleOrdinates: Ordinates.XYZ);
```
To process the M ordinate, you must initialize `GeometryServiceProvider.Instance` to a new `NtsGeometryServices` instance with `coordinateSequenceFactory` set to a `DotSpatialAffineCoordinateSequenceFactory`. Or you can specify the factory when calling `UseNetTopologySuite`.
```c#
// Place this at the beginning of your program to use the specified settings everywhere (recommended)
GeometryServiceProvider.Instance = new NtsGeometryServices(
new DotSpatialAffineCoordinateSequenceFactory(Ordinates.XYM),
new PrecisionModel(PrecisionModels.Floating),
-1);
// Or specify settings for Npgsql only
conn.TypeMapper.UseNetTopologySuite(
new DotSpatialAffineCoordinateSequenceFactory(Ordinates.XYM));
```
## Reading and Writing Geometry Values
When reading PostGIS values from the database, Npgsql will automatically return the appropriate NetTopologySuite types: `Point`, `LineString`, and so on. Npgsql will also automatically recognize NetTopologySuite's types in parameters, and will automatically send the corresponding PostGIS type to the database. The following code demonstrates a roundtrip of a NetTopologySuite `Point` to the database:
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<VersionPrefix>1.0.1</VersionPrefix>
<VersionPrefix>1.0.2</VersionPrefix>
<Description>NetTopologySuite plugin for Npgsql, allowing mapping of PostGIS geometry types to NetTopologySuite types.</Description>
<Authors>Yoh Deadfall, Shay Rojansky</Authors>
<Copyright>Copyright 2018 © The Npgsql Development Team</Copyright>
@@ -25,9 +25,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NetTopologySuite" Version="1.15.0-pre079" />
<PackageReference Include="NetTopologySuite.IO" Version="1.15.0-pre071" />
<PackageReference Include="GeoAPI" Version="1.7.5-pre025" />
<PackageReference Include="NetTopologySuite.IO.PostGIS" Version="1.15.0" />
</ItemGroup>
<ItemGroup>
@@ -56,7 +56,9 @@ public static class NpgsqlNetTopologySuiteExtensions
/// <param name="mapper">The type mapper to set up (global or connection-specific).</param>
/// <param name="coordinateSequenceFactory">The factory which knows how to build a particular implementation of ICoordinateSequence from an array of Coordinates.</param>
/// <param name="precisionModel">Specifies the grid of allowable points.</param>
/// <param name="handleOrdinates">Specifies the ordinates which will be handled. Not specified ordinates will be ignored.</param>
/// <param name="handleOrdinates">Specifies the ordinates which will be handled. Not specified ordinates will be ignored.
/// If <see cref="F:GeoAPI.Geometries.Ordiantes.None" /> is specified, an actual value will be taken from
/// the <see cref="P:GeoAPI.Geometries.ICoordinateSequenceFactory.Ordinates"/> property of <paramref name="coordinateSequenceFactory"/>.</param>
/// <param name="geographyAsDefault">Specifies that the geography type is used for mapping by default.</param>
public static INpgsqlTypeMapper UseNetTopologySuite(
this INpgsqlTypeMapper mapper,
@@ -76,7 +78,7 @@ public static class NpgsqlNetTopologySuiteExtensions
var typeHandlerFactory = new NetTopologySuiteHandlerFactory(
new PostGisReader(coordinateSequenceFactory, precisionModel, handleOrdinates),
new PostGisWriter());
new PostGisWriter() { HandleOrdinates = handleOrdinates });
return mapper
.AddMapping(new NpgsqlTypeMappingBuilder
@@ -248,6 +248,8 @@ internal async ValueTask<NpgsqlConnector> AllocateLong(NpgsqlConnection conn, Np
catch
{
// Physical open failed, decrement busy back down
conn.Connector = null;
var sw = new SpinWait();
while (true)
{
View
@@ -6,7 +6,7 @@
<Copyright>Copyright 2018 © The Npgsql Development Team</Copyright>
<Company>Npgsql</Company>
<PackageTags>npgsql postgresql postgres ado ado.net database sql</PackageTags>
<VersionPrefix>4.0.2</VersionPrefix>
<VersionPrefix>4.0.3</VersionPrefix>
<LangVersion>latest</LangVersion>
<TargetFrameworks>net45;net451;netstandard2.0</TargetFrameworks>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
@@ -179,15 +179,13 @@ void GetPoolAndSettings()
if (!_countersInitialized)
{
_countersInitialized = true;
Counters.Initialize(Settings.UsePerfCounters);
_countersInitialized = true;
}
// Maybe pooling is off
if (!Settings.Pooling)
{
return;
}
// Connstring may be equivalent to one that has already been seen though (e.g. different
// ordering). Have NpgsqlConnectionStringBuilder produce a canonical string representation
@@ -321,7 +319,15 @@ async Task OpenLong()
}
catch
{
Connector = null;
if (Connector != null)
{
if (_pool == null)
Connector.Close();
else
_pool.Release(Connector);
Connector = null;
}
throw;
}
Debug.Assert(Connector.Connection != null, "Open done but connector not set on Connection");
@@ -134,8 +134,9 @@ public override T GetFieldValue<T>(int column)
{
if (NullableHandler<T>.Exists)
return default;
else
throw new InvalidCastException("Column is null");
if (typeof(T) == typeof(object))
return (T)(object)DBNull.Value;
throw new InvalidCastException("Column is null");
}
var fieldDescription = RowDescription[column];
@@ -76,18 +76,17 @@ internal override void ResolveHandler(ConnectorTypeMapper typeMapper)
Handler = typeMapper.GetByDataTypeName(_dataTypeName);
else if (_dbType.HasValue)
Handler = typeMapper.GetByDbType(_dbType.Value);
else if (TypedValue != null)
Handler = typeMapper.GetByClrType(typeof(T));
else
throw new InvalidOperationException($"Parameter '{ParameterName}' must have its value set");
Handler = typeMapper.GetByClrType(typeof(T));
}
internal override int ValidateAndGetLength()
{
Debug.Assert(Handler != null);
if (TypedValue == null)
throw new InvalidCastException($"Parameter {ParameterName} must be set");
return 0;
// TODO: Why do it like this rather than a handler?
if (typeof(T) == typeof(DBNull))
return 0;
@@ -319,9 +319,8 @@ public float ReadSingle()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float ReadSingle(bool littleEndian)
{
var result = Read<float>();
return littleEndian == BitConverter.IsLittleEndian
? result : PGUtil.ReverseEndianness(result);
var result = ReadInt32(littleEndian);
return Unsafe.As<int, float>(ref result);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -331,9 +330,8 @@ public double ReadDouble()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double ReadDouble(bool littleEndian)
{
var result = Read<double>();
return littleEndian == BitConverter.IsLittleEndian
? result : PGUtil.ReverseEndianness(result);
var result = ReadInt64(littleEndian);
return Unsafe.As<long, double>(ref result);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -74,8 +74,9 @@ async ValueTask<T> GetFieldValue<T>(int column, bool async)
{
if (NullableHandler<T>.Exists)
return default;
else
throw new InvalidCastException("Column is null");
if (typeof(T) == typeof(object))
return (T)(object)DBNull.Value;
throw new InvalidCastException("Column is null");
}
var fieldDescription = RowDescription[column];
@@ -351,6 +351,13 @@ public enum NpgsqlDbType
[BuiltInPostgresType("tsquery", 3615)]
TsQuery = 46,
/// <summary>
/// Corresponds to the PostgreSQL "tsquery" type.
/// </summary>
/// <remarks>See http://www.postgresql.org/docs/current/static/datatype-textsearch.html</remarks>
[BuiltInPostgresType("regconfig", 3734)]
Regconfig = 56,
#endregion
#region UUID Type
@@ -267,18 +267,18 @@ public void WriteSingle(float value)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteSingle(float value, bool littleEndian)
=> Write(littleEndian == BitConverter.IsLittleEndian ? value : PGUtil.ReverseEndianness(value));
=> WriteInt32(Unsafe.As<float, int>(ref value), littleEndian);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteDouble(double value)
=> WriteDouble(value, false);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteDouble(double value, bool littleEndian)
=> Write(littleEndian == BitConverter.IsLittleEndian ? value : PGUtil.ReverseEndianness(value));
=> WriteInt64(Unsafe.As<double, long>(ref value), littleEndian);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Write<T>(T value)
void Write<T>(T value)
{
Debug.Assert(Unsafe.SizeOf<T>() <= WriteSpaceLeft);
Unsafe.WriteUnaligned(ref Buffer[WritePosition], value);
View
@@ -120,20 +120,6 @@ internal static uint ReverseEndianness(uint value)
internal static ulong ReverseEndianness(ulong value)
=> ((ulong)ReverseEndianness((uint)value) << 32) + ReverseEndianness((uint)(value >> 32));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal unsafe static float ReverseEndianness(float value)
{
var result = ReverseEndianness(*(int*)(&value));
return *(float*)(&result);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal unsafe static double ReverseEndianness(double value)
{
var result = ReverseEndianness(*(long*)(&value));
return *(double*)(&result);
}
internal static readonly Task CompletedTask = Task.FromResult(0);
internal static readonly Task<bool> TrueTask = Task.FromResult(true);
internal static readonly Task<bool> FalseTask = Task.FromResult(false);
@@ -39,6 +39,7 @@ static class PoolManager
{
internal const int InitialPoolsSize = 10;
static readonly object _lock = new object();
static (string Key, ConnectorPool Pool)[] _pools = new (string, ConnectorPool)[InitialPoolsSize];
static int _nextSlot;
@@ -82,7 +83,7 @@ internal static bool TryGetValue(string key, out ConnectorPool pool)
internal static ConnectorPool GetOrAdd(string key, ConnectorPool pool)
{
lock (_pools)
lock (_lock)
{
if (TryGetValue(key, out var result))
return result;
@@ -134,7 +135,7 @@ static PoolManager()
/// </summary>
internal static void Reset()
{
lock (_pools)
lock (_lock)
{
ClearAll();
_pools = new (string, ConnectorPool)[InitialPoolsSize];
@@ -129,6 +129,8 @@ internal async Task LoadPostgresInfo([NotNull] NpgsqlConnection conn, NpgsqlTime
[NotNull]
static string GenerateTypesQuery(bool withRange, bool withEnum, bool withEnumSortOrder, bool loadTableComposites)
=> $@"
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY;
/*** Load all supported types ***/
SELECT ns.nspname, a.typname, a.oid, a.typrelid, a.typbasetype,
CASE WHEN pg_proc.proname='array_recv' THEN 'a' ELSE a.typtype END AS type,
@@ -178,6 +180,8 @@ NOT attisdropped
FROM pg_enum
JOIN pg_type ON pg_type.oid=enumtypid
ORDER BY oid{(withEnumSortOrder ? ", enumsortorder" : "")};" : "")}
COMMIT TRANSACTION;
";
/// <summary>
@@ -52,7 +52,7 @@ namespace Npgsql
public sealed class PostgresException : NpgsqlException
{
[CanBeNull]
Dictionary<string, object> _data;
Dictionary<object, object> _data;
#region Message Fields
@@ -278,6 +278,8 @@ public override IDictionary Data
{
get
{
// Remarks: return Dictionary with object keys although all our keys are string keys
// because System.Windows.Threading.Dispatcher relies on that
return _data ?? (_data = (
from p in typeof(PostgresException).GetProperties()
let k = p.Name
@@ -287,7 +289,7 @@ public override IDictionary Data
where v != null
where k != nameof(Position) && k != nameof(InternalPosition) || (int)v != 0
select new { Key = k, Value = v }
).ToDictionary(kv => kv.Key, kv => kv.Value)
).ToDictionary(kv => (object)kv.Key, kv => kv.Value)
);
}
}
@@ -57,12 +57,10 @@ public override void Write(decimal value, NpgsqlWriteBuffer buf, NpgsqlParameter
if (scaleDifference > 0)
DecimalRaw.Multiply(ref raw, DecimalRaw.Powers10[scaleDifference]);
else
while (scaleDifference < 0)
{
var scaleChunk = Math.Min(DecimalRaw.MaxUInt32Scale, -scaleDifference);
DecimalRaw.Divide(ref raw, DecimalRaw.Powers10[scaleChunk]);
scaleDifference -= scaleChunk;
}
{
value = Math.Round(value, MoneyScale, MidpointRounding.AwayFromZero);
raw = Unsafe.As<decimal, DecimalRaw>(ref value);
}
var result = (long)raw.Mid << 32 | (long)raw.Low;
if (raw.Negative) result = -result;
@@ -35,6 +35,7 @@ namespace Npgsql.TypeHandlers.NumericHandlers
[TypeMapping("xid", NpgsqlDbType.Xid)]
[TypeMapping("cid", NpgsqlDbType.Cid)]
[TypeMapping("regtype", NpgsqlDbType.Regtype)]
[TypeMapping("regconfig", NpgsqlDbType.Regconfig)]
class UInt32Handler : NpgsqlSimpleTypeHandler<uint>
{
public override uint Read(NpgsqlReadBuffer buf, int len, FieldDescription fieldDescription = null)
Oops, something went wrong.

0 comments on commit 27fc3fc

Please sign in to comment.