diff --git a/DuckDB.NET.Data/DuckDBDataReader.cs b/DuckDB.NET.Data/DuckDBDataReader.cs index 94f2df4..b28207c 100644 --- a/DuckDB.NET.Data/DuckDBDataReader.cs +++ b/DuckDB.NET.Data/DuckDBDataReader.cs @@ -6,6 +6,7 @@ using System.IO; using System.Numerics; using System.Runtime.InteropServices; +using DuckDB.NET.Data.Types; namespace DuckDB.NET.Data { @@ -61,10 +62,7 @@ public override string GetDataTypeName(int ordinal) } public override DateTime GetDateTime(int ordinal) - { - var text = GetString(ordinal); - return DateTime.Parse(text, null, DateTimeStyles.RoundtripKind); - } + => Types.DuckDBTimestamp.Load(queryResult, ordinal, currentRow); public override decimal GetDecimal(int ordinal) { diff --git a/DuckDB.NET.Data/DuckDBParameter.cs b/DuckDB.NET.Data/DuckDBParameter.cs index 0e33581..00fff5d 100644 --- a/DuckDB.NET.Data/DuckDBParameter.cs +++ b/DuckDB.NET.Data/DuckDBParameter.cs @@ -1,6 +1,8 @@ +using System; using System.Data; using System.Data.Common; using DuckDB.NET.Data.Internal; +using DuckDB.NET.Data.Types; namespace DuckDB.NET.Data; @@ -47,7 +49,7 @@ public DuckDBParameter() } - public DuckDBParameter(string name, DbType type, object value) + private DuckDBParameter(string name, DbType type, object value) { parameterName = name; dbType = type; @@ -146,6 +148,16 @@ public DuckDBParameter(string name, string value) { } + public DuckDBParameter(string name, DateTime value) + : this(name, DbType.DateTime, Types.DuckDBTimestamp.FromDateTime(value)) + { + } + + public DuckDBParameter(DateTime value) + : this(DbType.DateTime, Types.DuckDBTimestamp.FromDateTime(value)) + { + } + public override void ResetDbType() { DbType = DbType.String; diff --git a/DuckDB.NET.Data/Internal/PreparedStatement.cs b/DuckDB.NET.Data/Internal/PreparedStatement.cs index 4fcb60b..84c4085 100644 --- a/DuckDB.NET.Data/Internal/PreparedStatement.cs +++ b/DuckDB.NET.Data/Internal/PreparedStatement.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using DuckDB.NET.Data.Types; namespace DuckDB.NET.Data; @@ -80,12 +81,21 @@ private static void BindParameter(DuckDBPreparedStatement preparedStatement, lon return; } - if (!Binders.TryGetValue(parameter.DbType, out var binder)) + DuckDBState result; + if (parameter.Value is IDuckDBParameterValue parameterValue) { - throw new InvalidOperationException($"Unable to bind value of type {parameter.DbType}."); + result = parameterValue.Bind(preparedStatement, index); + } + else + { + if (!Binders.TryGetValue(parameter.DbType, out var binder)) + { + throw new InvalidOperationException($"Unable to bind value of type {parameter.DbType}."); + } + + result = binder(preparedStatement, index, parameter.Value); } - var result = binder(preparedStatement, index, parameter.Value); if (!result.IsSuccess()) { var errorMessage = NativeMethods.PreparedStatements.DuckDBPrepareError(preparedStatement).ToManagedString(false); diff --git a/DuckDB.NET.Data/Types/DuckDBTimestamp.cs b/DuckDB.NET.Data/Types/DuckDBTimestamp.cs new file mode 100644 index 0000000..38df011 --- /dev/null +++ b/DuckDB.NET.Data/Types/DuckDBTimestamp.cs @@ -0,0 +1,122 @@ +using System; + +namespace DuckDB.NET.Data.Types; + +internal class DuckDBTimestamp : IDuckDBParameterValue +{ + private readonly DuckDBTimestampStruct nativeValue; + + private DuckDBTimestamp(DuckDBTimestampStruct native) + { + nativeValue = native; + } + + public DuckDBState Bind(DuckDBPreparedStatement preparedStatement, long index) + { + return NativeMethods.PreparedStatements.DuckDBParamType(preparedStatement, index) switch + { + DuckDBType.DuckdbTypeDate => BindDate(preparedStatement, index), + DuckDBType.DuckdbTypeTime => BindTime(preparedStatement, index), + DuckDBType.DuckdbTypeTimestamp => BindTimestamp(preparedStatement, index), + DuckDBType.DuckdbTypeInvalid => BindTimestamp(preparedStatement, index), + _ => throw new ArgumentOutOfRangeException("Unexpected target data type.") + }; + } + + private DuckDBState BindDate(DuckDBPreparedStatement preparedStatement, long index) + { + var date = NativeMethods.DateTime.DuckDBToDate(nativeValue.Date); + return NativeMethods.PreparedStatements.DuckDBBindDate(preparedStatement, index, date); + } + + private DuckDBState BindTime(DuckDBPreparedStatement preparedStatement, long index) + { + var time = NativeMethods.DateTime.DuckDBToTime(nativeValue.Time); + return NativeMethods.PreparedStatements.DuckDBBindTime(preparedStatement, index, time); + } + + private DuckDBState BindTimestamp(DuckDBPreparedStatement preparedStatement, long index) + { + var timestamp = NativeMethods.DateTime.DuckDBToTimestamp(nativeValue); + return NativeMethods.PreparedStatements.DuckDBBindTimestamp(preparedStatement, index, timestamp); + } + + public static DateTime Load(DuckDBResult result, long col, long row) + { + return (NativeMethods.Query.DuckDBColumnType(result, col) switch + { + DuckDBType.DuckdbTypeTimestamp => LoadTimestamp(result, col, row), + DuckDBType.DuckdbTypeTime => LoadTime(result, col, row), + DuckDBType.DuckdbTypeDate => LoadDate(result, col, row), + _ => throw new ArgumentOutOfRangeException("Unexpected data type.") + }).ToDateTime(); + } + + private static DuckDBTimestamp LoadTimestamp(DuckDBResult result, long col, long row) + { + var timestamp = NativeMethods.Types.DuckDbValueTimestamp(result, col, row); + var timestampStruct = NativeMethods.DateTime.DuckDBFromTimestamp(timestamp); + return new DuckDBTimestamp(timestampStruct); + } + + private static DuckDBTimestamp LoadTime(DuckDBResult result, long col, long row) + { + var time = NativeMethods.Types.DuckDbValueTime(result, col, row); + var timeStruct = NativeMethods.DateTime.DuckDBFromTime(time); + var timestamp = new DuckDBTimestampStruct + { + Time = timeStruct, + Date = new DuckDBDateStruct() + }; + return new DuckDBTimestamp(timestamp); + } + + private static DuckDBTimestamp LoadDate(DuckDBResult result, long col, long row) + { + var date = NativeMethods.Types.DuckDbValueDate(result, col, row); + var dateStruct = NativeMethods.DateTime.DuckDBFromDate(date); + var timestamp = new DuckDBTimestampStruct + { + Date = dateStruct, + Time = new DuckDBTimeStruct() + }; + return new DuckDBTimestamp(timestamp); + } + + public DateTime ToDateTime() + { + return new DateTime( + Math.Max(nativeValue.Date.Year, DateTime.MinValue.Year), + Math.Max(nativeValue.Date.Month, DateTime.MinValue.Month), + Math.Max(nativeValue.Date.Day, DateTime.MinValue.Day), + Math.Max(nativeValue.Time.Hour, DateTime.MinValue.Hour), + Math.Max(nativeValue.Time.Min, DateTime.MinValue.Minute), + Math.Max(nativeValue.Time.Sec, DateTime.MinValue.Second), + Math.Max(nativeValue.Time.Msec, DateTime.MinValue.Millisecond) + ); + } + + public static DuckDBTimestamp FromDateTime(DateTime dateTime) + { + var nativeDate = new DuckDBDateStruct + { + Year = dateTime.Year, + Month = (byte)dateTime.Month, + Day = (byte)dateTime.Day + }; + + var nativeTime = new DuckDBTimeStruct + { + Hour = (byte)dateTime.Hour, + Min = (byte)dateTime.Minute, + Sec = (byte)dateTime.Second, + Msec = dateTime.Millisecond + }; + + var value = new DuckDBTimestampStruct { + Date = nativeDate, + Time = nativeTime + }; + return new DuckDBTimestamp(value); + } +} \ No newline at end of file diff --git a/DuckDB.NET.Data/Types/IDuckDBParameterValue.cs b/DuckDB.NET.Data/Types/IDuckDBParameterValue.cs new file mode 100644 index 0000000..6281089 --- /dev/null +++ b/DuckDB.NET.Data/Types/IDuckDBParameterValue.cs @@ -0,0 +1,8 @@ +using System; + +namespace DuckDB.NET.Data.Types; + +internal interface IDuckDBParameterValue +{ + DuckDBState Bind(DuckDBPreparedStatement preparedStatement, long index); +} \ No newline at end of file diff --git a/DuckDB.NET.Test/DateTimeTests/DateTests.cs b/DuckDB.NET.Test/DateTimeTests/DateTests.cs new file mode 100644 index 0000000..86043b8 --- /dev/null +++ b/DuckDB.NET.Test/DateTimeTests/DateTests.cs @@ -0,0 +1,118 @@ +using System; +using DuckDB.NET.Data; +using FluentAssertions; +using Xunit; + +namespace DuckDB.NET.Test.DateTimeTests; + +public class DateTests +{ + [Theory] + [InlineData(1992, 09, 20)] + [InlineData(2022, 05, 04)] + [InlineData(2022, 04, 05)] + [InlineData(1, 1, 1)] + public void QueryScalarTest(int year, int mon, int day) + { + using var connection = new DuckDBConnection(DuckDBConnectionStringBuilder.InMemoryConnectionString); + connection.Open(); + + using var cmd = connection.CreateCommand(); + cmd.CommandText = $"SELECT DATE '{year}-{mon}-{day}';"; + + var scalar = cmd.ExecuteScalar(); + + scalar.Should().BeOfType(); + + var dateOnly = (DateTime) scalar; + + dateOnly.Year.Should().Be(year); + dateOnly.Month.Should().Be(mon); + dateOnly.Day.Should().Be(day); + dateOnly.Hour.Should().Be(DateTime.MinValue.Hour); + dateOnly.Minute.Should().Be(DateTime.MinValue.Minute); + dateOnly.Second.Should().Be(DateTime.MinValue.Second); + dateOnly.Minute.Should().Be(DateTime.MinValue.Millisecond); + } + + [Theory] + [InlineData(1992, 09, 20)] + [InlineData(2022, 05, 04)] + [InlineData(2022, 04, 05)] + [InlineData(1, 1, 1)] + public void BindParamTest(int year, int mon, int day) + { + using var connection = new DuckDBConnection(DuckDBConnectionStringBuilder.InMemoryConnectionString); + connection.Open(); + + var expectedValue = new DateTime(year, mon, day); + + using var cmd = connection.CreateCommand(); + cmd.CommandText = "SELECT ?::DATE;"; + cmd.Parameters.Add(new DuckDBParameter(expectedValue)); + + var scalar = cmd.ExecuteScalar(); + + scalar.Should().BeOfType(); + + var dateOnly = (DateTime) scalar; + + dateOnly.Year.Should().Be(year); + dateOnly.Month.Should().Be(mon); + dateOnly.Day.Should().Be(day); + dateOnly.Hour.Should().Be(DateTime.MinValue.Hour); + dateOnly.Minute.Should().Be(DateTime.MinValue.Minute); + dateOnly.Second.Should().Be(DateTime.MinValue.Second); + dateOnly.Minute.Should().Be(DateTime.MinValue.Millisecond); + + dateOnly.Should().Be(expectedValue); + } + + [Theory] + [InlineData(1992, 09, 20)] + [InlineData(2022, 05, 04)] + [InlineData(2022, 04, 05)] + [InlineData(1, 1, 1)] + public void BindAndInsert(int year, int mon, int day) + { + using var connection = new DuckDBConnection(DuckDBConnectionStringBuilder.InMemoryConnectionString); + connection.Open(); + + var expectedValue = new DateTime(year, mon, day); + + using var cmd = connection.CreateCommand(); + + try + { + cmd.CommandText = "CREATE TABLE date_test (d DATE);"; + cmd.ExecuteNonQuery(); + + cmd.CommandText = "INSERT INTO date_test (d) VALUES (?);"; + cmd.Parameters.Add(new DuckDBParameter(expectedValue)); + cmd.ExecuteNonQuery(); + + cmd.CommandText = "SELECT * FROM date_test;"; + cmd.Parameters.Clear(); + var scalar = cmd.ExecuteScalar(); + + scalar.Should().BeOfType(); + + var dateOnly = (DateTime) scalar; + + dateOnly.Year.Should().Be(year); + dateOnly.Month.Should().Be(mon); + dateOnly.Day.Should().Be(day); + dateOnly.Hour.Should().Be(DateTime.MinValue.Hour); + dateOnly.Minute.Should().Be(DateTime.MinValue.Minute); + dateOnly.Second.Should().Be(DateTime.MinValue.Second); + dateOnly.Minute.Should().Be(DateTime.MinValue.Millisecond); + + dateOnly.Should().Be(expectedValue); + } + finally + { + cmd.CommandText = "DROP TABLE date_test;"; + cmd.ExecuteNonQuery(); + } + } +} \ No newline at end of file diff --git a/DuckDB.NET.Test/DateTimeTests/TimeTests.cs b/DuckDB.NET.Test/DateTimeTests/TimeTests.cs new file mode 100644 index 0000000..880ec03 --- /dev/null +++ b/DuckDB.NET.Test/DateTimeTests/TimeTests.cs @@ -0,0 +1,120 @@ +using System; +using DuckDB.NET.Data; +using FluentAssertions; +using Xunit; + +namespace DuckDB.NET.Test.DateTimeTests; + +public class TimeTests +{ + [Theory] + [InlineData(12, 15, 17, 350)] + [InlineData(12, 17, 15, 450)] + [InlineData(18, 15, 17, 125)] + [InlineData(0, 0, 0, 0)] + public void QueryScalarTest(int hour, int minute, int second, int millisecond) + { + using var connection = new DuckDBConnection(DuckDBConnectionStringBuilder.InMemoryConnectionString); + connection.Open(); + + using var cmd = connection.CreateCommand(); + cmd.CommandText = $"SELECT TIME '{hour}:{minute}:{second}.{millisecond:000000}';"; + + var scalar = cmd.ExecuteScalar(); + + scalar.Should().BeOfType(); + + var timeOnly = (DateTime) scalar; + + timeOnly.Year.Should().Be(DateTime.MinValue.Year); + timeOnly.Month.Should().Be(DateTime.MinValue.Month); + timeOnly.Day.Should().Be(DateTime.MinValue.Day); + timeOnly.Hour.Should().Be(hour); + timeOnly.Minute.Should().Be(minute); + timeOnly.Second.Should().Be(second); + timeOnly.Millisecond.Should().Be(millisecond); + } + + [Theory] + [InlineData(12, 15, 17, 350)] + [InlineData(12, 17, 15, 450)] + [InlineData(18, 15, 17, 125)] + [InlineData(0, 0, 0, 0)] + public void BindParamTest(int hour, int minute, int second, int millisecond) + { + using var connection = new DuckDBConnection(DuckDBConnectionStringBuilder.InMemoryConnectionString); + connection.Open(); + + var expectedValue = new DateTime(DateTime.MinValue.Year, DateTime.MinValue.Month, DateTime.MinValue.Day, + hour, minute, second, millisecond); + + using var cmd = connection.CreateCommand(); + cmd.CommandText = "SELECT ?::TIME;"; + cmd.Parameters.Add(new DuckDBParameter(expectedValue)); + + var scalar = cmd.ExecuteScalar(); + + scalar.Should().BeOfType(); + + var timeOnly = (DateTime) scalar; + + timeOnly.Year.Should().Be(DateTime.MinValue.Year); + timeOnly.Month.Should().Be(DateTime.MinValue.Month); + timeOnly.Day.Should().Be(DateTime.MinValue.Day); + timeOnly.Hour.Should().Be(hour); + timeOnly.Minute.Should().Be(minute); + timeOnly.Second.Should().Be(second); + timeOnly.Millisecond.Should().Be(millisecond); + + timeOnly.Should().Be(expectedValue); + } + + [Theory] + [InlineData(12, 15, 17, 350)] + [InlineData(12, 17, 15, 450)] + [InlineData(18, 15, 17, 125)] + [InlineData(0, 0, 0, 0)] + public void BindAndInsert(int hour, int minute, int second, int millisecond) + { + using var connection = new DuckDBConnection(DuckDBConnectionStringBuilder.InMemoryConnectionString); + connection.Open(); + + var expectedValue = new DateTime(DateTime.MinValue.Year, DateTime.MinValue.Month, DateTime.MinValue.Day, + hour, minute, second, millisecond); + + using var cmd = connection.CreateCommand(); + + try + { + cmd.CommandText = "CREATE TABLE time_test (t TIME);"; + cmd.ExecuteNonQuery(); + + cmd.CommandText = "INSERT INTO time_test (t) VALUES (?);"; + cmd.Parameters.Add(new DuckDBParameter(expectedValue)); + cmd.ExecuteNonQuery(); + + cmd.CommandText = "SELECT * FROM time_test;"; + cmd.Parameters.Clear(); + var scalar = cmd.ExecuteScalar(); + + scalar.Should().BeOfType(); + + var timeOnly = (DateTime) scalar; + + timeOnly.Year.Should().Be(DateTime.MinValue.Year); + timeOnly.Month.Should().Be(DateTime.MinValue.Month); + timeOnly.Day.Should().Be(DateTime.MinValue.Day); + timeOnly.Hour.Should().Be(hour); + timeOnly.Minute.Should().Be(minute); + timeOnly.Second.Should().Be(second); + timeOnly.Millisecond.Should().Be(millisecond); + + timeOnly.Should().Be(expectedValue); + } + finally + { + cmd.CommandText = "DROP TABLE time_test;"; + cmd.ExecuteNonQuery(); + } + } +} \ No newline at end of file diff --git a/DuckDB.NET.Test/DateTimeTests/TimestampTests.cs b/DuckDB.NET.Test/DateTimeTests/TimestampTests.cs new file mode 100644 index 0000000..81b7210 --- /dev/null +++ b/DuckDB.NET.Test/DateTimeTests/TimestampTests.cs @@ -0,0 +1,124 @@ +using System; +using DuckDB.NET.Data; +using FluentAssertions; +using Xunit; + +namespace DuckDB.NET.Test.DateTimeTests; + +public class TimestampTests +{ + + [Theory] + [InlineData(1992, 09, 20, 12, 15, 17, 350)] + [InlineData(2022, 05, 04, 12, 17, 15, 450)] + [InlineData(2022, 04, 05, 18, 15, 17, 125)] + [InlineData(1, 1, 1, 0, 0, 0, 0)] + public void QueryScalarTest(int year, int mon, int day, int hour, int minute, int second, int millisecond) + { + using var connection = new DuckDBConnection(DuckDBConnectionStringBuilder.InMemoryConnectionString); + connection.Open(); + + var expectedValue = new DateTime(year, mon, day, hour, minute, second, millisecond); + + using var cmd = connection.CreateCommand(); + cmd.CommandText = $"SELECT TIMESTAMP '{year}-{mon}-{day} {hour}:{minute}:{second}.{millisecond:000000}';"; + + var scalar = cmd.ExecuteScalar(); + + scalar.Should().BeOfType(); + + var receivedTime = (DateTime) scalar; + + receivedTime.Year.Should().Be(year); + receivedTime.Month.Should().Be(mon); + receivedTime.Day.Should().Be(day); + receivedTime.Hour.Should().Be(hour); + receivedTime.Minute.Should().Be(minute); + receivedTime.Second.Should().Be(second); + receivedTime.Millisecond.Should().Be(millisecond); + + receivedTime.Should().Be(expectedValue); + } + + + [Theory] + [InlineData(1992, 09, 20, 12, 15, 17, 350)] + [InlineData(2022, 05, 04, 12, 17, 15, 450)] + [InlineData(2022, 04, 05, 18, 15, 17, 125)] + [InlineData(1, 1, 1, 0, 0, 0, 0)] + public void BindTest(int year, int mon, int day, int hour, int minute, int second, int millisecond) + { + using var connection = new DuckDBConnection(DuckDBConnectionStringBuilder.InMemoryConnectionString); + connection.Open(); + + var expectedValue = new DateTime(year, mon, day, hour, minute, second, millisecond); + + using var cmd = connection.CreateCommand(); + cmd.CommandText = "SELECT ?;"; + cmd.Parameters.Add(new DuckDBParameter(expectedValue)); + + var scalar = cmd.ExecuteScalar(); + + scalar.Should().BeOfType(); + + var receivedTime = (DateTime) scalar; + + receivedTime.Year.Should().Be(year); + receivedTime.Month.Should().Be(mon); + receivedTime.Day.Should().Be(day); + receivedTime.Hour.Should().Be(hour); + receivedTime.Minute.Should().Be(minute); + receivedTime.Second.Should().Be(second); + receivedTime.Millisecond.Should().Be(millisecond); + + receivedTime.Should().Be(expectedValue); + } + + [Theory] + [InlineData(1992, 09, 20, 12, 15, 17, 350)] + [InlineData(2022, 05, 04, 12, 17, 15, 450)] + [InlineData(2022, 04, 05, 18, 15, 17, 125)] + [InlineData(1, 1, 1, 0, 0, 0, 0)] + public void BindAndInsert(int year, int mon, int day, int hour, int minute, int second, int millisecond) + { + using var connection = new DuckDBConnection(DuckDBConnectionStringBuilder.InMemoryConnectionString); + connection.Open(); + + var expectedValue = new DateTime(year, mon, day, hour, minute, second, millisecond); + + using var cmd = connection.CreateCommand(); + + try + { + cmd.CommandText = "CREATE TABLE timestamp_test (d TIMESTAMP);"; + cmd.ExecuteNonQuery(); + + cmd.CommandText = "INSERT INTO timestamp_test (d) VALUES (?);"; + cmd.Parameters.Add(new DuckDBParameter(expectedValue)); + cmd.ExecuteNonQuery(); + + cmd.CommandText = "SELECT * FROM timestamp_test;"; + cmd.Parameters.Clear(); + var scalar = cmd.ExecuteScalar(); + + scalar.Should().BeOfType(); + + var receivedTime = (DateTime) scalar; + + receivedTime.Year.Should().Be(year); + receivedTime.Month.Should().Be(mon); + receivedTime.Day.Should().Be(day); + receivedTime.Hour.Should().Be(hour); + receivedTime.Minute.Should().Be(minute); + receivedTime.Second.Should().Be(second); + receivedTime.Millisecond.Should().Be(millisecond); + + receivedTime.Should().Be(expectedValue); + } + finally + { + cmd.CommandText = "DROP TABLE timestamp_test;"; + cmd.ExecuteNonQuery(); + } + } +} \ No newline at end of file diff --git a/DuckDB.NET/DuckDBNativeObjects.cs b/DuckDB.NET/DuckDBNativeObjects.cs index 3974ba7..17080fe 100644 --- a/DuckDB.NET/DuckDBNativeObjects.cs +++ b/DuckDB.NET/DuckDBNativeObjects.cs @@ -78,31 +78,51 @@ public void Dispose() } } - public struct DuckDBDate + [StructLayout(LayoutKind.Sequential)] + public struct DuckDBDateStruct { - public int Year { get; } + public int Year { get; set; } - public byte Month { get; } + public byte Month { get; set; } - public byte Day { get; } + public byte Day { get; set; } } - public struct DuckDBTime + [StructLayout(LayoutKind.Sequential)] + public struct DuckDBDate { - public byte Hour { get; } + public int Days { get; set; } + } - public byte Min { get; } + [StructLayout(LayoutKind.Sequential)] + public struct DuckDBTimeStruct + { + public byte Hour { get; set; } - public byte Sec { get; } + public byte Min { get; set; } - public short Msec { get; } + public byte Sec { get; set; } + + public int Msec { get; set; } } - public struct DuckDBTimestamp + [StructLayout(LayoutKind.Sequential)] + public struct DuckDBTime + { + public long Micros { get; set; } + } + + [StructLayout(LayoutKind.Sequential)] + public struct DuckDBTimestampStruct { - public DuckDBDate Date { get; } + public DuckDBDateStruct Date { get; set; } + public DuckDBTimeStruct Time { get; set; } + } - public DuckDBTime Time { get; } + [StructLayout(LayoutKind.Sequential)] + public struct DuckDBTimestamp + { + public long Micros { get; set; } } [StructLayout(LayoutKind.Sequential)] diff --git a/DuckDB.NET/NativeMethods.cs b/DuckDB.NET/NativeMethods.cs index 9ca21f2..1ab3435 100644 --- a/DuckDB.NET/NativeMethods.cs +++ b/DuckDB.NET/NativeMethods.cs @@ -109,6 +109,15 @@ public static class Types [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_value_blob")] public static extern DuckDBBlob DuckDBValueBlob([In, Out] DuckDBResult result, long col, long row); + + [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_value_date")] + public static extern DuckDBDate DuckDbValueDate([In, Out] DuckDBResult result, long col, long row); + + [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_value_time")] + public static extern DuckDBTime DuckDbValueTime([In, Out] DuckDBResult result, long col, long row); + + [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_value_timestamp")] + public static extern DuckDBTimestamp DuckDbValueTimestamp([In, Out] DuckDBResult result, long col, long row); } public static class PreparedStatements @@ -124,7 +133,10 @@ public static class PreparedStatements [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_nparams")] public static extern long DuckDBParams(DuckDBPreparedStatement preparedStatement); - + + [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_param_type")] + public static extern DuckDBType DuckDBParamType(DuckDBPreparedStatement preparedStatement, long index); + [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_bind_boolean")] public static extern DuckDBState DuckDBBindBoolean(DuckDBPreparedStatement preparedStatement, long index, bool val); @@ -155,6 +167,15 @@ public static class PreparedStatements [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_bind_null")] public static extern DuckDBState DuckDBBindNull(DuckDBPreparedStatement preparedStatement, long index); + [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_bind_date")] + public static extern DuckDBState DuckDBBindDate(DuckDBPreparedStatement preparedStatement, long index, DuckDBDate val); + + [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_bind_time")] + public static extern DuckDBState DuckDBBindTime(DuckDBPreparedStatement preparedStatement, long index, DuckDBTime val); + + [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_bind_timestamp")] + public static extern DuckDBState DuckDBBindTimestamp(DuckDBPreparedStatement preparedStatement, long index, DuckDBTimestamp val); + [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_execute_prepared")] public static extern DuckDBState DuckDBExecutePrepared(DuckDBPreparedStatement preparedStatement, [In, Out] DuckDBResult result); @@ -224,5 +245,26 @@ public static class Helpers [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_free")] public static extern void DuckDBFree(IntPtr ptr); } + + public static class DateTime + { + [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_from_date")] + public static extern DuckDBDateStruct DuckDBFromDate(DuckDBDate date); + + [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_to_date")] + public static extern DuckDBDate DuckDBToDate(DuckDBDateStruct dateStruct); + + [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_from_time")] + public static extern DuckDBTimeStruct DuckDBFromTime(DuckDBTime date); + + [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_to_time")] + public static extern DuckDBTime DuckDBToTime(DuckDBTimeStruct dateStruct); + + [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_from_timestamp")] + public static extern DuckDBTimestampStruct DuckDBFromTimestamp(DuckDBTimestamp date); + + [DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_to_timestamp")] + public static extern DuckDBTimestamp DuckDBToTimestamp(DuckDBTimestampStruct dateStruct); + } } }