Технология SQL-файл, препроцессор для T-SQL, “бок-о-бок” файлы и др.

Завершив свою недавнюю доработку легковесной технологии SQL-файл, применяемой для эффективной трансляции файлового SQL-кода в базу данных, автор данной статьи решил в очередной раз представить (в этой заметке) свои реализованные, хотя бы отчасти, идеи касательно программирования MSSQL, а также некоторые соображения относительно применения SQL вообще. Автор полагает, что, несмотря на форму предлагаемой им частной реализации SQL-файл (для MSSQL), лежащая в основе подхода концепция имеет определённую силу и смысл.

В качестве вступления предлагается прочитать короткую заметку о презентации технологии SQL-файл на SQL.RU (от 15 декабря 2020 г.):
Технология SQL-файл (для MSSQL)
https://www.sql.ru/forum/1331783-a/tehnologiya-sql-fayl-dlya-mssql
(форум – Microsoft SQL Server);
Презентация SQL-файл на SQL.RU
https://blog-hc.remelias.ru/presenting-sql-file-at-sql-ru/
(BLOG-HC, настоящий домен).

I. Предыстория (что не так с языком Transact-SQL, расширения SQLCMD и др.)

Автор данной статьи в течение долгого времени взаимодействовал с СУБД MS SQL Server. Когда-то в прошлом к автору данной статьи пришло осознание того, что режим исполнения инструкций (Control Flow) в языке Transact-SQL, который MSSQL предлагает по умолчанию (режим), не является надёжным. Без использования специальных блоков-обёрток для перехвата исключения — необходимо везде-везде проверять состояние последней ошибки @@ERROR. Исходя из желания использовать эффективный (полуавтоматический, с исключениями) контроль ошибок, а также и по другим (тоже веским) причинам, в течение длительного времени вырабатывалась и применялась интересная технология SQL-файл, основанная на расширениях SQLCMD. SQL-код хранится в файлах, организованных специальным образом в виде SQL-проекта (в дереве вложенных файловых папок). Для трансляции файлов в базу данных применяется легковесный обработчик — препроцессор-конкатенатор скриптов: SqlCatPP (EXE) в связке с вызывающей его обёрткой $SqlTrans (CMD). Так же, подразумевается использование вспомогательной библиотеки элементарных хэлпер-объектов и констант (вида “$(<ПеременнаяСреды>)”) SQLAUX (в приложение к основному транслятору/препроцессору). В качестве редактора SQL в настоящее время, помимо встроенного редактора Far-Manager, а также одного из GUI-редакторов для простого текста (см. в загрузках), доступно так же использование SQL Server Management Studio (+Environment), в немного ограниченном, однако, виде (см. устройство “SSMS.cmd” в загрузках).

II. Технология SQL-файл на страницах https://handicraft.remelias.ru/

Вот ссылки на страницы автора статьи (минимальное описание + картинки и примеры):

