X Tutup
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions Npgsql/Npgsql/ASCIIBytes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,18 @@ internal enum ASCIIBytes : byte

internal class ASCIIByteArrays
{
internal static readonly byte[] Empty = new byte[0];
internal static readonly byte[] Byte_0 = new byte[] { 0 };
internal static readonly byte[] Byte_1 = new byte[] { 1 };
internal static readonly byte[] NULL = BackendEncoding.UTF8Encoding.GetBytes("NULL");
internal static readonly byte[] AsciiDigit_0 = BackendEncoding.UTF8Encoding.GetBytes("0");
internal static readonly byte[] AsciiDigit_1 = BackendEncoding.UTF8Encoding.GetBytes("1");
internal static readonly byte[] TRUE = BackendEncoding.UTF8Encoding.GetBytes("TRUE");
internal static readonly byte[] FALSE = BackendEncoding.UTF8Encoding.GetBytes("FALSE");
internal static readonly byte[] INFINITY = BackendEncoding.UTF8Encoding.GetBytes("INFINITY");
internal static readonly byte[] NEG_INFINITY = BackendEncoding.UTF8Encoding.GetBytes("-INFINITY");
internal static readonly byte[] LineTerminator = BackendEncoding.UTF8Encoding.GetBytes("\r\n");
internal static readonly byte[] Empty = new byte[0];
internal static readonly byte[] Byte_0 = new byte[] { 0 };
internal static readonly byte[] Byte_1 = new byte[] { 1 };
internal static readonly byte[] NULL = BackendEncoding.UTF8Encoding.GetBytes("NULL");
internal static readonly byte[] AsciiDigit_0 = BackendEncoding.UTF8Encoding.GetBytes("0");
internal static readonly byte[] AsciiDigit_1 = BackendEncoding.UTF8Encoding.GetBytes("1");
internal static readonly byte[] TRUE = BackendEncoding.UTF8Encoding.GetBytes("TRUE");
internal static readonly byte[] FALSE = BackendEncoding.UTF8Encoding.GetBytes("FALSE");
internal static readonly byte[] INFINITY = BackendEncoding.UTF8Encoding.GetBytes("INFINITY");
internal static readonly byte[] NEG_INFINITY = BackendEncoding.UTF8Encoding.GetBytes("-INFINITY");
internal static readonly byte[] LineTerminator = BackendEncoding.UTF8Encoding.GetBytes("\r\n");
internal static readonly byte[] NaN = BackendEncoding.UTF8Encoding.GetBytes("NaN");
internal static readonly byte[] NaN_Quoted = BackendEncoding.UTF8Encoding.GetBytes("'NaN'");
}
}
71 changes: 70 additions & 1 deletion Npgsql/NpgsqlTypes/NpgsqlTypeConvNativeToBackend.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,55 @@ private static int StringEncodingInfoHash(bool forExtendedQuery, bool useConform
return hashValue;
}

internal static byte[] QuoteASCIIString(byte[] src, bool forExtendedQuery, bool arrayElement, byte[] singleQuotedValue = null, byte[] doubleQuotedValue = null)
{
if (arrayElement)
{
// Array elements always require double-quotes
if (doubleQuotedValue != null)
{
return doubleQuotedValue;
}
else
{
return WrapASCIIString(src, (byte)ASCIIBytes.DoubleQuote);
}
}
else
{
if (forExtendedQuery)
{
// Non-array-element values sent via Bind are not quoted
return src;
}
else
{
// Non-array-element values sent via simple query require single-quotes
if (singleQuotedValue != null)
{
return singleQuotedValue;
}
else
{
return WrapASCIIString(src, (byte)ASCIIBytes.SingleQuote);
}
}
}
}

private static byte[] WrapASCIIString(byte[] src, byte quote)
{
byte[] ret;

ret = new byte[src.Length + 2];

ret[0] = quote;
src.CopyTo(ret, 1);
ret[ret.Length - 1] = quote;

return ret;
}

