Skip to content

Commit

Permalink
Обновлен раздел SQLCLR
Browse files Browse the repository at this point in the history
- Добавлена библиотекаа для работы с ClickHouse из T-SQL.
- Обновлена документация.
- Исправлены ссылки в разделе проектов SQLCLR.
  • Loading branch information
YPermitin committed Feb 16, 2025
1 parent 6ebd9db commit 919bda1
Show file tree
Hide file tree
Showing 133 changed files with 7,399 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.1.17.0" newVersion="3.1.17.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.1.3" newVersion="4.1.1.3"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Primitives" publicKeyToken="adb9793829ddae60" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.1.17.0" newVersion="3.1.17.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Configuration.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.1.17.0" newVersion="3.1.17.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Options" publicKeyToken="adb9793829ddae60" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.1.17.0" newVersion="3.1.17.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.1.17.0" newVersion="3.1.17.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.DependencyInjection" publicKeyToken="adb9793829ddae60" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.1.17.0" newVersion="3.1.17.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging" publicKeyToken="adb9793829ddae60" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.1.17.0" newVersion="3.1.17.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D3D02050-BD31-460D-8087-76D98A226F78}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>YPermitin.SQLCLR.ClickHouseClient.CLI</RootNamespace>
<AssemblyName>ClickHouseClient.CLI</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
<LangVersion>9.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libs\ClickHouseClient.Entry\ClickHouseClient.Entry.csproj">
<Project>{ac5f49bf-4526-47a3-8034-75f84108cee5}</Project>
<Name>ClickHouseClient.Entry</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
using System;
using System.Data;
using System.Data.SqlClient;
using YPermitin.SQLCLR.ClickHouseClient.Entry;
using YPermitin.SQLCLR.ClickHouseClient.Entry.Extensions;
using YPermitin.SQLCLR.ClickHouseClient.Models;

namespace ClickHouseClient.CLI
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Начало проверки работы с ClickHouse.");

// Строка подключения к SQL Server
EntryBase.ConnectionString = @"server=localhost;database=master;trusted_connection=true;";
// Строка подключения к ClickHouse
string clickHouseConnectionString = @"Host=yy-comp;Port=8123;Username=default;password=;Database=default;";

Console.WriteLine("Строка подключения SQL Server: {0}", EntryBase.ConnectionString);
Console.WriteLine("Строка подключения ClickHouse: {0}", clickHouseConnectionString);

