From 011a6dda76883aeaca659e7dc50e32b2fd89eb38 Mon Sep 17 00:00:00 2001 From: Anton Titovets Date: Sat, 9 Aug 2025 00:03:32 +0300 Subject: [PATCH] Fastfix --- src/addins/mysql/Cargo.lock | 57 +++++++++++++ src/addins/mysql/Cargo.toml | 4 +- src/addins/mysql/dependencies.log | 18 ++-- src/addins/mysql/src/component/dataset.rs | 84 +++++++++++++++++++ src/addins/mysql/src/component/methods.rs | 84 +++++++++++++------ src/addins/mysql/src/component/mod.rs | 73 +++++++++++----- .../src/CommonModules/OPI_MySQL/Module.bsl | 36 ++++---- 7 files changed, 283 insertions(+), 73 deletions(-) create mode 100644 src/addins/mysql/src/component/dataset.rs diff --git a/src/addins/mysql/Cargo.lock b/src/addins/mysql/Cargo.lock index a65ee9813bc..c0f8bf94872 100644 --- a/src/addins/mysql/Cargo.lock +++ b/src/addins/mysql/Cargo.lock @@ -243,6 +243,20 @@ dependencies = [ "syn", ] +[[package]] +name = "dashmap" +version = "7.0.0-rc2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a1e35a65fe0538a60167f0ada6e195ad5d477f6ddae273943596d4a1a5730b" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "equivalent", + "hashbrown", + "lock_api", + "parking_lot_core", +] + [[package]] name = "dateparser" version = "0.2.1" @@ -651,6 +665,16 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.26" @@ -870,10 +894,25 @@ dependencies = [ "addin1c", "base64", "chrono", + "dashmap", "dateparser", "mysql", "mysql_common", "serde_json", + "uuid", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", ] [[package]] @@ -998,6 +1037,15 @@ dependencies = [ "getrandom 0.2.15", ] +[[package]] +name = "redox_syscall" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.11.1" @@ -1067,6 +1115,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "security-framework" version = "2.11.1" @@ -1360,6 +1414,9 @@ name = "uuid" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +dependencies = [ + "getrandom 0.3.2", +] [[package]] name = "vcpkg" diff --git a/src/addins/mysql/Cargo.toml b/src/addins/mysql/Cargo.toml index a3e754a674f..e1ad2b9c437 100644 --- a/src/addins/mysql/Cargo.toml +++ b/src/addins/mysql/Cargo.toml @@ -20,4 +20,6 @@ serde_json = "1.0" base64 = "0.22.1" chrono = "0.4.40" mysql_common = "0.34.1" -dateparser = "0.2.1" \ No newline at end of file +dateparser = "0.2.1" +dashmap = "7.0.0-rc2" +uuid = { version = "1.16.0", features = ["v4"] } \ No newline at end of file diff --git a/src/addins/mysql/dependencies.log b/src/addins/mysql/dependencies.log index a5fba6b2e1d..84dcbdeda39 100644 --- a/src/addins/mysql/dependencies.log +++ b/src/addins/mysql/dependencies.log @@ -1,13 +1,13 @@ "MAIN ---" - linux-vdso.so.1 (0x00007fffd6965000) - libssl.so.3 => /lib64/libssl.so.3 (0x0000781f44600000) - libcrypto.so.3 => /lib64/libcrypto.so.3 (0x0000781f43e00000) - libm.so.6 => /lib64/libm.so.6 (0x0000781f43a00000) - libpthread.so.0 => /lib64/libpthread.so.0 (0x0000781f43600000) - libc.so.6 => /lib64/libc.so.6 (0x0000781f43200000) - libdl.so.2 => /lib64/libdl.so.2 (0x0000781f42e00000) - /lib64/ld-linux-x86-64.so.2 (0x0000781f44c00000) - libz.so.1 => /lib64/libz.so.1 (0x0000781f42a00000) + linux-vdso.so.1 (0x00007ffe7cd0b000) + libssl.so.3 => /lib64/libssl.so.3 (0x00007066f1a00000) + libcrypto.so.3 => /lib64/libcrypto.so.3 (0x00007066f1200000) + libm.so.6 => /lib64/libm.so.6 (0x00007066f0e00000) + libpthread.so.0 => /lib64/libpthread.so.0 (0x00007066f0a00000) + libc.so.6 => /lib64/libc.so.6 (0x00007066f0600000) + libdl.so.2 => /lib64/libdl.so.2 (0x00007066f0200000) + /lib64/ld-linux-x86-64.so.2 (0x00007066f2000000) + libz.so.1 => /lib64/libz.so.1 (0x00007066efe00000) GLIBC_2.2.5 GLIBC_2.3 GLIBC_2.3.4 diff --git a/src/addins/mysql/src/component/dataset.rs b/src/addins/mysql/src/component/dataset.rs new file mode 100644 index 00000000000..abbed3ddc40 --- /dev/null +++ b/src/addins/mysql/src/component/dataset.rs @@ -0,0 +1,84 @@ +use dashmap::DashMap; +use serde_json::Value; +use std::sync::Arc; +use uuid::Uuid; + +pub struct Datasets { + data: Arc>, +} + +#[derive(Debug, Clone)] +pub struct QueryData { + pub results: Vec, + pub params: Vec, + pub text: String, + pub force_result: bool, +} + +impl Datasets { + pub fn new() -> Self { + Self { + data: Arc::new(DashMap::new()), + } + } + + pub fn init_query(&self) -> String { + let key = Uuid::new_v4().to_string(); + let query = QueryData::new(); + self.data.insert(key.clone(), query); + key + } + + pub fn get_query(&self, key: &str) -> Option { + self.data.get(key).map(|guard| guard.value().clone()) + } + + pub fn set_results(&self, key: &str, values: Vec) { + if let Some(mut entry) = self.data.get_mut(key) { + entry.results = values; + } + } + + pub fn add_param(&self, key: &str, value: Value) { + if let Some(mut entry) = self.data.get_mut(key) { + entry.params.push(value); + } + } + + pub fn set_text(&self, key: &str, text: &str) { + if let Some(mut entry) = self.data.get_mut(key) { + entry.text = text.to_string(); + } + } + + pub fn set_force_result(&self, key: &str, enabled: bool) { + if let Some(mut entry) = self.data.get_mut(key) { + entry.force_result = enabled; + } + } + + pub fn len(&self, key: &str) -> Option { + self.data.get(key).map(|entry| entry.results.len()) + } + + pub fn remove(&self, key: &str) { + self.data.remove(key); + } + + pub fn get_row(&self, key: &str, index: usize) -> Option { + let entry = self.data.get(key)?; + let value = entry.results.get(index)?; + serde_json::to_string(value).ok() + } +} + +impl QueryData { + fn new() -> Self { + Self { + results: Vec::new(), + params: Vec::new(), + text: String::new(), + force_result: false, + } + } +} \ No newline at end of file diff --git a/src/addins/mysql/src/component/methods.rs b/src/addins/mysql/src/component/methods.rs index 18e24761856..4ddb6915bed 100644 --- a/src/addins/mysql/src/component/methods.rs +++ b/src/addins/mysql/src/component/methods.rs @@ -1,56 +1,91 @@ use serde_json::{Value, json}; -use crate::component::format_json_error; +use crate::component::{format_json_error, AddIn}; use base64::{engine::general_purpose, Engine as _}; use mysql::prelude::Queryable; use std::collections::HashMap; use chrono::*; -use mysql::PooledConn; use mysql_common::packets::Column; use dateparser::parse; +pub fn init_query(add_in: &mut AddIn, text: &str, force_result: bool) -> String { + + let key = add_in.datasets.init_query(); + add_in.datasets.set_text(&key, text); + add_in.datasets.set_force_result(&key, force_result); + + key +} + +pub fn add_query_param(add_in: &mut AddIn, key: &str, param: String) -> String { + + let value: Value = match serde_json::from_str(¶m) { + Ok(param) => param, + Err(e) => return format_json_error(&e.to_string()), + }; + + add_in.datasets.add_param(key, value); + json!({"result": true}).to_string() + +} + pub fn execute_query( - conn: &mut PooledConn, - query: String, - params_json: String, - force_result: bool + add_in: &mut AddIn, + key: &str ) -> String { - // Парсинг JSON параметров - let mut parsed_params: Value = match serde_json::from_str(¶ms_json) { - Ok(params) => params, - Err(e) => return format_json_error(e) + let mut conn = match add_in.get_connection(){ + Ok(conn) => conn, + Err(e) => return format_json_error(e.to_string()), }; - let params_array = match parsed_params.as_array_mut() { - Some(array) => process_mysql_params(array), - None => return format_json_error("Parameters must be a JSON array") + let query = match add_in.datasets.get_query(key){ + Some(q) => q, + None => return format_json_error(format!("No query found by key: {}", key).as_str()), }; - // Определяем тип запроса - if query.trim_start().to_uppercase().starts_with("SELECT") || force_result == true { + let mut params = query.params; + let text = query.text; + let force_result = query.force_result; - let mut rows: Vec = match conn.exec(query, params_array){ + let params_array = process_mysql_params(&mut params); + + let result = if text.trim_start().to_uppercase().starts_with("SELECT") || force_result == true { + + let mut rows: Vec = match conn.exec(text, params_array){ Ok(rows) => rows, Err(e) => return format_json_error(e) }; - rows_to_json_array(&mut rows) + match rows_to_json_array(&mut rows){ + Ok(json) => { + add_in.datasets.set_results(&key, json); + json!({"result": true, "data": true}).to_string() + }, + Err(e) => return format_json_error(e) + } } else { let exec_result = match params_array.len() == 0 { - true => conn.query_drop(query), - false => conn.exec_drop(query, params_array) + true => conn.query_drop(text), + false => conn.exec_drop(text, params_array) }; match exec_result{ - Ok(_) => json!({"result": true}).to_string(), + Ok(_) => json!({"result": true, "data": false}).to_string(), Err(e) => format_json_error(e) } - } + }; + + match conn.as_mut().ping(){ + Ok(_) => add_in.connection = Some(conn), + Err(_) => drop(conn) + }; + + result } -fn rows_to_json_array(rows: &mut Vec) -> String { +fn rows_to_json_array(rows: &mut Vec) -> Result, String> { let mut json_array = Vec::new(); @@ -72,12 +107,13 @@ fn rows_to_json_array(rows: &mut Vec) -> String { } match serde_json::to_value(json_obj){ Ok(json) => json_array.push(json), - Err(e) => return format_json_error(e) + Err(e) => return Err(e.to_string()) } } - json!({ "result": true, "data": json_array }).to_string() + Ok(json_array) + } fn from_sql_to_json(value: mysql::Value, column: &Column) -> Value { diff --git a/src/addins/mysql/src/component/mod.rs b/src/addins/mysql/src/component/mod.rs index 3da29a13d3d..108fa7ff15e 100644 --- a/src/addins/mysql/src/component/mod.rs +++ b/src/addins/mysql/src/component/mod.rs @@ -1,11 +1,12 @@ mod methods; +mod dataset; use addin1c::{name, Variant}; use crate::core::getset; use serde_json::json; use mysql::*; use std::path::PathBuf; - +use crate::component::dataset::Datasets; // МЕТОДЫ КОМПОНЕНТЫ ------------------------------------------------------------------------------- // Синонимы @@ -13,7 +14,12 @@ pub const METHODS: &[&[u16]] = &[ name!("Connect"), name!("Close"), name!("Execute"), - name!("SetTLS") + name!("SetTLS"), + name!("GetQueryResultRow"), + name!("GetQueryResultLength"), + name!("RemoveQuery"), + name!("InitQuery"), + name!("AddQueryParam"), ]; @@ -22,8 +28,13 @@ pub fn get_params_amount(num: usize) -> usize { match num { 0 => 0, 1 => 0, - 2 => 3, + 2 => 1, 3 => 3, + 4 => 2, + 5 => 1, + 6 => 1, + 7 => 2, + 8 => 2, _ => 0, } } @@ -38,24 +49,9 @@ pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box Box::new(obj.close_connection()), 2 => { - let query = params[0].get_string().unwrap_or("".to_string()); - let params_json = params[1].get_string().unwrap_or("".to_string()); - let force_result = params[2].get_bool().unwrap_or(false); + let key = params[0].get_string().unwrap_or("".to_string()); + Box::new(methods::execute_query(obj, &key)) - match obj.get_connection(){ - Ok(mut conn) => { - - let result = Box::new(methods::execute_query(&mut conn, query, params_json, force_result)); - - match conn.as_mut().ping(){ - Ok(_) => obj.connection = Some(conn), - Err(_) => drop(conn) - } - - result - }, - Err(e) => Box::new(e), - } }, 3 => { @@ -65,6 +61,41 @@ pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box { + let key = params[0].get_string().unwrap_or("".to_string()); + let index = params[1].get_i32().unwrap_or(0); + + Box::new(obj.datasets.get_row(&key, index as usize).unwrap_or_else(|| "".to_string())) + }, + 5 => { + let key = params[0].get_string().unwrap_or("".to_string()); + + match obj.datasets.len(&key){ + Some(len) => Box::new(len as i32), + None => Box::new(json!( + {"result": false, "error": format!("Dataset {} not found", key)} + ).to_string()), + } + }, + 6 => { + let key = params[0].get_string().unwrap_or("".to_string()); + obj.datasets.remove(&key); + Box::new(json!({"result": true}).to_string()) + }, + 7 => { + + let text = params[0].get_string().unwrap_or("".to_string()); + let force = params[1].get_bool().unwrap_or(false); + + Box::new(methods::init_query(obj, &text, force)) + }, + 8 => { + let key = params[0].get_string().unwrap_or("".to_string()); + let param = params[1].get_string().unwrap_or("".to_string()); + + Box::new(methods::add_query_param(obj, &key, param)) + } _ => Box::new(false), // Неверный номер команды } @@ -88,6 +119,7 @@ pub struct AddIn { use_tls: bool, accept_invalid_certs: bool, ca_cert_path: String, + datasets: Datasets, } impl AddIn { @@ -100,6 +132,7 @@ impl AddIn { use_tls: false, accept_invalid_certs: false, ca_cert_path: String::new(), + datasets: Datasets::new(), } } diff --git a/src/ru/OPI/src/CommonModules/OPI_MySQL/Module.bsl b/src/ru/OPI/src/CommonModules/OPI_MySQL/Module.bsl index 98f0b629d8c..557310c9827 100644 --- a/src/ru/OPI/src/CommonModules/OPI_MySQL/Module.bsl +++ b/src/ru/OPI/src/CommonModules/OPI_MySQL/Module.bsl @@ -144,11 +144,6 @@ , Знач Соединение = "" , Знач Tls = "") Экспорт - OPI_ПреобразованиеТипов.ПолучитьСтроку(ТекстЗапроса, Истина); - OPI_ПреобразованиеТипов.ПолучитьБулево(ФорсироватьРезультат); - - Параметры_ = ОбработатьПараметры(Параметры); - Если ЭтоКоннектор(Соединение) Тогда ЗакрыватьСоединение = Ложь; Коннектор = Соединение; @@ -161,14 +156,16 @@ Возврат Коннектор; КонецЕсли; - Результат = Коннектор.Execute(ТекстЗапроса, Параметры_, ФорсироватьРезультат); + OPI_ПреобразованиеТипов.ПолучитьСтроку(ТекстЗапроса, Истина); + OPI_ПреобразованиеТипов.ПолучитьБулево(ФорсироватьРезультат); + + Параметры_ = ОбработатьПараметры(Параметры); + Результат = OPI_ЗапросыSQL.ВыполнитьЗапросСОбработкой(Коннектор, ТекстЗапроса, ФорсироватьРезультат, Параметры_); Если ЗакрыватьСоединение Тогда ЗакрытьСоединение(Коннектор); КонецЕсли; - Результат = OPI_Инструменты.JsonВСтруктуру(Результат); - Возврат Результат; КонецФункции @@ -544,27 +541,28 @@ Функция ОбработатьПараметры(Знач Параметры) Если Не ЗначениеЗаполнено(Параметры) Тогда - Возврат "[]"; + Возврат Новый Массив; КонецЕсли; + Параметры_ = Новый Массив; OPI_ПреобразованиеТипов.ПолучитьМассив(Параметры); - Для Н = 0 По Параметры.ВГраница() Цикл + Счетчик = 0; + Для Каждого Параметр Из Параметры Цикл - ТекущийПараметр = Параметры[Н]; + ТекущийПараметр = ОбработатьПараметр(Параметр); + ТекущийПараметр = OPI_Инструменты.JSONСтрокой(ТекущийПараметр, , Ложь); - ТекущийПараметр = ОбработатьПараметр(ТекущийПараметр); + Если СтрНачинаетсяС(ТекущийПараметр, "НЕ JSON") Тогда + ВызватьИсключение СтрШаблон("Ошибка валидации JSON параметра. Индекс массив %1", Счетчик); + Иначе + Параметры_.Добавить(ТекущийПараметр); + КонецЕсли; - Параметры[Н] = ТекущийПараметр; + Счетчик = Счетчик + 1; КонецЦикла; - Параметры_ = OPI_Инструменты.JSONСтрокой(Параметры, , Ложь); - - Если СтрНачинаетсяС(Параметры_, "НЕ JSON") Тогда - ВызватьИсключение "Ошибка валидации JSON массива параметров!"; - КонецЕсли; - Возврат Параметры_; КонецФункции