From 2131f95e657b3d657ddd6d1349198f7490611a41 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 26 Nov 2025 06:38:12 +0000
Subject: [PATCH 1/7] Initial plan
From d9b1860eccd935c776fd48d25b27eb94add447d8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 26 Nov 2025 06:43:40 +0000
Subject: [PATCH 2/7] Fix INSERT RETURNING clause to return actual values
instead of just AffectedRows
Co-authored-by: jefim <1387820+jefim@users.noreply.github.com>
---
.../ExecuteQueryTests.cs | 76 ++++++++++++++++++-
.../ExecuteQuery.cs | 3 +-
2 files changed, 77 insertions(+), 2 deletions(-)
diff --git a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.Tests/ExecuteQueryTests.cs b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.Tests/ExecuteQueryTests.cs
index 89139c0..940cf46 100644
--- a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.Tests/ExecuteQueryTests.cs
+++ b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.Tests/ExecuteQueryTests.cs
@@ -36,7 +36,7 @@ public void TestSetup()
{
cmd.ExecuteNonQuery();
}
- using (var cmd = new NpgsqlCommand(@"INSERT INTO ""lista"" (Id, Selite) VALUES (1, 'Ensimmäinen'), (2, 'foobar'), (3, ''), (4, null)", conn))
+ using (var cmd = new NpgsqlCommand(@"INSERT INTO ""lista"" (Id, Selite) VALUES (1, 'Ensimm�inen'), (2, 'foobar'), (3, ''), (4, null)", conn))
{
cmd.ExecuteNonQuery();
}
@@ -113,4 +113,78 @@ public async Task TestInsertQuery()
result = await PostgreSQL.ExecuteQuery(input, _options, new CancellationToken());
Assert.AreEqual("Viides", (string)result.QueryResult[0]["selite"]);
}
+
+ ///
+ /// Test INSERT with RETURNING clause.
+ ///
+ [Test]
+ public async Task TestInsertWithReturning()
+ {
+ var input = new Input
+ {
+ Query = @"INSERT INTO ""lista"" (Id, Selite) VALUES (6, 'Kuudes') RETURNING Id, Selite",
+ Parameters = null,
+ ConnectionString = _connection
+ };
+
+ var result = await PostgreSQL.ExecuteQuery(input, _options, new CancellationToken());
+
+ // Should return the inserted values, not AffectedRows
+ Assert.IsNotNull(result.QueryResult);
+ Assert.AreEqual(1, result.QueryResult.Count);
+ Assert.AreEqual(6, (int)result.QueryResult[0]["id"]);
+ Assert.AreEqual("Kuudes", (string)result.QueryResult[0]["selite"]);
+ }
+
+ ///
+ /// Test UPDATE with RETURNING clause.
+ ///
+ [Test]
+ public async Task TestUpdateWithReturning()
+ {
+ var input = new Input
+ {
+ Query = @"UPDATE ""lista"" SET Selite = 'Updated' WHERE Id = 1 RETURNING Id, Selite",
+ Parameters = null,
+ ConnectionString = _connection
+ };
+
+ var result = await PostgreSQL.ExecuteQuery(input, _options, new CancellationToken());
+
+ // Should return the updated values
+ Assert.IsNotNull(result.QueryResult);
+ Assert.AreEqual(1, result.QueryResult.Count);
+ Assert.AreEqual(1, (int)result.QueryResult[0]["id"]);
+ Assert.AreEqual("Updated", (string)result.QueryResult[0]["selite"]);
+
+ // Restore original value
+ input.Query = @"UPDATE ""lista"" SET Selite = 'Ensimm�inen' WHERE Id = 1";
+ await PostgreSQL.ExecuteQuery(input, _options, new CancellationToken());
+ }
+
+ ///
+ /// Test DELETE with RETURNING clause.
+ ///
+ [Test]
+ public async Task TestDeleteWithReturning()
+ {
+ // First, insert a row to delete
+ var input = new Input
+ {
+ Query = @"INSERT INTO ""lista"" (Id, Selite) VALUES (7, 'Seitsem�s')",
+ Parameters = null,
+ ConnectionString = _connection
+ };
+ await PostgreSQL.ExecuteQuery(input, _options, new CancellationToken());
+
+ // Now delete it with RETURNING
+ input.Query = @"DELETE FROM ""lista"" WHERE Id = 7 RETURNING Id, Selite";
+ var result = await PostgreSQL.ExecuteQuery(input, _options, new CancellationToken());
+
+ // Should return the deleted values
+ Assert.IsNotNull(result.QueryResult);
+ Assert.AreEqual(1, result.QueryResult.Count);
+ Assert.AreEqual(7, (int)result.QueryResult[0]["id"]);
+ Assert.AreEqual("Seitsem�s", (string)result.QueryResult[0]["selite"]);
+ }
}
diff --git a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs
index d7b537d..ff490f0 100644
--- a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs
+++ b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs
@@ -57,7 +57,8 @@ public static async Task ExecuteQuery([PropertyTab] Input input, [Proper
// Execute command.
- if (input.Query.ToLower().Contains("select"))
+ var queryLower = input.Query.ToLower();
+ if (queryLower.Contains("select") || queryLower.Contains("returning"))
{
var reader = await cmd.ExecuteReaderAsync(cancellationToken);
result = new Result(reader.ToJson(cancellationToken));
From bd84334fb9c40585fc1970ea73db7ff4d2d9b214 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 26 Nov 2025 07:04:52 +0000
Subject: [PATCH 3/7] Add ExecuteType parameter for explicit control over query
execution
Co-authored-by: jefim <1387820+jefim@users.noreply.github.com>
---
.../ExecuteQueryTests.cs | 43 +++++++++++++++
.../Definitions/ExecuteTypes.cs | 28 ++++++++++
.../Definitions/Input.cs | 10 ++++
.../ExecuteQuery.cs | 55 ++++++++++++++-----
4 files changed, 122 insertions(+), 14 deletions(-)
create mode 100644 Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/Definitions/ExecuteTypes.cs
diff --git a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.Tests/ExecuteQueryTests.cs b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.Tests/ExecuteQueryTests.cs
index 940cf46..b8839ba 100644
--- a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.Tests/ExecuteQueryTests.cs
+++ b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.Tests/ExecuteQueryTests.cs
@@ -187,4 +187,47 @@ public async Task TestDeleteWithReturning()
Assert.AreEqual(7, (int)result.QueryResult[0]["id"]);
Assert.AreEqual("Seitsem�s", (string)result.QueryResult[0]["selite"]);
}
+
+ ///
+ /// Test INSERT with RETURNING clause using ExecuteType.ExecuteReader explicitly.
+ ///
+ [Test]
+ public async Task TestInsertWithReturningExplicit()
+ {
+ var input = new Input
+ {
+ Query = @"INSERT INTO ""lista"" (Id, Selite) VALUES (8, 'Kahdeksas') RETURNING Id, Selite",
+ Parameters = null,
+ ConnectionString = _connection,
+ ExecuteType = ExecuteTypes.ExecuteReader
+ };
+
+ var result = await PostgreSQL.ExecuteQuery(input, _options, new CancellationToken());
+
+ // Should return the inserted values
+ Assert.IsNotNull(result.QueryResult);
+ Assert.AreEqual(1, result.QueryResult.Count);
+ Assert.AreEqual(8, (int)result.QueryResult[0]["id"]);
+ Assert.AreEqual("Kahdeksas", (string)result.QueryResult[0]["selite"]);
+ }
+
+ ///
+ /// Test INSERT without RETURNING using ExecuteType.NonQuery explicitly.
+ ///
+ [Test]
+ public async Task TestInsertWithNonQueryExplicit()
+ {
+ var input = new Input
+ {
+ Query = @"INSERT INTO ""lista"" (Id, Selite) VALUES (9, 'Yhdeks�s')",
+ Parameters = null,
+ ConnectionString = _connection,
+ ExecuteType = ExecuteTypes.NonQuery
+ };
+
+ var result = await PostgreSQL.ExecuteQuery(input, _options, new CancellationToken());
+
+ // Should return affected rows
+ Assert.AreEqual(1, (int)result.QueryResult["AffectedRows"]);
+ }
}
diff --git a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/Definitions/ExecuteTypes.cs b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/Definitions/ExecuteTypes.cs
new file mode 100644
index 0000000..5261db7
--- /dev/null
+++ b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/Definitions/ExecuteTypes.cs
@@ -0,0 +1,28 @@
+namespace Frends.PostgreSQL.ExecuteQuery.Definitions;
+
+///
+/// Specifies how a command string is interpreted.
+///
+public enum ExecuteTypes
+{
+ ///
+ /// Auto-detect based on query structure.
+ /// Uses ExecuteReader for queries that return data (SELECT or queries with RETURNING clause).
+ /// Uses NonQuery for INSERT, UPDATE, DELETE statements without RETURNING clause.
+ ///
+ Auto,
+
+ ///
+ /// Execute the query without expecting any result set.
+ /// Use for INSERT, UPDATE, DELETE statements without RETURNING clause.
+ /// Returns the number of rows affected.
+ ///
+ NonQuery,
+
+ ///
+ /// Execute the query and return the result set.
+ /// Use for SELECT queries or INSERT/UPDATE/DELETE with RETURNING clause.
+ /// Returns the data rows.
+ ///
+ ExecuteReader
+}
diff --git a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/Definitions/Input.cs b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/Definitions/Input.cs
index e6ca37d..85b165e 100644
--- a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/Definitions/Input.cs
+++ b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/Definitions/Input.cs
@@ -32,4 +32,14 @@ public class Input
[PasswordPropertyText]
public string ConnectionString { get; set; }
+ ///
+ /// Specifies how a command string is interpreted.
+ /// Auto: Automatically detects if the query returns data (SELECT or RETURNING clause) and uses ExecuteReader, otherwise uses NonQuery.
+ /// ExecuteReader: Use this to execute queries that return a result set (SELECT or INSERT/UPDATE/DELETE with RETURNING clause).
+ /// NonQuery: Use this to execute commands that don't return a result set (INSERT, UPDATE, DELETE without RETURNING). Returns the number of affected rows.
+ ///
+ /// ExecuteTypes.Auto
+ [DefaultValue(ExecuteTypes.Auto)]
+ public ExecuteTypes ExecuteType { get; set; }
+
}
diff --git a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs
index ff490f0..50d32ae 100644
--- a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs
+++ b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs
@@ -55,24 +55,51 @@ public static async Task ExecuteQuery([PropertyTab] Input input, [Proper
}
}
- // Execute command.
+ // Execute command based on ExecuteType.
+ var transaction = conn.BeginTransaction(GetIsolationLevel(options.SqlTransactionIsolationLevel));
+ cmd.Transaction = transaction;
- var queryLower = input.Query.ToLower();
- if (queryLower.Contains("select") || queryLower.Contains("returning"))
+ switch (input.ExecuteType)
{
- var reader = await cmd.ExecuteReaderAsync(cancellationToken);
- result = new Result(reader.ToJson(cancellationToken));
- }
- else
- {
- var transaction = conn.BeginTransaction(GetIsolationLevel(options.SqlTransactionIsolationLevel));
- cmd.Transaction = transaction;
- var rows = await cmd.ExecuteNonQueryAsync(cancellationToken);
- await transaction.CommitAsync(cancellationToken);
- transaction.Dispose();
- result = new Result(JToken.FromObject(new { AffectedRows = rows }));
+ case ExecuteTypes.Auto:
+ // Auto-detect: Use ExecuteReader and check if data is returned
+ using (var reader = await cmd.ExecuteReaderAsync(cancellationToken))
+ {
+ // Check if the query returned any data (has columns)
+ if (reader.FieldCount > 0)
+ {
+ // Query returned data (SELECT or RETURNING clause)
+ result = new Result(reader.ToJson(cancellationToken));
+ }
+ else
+ {
+ // Query did not return data, use RecordsAffected
+ result = new Result(JToken.FromObject(new { AffectedRows = reader.RecordsAffected }));
+ }
+ }
+ break;
+
+ case ExecuteTypes.ExecuteReader:
+ // Explicitly return data
+ using (var reader = await cmd.ExecuteReaderAsync(cancellationToken))
+ {
+ result = new Result(reader.ToJson(cancellationToken));
+ }
+ break;
+
+ case ExecuteTypes.NonQuery:
+ // Execute without returning data
+ var rows = await cmd.ExecuteNonQueryAsync(cancellationToken);
+ result = new Result(JToken.FromObject(new { AffectedRows = rows }));
+ break;
+
+ default:
+ throw new ArgumentException($"Unsupported ExecuteType: {input.ExecuteType}");
}
+ await transaction.CommitAsync(cancellationToken);
+ transaction.Dispose();
+
await conn.CloseAsync();
return result;
From 9421ca644afd31d8e70bd73357778a9f6930613b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 26 Nov 2025 07:07:36 +0000
Subject: [PATCH 4/7] Fix transaction handling and reader disposal issues
Co-authored-by: jefim <1387820+jefim@users.noreply.github.com>
---
.../ExecuteQuery.cs | 52 +++++++++++--------
1 file changed, 30 insertions(+), 22 deletions(-)
diff --git a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs
index 50d32ae..e2801a0 100644
--- a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs
+++ b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs
@@ -56,31 +56,36 @@ public static async Task ExecuteQuery([PropertyTab] Input input, [Proper
}
// Execute command based on ExecuteType.
- var transaction = conn.BeginTransaction(GetIsolationLevel(options.SqlTransactionIsolationLevel));
- cmd.Transaction = transaction;
-
switch (input.ExecuteType)
{
case ExecuteTypes.Auto:
- // Auto-detect: Use ExecuteReader and check if data is returned
- using (var reader = await cmd.ExecuteReaderAsync(cancellationToken))
+ // Auto-detect: Try ExecuteReader first to check if data is returned
{
- // Check if the query returned any data (has columns)
- if (reader.FieldCount > 0)
- {
- // Query returned data (SELECT or RETURNING clause)
- result = new Result(reader.ToJson(cancellationToken));
- }
- else
+ var transaction = conn.BeginTransaction(GetIsolationLevel(options.SqlTransactionIsolationLevel));
+ cmd.Transaction = transaction;
+
+ using (var reader = await cmd.ExecuteReaderAsync(cancellationToken))
{
- // Query did not return data, use RecordsAffected
- result = new Result(JToken.FromObject(new { AffectedRows = reader.RecordsAffected }));
- }
+ // Check if the query returned any data (has columns)
+ if (reader.FieldCount > 0)
+ {
+ // Query returned data (SELECT or RETURNING clause)
+ result = new Result(reader.ToJson(cancellationToken));
+ }
+ else
+ {
+ // Query did not return data, use RecordsAffected
+ result = new Result(JToken.FromObject(new { AffectedRows = reader.RecordsAffected }));
+ }
+ } // Reader is disposed here
+
+ await transaction.CommitAsync(cancellationToken);
+ transaction.Dispose();
}
break;
case ExecuteTypes.ExecuteReader:
- // Explicitly return data
+ // Explicitly return data - no transaction needed for read-only queries
using (var reader = await cmd.ExecuteReaderAsync(cancellationToken))
{
result = new Result(reader.ToJson(cancellationToken));
@@ -88,18 +93,21 @@ public static async Task ExecuteQuery([PropertyTab] Input input, [Proper
break;
case ExecuteTypes.NonQuery:
- // Execute without returning data
- var rows = await cmd.ExecuteNonQueryAsync(cancellationToken);
- result = new Result(JToken.FromObject(new { AffectedRows = rows }));
+ // Execute without returning data - use transaction
+ {
+ var transaction = conn.BeginTransaction(GetIsolationLevel(options.SqlTransactionIsolationLevel));
+ cmd.Transaction = transaction;
+ var rows = await cmd.ExecuteNonQueryAsync(cancellationToken);
+ result = new Result(JToken.FromObject(new { AffectedRows = rows }));
+ await transaction.CommitAsync(cancellationToken);
+ transaction.Dispose();
+ }
break;
default:
throw new ArgumentException($"Unsupported ExecuteType: {input.ExecuteType}");
}
- await transaction.CommitAsync(cancellationToken);
- transaction.Dispose();
-
await conn.CloseAsync();
return result;
From 882992555a4de48383a45e5607aabfaecf301644 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 26 Nov 2025 07:09:30 +0000
Subject: [PATCH 5/7] Improve transaction disposal with using statements
Co-authored-by: jefim <1387820+jefim@users.noreply.github.com>
---
.../Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs
index e2801a0..cac610c 100644
--- a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs
+++ b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs
@@ -61,7 +61,7 @@ public static async Task ExecuteQuery([PropertyTab] Input input, [Proper
case ExecuteTypes.Auto:
// Auto-detect: Try ExecuteReader first to check if data is returned
{
- var transaction = conn.BeginTransaction(GetIsolationLevel(options.SqlTransactionIsolationLevel));
+ using var transaction = conn.BeginTransaction(GetIsolationLevel(options.SqlTransactionIsolationLevel));
cmd.Transaction = transaction;
using (var reader = await cmd.ExecuteReaderAsync(cancellationToken))
@@ -80,7 +80,6 @@ public static async Task ExecuteQuery([PropertyTab] Input input, [Proper
} // Reader is disposed here
await transaction.CommitAsync(cancellationToken);
- transaction.Dispose();
}
break;
@@ -95,12 +94,11 @@ public static async Task ExecuteQuery([PropertyTab] Input input, [Proper
case ExecuteTypes.NonQuery:
// Execute without returning data - use transaction
{
- var transaction = conn.BeginTransaction(GetIsolationLevel(options.SqlTransactionIsolationLevel));
+ using var transaction = conn.BeginTransaction(GetIsolationLevel(options.SqlTransactionIsolationLevel));
cmd.Transaction = transaction;
var rows = await cmd.ExecuteNonQueryAsync(cancellationToken);
result = new Result(JToken.FromObject(new { AffectedRows = rows }));
await transaction.CommitAsync(cancellationToken);
- transaction.Dispose();
}
break;
From 4f62ec1ac57b1c1fef88db12304dfe516d4fd62c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 26 Nov 2025 07:35:41 +0000
Subject: [PATCH 6/7] Fix whitespace formatting issues for superlinter
Co-authored-by: jefim <1387820+jefim@users.noreply.github.com>
---
.../ExecuteQueryTests.cs | 10 +++++-----
.../Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs | 4 ++--
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.Tests/ExecuteQueryTests.cs b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.Tests/ExecuteQueryTests.cs
index b8839ba..8410109 100644
--- a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.Tests/ExecuteQueryTests.cs
+++ b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.Tests/ExecuteQueryTests.cs
@@ -128,7 +128,7 @@ public async Task TestInsertWithReturning()
};
var result = await PostgreSQL.ExecuteQuery(input, _options, new CancellationToken());
-
+
// Should return the inserted values, not AffectedRows
Assert.IsNotNull(result.QueryResult);
Assert.AreEqual(1, result.QueryResult.Count);
@@ -150,7 +150,7 @@ public async Task TestUpdateWithReturning()
};
var result = await PostgreSQL.ExecuteQuery(input, _options, new CancellationToken());
-
+
// Should return the updated values
Assert.IsNotNull(result.QueryResult);
Assert.AreEqual(1, result.QueryResult.Count);
@@ -180,7 +180,7 @@ public async Task TestDeleteWithReturning()
// Now delete it with RETURNING
input.Query = @"DELETE FROM ""lista"" WHERE Id = 7 RETURNING Id, Selite";
var result = await PostgreSQL.ExecuteQuery(input, _options, new CancellationToken());
-
+
// Should return the deleted values
Assert.IsNotNull(result.QueryResult);
Assert.AreEqual(1, result.QueryResult.Count);
@@ -203,7 +203,7 @@ public async Task TestInsertWithReturningExplicit()
};
var result = await PostgreSQL.ExecuteQuery(input, _options, new CancellationToken());
-
+
// Should return the inserted values
Assert.IsNotNull(result.QueryResult);
Assert.AreEqual(1, result.QueryResult.Count);
@@ -226,7 +226,7 @@ public async Task TestInsertWithNonQueryExplicit()
};
var result = await PostgreSQL.ExecuteQuery(input, _options, new CancellationToken());
-
+
// Should return affected rows
Assert.AreEqual(1, (int)result.QueryResult["AffectedRows"]);
}
diff --git a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs
index cac610c..8b81501 100644
--- a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs
+++ b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/ExecuteQuery.cs
@@ -63,7 +63,7 @@ public static async Task ExecuteQuery([PropertyTab] Input input, [Proper
{
using var transaction = conn.BeginTransaction(GetIsolationLevel(options.SqlTransactionIsolationLevel));
cmd.Transaction = transaction;
-
+
using (var reader = await cmd.ExecuteReaderAsync(cancellationToken))
{
// Check if the query returned any data (has columns)
@@ -78,7 +78,7 @@ public static async Task ExecuteQuery([PropertyTab] Input input, [Proper
result = new Result(JToken.FromObject(new { AffectedRows = reader.RecordsAffected }));
}
} // Reader is disposed here
-
+
await transaction.CommitAsync(cancellationToken);
}
break;
From 0568b7bf41f6eb0cabb669d3722d224765262d9c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 2 Dec 2025 07:12:43 +0000
Subject: [PATCH 7/7] Bump version to 2.0.0 and update CHANGELOG.md
Co-authored-by: jefim <1387820+jefim@users.noreply.github.com>
---
Frends.PostgreSQL.ExecuteQuery/CHANGELOG.md | 14 ++++++++++++++
.../Frends.PostgreSQL.ExecuteQuery.csproj | 2 +-
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/Frends.PostgreSQL.ExecuteQuery/CHANGELOG.md b/Frends.PostgreSQL.ExecuteQuery/CHANGELOG.md
index 552dff1..589618e 100644
--- a/Frends.PostgreSQL.ExecuteQuery/CHANGELOG.md
+++ b/Frends.PostgreSQL.ExecuteQuery/CHANGELOG.md
@@ -1,5 +1,19 @@
# Changelog
+## [2.0.0] - 2025-12-02
+### Added
+- Added `ExecuteType` parameter to Input class with options: Auto (default), ExecuteReader, and NonQuery.
+- Added support for INSERT/UPDATE/DELETE statements with RETURNING clause to return actual column values instead of just AffectedRows.
+- Added `ExecuteTypes` enum to provide explicit control over query execution behavior.
+
+### Changed
+- Modified query execution logic to use ExecuteType parameter instead of simple string parsing.
+- Auto mode now checks reader.FieldCount to determine if data is returned, providing more reliable detection than keyword matching.
+- Transaction handling now only applies to write operations (Auto and NonQuery modes), not read-only queries (ExecuteReader mode).
+
+### Fixed
+- Fixed issue where INSERT/UPDATE/DELETE with RETURNING clause only returned AffectedRows instead of the actual returned column values.
+
## [1.1.0] - 2024-08-23
### Changed
- Updated the Newtonsoft.Json package to version 13.0.3 and the Npgsql package to version 8.0.3.
diff --git a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.csproj b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.csproj
index 2af857f..2ab6208 100644
--- a/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.csproj
+++ b/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery/Frends.PostgreSQL.ExecuteQuery.csproj
@@ -7,7 +7,7 @@
true
Frends.PostgreSQL.ExecuteQuery
Frends.PostgreSQL.ExecuteQuery
- 1.1.0
+ 2.0.0
Frends
Frends
Frends