You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@ -0,0 +1,107 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="SqlSpatialDataReader.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner willa
|
||||
// @backupOwner [....]
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Data.Common.Utils;
|
||||
using System.Data.Entity;
|
||||
using System.Data.Spatial;
|
||||
using System.Data.SqlTypes;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace System.Data.SqlClient
|
||||
{
|
||||
/// <summary>
|
||||
/// SqlClient specific implementation of <see cref="DbSpatialDataReader"/>
|
||||
/// </summary>
|
||||
internal sealed partial class SqlSpatialDataReader : DbSpatialDataReader
|
||||
{
|
||||
private readonly SqlDataReader reader;
|
||||
private const string geometrySqlType = "sys.geometry";
|
||||
private const string geographySqlType = "sys.geography";
|
||||
|
||||
internal SqlSpatialDataReader(SqlDataReader underlyingReader)
|
||||
{
|
||||
this.reader = underlyingReader;
|
||||
}
|
||||
|
||||
public override DbGeography GetGeography(int ordinal)
|
||||
{
|
||||
EnsureGeographyColumn(ordinal);
|
||||
SqlBytes geogBytes = this.reader.GetSqlBytes(ordinal);
|
||||
object providerValue = sqlGeographyFromBinaryReader.Value(new BinaryReader(geogBytes.Stream));
|
||||
return SqlSpatialServices.Instance.GeographyFromProviderValue(providerValue);
|
||||
}
|
||||
|
||||
public override DbGeometry GetGeometry(int ordinal)
|
||||
{
|
||||
EnsureGeometryColumn(ordinal);
|
||||
SqlBytes geomBytes = this.reader.GetSqlBytes(ordinal);
|
||||
object providerValue = sqlGeometryFromBinaryReader.Value(new BinaryReader(geomBytes.Stream));
|
||||
return SqlSpatialServices.Instance.GeometryFromProviderValue(providerValue);
|
||||
}
|
||||
|
||||
private static readonly Singleton<Func<BinaryReader, object>> sqlGeographyFromBinaryReader = new Singleton<Func<BinaryReader, object>>(() => CreateBinaryReadDelegate(SqlProviderServices.GetSqlTypesAssembly().SqlGeographyType));
|
||||
private static readonly Singleton<Func<BinaryReader, object>> sqlGeometryFromBinaryReader = new Singleton<Func<BinaryReader, object>>(() => CreateBinaryReadDelegate(SqlProviderServices.GetSqlTypesAssembly().SqlGeometryType));
|
||||
|
||||
// test to ensure that the SQL column has the expected SQL type. Don't use the CLR type to avoid having to worry about differences in
|
||||
// type versions between the client and the database.
|
||||
private void EnsureGeographyColumn(int ordinal)
|
||||
{
|
||||
string fieldTypeName = this.reader.GetDataTypeName(ordinal);
|
||||
if (!fieldTypeName.EndsWith(geographySqlType, StringComparison.Ordinal)) // Use EndsWith so that we just see the schema and type name, not the database name.
|
||||
{
|
||||
throw new InvalidDataException(Strings.SqlProvider_InvalidGeographyColumn(fieldTypeName));
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureGeometryColumn(int ordinal)
|
||||
{
|
||||
string fieldTypeName = this.reader.GetDataTypeName(ordinal);
|
||||
if (!fieldTypeName.EndsWith(geometrySqlType, StringComparison.Ordinal)) // Use EndsWith so that we just see the schema and type name, not the database name.
|
||||
{
|
||||
throw new InvalidDataException(Strings.SqlProvider_InvalidGeometryColumn(fieldTypeName));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds and compiles the Expression equivalent of the following:
|
||||
///
|
||||
/// (BinaryReader r) => { var result = new SpatialType(); result.Read(r); return r; }
|
||||
///
|
||||
/// The construct/read pattern is preferred over casting the result of calling GetValue on the DataReader,
|
||||
/// because constructing the value directly allows client code to specify the type, rather than SqlClient using
|
||||
/// the server-specified assembly qualified type name from TDS to try to locate the correct type on the client.
|
||||
/// </summary>
|
||||
/// <param name="spatialType"></param>
|
||||
/// <returns></returns>
|
||||
private static Func<BinaryReader, object> CreateBinaryReadDelegate(Type spatialType)
|
||||
{
|
||||
Debug.Assert(spatialType != null, "Ensure spatialType is non-null before calling CreateBinaryReadDelegate");
|
||||
|
||||
var readerParam = Expression.Parameter(typeof(BinaryReader));
|
||||
var binarySerializable = Expression.Variable(spatialType);
|
||||
var readMethod = spatialType.GetMethod("Read", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(System.IO.BinaryReader) }, null);
|
||||
|
||||
var ex = Expression.Lambda<Func<BinaryReader, object>>(
|
||||
Expression.Block(
|
||||
new[] { binarySerializable },
|
||||
Expression.Assign(binarySerializable, Expression.New(spatialType)),
|
||||
Expression.Call(binarySerializable, readMethod, readerParam),
|
||||
binarySerializable
|
||||
),
|
||||
readerParam
|
||||
);
|
||||
|
||||
Func<BinaryReader, object> result = ex.Compile();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user