/// <summary>
/// Convert a string to UTF8 encoded text, escaped and quoted as required.
/// </summary>
Expand Down Expand Up @@ -460,11 +509,31 @@ internal static byte[] ToBasicType<T>(NpgsqlNativeTypeInfo TypeInfo, object Nati
/// <summary>
/// Convert to a postgres double with maximum precision.
/// </summary>
internal static byte[] SingleDoubleToFloat4Float8Text(NpgsqlNativeTypeInfo TypeInfo, Object NativeData, Boolean forExtendedQuery, NativeToBackendTypeConverterOptions options, bool arrayElement)
internal static byte[] SingleToFloat4Text(NpgsqlNativeTypeInfo TypeInfo, Object NativeData, Boolean forExtendedQuery, NativeToBackendTypeConverterOptions options, bool arrayElement)
{
//Formats accepted vary according to locale, but it always accepts a plain number (no currency or
//grouping symbols) passed as a string (with the appropriate cast appended, as UseCast will cause
//to happen.
//NaN must be quoted for use outside of an array. In an array, no quoting is needed.
if (NativeData.Equals(float.NaN) && !arrayElement)
{
return QuoteASCIIString(ASCIIByteArrays.NaN, forExtendedQuery, arrayElement, ASCIIByteArrays.NaN_Quoted);
}

return BackendEncoding.UTF8Encoding.GetBytes(((IFormattable)NativeData).ToString("R", CultureInfo.InvariantCulture.NumberFormat));
}

internal static byte[] DoubleToFloat8Text(NpgsqlNativeTypeInfo TypeInfo, Object NativeData, Boolean forExtendedQuery, NativeToBackendTypeConverterOptions options, bool arrayElement)
{
//Formats accepted vary according to locale, but it always accepts a plain number (no currency or
//grouping symbols) passed as a string (with the appropriate cast appended, as UseCast will cause
//to happen.
//NaN must be quoted for use outside of an array. In an array, no quoting is needed.
if (NativeData.Equals(double.NaN) && !arrayElement)
{
return QuoteASCIIString(ASCIIByteArrays.NaN, forExtendedQuery, arrayElement, ASCIIByteArrays.NaN_Quoted);
}

return BackendEncoding.UTF8Encoding.GetBytes(((IFormattable)NativeData).ToString("R", CultureInfo.InvariantCulture.NumberFormat));
}

Expand Down
44 changes: 5 additions & 39 deletions Npgsql/NpgsqlTypes/NpgsqlTypeInfoNative.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ private byte[] ConvertToBackendPlainQuery(Object NativeData, NativeToBackendType

if (Quote)
{
backendSerialization = QuoteASCIIString(backendSerialization, false, arrayElement);
backendSerialization = BasicNativeToBackendTypeConverter.QuoteASCIIString(backendSerialization, false, arrayElement);
}

return backendSerialization;
Expand All @@ -259,7 +259,7 @@ private byte[] ConvertToBackendPlainQuery(Object NativeData, NativeToBackendType
)
);

backendSerialization = QuoteASCIIString(backendSerialization, false, arrayElement);
backendSerialization = BasicNativeToBackendTypeConverter.QuoteASCIIString(backendSerialization, false, arrayElement);

return backendSerialization;
}
Expand All @@ -278,7 +278,7 @@ private byte[] ConvertToBackendPlainQuery(Object NativeData, NativeToBackendType

if (Quote)
{
backendSerialization = QuoteASCIIString(backendSerialization, false, arrayElement);
backendSerialization = BasicNativeToBackendTypeConverter.QuoteASCIIString(backendSerialization, false, arrayElement);
}

return backendSerialization;
Expand All @@ -304,7 +304,7 @@ private byte[] ConvertToBackendExtendedQuery(Object NativeData, NativeToBackendT

if (Quote)
{
backendSerialization = QuoteASCIIString(backendSerialization, true, arrayElement);
backendSerialization = BasicNativeToBackendTypeConverter.QuoteASCIIString(backendSerialization, true, arrayElement);
}

return backendSerialization;
Expand Down Expand Up @@ -332,47 +332,13 @@ private byte[] ConvertToBackendExtendedQuery(Object NativeData, NativeToBackendT

if (Quote)
{
backendSerialization = QuoteASCIIString(backendSerialization, true, arrayElement);
backendSerialization = BasicNativeToBackendTypeConverter.QuoteASCIIString(backendSerialization, true, arrayElement);
}

return backendSerialization;
}
}

private static byte[] QuoteASCIIString(byte[] src, bool forExtendedQuery, bool arrayElement)
{
byte[] ret = null;

if (arrayElement)
{
// Array elements always require double-quotes
ret = new byte[src.Length + 2];

ret[0] = (byte)ASCIIBytes.DoubleQuote;
src.CopyTo(ret, 1);
ret[ret.Length - 1] = (byte)ASCIIBytes.DoubleQuote;
}
else
{
if (forExtendedQuery)
{
// Non-array-element values sent via Bind are not quoted
ret = src;
}
else
{
// Non-array-element values sent via simple query require single-quotes
ret = new byte[src.Length + 2];

ret[0] = (byte)ASCIIBytes.SingleQuote;
src.CopyTo(ret, 1);
ret[ret.Length - 1] = (byte)ASCIIBytes.SingleQuote;
}
}

return ret;
}

/// <summary>
/// Reports whether a native to backend binary encoder is available for this type.
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions Npgsql/NpgsqlTypes/NpgsqlTypesHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -342,13 +342,13 @@ private static NpgsqlNativeTypeMapping PrepareDefaultTypesMap()
nativeTypeMapping.AddTypeAlias("int8", typeof(Int64));

nativeTypeMapping.AddType("float4", NpgsqlDbType.Real, DbType.Single, false,
BasicNativeToBackendTypeConverter.SingleDoubleToFloat4Float8Text,
BasicNativeToBackendTypeConverter.SingleToFloat4Text,
BasicNativeToBackendTypeConverter.SingleToFloat4Binary);

nativeTypeMapping.AddTypeAlias("float4", typeof(Single));

nativeTypeMapping.AddType("float8", NpgsqlDbType.Double, DbType.Double, false,
BasicNativeToBackendTypeConverter.SingleDoubleToFloat4Float8Text,
BasicNativeToBackendTypeConverter.DoubleToFloat8Text,
BasicNativeToBackendTypeConverter.DoubleToFloat8Binary);

nativeTypeMapping.AddTypeAlias("float8", typeof(Double));
Expand Down
41 changes: 41 additions & 0 deletions tests/CommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,8 @@ public void InsertInfinityDateTimeSupportNpgsqlDbType()
[TestCase(null, NpgsqlDbType.Double, "field_float8", 7.4D, TestName = "NpgsqlDouble")]
[TestCase(null, NpgsqlDbType.Real, "field_float4", 7.4F, TestName = "NpgsqlSingle")]
[TestCase(null, NpgsqlDbType.Text, "field_text", @"\test", TestName = "StringWithBackslashes")]
[TestCase(null, NpgsqlDbType.Double, "field_float8", Double.NaN, TestName = "DoubleNaN")]
[TestCase(null, NpgsqlDbType.Real, "field_float4", Single.NaN, TestName = "SingleNaN")]
public void InsertValue(DbType? dbType, NpgsqlDbType? npgsqlDbType, string fieldName, object value)
{
if (dbType.HasValue && npgsqlDbType.HasValue || (!dbType.HasValue && !npgsqlDbType.HasValue))
Expand Down Expand Up @@ -3003,6 +3005,45 @@ public void DoubleArrayHandlingZeroItemPrepared()
}
}

