Skip to content

Commit

Permalink
fix(csharp/src/Apache.Arrow.Adbc/C): imported errors don't return a n…
Browse files Browse the repository at this point in the history
…ative error or SQL state (#1815)

Creates subclass of AdbcException for imported drivers which reads the
native error code and SQLState from the C error structure.

Closes #1813
  • Loading branch information
CurtHagenlocher authored May 4, 2024
1 parent 73cd1e7 commit 4cffa7b
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 15 deletions.
2 changes: 0 additions & 2 deletions csharp/src/Apache.Arrow.Adbc/AdbcConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@

using System;
using System.Collections.Generic;
using System.Linq;
using Apache.Arrow.Adbc.C;
using Apache.Arrow.Ipc;

namespace Apache.Arrow.Adbc
Expand Down
31 changes: 25 additions & 6 deletions csharp/src/Apache.Arrow.Adbc/C/CAdbcDriverImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Apache.Arrow.Adbc.Extensions;
using Apache.Arrow.C;
Expand Down Expand Up @@ -1099,6 +1100,28 @@ private unsafe void SetSqlQuery(string sqlQuery)
}
}

internal class ImportedAdbcException : AdbcException
{
private readonly string? _sqlState;
private readonly int _nativeError;

public unsafe ImportedAdbcException(ref CAdbcError error, AdbcStatusCode statusCode)
: base(MarshalExtensions.PtrToStringUTF8(error.message) ?? "Undefined error", statusCode)
{
if (error.sqlstate0 != 0)
{
fixed (CAdbcError* fixedError = &error)
{
_sqlState = Encoding.ASCII.GetString(&fixedError->sqlstate0, 5);
}
_nativeError = error.vendor_code;
}
}

public override string? SqlState => _sqlState;
public override int NativeError => _nativeError;
}

/// <summary>
/// Assists with UTF8/string marshalling
/// </summary>
Expand Down Expand Up @@ -1424,15 +1447,11 @@ public unsafe void TranslateCode(AdbcStatusCode statusCode)
{
if (statusCode != AdbcStatusCode.Success)
{
string message = "Undefined error";
if (_error.message != null)
{
message = MarshalExtensions.PtrToStringUTF8(_error.message)!;
}
ImportedAdbcException exception = new ImportedAdbcException(ref _error, statusCode);

Dispose();

throw new AdbcException(message);
throw exception;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public void SetIsolationLevelFails()
using var connection = _duckDb.CreateConnection("clientisolation.db", null);
connection.Open();

Assert.Throws<AdbcException>(() =>
Assert.ThrowsAny<AdbcException>(() =>
{
connection.BeginTransaction(System.Data.IsolationLevel.ReadCommitted);
});
Expand Down
6 changes: 3 additions & 3 deletions csharp/test/Apache.Arrow.Adbc.Tests/ImportedDuckDbTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public void ReadOnlyTest()

connection.ReadOnly = true;

AdbcException exception = Assert.Throws<AdbcException>(() =>
AdbcException exception = Assert.ThrowsAny<AdbcException>(() =>
{
statement.SqlQuery = "INSERT INTO test VALUES (3), (5), (7);";
statement.ExecuteUpdate();
Expand All @@ -144,7 +144,7 @@ public void ReadOnlyFails()
using var database = _duckDb.OpenDatabase("readonly.db");
using var connection = database.Connect(null);

Assert.Throws<AdbcException>(() =>
Assert.ThrowsAny<AdbcException>(() =>
{
connection.ReadOnly = true;
});
Expand All @@ -156,7 +156,7 @@ public void SetIsolationLevelFails()
using var database = _duckDb.OpenDatabase("isolation.db");
using var connection = database.Connect(null);

Assert.Throws<AdbcException>(() =>
Assert.ThrowsAny<AdbcException>(() =>
{
connection.IsolationLevel = IsolationLevel.Default;
});
Expand Down
6 changes: 3 additions & 3 deletions csharp/test/Drivers/Interop/Snowflake/ValueTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public void TestSmallNumberRangeOverlimit(int value)
{
string columnName = "SMALLNUMBER";
string table = CreateTemporaryTable(string.Format("{0} NUMBER(2,0)", columnName));
Assert.Throws<AdbcException>(() => ValidateInsertSelectDeleteSingleDecimalValue(table, columnName, value));
Assert.ThrowsAny<AdbcException>(() => ValidateInsertSelectDeleteSingleDecimalValue(table, columnName, value));
}

/// <summary>
Expand Down Expand Up @@ -138,7 +138,7 @@ public void TestLargeScaleNumberOverlimit(string value)
{
string columnName = "LARGESCALENUMBER";
string table = CreateTemporaryTable(string.Format("{0} NUMBER(38,37)", columnName));
Assert.Throws<AdbcException>(() => ValidateInsertSelectDeleteSingleDecimalValue(table, columnName, SqlDecimal.Parse(value)));
Assert.ThrowsAny<AdbcException>(() => ValidateInsertSelectDeleteSingleDecimalValue(table, columnName, SqlDecimal.Parse(value)));
}

/// <summary>
Expand Down Expand Up @@ -166,7 +166,7 @@ public void TestSmallScaleNumberOverlimit(string value)
{
string columnName = "SMALLSCALENUMBER";
string table = CreateTemporaryTable(string.Format("{0} NUMBER(38,2)", columnName));
Assert.Throws<AdbcException>(() => ValidateInsertSelectDeleteSingleDecimalValue(table, columnName, SqlDecimal.Parse(value)));
Assert.ThrowsAny<AdbcException>(() => ValidateInsertSelectDeleteSingleDecimalValue(table, columnName, SqlDecimal.Parse(value)));
}


Expand Down

0 comments on commit 4cffa7b

Please sign in to comment.