Skip to content

Commit

Permalink
Merge pull request #58 from IvaYan/extened-types
Browse files Browse the repository at this point in the history
All integers, decimal & guid
  • Loading branch information
Giorgi committed Aug 20, 2022
2 parents b7f3e52 + 37f74b1 commit 84da3fe
Show file tree
Hide file tree
Showing 8 changed files with 428 additions and 8 deletions.
43 changes: 36 additions & 7 deletions DuckDB.NET.Data/DuckDBDataReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ public override bool GetBoolean(int ordinal)

public override byte GetByte(int ordinal)
{
throw new NotImplementedException();
return NativeMethods.Types.DuckDBValueUInt8(queryResult, ordinal, currentRow);
}

public sbyte GetSByte(int ordinal)
{
return NativeMethods.Types.DuckDBValueInt8(queryResult, ordinal, currentRow);
}

public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length)
Expand All @@ -47,12 +52,12 @@ public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int b

public override char GetChar(int ordinal)
{
throw new NotImplementedException();
throw new NotSupportedException();
}

public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length)
{
throw new NotImplementedException();
throw new NotSupportedException();
}

public override string GetDataTypeName(int ordinal)
Expand Down Expand Up @@ -82,9 +87,14 @@ public override Type GetFieldType(int ordinal)
{
DuckDBType.DuckdbTypeInvalid => throw new DuckDBException("Invalid type"),
DuckDBType.DuckdbTypeBoolean => typeof(bool),
DuckDBType.DuckdbTypeTinyInt => typeof(sbyte),
DuckDBType.DuckdbTypeSmallInt => typeof(short),
DuckDBType.DuckdbTypeInteger => typeof(int),
DuckDBType.DuckdbTypeBigInt => typeof(long),
DuckDBType.DuckdbTypeUnsignedTinyInt => typeof(byte),
DuckDBType.DuckdbTypeUnsignedSmallInt => typeof(ushort),
DuckDBType.DuckdbTypeUnsignedInteger => typeof(uint),
DuckDBType.DuckdbTypeUnsignedBigInt => typeof(ulong),
DuckDBType.DuckdbTypeFloat => typeof(float),
DuckDBType.DuckdbTypeDouble => typeof(double),
DuckDBType.DuckdbTypeTimestamp => typeof(DateTime),
Expand All @@ -93,8 +103,8 @@ public override Type GetFieldType(int ordinal)
DuckDBType.DuckdbTypeInterval => throw new NotImplementedException(),
DuckDBType.DuckdbTypeHugeInt => typeof(BigInteger),
DuckDBType.DuckdbTypeVarchar => typeof(string),
DuckDBType.DuckdbTypeDecimal => typeof(Decimal),
var typ => throw new ArgumentException($"Unrecognised type {typ} in column {ordinal+1}")
DuckDBType.DuckdbTypeDecimal => typeof(decimal),
var type => throw new ArgumentException($"Unrecognised type {type} ({(int)type}) in column {ordinal+1}")
};
}

Expand Down Expand Up @@ -122,6 +132,21 @@ public override long GetInt64(int ordinal)
{
return NativeMethods.Types.DuckDBValueInt64(queryResult, ordinal, currentRow);
}

public ushort GetUInt16(int ordinal)
{
return NativeMethods.Types.DuckDBValueUInt16(queryResult, ordinal, currentRow);
}

public uint GetUInt32(int ordinal)
{
return NativeMethods.Types.DuckDBValueUInt32(queryResult, ordinal, currentRow);
}

public ulong GetUInt64(int ordinal)
{
return NativeMethods.Types.DuckDBValueUInt64(queryResult, ordinal, currentRow);
}

public BigInteger GetBigInteger(int ordinal)
{
Expand Down Expand Up @@ -161,14 +186,18 @@ public override object GetValue(int ordinal)
{
return DBNull.Value;
}

return NativeMethods.Query.DuckDBColumnType(queryResult, ordinal) switch
{
DuckDBType.DuckdbTypeInvalid => throw new DuckDBException("Invalid type"),
DuckDBType.DuckdbTypeBoolean => GetBoolean(ordinal),
DuckDBType.DuckdbTypeTinyInt => GetSByte(ordinal),
DuckDBType.DuckdbTypeSmallInt => GetInt16(ordinal),
DuckDBType.DuckdbTypeInteger => GetInt32(ordinal),
DuckDBType.DuckdbTypeBigInt => GetInt64(ordinal),
DuckDBType.DuckdbTypeUnsignedTinyInt => GetByte(ordinal),
DuckDBType.DuckdbTypeUnsignedSmallInt => GetUInt16(ordinal),
DuckDBType.DuckdbTypeUnsignedInteger => GetUInt32(ordinal),
DuckDBType.DuckdbTypeUnsignedBigInt => GetUInt64(ordinal),
DuckDBType.DuckdbTypeFloat => GetFloat(ordinal),
DuckDBType.DuckdbTypeDouble => GetDouble(ordinal),
DuckDBType.DuckdbTypeTimestamp => GetDateTime(ordinal),
Expand All @@ -178,7 +207,7 @@ public override object GetValue(int ordinal)
DuckDBType.DuckdbTypeHugeInt => GetBigInteger(ordinal),
DuckDBType.DuckdbTypeVarchar => GetString(ordinal),
DuckDBType.DuckdbTypeDecimal => GetDecimal(ordinal),
_ => throw new ArgumentException("Unrecognised type")
var type => throw new ArgumentException($"Unrecognised type {type} ({(int)type}) in column {ordinal+1}")
};
}