Ещё картинки (вспомогательное применение SQL-файл, бок-о-бок файлы SQL/C# и др.):

II.1. Запуск SQL-файлов с учётом подготовленного окружения

После настройки, проведённой соответствующим образом, легковесных инструментов, появляется возможность “запускать” правильно сконфигурированные (снабжённые лежащим в том же каталоге “$sql_settings.cmd”) файлы кода с усиленным Transact SQL. В Far-Manager подобная трансляция срабатывает (приводится в действие) из панели по <Enter> (для ассоциации SQL), из встроенного редактора по <Ctrl+Enter> (простейший макрос); в отдельном окне (запуск из панели) — по <Ctrl+PgDown>, в отдельном окне (запуск из встроенного редактора) — по <Ctrl+F12>. Утилита $SQLTRANS “подхватывает” “$sql_settings.cmd”; файлы из подкаталогов, как правило, наследуют (и, возможно, расширяют) сеттинг-и (окружение) более высокого уровня расположения. Корневой же “$sql_settings.cmd” подключает, как правило, “SQLAUX.cmd” (из каталога библиотеки), а также “@<имя_проекта>.cmd” (в UTF-8). Запустив же SQL Server Management Studio посредством стартера “SSMS.cmd” (располагается в корне SQL-проекта), данный процесс также получает возможность использовать все тонкости настроенного окружения:

– Доступны слова для обёртки основного блока: $(BEGIN_AUX), $(END_AUX), с автоматической защитой от ошибки (т. н. “заворачивание” в “begin try”/“end try”/ … и т. д.), которые, так же, инициализируют некоторые T-SQL-установки SET (при раскрытии “$(BEGIN_AUX)”);

– Многочисленные ключевые слова и константы: $(LOOP_AUX), $(TRUE_AUX), $(DropFunctionScript_AUX), $(num_IntStrMaxLength_AUX), $(dt_Name_AUX), и т.п.;

– Ссылки на собственные переменные проекта “$(<ИмяПеременной>)”.

Необходимо сначала должным образом установить и настроить поддержку SQL-файл!!!

– При установленном плагин-е для Far Manager CmdCpAuto, появляется возможность комфортно просматривать (по F4) многочисленные CMD (с автоматическим переключением на нужную кодировку).

– После прописывания в системе пути (PATH) к командным утилитам “…\HandicraftSDK\CMD-utilities” (папка с CMD, EXE) — становится работоспособным следующее: $sqltrans.cmd, $sqlupload.cmd, $sql.cmd, $sqlcon.cmd, $sqltocsvexp.cmd и прочие “$”-команды.

– Так же, в системе потребуется определить путь к библиотеке скриптов и констант окружения SQLAUX: SQLAUX_ROOT = …\HandicraftSDK\SQL\SQLAUX.

– При установленных макросах LUA из “HandicraftSDK\CMD-utilities\Shell\Integration(\RU)”, а так же после настройки ассоциаций FAR-а согласно “!Integration of $SqlTrans with FAR Manager.txt” (или “RU\!Интеграция $SqlTrans с FAR Manager.txt”) — всё становится довольно-таки удобным для программирования с применением SQL-файл.

Обратите внимание на папку(и): “HandicraftSDK\CMD-utilities\Shell\Integration(\RU)”.

II.2. Трансляция множеств (файлы SQL)

Помимо простой трансляции отдельного файла, имеется возможность обработать группу / подгруппу SQL. Для запуска подобной трансляции применяются, как правило, простые стартеры CMD. В одну трансляцию могут попадать не только файлы шаблона “*.sql”, но также (при соответствующем запуске $SqlCmd) и сразу несколько подпапок, а также и некоторый специальный SQL-файл. Порядок обработки файлов перестраивается посредством простейших файлов коррекции “$sql_order.list”. Сложные же (составные) трансляции описываются соответствующими CMD-сценариями. Подобные сценарии играют в SQL-файл значительную роль (удаление файла, запрос подтверждения, формирование текстового отчёта, и т. п.)

В загрузке, соответствующей Handicraft-SDK, присутствуют три условных SQL-проекта (перечислены в “SQL-project-list.txt”), а в состав “BookRegistry app.” входит один сложный (из 2-х разнесённых частей) SQL-проект.

II.3. Слабый и сильный препроцессинг (осуществляется подпрограммой SqlCatPP)

При использовании Environment зачастую нормальным будет положиться на поведение базового средства SQLCMD. По умолчанию (при обращении к $SQLTRANS) SqlCatPP (EXE) применяет так называемый “слабый препроцессинг”, затрагивающий одну лишь директиву “:SetVar”. Он попросту добавляет перед ней одну строчку-комментарий: –:SetVar … (чтобы иметь неиспорченную диагностику относительно номера строки ошибки). Однако, когда Вы не взаимодействуете с БД напрямую, а отдаёте свои скрипты дилеру (посреднику), то возникает потребность в тщательной подготовке такого скрипта, с учётом Environment SQL-проекта. (Навряд ли удастся на стороне дилера использовать какие-либо окружения.) В данном случае необходим так называемый “сильный препроцессинг”, который реализуется в SqlCatPP в тестовом виде, затрагивает директивы “:SetVar”, “:r”, а также ссылки на переменные среды: “$(<ИмяПеременной>)”. Результат подобной обработки доступен для примера в подкаталогах $OUTPUT и $GENERATED проектов SQLAUX и “Extralight-ORM test legacy sample (En+Ru)\MyFlat app. (MVC_Razor+TS+ADO+TSQL)\SQL (DB-modelling)”. В состав “sqlaux_library.sql” (из $OUTPUT), например, входят (как минимум) 173 исходных SQL-скрипта (фрагменты с разделителем GO), присутствующие так же и в $GENERATED (с порядковым префиксом имени файла: “XNNN.<BaseFileName>.sql”).

Так же, утилита $SQLTRANS имеет возможность производить фиктивную трансляцию (“set $sqltrans.TranslateToDatabase=0”), выводить данные в текстовый файл результатов (для этого необходимо задать действительный 2-й параметр, например: $SqlTrans “%~n0.sql” “%~n0.txt”), а также поддерживает передачу дополнительных параметров в базовый SQLCMD (например: “set $sqltrans.AdditionalParams=-y0”, “set $sqltrans.ContinueOnBatchError=1”). И не только это (см. страницы, картинки и загрузки).

II.4. Два основных направления в использовании SQL-файл

Технология SQL-файл применяется для достижения следующих 2-х основных целей:

1) Хозяйственная обработка базы данных MSSQL: добавление таблиц, наполнение их данными, правка структуры БД, прочие рутинные операции административного характера. Поскольку всё оформляется в виде файлов, то то или иное действие может быть повторно воспроизведено впоследствии (с соответствующей доработкой скриптов).

