Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Frends.MicrosoftSQL.ExecuteQueryToFile/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## [2.2.0] - 2026-01-14
### Fixed
- Fix unloading assembly

## [2.1.0] - 2024-12-16
### Added
- Added Microsoft.SqlServer.Types dependency so that SqlGeography and SqlGeometry typed objects can be handled.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

namespace Frends.MicrosoftSQL.ExecuteQueryToFile.Definitions;

internal class CsvFileWriter
internal class CsvFileWriter : IAsyncDisposable
{
internal CsvFileWriter(SqlCommand sqlCommand, Input input, CsvOptions options)
{
Expand All @@ -30,31 +30,27 @@ internal CsvFileWriter(SqlCommand sqlCommand, Input input, CsvOptions options)

private CsvOptions Options { get; set; }

public async Task<Result> SaveQueryToCSV(CancellationToken cancellationToken)
public async ValueTask DisposeAsync()
{
var output = 0;
var encoding = GetEncoding(Options.FileEncoding, Options.EnableBom, Options.EncodingInString);

using (var writer = new StreamWriter(Input.OutputFilePath, false, encoding))
using (var csvFile = CreateCsvWriter(Options.GetFieldDelimiterAsString(), writer))
{
writer.NewLine = Options.GetLineBreakAsString();

var reader = await SqlCommand.ExecuteReaderAsync(cancellationToken);
output = DataReaderToCsv(reader, csvFile, Options, cancellationToken);
if (SqlCommand != null) await SqlCommand.DisposeAsync();
}

csvFile.Flush();
}
public async Task<Result> SaveQueryToCsv(CancellationToken cancellationToken)
{
var encoding = GetEncoding(Options.FileEncoding, Options.EnableBom, Options.EncodingInString);
await using var writer = new StreamWriter(Input.OutputFilePath, false, encoding);
await using var csvFile = CreateCsvWriter(Options.GetFieldDelimiterAsString(), writer);
writer.NewLine = Options.GetLineBreakAsString();
var reader = await SqlCommand.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
var output = DataReaderToCsv(reader, csvFile, Options, cancellationToken);
await csvFile.FlushAsync().ConfigureAwait(false);

return new Result(output, Input.OutputFilePath, Path.GetFileName(Input.OutputFilePath));
}

private static CsvWriter CreateCsvWriter(string delimiter, TextWriter writer)
{
var csvOptions = new CsvConfiguration(CultureInfo.InvariantCulture)
{
Delimiter = delimiter,
};
var csvOptions = new CsvConfiguration(CultureInfo.InvariantCulture) { Delimiter = delimiter, };

return new CsvWriter(writer, csvOptions);
}
Expand All @@ -63,10 +59,11 @@ private static string FormatDbHeader(string header, bool forceSpecialFormatting)
{
if (!forceSpecialFormatting) return header;

// First part of regex removes all non-alphanumeric ('_' also allowed) chars from the whole string.
// Second part removed any leading numbers or underscoress.
// The first part of regex removes all non-alphanumeric ('_' also allowed) chars from the whole string.
// The second part removed any leading numbers or underscores.
var rgx = new Regex("[^a-zA-Z0-9_-]|^[0-9_]+");
header = rgx.Replace(header, string.Empty);

return header.ToLower();
}

Expand All @@ -76,6 +73,7 @@ private static string FormatDbValue(object value, string dbTypeName, Type dotnet
{
if (dotnetType == typeof(string)) return "\"\"";
if (dotnetType == typeof(DateTime) && options.AddQuotesToDates) return "\"\"";

return string.Empty;
}

Expand All @@ -87,8 +85,10 @@ private static string FormatDbValue(object value, string dbTypeName, Type dotnet
str = str.Replace("\r\n", " ");
str = str.Replace("\r", " ");
str = str.Replace("\n", " ");

if (options.AddQuotesToStrings)
return $"\"{str}\"";

return str;
}

Expand All @@ -101,7 +101,9 @@ private static string FormatDbValue(object value, string dbTypeName, Type dotnet
"date" => dateTime.ToString(options.DateFormat, CultureInfo.InvariantCulture),
_ => dateTime.ToString(options.DateTimeFormat, CultureInfo.InvariantCulture),
};

if (options.AddQuotesToDates) return $"\"{output}\"";

return output;
}

Expand All @@ -126,8 +128,9 @@ private static int DataReaderToCsv(
CsvOptions options,
CancellationToken cancellationToken)
{
// Write header and remember column indexes to include.
// Write a header and remember column indexes to include it.
var columnIndexesToInclude = new List<int>();

for (var i = 0; i < reader.FieldCount; i++)
{
var columnName = reader.GetName(i);
Expand All @@ -153,6 +156,7 @@ private static int DataReaderToCsv(
if (options.IncludeHeadersInOutput) csvWriter.NextRecord();

int count = 0;

while (reader.Read())
{
foreach (var columnIndex in columnIndexesToInclude)
Expand All @@ -172,7 +176,10 @@ private static int DataReaderToCsv(
return count;
}

private static Encoding GetEncoding(FileEncoding optionsFileEncoding, bool optionsEnableBom, string optionsEncodingInString)
private static Encoding GetEncoding(
FileEncoding optionsFileEncoding,
bool optionsEnableBom,
string optionsEncodingInString)
{
return optionsFileEncoding switch
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
namespace Frends.MicrosoftSQL.ExecuteQueryToFile.Enums;
#pragma warning disable CS1591 // Self-explanatory
/// <summary>
/// File encoding used to encode the file.
/// </summary>
public enum FileEncoding
{
UTF8,
ANSI,
ASCII,
Unicode,
Other,
}
namespace Frends.MicrosoftSQL.ExecuteQueryToFile.Enums;

#pragma warning disable CS1591 // Self-explanatory

/// <summary>
/// File encoding used to encode the file.
/// </summary>
public enum FileEncoding
{
UTF8,
ANSI,
ASCII,
Unicode,
Other,
}

#pragma warning restore CS1591 // Self-explanatory
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
namespace Frends.MicrosoftSQL.ExecuteQueryToFile.Enums;
#pragma warning disable CS1591 // Self-explanatory
/// <summary>
/// Enumeration for output format.
/// </summary>
public enum ReturnFormat
{
CSV,
}
namespace Frends.MicrosoftSQL.ExecuteQueryToFile.Enums;

#pragma warning disable CS1591 // Self-explanatory

/// <summary>
/// Enumeration for output format.
/// </summary>
public enum ReturnFormat
{
CSV,
}

#pragma warning restore CS1591 // Self-explanatory
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
namespace Frends.MicrosoftSQL.ExecuteQueryToFile;

using System;
using System;
using System.ComponentModel;
using System.Data;
using System.Threading;
Expand All @@ -9,6 +7,8 @@
using Frends.MicrosoftSQL.ExecuteQueryToFile.Enums;
using Microsoft.Data.SqlClient;

namespace Frends.MicrosoftSQL.ExecuteQueryToFile;

/// <summary>
/// Main class of the Task.
/// </summary>
Expand All @@ -22,45 +22,49 @@ public static class MicrosoftSQL
/// <param name="options">Options parameters.</param>
/// <param name="cancellationToken">Cancellation token given by Frends.</param>
/// <returns>Object { int EntriesWritten, string Path, string FileName }</returns>
public static async Task<Result> ExecuteQueryToFile([PropertyTab] Input input, [PropertyTab] Options options, CancellationToken cancellationToken)
public static async Task<Result> ExecuteQueryToFile(
[PropertyTab] Input input,
[PropertyTab] Options options,
CancellationToken cancellationToken)
{
Result result = new();
using (var sqlConnection = new SqlConnection(input.ConnectionString))
{
await sqlConnection.OpenAsync(cancellationToken);

using var command = sqlConnection.CreateCommand();
command.CommandTimeout = options.TimeoutSeconds;
command.CommandText = input.Query;
command.CommandType = CommandType.Text;
await using var sqlConnection = new SqlConnection(input.ConnectionString);
await sqlConnection.OpenAsync(cancellationToken).ConfigureAwait(false);

await using var command = sqlConnection.CreateCommand();
command.CommandTimeout = options.TimeoutSeconds;
command.CommandText = input.Query;
command.CommandType = CommandType.Text;

if (input.QueryParameters != null)
if (input.QueryParameters != null)
{
foreach (var parameter in input.QueryParameters)
{
foreach (var parameter in input.QueryParameters)
{
if (parameter.Value is null)
parameter.Value = DBNull.Value;
parameter.Value ??= DBNull.Value;

if (parameter.SqlDataType is SqlDataTypes.Auto)
{
command.Parameters.AddWithValue(parameterName: parameter.Name, value: parameter.Value);
}
else
{
var sqlDbType = (SqlDbType)Enum.Parse(typeof(SqlDbType), parameter.SqlDataType.ToString());
var commandParameter = command.Parameters.Add(parameter.Name, sqlDbType);
commandParameter.Value = parameter.Value;
}
if (parameter.SqlDataType is SqlDataTypes.Auto)
{
command.Parameters.AddWithValue(parameterName: parameter.Name, value: parameter.Value);
}
else
{
var sqlDbType = (SqlDbType)Enum.Parse(typeof(SqlDbType), parameter.SqlDataType.ToString());
var commandParameter = command.Parameters.Add(parameter.Name, sqlDbType);
commandParameter.Value = parameter.Value;
}
}
}

switch (options.ReturnFormat)
{
case ReturnFormat.CSV:
{
await using var csvWriter = new CsvFileWriter(command, input, options.CsvOptions);
result = await csvWriter.SaveQueryToCsv(cancellationToken).ConfigureAwait(false);

switch (options.ReturnFormat)
{
case ReturnFormat.CSV:
var csvWriter = new CsvFileWriter(command, input, options.CsvOptions);
result = await csvWriter.SaveQueryToCSV(cancellationToken);
break;
}
}
}

return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>Latest</LangVersion>
<Version>2.1.0</Version>
<Version>2.2.0</Version>
<Authors>Frends</Authors>
<Copyright>Frends</Copyright>
<Company>Frends</Company>
Expand Down
Loading