Console.Write("Установка соединения с SQL Server...");
// Создаем соединение с SQL Server для дальнейшей работы
using (SqlConnection sqlConnection = new SqlConnection(EntryBase.ConnectionString))
{
sqlConnection.Open();
Console.WriteLine("OK!");
// Устанавливаем подключение для отладки
EntryBase.DebugConnection = sqlConnection;

#region ExecuteScalar

Console.WriteLine("Начало работы метода ExecuteScalar.");

// Выполняем запрос с возвратом одного значения
string clickHouseVersion = EntryClickHouseClient.ExecuteScalar(
connectionString: clickHouseConnectionString.ToSqlChars(),
queryText: "SELECT version()".ToSqlChars())
.ToStringFromSqlChars();
Console.WriteLine("Версия ClickHouse: {0}", clickHouseVersion);

Console.WriteLine("Окончание работы метода ExecuteScalar.");

#endregion

#region ExecuteStatement

Console.WriteLine("Начало работы метода ExecuteStatement.");

// Выполняем запрос без возврата результата.
// В качестве примера создаем таблицу, предварительно удалив, если она существовала.

Console.WriteLine("Удаляем существующую таблицу, если она существует.");
EntryClickHouseClient.ExecuteStatement(
connectionString: clickHouseConnectionString.ToSqlChars(),
queryText: @"
DROP TABLE IF EXISTS SimpleTable
".ToSqlChars());

Console.WriteLine("Создаем таблицу.");
EntryClickHouseClient.ExecuteStatement(
connectionString: clickHouseConnectionString.ToSqlChars(),
queryText: @"
CREATE TABLE IF NOT EXISTS SimpleTable
(
Id UInt64,
Period datetime DEFAULT now(),
Name String
)
ENGINE = MergeTree
ORDER BY Id;
".ToSqlChars());

// А затем вставляем 100 записей
Console.WriteLine("Добавленые новых записей....");
for (int i = 1; i <= 10; i++)
{
string rowName = "Row " + i;
EntryClickHouseClient.ExecuteStatement(
connectionString: clickHouseConnectionString.ToSqlChars(),
queryText: (@"
INSERT INTO SimpleTable
(
Id,
Name
)
VALUES(" + i + @", '" + rowName + @"');
").ToSqlChars()
);

Console.WriteLine("Добавлена запись {0} - {1}", i, rowName);
}

Console.WriteLine("Окончание работы метода ExecuteStatement.");

#endregion

#region ExecuteSimple

Console.WriteLine("Начало работы метода ExecuteSimple.");

// Выполняем просто запрос с возвратом результата.
// У этого метода одно ограничение - возвращается только первая колонока запроса SELECT
// и только в виде строки.
// Для возвращения нескольких колонок можно возвращать кортеж, который будет преобразован к JSON-строке.

var simpleQueryResult = EntryClickHouseClient.ExecuteSimple(
connectionString: clickHouseConnectionString.ToSqlChars(),
queryText: @"
SELECT
tuple(name, engine, data_path)
FROM `system`.`databases`
".ToSqlChars());

var enumerator = simpleQueryResult.GetEnumerator();
int rowsCount = 0;
while (enumerator.MoveNext())
{
Console.WriteLine(((ExecuteSimpleRowResult)enumerator.Current).ResultValue);
rowsCount++;
}

Console.WriteLine("Количество записей из результата запроса: {0}.", rowsCount);

Console.WriteLine("Окончание работы метода ExecuteSimple.");

#endregion

#region ExecuteToTempTable

Console.WriteLine("Начало работы метода ExecuteToTempTable.");

// Создаем временную таблицу для сохранения результата запроса из ClickHouse
Console.WriteLine("Создаем временную таблицу.");
string sqlCreateTempTable = @"
IF(OBJECT_ID('tempdb..#logs') IS NOT NULL)
DROP TABLE #logs;
CREATE TABLE #logs
(
[EventTime] datetime2(0),
[Query] nvarchar(max),
[Tables] nvarchar(max),
[QueryId] uniqueidentifier
);
";
SqlCommand sqlCreateTempTableCommand = new SqlCommand(sqlCreateTempTable, sqlConnection);
sqlCreateTempTableCommand.CommandType = System.Data.CommandType.Text;
sqlCreateTempTableCommand.ExecuteNonQuery();

// Выполняем запрос к ClickHouse и сохраняем во временную таблицу
Console.WriteLine("Выполняем запрос к ClickHouse и сохраняем результат во временную таблицу.");
EntryClickHouseClient.ExecuteToTempTable(
connectionString: clickHouseConnectionString.ToSqlChars(),
queryText: @"
select
event_time,
query,
tables,
query_id
from `system`.query_log
limit 1000
".ToSqlChars(),
tempTableName: "#logs".ToSqlChars());

int totalRows = 0;
SqlCommand sqlTempTableRows = new SqlCommand("SELECT COUNT(*) FROM #logs", sqlConnection);
sqlTempTableRows.CommandType = System.Data.CommandType.Text;
totalRows = (int)sqlTempTableRows.ExecuteScalar();
Console.WriteLine("Всего записей прочитано: {0}", totalRows);

Console.WriteLine("Окончание работы метода ExecuteToTempTable.");

#endregion

#region ExecuteToGlobalTempTable

Console.WriteLine("Начало работы метода ExecuteToGlobalTempTable.");

// Создаем временную таблицу для сохранения результата запроса из ClickHouse
Console.WriteLine("Создаем ГЛОБАЛЬНУЮ временную таблицу.");
string sqlCreateGlobalTempTable = @"
IF(OBJECT_ID('tempdb..##logs') IS NOT NULL)
DROP TABLE #logs;
CREATE TABLE ##logs
(
[EventTime] datetime2(0),
[Query] nvarchar(max),
[Tables] nvarchar(max),
[QueryId] uniqueidentifier
);
";
SqlCommand sqlCreateGlobalTempTableCommand = new SqlCommand(sqlCreateGlobalTempTable, sqlConnection);
sqlCreateTempTableCommand.CommandType = System.Data.CommandType.Text;
sqlCreateTempTableCommand.ExecuteNonQuery();

// Выполняем запрос к ClickHouse и сохраняем во временную таблицу
Console.WriteLine("Выполняем запрос к ClickHouse и сохраняем результат во временную таблицу.");
EntryClickHouseClient.ExecuteToGlobalTempTable(
connectionString: clickHouseConnectionString.ToSqlChars(),
queryText: @"
select
event_time,
query,
tables,
query_id
from `system`.query_log
limit 10
".ToSqlChars(),
tempTableName: "##logs".ToSqlChars(),
sqlServerConnectionString: EntryBase.ConnectionString.ToSqlChars());

int totalRowsGlobal = 0;
SqlCommand sqlTempTableRowsGlobal = new SqlCommand("SELECT COUNT(*) FROM ##logs", sqlConnection);
sqlTempTableRowsGlobal.CommandType = System.Data.CommandType.Text;
totalRowsGlobal = (int)sqlTempTableRowsGlobal.ExecuteScalar();
Console.WriteLine("Всего записей прочитано: {0}", totalRowsGlobal);

Console.WriteLine("Окончание работы метода ExecuteToGlobalTempTable.");

#endregion
}

// Очищаем отладочное соединение SQL Server
EntryBase.DebugConnection = null;

Console.WriteLine("Окончание проверки работы с ClickHouse.");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// Общие сведения об этой сборке предоставляются следующим набором
// набора атрибутов. Измените значения этих атрибутов для изменения сведений,
// связанные с этой сборкой.
[assembly: AssemblyTitle("ClickHouseClient.CLI")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ClickHouseClient.CLI")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми
// для компонентов COM. Если необходимо обратиться к типу в этой сборке через
// из модели COM задайте для атрибута ComVisible этого типа значение true.
[assembly: ComVisible(false)]

// Следующий GUID представляет идентификатор typelib, если этот проект доступен из модели COM
[assembly: Guid("d3d02050-bd31-460d-8087-76d98a226f78")]

// Сведения о версии сборки состоят из указанных ниже четырех значений:
//
// Основной номер версии
// Дополнительный номер версии
// Номер сборки
// Номер редакции
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
Loading

0 comments on commit 919bda1

Please sign in to comment.