2) Программирование в базе данных MSSQL, а именно — написание подсистемы хранимых объектов кода SQL (процедуры, функции, триггеры, представления), которые в терминологии SQL-файл обозначаются как “программатики” (общий термин). Серверную SQL-часть приложения принято, зачастую, генерировать целиком — удалять все (или подгруппу) программатики (соответствующие, например, такому-то именному префиксу) и создавать их заново. (Данное действие можно производить на разных экземплярах сервера и БД, указываемых в корневом “$sql_settings.cmd” соответствующего SQL-проекта.)

III. Небольшая попытка создания экспериментального псевдо-микро-ORM для доступа к своим SQL-запросам и ХП, бок-о-бок файлы (SQL/C#) и прочее

III.1. Техника Side-by-Side (SQL/C#)

В экспериментальных проектах “Client-Server.WEB (idea)” а также “MyFlat app. (MVC_Razor+TS+ADO+TSQL)” была предпринята небольшая попытка непрямого соединения исполняемого SQL-сервером кода Transact-SQL с исполняемым веб-сервером ASP C#-кодом для .NET. В 1-м случае подобный CS-код, так же (с учётом соответствующих директив условной компиляции), работает в браузере (применяется WASM-Blazor), что привносит дополнительные усложнения. Каждый запрос к БД оформляется в виде 2-х рядом лежащих файлов с одним и тем же базовым именем: “<ИмяЗапроса>.sql” и “<ИмяЗапроса>.cs”. В данном случае под SQL-запросом понимается код хранимой процедуры T-SQL, который “попадает” на сервер в момент трансляции SQL-файла, каталога с файлами либо всего большого проекта (с применением $SqlTrans+SqlCatPP).

Соединение SBS-файлов условное (смешения кода нет). Данное исполнение стремится видеть (представлять) SQL-запросы в довольно унифицированной форме: с параметрами ХП, статусом возврата “@Status uniqueidentifier = null out” (параметр), сообщением ошибки “@Message $(dt_Message_AUX) = null out”, с возможными несколькими резалт-сетами. (В последующей неопубликованной версии аналогичного SDK данные параметры имеют, соответственно, имена “@RStatus” и “@RMessage”.)

Легковесный ORM к ХП и SQL-запросам (Handicraft-CODE):
https://handicraft.remelias.ru/csweb/lightweight_orm.html

Попытки успешного смешивания разнородного кода известны. Например: “.razor” и “.cshtml” (смешение HTML+C#) — используются для генерации HTML-разметки посредством C#, с частичной проверкой правильности разметки. При компиляции же SQL-процедуры (например, из файла SQL) — также проводится определённая проверка правильности SQL. Совмещение SQL+CS возможно было бы, в определённой степени, усовершенствовать. Например, в некоторых трудоёмких случаях — использовать объявление параметра (с типом) по месту его применения в теле запроса, “поручив” оформление заголовка(ов) запроса(ов) генератору-препроцессору SQL (добавив в него соответствующую функциональность). Так же, используя специальный вспомогательный формат двойственного (SQL-сервер/SQL-клиент) определения значений и типов, теоретически возможно было бы достичь определённого успеха. Однако, смешивание кода, работающего в совершенно разных средах и местах, навряд ли должно выглядеть просто.

В примере “BookRegistry app.” излишнюю сложность, однако, привносит использование JSON, а также желание надёжно “защититься” (проверки-исключения) от Null-ов на стороне C# (после передачи данных через HTTP в упакованном виде, посредством JSON). В примере же “MyFlat app. (MVC_Razor+TS+ADO+TSQL)” применяется сочетание 2-х языков для наименований: английский (ASP веб-сервер) <=> русский (объекты в SQL-БД).

III.2. Зачем всё это нужно (или же почему не всё так складно в ORM)?

Данный пункт можно отнести к области фантастики. Он предполагает существование возможности вносить изменения/дополнения в некоторую реляционную СУБД, поддерживающую расширяемый диалект языка SQL.

В настоящее время, при доступности применения ORM для взаимодействия с БД, её (одну из ORM) естественно будут использовать очень многие. Несмотря даже на то, что подобное применение зачастую ведёт к определённому перевороту, когда, например, язык C# может быть поставлен выше базы данных, как принято на это смотреть в контексте применения EF Code First, и любое общение/взаимодействие с БД (даже не от имени разрабатываемого приложения) подчиняется уже C# и особенностям Entity Framework (при использовании Code First). А ежели подход с центральным Code First — это востребованное передовое, то всё, что не Code First — уже не годится (не то, что надо) и т. п. Есть и другие причины, также говорящие в пользу применения своих SQL-запросов для общения с сервером SQL. (Крупные базы данных, кстати, способны пережить и несколько клиентских фреймворков и ORM.)

Что же касается использования хранимых процедур в БД для приложения, то существует обоснованное мнение, что это (1) не современно, (2) не кроссплатформенно, а также (3) тяжело в поддержке. Поэтому — опять приходим к ORM, большому ORM. (И даже микро-ORM применять, как правило, обычно не рекомендуется.)

Непростая идея компилируемых запросов SQL:

Бок-о-бок файлы (приводятся выше), реализованные автором статьи в экспериментальном виде на базе классических хранимых процедур-запросов MSSQL, могли бы, так же (потенциально), при должной поддержке со стороны СУБД, быть исполнены, по части обработки SQL, в виде так называемых “компилируемых запросов SQL” (Compiled SQL Queries с ограниченным управляемым временем жизни), поддерживаемых гипотетическим SQL-сервером (с функцией Compiled SQL Queries). Компилируемые SQL-запросы возможно было бы унифицировать по части заголовков с параметрами-значениями, параметрами-таблицами, резалт-сет-ами, кодом/статусом/сообщением возврата и т. п. (Т.е. — такие специальные кроссплатформенные по отношению к диалектам SQL заголовки для SQL-запросов.) Хранящийся в SQL-файле клиента SQL-сервера параметризованный код (параметры запроса + клиентская Environment) должен соответствующим образом подготавливаться (“на лету” при первом запуске запроса, или, возможно, на старте приложения):

сначала (на стороне клиента SQL) — применение аналога Environment SQL-проекта;

далее (на стороне клиента) — препроцессинг SQL (раскрытие аналогов переменных среды);

затем — подготовка на SQL-сервере, с проверкой ошибок (компиляция аналога временной ХП с параметрами, со специальным уникальным наименованием временно сохраняемого запроса).

Исправление же кода в файле с SQL-запросом приложения на работающей программе (желательно это делать, конечно, не в части заголовка) — должно восприниматься как необходимость повторной компиляции (когда потребуется) временного запроса: уничтожение/создание временного запроса+имени на сервере SQL.

Таким вот примерно образом автор статьи представляет себе общение с базой данных SQL на языке SQL, со стороны программы (например веб-сервера), использующей какой-либо компилируемый либо скриптовый язык. Для работы такого приложения потребуется технология, подобная SQL-файл (обозначим расширение как “SQL-file-app.”). Компилируемые запросы приложения (SQL-файлы) могли бы заранее (на этапе разработки) проверяться специальными командами трансляции (отсылаться на сервер) на предмет ошибок предварительной подготовки (компиляция запроса на стороне SQL). Более того: базирующиеся на SQL-файлах компилируемые запросы должны быть доступны из папок SQL-проекта для исполнения их отдельно от, собственно, приложения, — как из подготовившего запрос файла сценариев, так и из специального проверочного или хозяйственного SQL-скрипта, работающего в контексте того же (подготовившего запрос) SQL-подключения.

Кроме того, обычная (подобная существующей в исполнении автора статьи, для MSSQL) не расширенная функциональность технологии SQL-файл, также могла бы оказаться весьма полезной для работы вокруг подобного приложения.

IV. Завершение (резюме)

Как было обозначено в начале пункта III.2, то, о чём (в п. III.2) фантазируется автором статьи, весьма удалено от нашей реальности. И всё же (насчёт реальности): несмотря на могущество отдельных диалектов SQL, длительную историю знаменитых СУБД, трудно, в контексте понимания того, как обычно оформляются/выглядят запросы к базе данных (SQL-вкрапления в другую программу, либо посредством драйвера большой и умной ORM, либо же с применением отдельного SQL-файла или объекта с кодом, открываемом в консоли-редакторе БД), — трудно называть SQL первосортным языком программирования, который мы можем полноценно поддерживать (с тем же комфортом, что и классические языки ОП), когда применяем SQL для взаимодействия с БД из кода приложения или из отдельного скрипта.

Автор блог-а

Китаев Сергей Юрьевич
Автор ресурса Handicraft-CODE
https://handicraft.remelias.ru/

Client-Server WASM-Application In C#, TypeScript And Transact-SQL

FEATURES OF THE WORK
— Pseudo-ORM helpers are used in C# for explicit manual mapping from/to SQL;
— Automated error handling is implemented in SPA (unified behaviour for unexpected exception at the top);
— Quasi-blocking pseudo-synchronous UI is probed in browser in SPA;
— Binary independent Client-Server integration is applied, on base of C# source-code files;
— Through error reporting is available (explicit message + error GUID), from SQL Server to SPA-Client;
— Unified communication with automatic JWT request/update-token(s) renovation is embedded;
— Automation of JSON/C# null-checkings is introduced (with back-packing trick on client-side);
— SQL-File Technology is demonstrated inside the Work — translation from SQL-files to database objects;
— Many other interesting things are present in the Work.

Idea of Client-Server.WEB

The idea is to create reusable skeleton for Web-application simultaneously on both client and server sides, including also some support at database level. This idea also may be named simply as Web-application engine. Such an engine is build in several languages which are normally the same that are used in user application code. (Let us shortly reference to this idea as CSWEB.)

BookRegistry application

I would like to represent to you a little but able-to-work sample program which is based on above mentioned app.skeleton — BookRegistry application in Blazor-WASM, with presence of library-level code and user code in three languages: C#, TypeScript and Transact-SQL. (User interface markup is in HTML/CSS.)

The program demonstrates some operations of simple tool (Web-application), which is intended to support following two things: (I) book selection from database by different parameters, and also (II) editing of book registry. Authorized user may: (1) correct book-record, (2) add new book into book-registry (database), and (3) to delete unnecessary book-record. It’s simple itself (not much user code), but it is strongly cooperated with the engine (skeleton). This construction (engine+app.) provides certain unification into UI and into user app. behaviour. Simplified preuso-synchronous approach for UI-interaction is used in this SPA like somewhere in classic desktop UI (but this is not very restrictive). The program is provided with so-called Magistral layout for SPA performed in a special manner, so as if it is embedded at browser level. This layout is intended to supplement a lack of some important user accessors to UI (that are: vertical side-bar inside application page — with top/bottom scrolling, content selection button, operation escape-unblock, intentional reloading of virtual-page etc.) and also supports so-called Foreground UI-operation (with corresponding visual indication of performing action). Magistral layout is interesting thing which is potentially useful in terms of its general application. It is implemented in TypeScript and it has corresponding simple API for C# (WASM DLL).

Handicraft programming style

Handicraft approach to program development (so-called “handicraft programming”) implies, that somebody maintains or controls a part of system-like code and this significant part of auxiliary and/or low-level code in the application may be kept in hands of one or more individual developers. Non-trivial organization on base of modules (DLLs and not only) is inherent feature of such handicraft programming, as well as a tendency to strong fractional division of program text into numerous source files grouped into subfolders (instead of working with kilometer-long files of code). Handicraft-coding style is good suitable for building of somebody’s own AFX (Application Framework Extension) — your own small auxiliary framework and/or collection of simple general helpers for different purposes. In other words all this may be denoted as User Runtime Extensions (let us name it as URX).

Client-Server WASM-app. skeleton is built with help of DotNetHelpers libraries — set of modules: “CommonHelpers.*.dll” (general purpose libs). DotNetHelpers library set is part of Handicraft-SDK.

Client-Server Web-engine and the application

BookRegistry application together with all its libraries and auxiliaries, all this is standing directly on three imperative languages and without intensive usage of something high-level — as in Web-client so as at server-side. For instance, Bootstrap framework is used superficially (mainly for decorations of different kinds). The server which is in C# (in ASP.NET-Core) operates with database with help of extremely lightweight ORM to SP and queries which is implemented in DotNetHelpers. (This construction sits on ADO.NET-Core.)

Both parts of the program Client & Server are in C# and this is determinative here. For the sake of unified Client-Server interoperation special C#-classes are introduced (as base exchanging structures for data-models). Normally user code does not use JSON-features (C# attributes) intensively. Instead, all declarations of data exchange are specified mainly in pure C# language, which has priority over JSON (in this approach). Conditional compilation is used extensively however for declaration of C# exchangeable objects and in some implementations (code-files). Such non-trivial declaration is used in order to represent exchange data-model in one single place, so that this description takes effect for the both sides (client/server), but with some differences in behaviour at sides of the server and the client.

Also, there is a lot interesting concerning to error handling, especially in client-side. For example, error page is implemented in WASM-Blazor. Special technique is used when dealing with possible exceptions. See source code of BookRegistry.Client subproject (in corresponding BookRegistry app. download from supporting site).

Experimental way

My approach is not simple of cause, but looking to user written code as onto separate part from one side and onto CSWEB-engine so as it is framework extension or base skeleton (which does already exist) from the other side, the program then doesn’t seem so complex (at least in its user part). Also, some reorganization may improve the situation concerning to clarity and accessibility. (This is experimental application.)

Blog publisher

Sergei Y.Kitáev
Handicraft-CODE resource author
https://handicraft.remelias.ru/

CSWEB introductory article at C# Corner

Client-Server WASM-Application In C#, TypeScript And Transact-SQL
C# Corner / Technologies / Blazor (Developer Community Web-Site)