Copilot commented on code in PR #4911:
URL: https://github.com/apache/arrow-adbc/pull/4911#discussion_r4290668268


##########
csharp/test/Apache.Arrow.Adbc.Tests/ImportedDuckDbTests.cs:
##########
@@ -384,6 +388,267 @@ public async Task CancelConnection()
             Assert.Contains("Interrupted", exception.Message);
         }
 
+        [Fact]
+        public void DatabaseGetOption()
+        {
+            using var database = _duckDb.OpenDatabase("dbgetoption.db");
+
+            Assert.EndsWith("dbgetoption.db", database.GetOption("path"));
+            Assert.Equal(AdbcStatusCode.NotFound, 
Assert.ThrowsAny<AdbcException>(() => database.GetOption("unknown")).Status);
+        }
+
+        [Fact]
+        public void TypedDatabaseOptionsAreAppliedAtOpen()
+        {
+            // A long goes through DatabaseSetOptionInt rather than 
DatabaseSetOption
+            using var database = _duckDb.OpenDatabase("typedopen.db", new 
Dictionary<string, object> { { "threads", 3L } });
+            using var connection = database.Connect(null);
+            using var statement = connection.CreateStatement();
+
+            Assert.Equal("3", GetScalarString(statement, "SELECT 
current_setting('threads')::VARCHAR"));
+            Assert.Equal("3", database.GetOption("threads"));
+        }
+
+        [Fact]
+        public async Task OpenAndConnectAsync()
+        {
+            using var database = await 
_duckDb.OpenDatabaseAsync("openasync.db");
+            using var connection = await database.ConnectAsync(null);
+            using var statement = connection.CreateStatement();
+
+            Assert.Equal(3, GetResultCount(statement, "SELECT * FROM 
range(3)"));
+        }
+
+        [Fact]
+        public void StandardConnectionOptionsComeFromTheDriver()
+        {
+            using var database = _duckDb.OpenDatabase("standardoptions.db");
+            using var connection = database.Connect(null);
+
+            // Nothing has been set through this connection, so these are read 
from DuckDB
+            Assert.True(connection.AutoCommit);
+            Assert.Equal(AdbcOptions.Enabled, 
connection.GetOption(AdbcOptions.Connection.Autocommit));
+
+            connection.AutoCommit = false;
+            Assert.Equal(AdbcOptions.Disabled, 
connection.GetOption(AdbcOptions.Connection.Autocommit));
+
+            // In DuckDB 1.5.6, reading the current catalog or schema causes a 
later attempt
+            // to disable autocommit to be silently ignored, so these are 
checked last.
+            Assert.Equal("standardoptions", connection.CurrentCatalog);
+            Assert.Equal("main", connection.CurrentDbSchema);
+        }
+
+        [Fact]
+        public async Task SetCurrentDbSchema()
+        {
+            using var database = _duckDb.OpenDatabase("currentschema.db");
+            using var connection = database.Connect(null);
+            using var statement = connection.CreateStatement();
+
+            statement.SqlQuery = "CREATE SCHEMA other";
+            statement.ExecuteUpdate();
+
+            await 
connection.SetOptionAsync(AdbcOptions.Connection.CurrentDbSchema, "other");
+            Assert.Equal("other", await 
connection.GetOptionAsync(AdbcOptions.Connection.CurrentDbSchema));
+            Assert.Equal("other", connection.CurrentDbSchema);
+
+            statement.SqlQuery = "CREATE TABLE unqualified(x INTEGER)";
+            statement.ExecuteUpdate();
+            Assert.Equal("other", GetScalarString(statement, "SELECT 
schema_name FROM duckdb_tables() WHERE table_name = 'unqualified'"));
+
+            connection.CurrentDbSchema = "main";
+            Assert.Equal("main", GetScalarString(statement, "SELECT 
current_schema()"));
+        }
+
+        [Fact]
+        public void ConnectWithTypedOptions()
+        {
+            using var database = _duckDb.OpenDatabase("connecttyped.db");
+
+            // The bool is sent to DuckDB as the string "false". (That it's 
sent before the
+            // connection is initialized is covered by 
ExportedDriverRoundTrip11Tests.)
+            using var connection = database.ConnectWithTypedOptions(new 
Dictionary<string, object>
+            {
+                { AdbcOptions.Connection.Autocommit, false },
+            });
+
+            Assert.Equal(AdbcOptions.Disabled, 
connection.GetOption(AdbcOptions.Connection.Autocommit));
+            Assert.False(connection.AutoCommit);
+        }
+
+        [Fact]
+        public async Task ConnectWithTypedOptionsAsync()
+        {
+            using var database = _duckDb.OpenDatabase("connecttypedasync.db");
+
+            using var connection = await 
database.ConnectWithTypedOptionsAsync(new Dictionary<string, object>
+            {
+                { AdbcOptions.Connection.Autocommit, false },
+            });
+
+            Assert.Equal(AdbcOptions.Disabled, 
connection.GetOption(AdbcOptions.Connection.Autocommit));
+        }
+
+        [Fact]
+        public void UnsupportedOptions()
+        {
+            using var database = _duckDb.OpenDatabase("unsupportedoptions.db");
+            using var connection = database.Connect(null);
+            using var statement = connection.CreateStatement();
+
+            Assert.Equal(AdbcStatusCode.NotFound, 
Assert.ThrowsAny<AdbcException>(() => connection.GetOption("unknown")).Status);
+            Assert.Equal(AdbcStatusCode.NotFound, 
Assert.ThrowsAny<AdbcException>(() => 
connection.GetOptionInt64("unknown")).Status);
+            Assert.Equal(AdbcStatusCode.NotFound, 
Assert.ThrowsAny<AdbcException>(() => 
connection.GetOptionDouble("unknown")).Status);
+            Assert.Equal(AdbcStatusCode.NotFound, 
Assert.ThrowsAny<AdbcException>(() => 
connection.GetOptionBytes("unknown")).Status);
+            Assert.Equal(AdbcStatusCode.NotImplemented, 
Assert.ThrowsAny<AdbcException>(() => connection.SetOption("unknown", 
"x")).Status);
+            Assert.Equal(AdbcStatusCode.NotImplemented, 
Assert.ThrowsAny<AdbcException>(() => connection.SetOptionDouble("unknown", 
1.5)).Status);
+            Assert.Equal(AdbcStatusCode.NotImplemented, 
Assert.ThrowsAny<AdbcException>(() => connection.SetOptionBytes("unknown", new 
byte[] { 1 })).Status);
+
+            Assert.Equal(AdbcStatusCode.NotFound, 
Assert.ThrowsAny<AdbcException>(() => statement.GetOption("unknown")).Status);
+
+            // The spec says NotImplemented, but DuckDB 1.5.6 returns 
InvalidArgument for
+            // unknown statement options. Accept either so a DuckDB fix 
doesn't break this.
+            AdbcStatusCode status = Assert.ThrowsAny<AdbcException>(() => 
statement.SetOptionInt64("unknown", 1)).Status;
+            Assert.Contains(status, new[] { AdbcStatusCode.NotImplemented, 
AdbcStatusCode.InvalidArgument });
+        }
+
+        [Fact]
+        public void StatementGetOption()
+        {
+            using var database = _duckDb.OpenDatabase("statementoption.db");
+            using var connection = database.Connect(null);
+            using var statement = connection.CreateStatement();
+
+            statement.SetOption(AdbcOptions.Ingest.TargetTable, "target");
+            Assert.Equal("target", 
statement.GetOption(AdbcOptions.Ingest.TargetTable));
+        }
+
+        [Fact]
+        public void ErrorDetails()
+        {
+            using var database = _duckDb.OpenDatabase("errordetails.db");
+            using var connection = database.Connect(null);
+            using var statement = connection.CreateStatement();
+
+            statement.SqlQuery = "SELECT CAST('abc' AS INTEGER)";
+            AdbcException exception = Assert.ThrowsAny<AdbcException>(() => 
statement.ExecuteQuery());
+
+            Assert.Equal(AdbcStatusCode.InvalidArgument, exception.Status);
+            Assert.Contains("Conversion Error", exception.Message);
+            KeyValuePair<string, byte[]> detail = 
Assert.Single(exception.Details, d => d.Key == "duckdb:error_type");
+            Assert.Equal("Conversion", Encoding.UTF8.GetString(detail.Value));
+
+            // The 1.1 error layout reuses the vendor code field, so it 
mustn't leak through
+            Assert.Equal(0, exception.NativeError);
+        }
+
+        [Fact]
+        public async Task Statistics()
+        {
+            using var database = _duckDb.OpenDatabase("statistics.db");
+            using var connection = database.Connect(null);
+            using var statement = connection.CreateStatement();
+
+            using (IArrowArrayStream names = connection.GetStatisticsNames())
+            {
+                Assert.Equal(new[] { "statistic_name", "statistic_key" }, 
names.Schema.FieldsList.Select(f => f.Name));
+                Assert.Equal(ArrowTypeId.String, 
names.Schema.FieldsList[0].DataType.TypeId);
+                Assert.Equal(ArrowTypeId.Int16, 
names.Schema.FieldsList[1].DataType.TypeId);
+            }
+
+            statement.SqlQuery = "CREATE TABLE stats AS SELECT * FROM 
range(10) r(x)";
+            statement.ExecuteUpdate();
+
+            using IArrowArrayStream statistics = 
connection.GetStatistics(null, null, "stats", approximate: false);
+            Assert.Equal(new[] { "catalog_name", "catalog_db_schemas" }, 
statistics.Schema.FieldsList.Select(f => f.Name));
+
+            var catalogs = new List<string?>();
+            RecordBatch? batch;
+            while ((batch = await statistics.ReadNextRecordBatchAsync()) != 
null)
+            {
+                using (batch)
+                {
+                    StringArray names = (StringArray)batch.Column(0);
+                    for (int i = 0; i < names.Length; i++)
+                    {
+                        catalogs.Add(names.GetString(i));
+                    }
+                }
+            }
+            Assert.Contains("statistics", catalogs);
+        }
+
+        [Fact]
+        public async Task ExecuteAsyncWithCancellationToken()
+        {
+            using var database = _duckDb.OpenDatabase("executeasync.db");
+            using var connection = database.Connect(null);
+            using var statement = connection.CreateStatement();
+            using var cts = new CancellationTokenSource();
+
+            statement.SqlQuery = "CREATE TABLE test(x INTEGER)";
+            await statement.ExecuteUpdateAsync(cts.Token);
+
+            statement.SqlQuery = "INSERT INTO test VALUES (1), (2)";
+            UpdateResult update = await 
statement.ExecuteUpdateAsync(cts.Token);
+            Assert.Equal(2, update.AffectedRows);
+
+            statement.SqlQuery = "SELECT * FROM test";
+            QueryResult result = await statement.ExecuteQueryAsync(cts.Token);
+            Assert.Equal(2, GetResultCount(result));
+        }
+
+        [Fact]
+        public async Task CancellationTokenCancelsQuery()
+        {
+            using var database = _duckDb.OpenDatabase("canceltoken.db");
+            using var connection = database.Connect(null);
+            using var statement = connection.CreateStatement();
+            using var cts = new CancellationTokenSource();
+
+            statement.SqlQuery = "SELECT count(*) FROM range(1000000000000)";
+            Task<QueryResult> query = 
statement.ExecuteQueryAsync(cts.Token).AsTask();
+
+            await Task.Delay(500);
+            cts.Cancel();
+
+            // The token calls Cancel once. Keep cancelling in case that 
happened before
+            // DuckDB started the query; the token stays cancelled either way.
+            await CancelUntilCompleteAsync(statement.Cancel, query);
+            OperationCanceledException exception = await 
Assert.ThrowsAnyAsync<OperationCanceledException>(() => query);
+            Assert.Equal(cts.Token, exception.CancellationToken);
+
+            // There's no inner exception if the token was cancelled before 
the work started
+            if (exception.InnerException != null)
+            {
+                // DuckDB reports interruption as InvalidArgument rather than 
Cancelled
+                Assert.Contains("Interrupted", 
Assert.IsAssignableFrom<AdbcException>(exception.InnerException).Message);
+            }
+        }
+
+        [Fact]
+        public async Task TransactionsAsync()
+        {
+            using var database = _duckDb.OpenDatabase("transactionsasync.db");
+            using var connection = database.Connect(null);
+            using var statement = connection.CreateStatement();
+
+            statement.SqlQuery = "CREATE TABLE test(x INTEGER)";
+            statement.ExecuteUpdate();
+
+            connection.AutoCommit = false;
+
+            statement.SqlQuery = "INSERT INTO test VALUES (1)";
+            statement.ExecuteUpdate();
+            await connection.RollbackAsync();
+            Assert.Equal(0, GetResultCount(statement, "SELECT * FROM test"));
+
+            statement.SqlQuery = "INSERT INTO test VALUES (2)";
+            statement.ExecuteUpdate();
+            await connection.CommitAsync();
+            Assert.Equal(1, GetResultCount(statement, "SELECT * FROM test"));

Review Comment:
   This assertion also passes if `CommitAsync` does nothing: the inserting 
connection can read its own uncommitted row. Check visibility from a second 
connection before and after `CommitAsync` so the test detects a missing commit.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to