[Test]
public void DoubleArrayHandlingNaNValue([Values(true, false)] bool prepareCommand)
{
using (var cmd = new NpgsqlCommand("select :p1", Conn))
{
var inVal = new[] { double.NaN, 12345.12345d };
var parameter = new NpgsqlParameter("p1", NpgsqlDbType.Double | NpgsqlDbType.Array);
parameter.Value = inVal;
cmd.Parameters.Add(parameter);
if (prepareCommand)
cmd.Prepare();

var retVal = (Double[])cmd.ExecuteScalar();
Assert.AreEqual(inVal.Length, retVal.Length);
Assert.AreEqual(inVal[0], retVal[0]);
Assert.AreEqual(inVal[1], retVal[1]);
}
}

[Test]
public void SingleArrayHandlingNaNValue([Values(true, false)] bool prepareCommand)
{
using (var cmd = new NpgsqlCommand("select :p1", Conn))
{
var inVal = new[] { float.NaN, 12345.12345f };
var parameter = new NpgsqlParameter("p1", NpgsqlDbType.Real | NpgsqlDbType.Array);
parameter.Value = inVal;
cmd.Parameters.Add(parameter);
if (prepareCommand)
cmd.Prepare();

var retVal = (float[])cmd.ExecuteScalar();
Assert.AreEqual(inVal.Length, retVal.Length);
Assert.AreEqual(inVal[0], retVal[0]);
Assert.AreEqual(inVal[1], retVal[1]);
}
}


[Test]
public void ByteaArrayHandling()
{
Expand Down
X Tutup