Skip to content

Commit

Permalink
Binary backend format support
Browse files Browse the repository at this point in the history
Added infrastructure to enable binary backend formatting.
Added binary conversion handlers for int2, int4, and int8.
Merged existing bytea binary support into new infrastructure, making it transparent.
Renamed some of the conversion functions to be more descriptive.
  • Loading branch information
glenebob committed Aug 10, 2013
1 parent 48d7117 commit de3e670
Show file tree
Hide file tree
Showing 3 changed files with 237 additions and 146 deletions.
35 changes: 10 additions & 25 deletions src/Npgsql/NpgsqlCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -663,29 +663,15 @@ private void BindParameters()

for (Int32 i = 0; i < parameters.Count; i++)
{
// Do not quote strings, or escape existing quotes - this will be handled by the backend.
// DBNull or null values are returned as null.
// TODO: Would it be better to remove this null special handling out of ConvertToBackend??
parameterValues[i] = parameters[i].TypeInfo.ConvertToBackend(parameters[i].Value, true, Connector.NativeToBackendTypeConverterOptions);

// Do special handling of bytea values. They will be send in binary form.
// TODO: Add binary format support for all supported types. Not only bytea.
if (parameters[i].TypeInfo.NpgsqlDbType != NpgsqlDbType.Bytea)
{
parameterValues[i] = parameters[i].TypeInfo.ConvertToBackend(parameters[i].Value, true, Connector.NativeToBackendTypeConverterOptions);
}
else
{
if (parameters[i].Value != DBNull.Value)
{
parameterFormatCodes[i] = (Int16)FormatCode.Binary;
parameterValues[i] = (byte[])parameters[i].Value;
}
else
{
parameterValues[i] = parameters[i].TypeInfo.ConvertToBackend(parameters[i].Value, true, Connector.NativeToBackendTypeConverterOptions);
}
if (parameterValues[i] == null) {
parameterFormatCodes[i]= (Int16)FormatCode.Binary;
} else {
parameterFormatCodes[i] = parameterValues[i].GetType() == typeof(byte[]) ? (Int16)FormatCode.Binary : (Int16)FormatCode.Text;
}
}

bind.ParameterValues = parameterValues;
bind.ParameterFormatCodes = parameterFormatCodes;
}
Expand Down Expand Up @@ -797,11 +783,10 @@ public override void Prepare()
{
NpgsqlRowDescription.FieldData returnRowDescData = returnRowDesc[i];


if (returnRowDescData.TypeInfo != null && returnRowDescData.TypeInfo.NpgsqlDbType == NpgsqlDbType.Bytea)
if (returnRowDescData.TypeInfo != null)
{
// Binary format
resultFormatCodes[i] = (Int16)FormatCode.Binary;
// Binary format?
resultFormatCodes[i] = returnRowDescData.TypeInfo.SupportsBinaryBackendData ? (Int16)FormatCode.Binary : (Int16)FormatCode.Text;
}
else
{
Expand Down Expand Up @@ -909,7 +894,7 @@ internal StringBuilder GetCommandText()

private void PassParam(StringBuilder query, NpgsqlParameter p)
{
string serialised = p.TypeInfo.ConvertToBackend(p.Value, false, Connector.NativeToBackendTypeConverterOptions);
string serialised = (string)p.TypeInfo.ConvertToBackend(p.Value, false, Connector.NativeToBackendTypeConverterOptions);

// Add parentheses wrapping parameter value before the type cast to avoid problems with Int16.MinValue, Int32.MinValue and Int64.MinValue
// See bug #1010543
Expand Down
67 changes: 59 additions & 8 deletions src/NpgsqlTypes/NpgsqlTypeConverters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ internal abstract class BasicBackendToNativeTypeConverter
};

/// <summary>
/// Binary data.
/// Byte array from bytea encoded as text, escaped or hex format.
/// </summary>
internal static Object ToBinary(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
internal static Object ByteaTextToByteArray(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
{
Int32 octalValue = 0;
Int32 byteAPosition = 0;
Expand Down Expand Up @@ -164,6 +164,14 @@ internal static Object ToBinary(NpgsqlBackendTypeInfo TypeInfo, String BackendDa
return ms.ToArray();
}

/// <summary>
/// Byte array from bytea in ray binary.
/// </summary>
internal static Object ByteaBinaryToByteArray(NpgsqlBackendTypeInfo TypeInfo, byte[] BackendData, Int32 fieldValueSize, Int32 TypeModifier)
{
return BackendData;
}

/// <summary>
/// Convert a postgresql boolean to a System.Boolean.
/// </summary>
Expand All @@ -173,6 +181,17 @@ internal static Object ToBinary(NpgsqlBackendTypeInfo TypeInfo, String BackendDa
return (BackendData.ToLower() == "t" ? true : false);
}

internal static Object IntBinaryToInt(NpgsqlBackendTypeInfo TypeInfo, byte[] BackendData, Int32 fieldValueSize,
Int32 TypeModifier)
{
switch (BackendData.Length)
{
case 2 : return IPAddress.NetworkToHostOrder(BitConverter.ToInt16(BackendData, 0));
case 4 : return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(BackendData, 0));
case 8 : return IPAddress.NetworkToHostOrder(BitConverter.ToInt64(BackendData, 0));
default: throw new NpgsqlException("Unexpected integer binary field length");
}
}

/// <summary>
/// Convert a postgresql bit to a System.Boolean.
Expand Down Expand Up @@ -271,22 +290,22 @@ internal abstract class BasicNativeToBackendTypeConverter
/// <summary>
/// Binary data, escaped as needed per options.
/// </summary>
internal static String ToBinary(NpgsqlNativeTypeInfo TypeInfo, Object NativeData, bool forExtendedQuery, NativeToBackendTypeConverterOptions options)
internal static String ByteArrayToByteaText(NpgsqlNativeTypeInfo TypeInfo, Object NativeData, bool forExtendedQuery, NativeToBackendTypeConverterOptions options)
{
if (! options.SupportsHexByteFormat)
{
return ToBinaryEscaped(NativeData, options.UseConformantStrings);
return ByteArrayToByteaTextEscaped(NativeData, options.UseConformantStrings);
}
else
{
return ToBinaryHexFormat(NativeData, options.UseConformantStrings);
return ByteArrayToByteaTextHexFormat(NativeData, options.UseConformantStrings);
}
}

/// <summary>
/// Binary data with possible older style escapes.
/// </summary>
private static String ToBinaryEscaped(Object NativeData, bool UseConformantStrings)
private static String ByteArrayToByteaTextEscaped(Object NativeData, bool UseConformantStrings)
{
Byte[] byteArray = (Byte[])NativeData;
StringBuilder res = new StringBuilder(byteArray.Length);
Expand All @@ -309,11 +328,11 @@ private static String ToBinaryEscaped(Object NativeData, bool UseConformantStrin

return res.ToString();
}


/// <summary>
/// Binary data in the new hex format (>= 9.0).
/// </summary>
private static String ToBinaryHexFormat(Object NativeData, bool UseConformantStrings)
private static String ByteArrayToByteaTextHexFormat(Object NativeData, bool UseConformantStrings)
{
Byte[] byteArray = (Byte[])NativeData;

Expand All @@ -340,6 +359,14 @@ private static String ToBinaryHexFormat(Object NativeData, bool UseConformantStr

return new string(ret);
}

/// <summary>
/// Binary data, raw.
/// </summary>
internal static byte[] ByteArrayToByteaBinary(NpgsqlNativeTypeInfo TypeInfo, Object NativeData, NativeToBackendTypeConverterOptions options)
{
return (byte[])NativeData;
}

/// <summary>
/// Convert to a postgresql boolean.
Expand All @@ -348,6 +375,30 @@ internal static String ToBoolean(NpgsqlNativeTypeInfo TypeInfo, Object NativeDat
{
return ((bool)NativeData) ? "TRUE" : "FALSE";
}

/// <summary>
/// Convert to a postgresql binary int2.
/// </summary>
internal static byte[] Int16ToInt2Binary(NpgsqlNativeTypeInfo TypeInfo, Object NativeData, NativeToBackendTypeConverterOptions options)
{
return BitConverter.GetBytes(IPAddress.HostToNetworkOrder(Convert.ToInt16(NativeData)));
}

/// <summary>
/// Convert to a postgresql binary int4.
/// </summary>
internal static byte[] Int32ToInt4Binary(NpgsqlNativeTypeInfo TypeInfo, Object NativeData, NativeToBackendTypeConverterOptions options)
{
return BitConverter.GetBytes(IPAddress.HostToNetworkOrder(Convert.ToInt32(NativeData)));
}

/// <summary>
/// Convert to a postgresql binary int8.
/// </summary>
internal static byte[] Int64ToInt8Binary(NpgsqlNativeTypeInfo TypeInfo, Object NativeData, NativeToBackendTypeConverterOptions options)
{
return BitConverter.GetBytes(IPAddress.HostToNetworkOrder(Convert.ToInt64(NativeData)));
}

/// <summary>
/// Convert to a postgresql bit.
Expand Down

1 comment on commit de3e670

@udoliess
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see #146

Please sign in to comment.