Expand Down
61 changes: 61 additions & 0 deletions DuckDB.NET.Data/DuckDBParameter.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Data;
using System.Data.Common;
using DuckDB.NET.Data.Internal;
Expand Down Expand Up @@ -66,6 +67,16 @@ public DuckDBParameter(object value)
this.value = value;
}

public DuckDBParameter(Guid value)
: this(DbType.Guid, value)
{
}

public DuckDBParameter(decimal value)
: this(DbType.Currency, value)
{
}

public DuckDBParameter(bool value)
: this(DbType.Boolean, value)
{
Expand All @@ -90,6 +101,26 @@ public DuckDBParameter(long value)
: this(DbType.Int64, value)
{
}

public DuckDBParameter(byte value)
: this(DbType.Byte, value)
{
}

public DuckDBParameter(ushort value)
: this(DbType.UInt16, value)
{
}

public DuckDBParameter(uint value)
: this(DbType.UInt32, value)
{
}

public DuckDBParameter(ulong value)
: this(DbType.UInt64, value)
{
}

public DuckDBParameter(float value)
: this(DbType.Single, value)
Expand All @@ -106,6 +137,16 @@ public DuckDBParameter(string value)
{
}

public DuckDBParameter(string name, Guid value)
: this(name, DbType.Guid, value)
{
}

public DuckDBParameter(string name, decimal value)
: this(name, DbType.Currency, value)
{
}

public DuckDBParameter(string name, bool value)
: this(name, DbType.Boolean, value)
{
Expand All @@ -130,6 +171,26 @@ public DuckDBParameter(string name, long value)
: this(name, DbType.Int64, value)
{
}

public DuckDBParameter(string name, byte value)
: this(name, DbType.Byte, value)
{
}

public DuckDBParameter(string name, ushort value)
: this(name, DbType.UInt16, value)
{
}

public DuckDBParameter(string name, uint value)
: this(name, DbType.UInt32, value)
{
}

public DuckDBParameter(string name, ulong value)
: this(name, DbType.UInt64, value)
{
}

public DuckDBParameter(string name, float value)
: this(name, DbType.Single, value)
Expand Down
22 changes: 22 additions & 0 deletions DuckDB.NET.Data/Internal/PreparedStatement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,17 @@ internal sealed class PreparedStatement : IDisposable
{
private static readonly Dictionary<DbType, Func<DuckDBPreparedStatement, long, object, DuckDBState>> Binders = new()
{
{ DbType.Guid, BindObject },
{ DbType.Currency, BindObject },
{ DbType.Boolean, BindBoolean },
{ DbType.SByte, BindInt8 },
{ DbType.Int16, BindInt16 },
{ DbType.Int32, BindInt32 },
{ DbType.Int64, BindInt64 },
{ DbType.Byte, BindUInt8 },
{ DbType.UInt16, BindUInt16 },
{ DbType.UInt32, BindUInt32 },
{ DbType.UInt64, BindUInt64 },
{ DbType.Single, BindFloat },
{ DbType.Double, BindDouble },
{ DbType.String, BindString },
Expand Down Expand Up @@ -93,6 +99,9 @@ private static void BindParameter(DuckDBPreparedStatement preparedStatement, lon
}
}

private static DuckDBState BindObject(DuckDBPreparedStatement preparedStatement, long index, object value)
=> BindString(preparedStatement, index, value.ToString());

private static DuckDBState BindBoolean(DuckDBPreparedStatement preparedStatement, long index, object value)
=> NativeMethods.PreparedStatements.DuckDBBindBoolean(preparedStatement, index, (bool)value);

Expand All @@ -108,6 +117,19 @@ private static DuckDBState BindInt32(DuckDBPreparedStatement preparedStatement,
private static DuckDBState BindInt64(DuckDBPreparedStatement preparedStatement, long index, object value)
=> NativeMethods.PreparedStatements.DuckDBBindInt64(preparedStatement, index, (long)value);

private static DuckDBState BindUInt8(DuckDBPreparedStatement preparedStatement, long index, object value)
=> NativeMethods.PreparedStatements.DuckDBBindUInt8(preparedStatement, index, (byte)value);

private static DuckDBState BindUInt16(DuckDBPreparedStatement preparedStatement, long index, object value)
=> NativeMethods.PreparedStatements.DuckDBBindUInt16(preparedStatement, index, (ushort)value);

private static DuckDBState BindUInt32(DuckDBPreparedStatement preparedStatement, long index, object value)
=> NativeMethods.PreparedStatements.DuckDBBindUInt32(preparedStatement, index, (uint)value);

private static DuckDBState BindUInt64(DuckDBPreparedStatement preparedStatement, long index, object value)
=> NativeMethods.PreparedStatements.DuckDBBindUInt64(preparedStatement, index, (ulong)value);


private static DuckDBState BindFloat(DuckDBPreparedStatement preparedStatement, long index, object value)
=> NativeMethods.PreparedStatements.DuckDBBindFloat(preparedStatement, index, (float)value);

Expand Down
64 changes: 64 additions & 0 deletions DuckDB.NET.Test/Parameters/DecimalParameterTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System.Globalization;
using DuckDB.NET.Data;
using FluentAssertions;
using Xunit;

namespace DuckDB.NET.Test.Parameters;

public class DecimalParameterTests
{
[Fact]
public void SimpleTest()
{
using var connection = new DuckDBConnection("DataSource=:memory:");
connection.Open();

var values = new []{0m, decimal.Zero, decimal.MinValue,
decimal.MaxValue, decimal.MaxValue / 3, decimal.One,
decimal.One / 2, decimal.One / 3, decimal.MinusOne,
decimal.MinusOne / 2, decimal.MinusOne / 3};

foreach (var value in values)
{
var command = connection.CreateCommand();
command.CommandText = $"SELECT '{value}';";
command.ExecuteNonQuery();

var scalar = command.ExecuteScalar();
scalar.Should().Be(value.ToString(CultureInfo.InvariantCulture));

var reader = command.ExecuteReader();
reader.Read();
var receivedValue = reader.GetDecimal(0);
receivedValue.Should().Be(value);
}
}

[Fact]
public void BindValueTest()
{
using var connection = new DuckDBConnection("DataSource=:memory:");
connection.Open();

var values = new []{0m, decimal.Zero, decimal.MinValue,
decimal.MaxValue, decimal.MaxValue / 3, decimal.One,
decimal.One / 2, decimal.One / 3, decimal.MinusOne,
decimal.MinusOne / 2, decimal.MinusOne / 3};

foreach (var value in values)
{
var command = connection.CreateCommand();
command.CommandText = "SELECT ?;";
command.Parameters.Add(new DuckDBParameter(value));
command.ExecuteNonQuery();

var scalar = command.ExecuteScalar();
scalar.Should().Be(value.ToString(CultureInfo.InvariantCulture));

var reader = command.ExecuteReader();
reader.Read();
var receivedValue = reader.GetDecimal(0);
receivedValue.Should().Be(value);
}
}
}
58 changes: 58 additions & 0 deletions DuckDB.NET.Test/Parameters/GuidParameterTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System;
using DuckDB.NET.Data;
using FluentAssertions;
using Xunit;

namespace DuckDB.NET.Test.Parameters;

public class GuidParameterTests
{
[Fact]
public void SimpleTest()
{
using var connection = new DuckDBConnection("DataSource=:memory:");
connection.Open();

var guids = new[] { Guid.NewGuid(), Guid.Empty };

foreach (var guid in guids)
{
var command = connection.CreateCommand();
command.CommandText = $"SELECT '{guid}';";
command.ExecuteNonQuery();

var scalar = command.ExecuteScalar();
scalar.Should().Be(guid.ToString());

var reader = command.ExecuteReader();
reader.Read();
var receivedValue = reader.GetGuid(0);
receivedValue.Should().Be(guid);
}
}

[Fact]
public void BindValueTest()
{
using var connection = new DuckDBConnection("DataSource=:memory:");
connection.Open();

var guids = new[] { Guid.NewGuid(), Guid.Empty };

foreach (var guid in guids)
{
var command = connection.CreateCommand();
command.CommandText = "SELECT ?;";
command.Parameters.Add(new DuckDBParameter(guid));
command.ExecuteNonQuery();

var scalar = command.ExecuteScalar();
scalar.Should().Be(guid.ToString());

var reader = command.ExecuteReader();
reader.Read();
var receivedValue = reader.GetGuid(0);
receivedValue.Should().Be(guid);
}
}
}
Loading

0 comments on commit 84da3fe

Please sign in to comment.