diff --git a/.gitignore b/.gitignore
index b872144c1f..dce515cf62 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,3 +23,4 @@ target/
!oscript.exe
addin.zip
src/addins/tcp_server/OPI_TCPServer.zip
+src/addins/sqlite/OPI_SQLite.zip
diff --git a/src/addins/sqlite/Cargo.lock b/src/addins/sqlite/Cargo.lock
new file mode 100644
index 0000000000..3be5158974
--- /dev/null
+++ b/src/addins/sqlite/Cargo.lock
@@ -0,0 +1,275 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "addin1c"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef34e8b7ff4c43e87491a4cc30a4779a9f67c50db43378a36362c7a56246e05b"
+dependencies = [
+ "smallvec",
+ "utf16_lit",
+]
+
+[[package]]
+name = "ahash"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
+[[package]]
+name = "cc"
+version = "1.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "fallible-iterator"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
+
+[[package]]
+name = "fallible-streaming-iterator"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+dependencies = [
+ "ahash",
+]
+
+[[package]]
+name = "hashlink"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
+dependencies = [
+ "hashbrown",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
+
+[[package]]
+name = "libsqlite3-sys"
+version = "0.30.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
+dependencies = [
+ "cc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "once_cell"
+version = "1.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
+
+[[package]]
+name = "opi_sqlite"
+version = "0.1.0"
+dependencies = [
+ "addin1c",
+ "base64",
+ "rusqlite",
+ "serde_json",
+ "serde_rusqlite",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rusqlite"
+version = "0.32.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e"
+dependencies = [
+ "bitflags",
+ "fallible-iterator",
+ "fallible-streaming-iterator",
+ "hashlink",
+ "libsqlite3-sys",
+ "smallvec",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "serde"
+version = "1.0.217"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.217"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.134"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_rusqlite"
+version = "0.36.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b741cc5ef185cd96157e762c3bba743c4e94c8dc6af0edb053c48d2b3c27e691"
+dependencies = [
+ "rusqlite",
+ "serde",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
+[[package]]
+name = "syn"
+version = "2.0.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
+
+[[package]]
+name = "utf16_lit"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14706d2a800ee8ff38c1d3edb873cd616971ea59eb7c0d046bb44ef59b06a1ae"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "zerocopy"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/src/addins/sqlite/Cargo.toml b/src/addins/sqlite/Cargo.toml
new file mode 100644
index 0000000000..7689397d55
--- /dev/null
+++ b/src/addins/sqlite/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "opi_sqlite"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib"]
+
+[profile.release]
+lto = true # Enable Link Time Optimization
+codegen-units = 1 # Reduce number of codegen units to increase optimizations.
+panic = "abort" # Abort on panic
+strip = true # Automatically strip symbols from the binary.
+
+[dependencies]
+addin1c = "0.5.0"
+rusqlite = { version = "0.32.1", features = ["bundled"]}
+serde_json = "1.0"
+serde_rusqlite = "0.36.0"
+base64 = "0.22.1"
\ No newline at end of file
diff --git a/src/addins/sqlite/MANIFEST.XML b/src/addins/sqlite/MANIFEST.XML
new file mode 100644
index 0000000000..eb28e4669f
--- /dev/null
+++ b/src/addins/sqlite/MANIFEST.XML
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/addins/sqlite/release.bat b/src/addins/sqlite/release.bat
new file mode 100644
index 0000000000..ca42221645
--- /dev/null
+++ b/src/addins/sqlite/release.bat
@@ -0,0 +1,69 @@
+@echo off
+
+:: Установить переменную
+set CARGO_NAME=opi_sqlite
+set LIB_NAME=OPI_SQLite
+set OPENSSL_DIR=C:\msys64\mingw64
+set OPENSSL_LIB_DIR=%OPENSSL_DIR%\lib
+set OPENSSL_INCLUDE_DIR=%OPENSSL_DIR%\include
+
+
+:: Перейти в директорию проекта
+cd /d "%~dp0"
+
+:: Создать папку для артефактов
+set OUTPUT_DIR=artifacts
+if not exist "%OUTPUT_DIR%" mkdir "%OUTPUT_DIR%"
+
+:: Сборка для x86_64-pc-windows-msvc
+cargo build --release --target x86_64-pc-windows-msvc
+if errorlevel 1 goto :error
+
+:: Сборка для x86_64-unknown-linux-gnu
+cargo zigbuild --release --target x86_64-unknown-linux-gnu
+if errorlevel 1 goto :error
+
+:: Сборка для i686-pc-windows-msvc
+cargo build --release --target i686-pc-windows-msvc
+if errorlevel 1 goto :error
+
+:: Сборка для i686-unknown-linux-gnu
+cargo zigbuild --release --target i686-unknown-linux-gnu
+if errorlevel 1 goto :error
+
+:: Копирование файлов .dll и .so
+copy /y target\x86_64-pc-windows-msvc\release\%CARGO_NAME%.dll "%OUTPUT_DIR%\AddIn_x64_windows.dll"
+if errorlevel 1 goto :error
+
+copy /y target\i686-pc-windows-msvc\release\%CARGO_NAME%.dll "%OUTPUT_DIR%\AddIn_x86_windows.dll"
+if errorlevel 1 goto :error
+
+copy /y target\x86_64-unknown-linux-gnu\release\lib%CARGO_NAME%.so "%OUTPUT_DIR%\AddIn_x64_linux.so"
+if errorlevel 1 goto :error
+
+copy /y target\i686-unknown-linux-gnu\release\lib%CARGO_NAME%.so "%OUTPUT_DIR%\AddIn_x86_linux.so"
+if errorlevel 1 goto :error
+
+copy /y MANIFEST.XML "%OUTPUT_DIR%\MANIFEST.XML"
+if errorlevel 1 goto :error
+
+:: Архивация
+powershell -Command "Compress-Archive -Path '%OUTPUT_DIR%\*' -Force -DestinationPath '%LIB_NAME%.zip'"
+if errorlevel 1 goto :error
+
+copy /y "%LIB_NAME%.zip" "../../ru/OInt/addins/%LIB_NAME%.zip"
+copy /y "%LIB_NAME%.zip" "../../en/OInt/addins/%LIB_NAME%.zip"
+
+copy /y "%LIB_NAME%.zip" "../../ru/OPI/src/CommonTemplates/%LIB_NAME%/Template.addin"
+copy /y "%LIB_NAME%.zip" "../../en/OPI/src/CommonTemplates/%LIB_NAME%/Template.addin"
+
+if exist "%OUTPUT_DIR%" (
+ rmdir /S /Q "%OUTPUT_DIR%"
+)
+
+@echo Build and packaging completed successfully.
+exit /b 0
+
+:error
+@echo An error occurred during the build or packaging process.
+exit /b 1
diff --git a/src/addins/sqlite/src/component/methods.rs b/src/addins/sqlite/src/component/methods.rs
new file mode 100644
index 0000000000..5e94977757
--- /dev/null
+++ b/src/addins/sqlite/src/component/methods.rs
@@ -0,0 +1,126 @@
+use rusqlite::{types::ValueRef};
+use serde_json::{Value, json, Map};
+use crate::component;
+use serde_rusqlite::{to_params};
+use base64::{engine::general_purpose, Engine as _};
+
+pub fn execute_query(
+ client: &mut component::AddIn,
+ query: String,
+ params_json: String,
+) -> String {
+
+ let conn = match client.get_connection() {
+ Some(c) => c,
+ None => return r#"{"result": false, "error": "No connection initialized"}"#.to_string(),
+ };
+
+ // Парсинг JSON параметров
+ let parsed_params: Value = match serde_json::from_str(¶ms_json) {
+ Ok(params) => params,
+ Err(e) => {
+ return format!(
+ r#"{{"result": false, "error": "Invalid JSON parameters: {}"}}"#,
+ e.to_string()
+ );
+ }
+ };
+
+ let params_array = match parsed_params.as_array() {
+ Some(array) => array,
+ None => {
+ return r#"{"result": false, "error": "Parameters must be a JSON array"}"#.to_string();
+ }
+ };
+
+
+ let convert = to_params(params_array).unwrap();
+
+ // Определяем тип запроса
+ if query.trim_start().to_uppercase().starts_with("SELECT") {
+ // Выполняем SELECT
+ match conn.prepare(&query) {
+ Ok(mut query_result) => {
+
+ let cols: Vec = query_result
+ .column_names()
+ .iter()
+ .map(|name| name.to_string())
+ .collect();
+
+ let res = query_result.query(convert);
+
+ match res{
+ Ok(mut rows) => {
+ rows_to_json_array(&mut rows, &cols)
+ }
+ Err(e) => {
+ format!(r#"{{"result": false, "error": "{}"}}"#, e.to_string())
+ }
+ }
+
+ }
+ Err(e) => {
+ format!(r#"{{"result": false, "error": "{}"}}"#, e.to_string())
+ }
+ }
+ } else {
+
+ match conn.execute(&query, convert) {
+ Ok(_) => r#"{"result": true}"#.to_string(),
+ Err(e) => format!(r#"{{"result": false, "error": "{}"}}"#, e.to_string()),
+ }
+ }
+}
+
+fn rows_to_json_array(rows: &mut rusqlite::Rows, cols: &Vec) -> String {
+
+ let mut json_array = Vec::new();
+
+ loop {
+
+ let mut current: Map = Map::new();
+
+ match rows.next() {
+
+ Ok(Some(row)) => {
+
+ for i in 0..cols.len() {
+
+ let val = row.get_ref_unwrap(i);
+ let jval = from_sql_to_json(val);
+
+ current.insert(cols[i].to_string(), jval);
+ };
+
+ json_array.push(current);
+
+ }
+
+ Ok(None) => break,
+ Err(e) => {
+ current.insert("error".to_string(), Value::String(e.to_string()));
+ }
+
+ }
+ }
+
+ json!(json_array).to_string()
+}
+
+fn from_sql_to_json(value: ValueRef) -> Value {
+ match value {
+ ValueRef::Null => Value::Null,
+ ValueRef::Integer(i) => Value::Number(i.into()),
+ ValueRef::Real(f) => {
+ serde_json::Number::from_f64(f).map(Value::Number).unwrap_or(Value::Null)
+ }
+ ValueRef::Text(t) => Value::String(String::from_utf8_lossy(t).into_owned()),
+ ValueRef::Blob(b) => {
+ let base64_string = general_purpose::STANDARD.encode(b); // Кодируем в Base64
+ let mut blob_object = serde_json::Map::new();
+ blob_object.insert("blob".to_string(), Value::String(base64_string)); // Оборачиваем в объект
+ Value::Object(blob_object)
+ },
+ }
+}
\ No newline at end of file
diff --git a/src/addins/sqlite/src/component/mod.rs b/src/addins/sqlite/src/component/mod.rs
new file mode 100644
index 0000000000..ca589d55fb
--- /dev/null
+++ b/src/addins/sqlite/src/component/mod.rs
@@ -0,0 +1,108 @@
+mod methods;
+
+use addin1c::{name, Variant};
+use crate::core::getset;
+use rusqlite::{Connection};
+
+// МЕТОДЫ КОМПОНЕНТЫ -------------------------------------------------------------------------------
+
+// Синонимы
+pub const METHODS: &[&[u16]] = &[
+ name!("Connect"),
+ name!("Execute"), // 0
+
+];
+
+// Число параметров функций компоненты
+pub fn get_params_amount(num: usize) -> usize {
+ match num {
+ 0 => 0,
+ 1 => 2,
+ _ => 0,
+ }
+}
+
+// Соответствие функций Rust функциям компоненты
+// Вызовы должны быть обернуты в Box::new
+pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box {
+
+ match num {
+
+ 0 =>{
+ Box::new(obj.initialize())
+ },
+
+ 1 => {
+
+ let query = params[0].get_string().unwrap_or("".to_string());
+ let params_json = params[1].get_string().unwrap_or("".to_string());
+
+ Box::new(methods::execute_query(obj, query, params_json))
+ },
+ _ => Box::new(false), // Неверный номер команды
+ }
+
+}
+
+// -------------------------------------------------------------------------------------------------
+
+// ПОЛЯ КОМПОНЕНТЫ ---------------------------------------------------------------------------------
+
+// Синонимы
+pub const PROPS: &[&[u16]] = &[
+ name!("Database")
+];
+
+
+pub struct AddIn {
+ connection_string: String,
+ connection: Option,
+}
+
+impl AddIn {
+ /// Создает новый объект
+ pub fn new() -> Self {
+ AddIn {
+ connection_string: String::new(),
+ connection: None,
+ }
+ }
+
+ pub fn initialize(&mut self) -> String {
+ let conn_result = if self.connection_string.is_empty() {
+ Connection::open_in_memory()
+ } else {
+ Connection::open(&self.connection_string)
+ };
+
+ match conn_result {
+ Ok(conn) => {
+ self.connection = Some(conn);
+ r#"{"result": true}"#.to_string()
+ }
+ Err(e) => {
+ format!(r#"{{"result": false, "error": "{}"}}"#, e.to_string())
+ }
+ }
+ }
+
+ pub fn get_connection(&self) -> Option<&Connection> {
+ self.connection.as_ref()
+ }
+
+ pub fn get_field_ptr(&self, index: usize) -> *const dyn getset::ValueType {
+ match index {
+ 0 => &self.connection_string as &dyn getset::ValueType as *const _,
+ _ => panic!("Index out of bounds"),
+ }
+ }
+ pub fn get_field_ptr_mut(&mut self, index: usize) -> *mut dyn getset::ValueType { self.get_field_ptr(index) as *mut _ }
+}
+// -------------------------------------------------------------------------------------------------
+
+// УНИЧТОЖЕНИЕ ОБЪЕКТА -----------------------------------------------------------------------------
+
+// Обработка удаления объекта
+impl Drop for AddIn {
+ fn drop(&mut self) {}
+}
\ No newline at end of file
diff --git a/src/addins/sqlite/src/core/getset.rs b/src/addins/sqlite/src/core/getset.rs
new file mode 100644
index 0000000000..dfb6f65bc8
--- /dev/null
+++ b/src/addins/sqlite/src/core/getset.rs
@@ -0,0 +1,78 @@
+use addin1c::{Variant, Tm};
+
+
+pub trait ValueType {
+ fn get_value(&self, val: &mut Variant) -> bool;
+ fn set_value(&mut self, val: &Variant);
+}
+
+// Реализация для i32
+impl ValueType for i32 {
+ fn get_value(&self, val: &mut Variant) -> bool {
+ val.set_i32(*self);
+ true
+ }
+
+ fn set_value(&mut self, val: &Variant) {
+ *self = val.get_i32().unwrap_or(0);
+ }
+}
+
+// Реализация для f64
+impl ValueType for f64 {
+ fn get_value(&self, val: &mut Variant) -> bool {
+ val.set_f64(*self);
+ true
+ }
+
+ fn set_value(&mut self, val: &Variant) {
+ *self = val.get_f64().unwrap_or(0.0);
+ }
+}
+
+// Реализация для bool
+impl ValueType for bool {
+ fn get_value(&self, val: &mut Variant) -> bool {
+ val.set_bool(*self);
+ true
+ }
+
+ fn set_value(&mut self, val: &Variant) {
+ *self = val.get_bool().unwrap_or(false);
+ }
+}
+
+// Реализация для tm
+impl ValueType for Tm {
+ fn get_value(&self, val: &mut Variant) -> bool {
+ val.set_date(*self);
+ true
+ }
+
+ fn set_value(&mut self, val: &Variant) {
+ *self = val.get_date().unwrap_or(Tm::default());
+ }
+}
+
+// Реализация для String
+impl ValueType for String {
+ fn get_value(&self, val: &mut Variant) -> bool {
+ let s: Vec = self.encode_utf16().collect();
+ val.set_str1c(s.as_slice()).is_ok()
+ }
+
+ fn set_value(&mut self, val: &Variant) {
+ *self = val.get_string().unwrap_or("".to_string());
+ }
+}
+
+// Реализация для Vec
+impl ValueType for Vec {
+ fn get_value(&self, val: &mut Variant) -> bool {
+ val.set_blob(self.as_slice()).is_ok()
+ }
+
+ fn set_value(&mut self, val: &Variant) {
+ *self = val.get_blob().unwrap_or(&[]).to_vec()
+ }
+}
\ No newline at end of file
diff --git a/src/addins/sqlite/src/core/mod.rs b/src/addins/sqlite/src/core/mod.rs
new file mode 100644
index 0000000000..9f8e10c39f
--- /dev/null
+++ b/src/addins/sqlite/src/core/mod.rs
@@ -0,0 +1,53 @@
+pub mod getset;
+
+use addin1c::{name, RawAddin, Variant};
+
+use crate::component::METHODS;
+use crate::component::PROPS;
+use crate::component::get_params_amount;
+use crate::component::cal_func;
+use crate::component::AddIn;
+
+// Определение класса
+impl RawAddin for AddIn {
+
+ fn register_extension_as(&mut self) -> &'static [u16] {
+ name!("Main")
+ }
+ fn get_n_props(&mut self) -> usize {
+ PROPS.len()
+ }
+ fn find_prop(&mut self, name: &[u16]) -> Option {
+ PROPS.iter().position(|&x| x == name)
+ }
+ fn get_prop_name(&mut self, num: usize, _alias: usize) -> Option<&'static [u16]> { PROPS.get(num).copied() }
+ fn get_prop_val(&mut self, num: usize, val: &mut Variant) -> bool {let field: &dyn getset::ValueType = &self[num]; field.get_value(val) }
+ fn set_prop_val(&mut self, num: usize, val: &Variant) -> bool {let field: &mut dyn getset::ValueType = &mut self[num]; field.set_value(val); true }
+ fn is_prop_readable(&mut self, _num: usize) -> bool { true }
+ fn is_prop_writable(&mut self, _num: usize) -> bool { true }
+ fn get_n_methods(&mut self) -> usize { METHODS.len() }
+ fn find_method(&mut self, name: &[u16]) -> Option { METHODS.iter().position(|&x| x == name) }
+ fn get_method_name(&mut self, num: usize, _alias: usize) -> Option<&'static [u16]> { METHODS.get(num).copied() }
+ fn get_n_params(&mut self, num: usize) -> usize { get_params_amount(num) }
+ fn get_param_def_value(&mut self, _method_num: usize, _param_num: usize, _value: Variant, ) -> bool { true }
+ fn has_ret_val(&mut self, _num: usize) -> bool { true }
+ fn call_as_proc(&mut self, _num: usize, _params: &mut [Variant]) -> bool { false }
+ fn call_as_func(&mut self, num: usize, params: &mut [Variant], ret_value: &mut Variant, ) -> bool { cal_func(self, num, params).get_value(ret_value) }
+
+}
+
+impl std::ops::Index for AddIn {
+ type Output = dyn getset::ValueType;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ unsafe { &*self.get_field_ptr(index) }
+ }
+}
+
+impl std::ops::IndexMut for AddIn {
+ fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+ unsafe { &mut *self.get_field_ptr_mut(index) }
+ }
+}
+
+
diff --git a/src/addins/sqlite/src/lib.rs b/src/addins/sqlite/src/lib.rs
new file mode 100644
index 0000000000..6b7c2f62a1
--- /dev/null
+++ b/src/addins/sqlite/src/lib.rs
@@ -0,0 +1,49 @@
+pub mod component;
+mod core;
+
+
+use std::{
+ ffi::{c_int, c_long, c_void},
+ sync::atomic::{AtomicI32, Ordering},
+};
+
+use component::AddIn;
+use addin1c::{create_component, destroy_component, name, AttachType};
+
+pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1);
+
+#[allow(non_snake_case)]
+#[no_mangle]
+pub unsafe extern "C" fn GetClassObject(_name: *const u16, component: *mut *mut c_void) -> c_long {
+
+ let addin = AddIn::new();
+ create_component(component, addin)
+
+}
+
+#[allow(non_snake_case)]
+#[no_mangle]
+pub unsafe extern "C" fn DestroyObject(component: *mut *mut c_void) -> c_long {
+ destroy_component(component)
+}
+
+#[allow(non_snake_case)]
+#[no_mangle]
+pub extern "C" fn GetClassNames() -> *const u16 {
+ // small strings for performance
+ name!("Main").as_ptr()
+}
+
+#[allow(non_snake_case)]
+#[no_mangle]
+#[allow(static_mut_refs)]
+pub unsafe extern "C" fn SetPlatformCapabilities(capabilities: c_int) -> c_int {
+ PLATFORM_CAPABILITIES.store(capabilities, Ordering::Relaxed);
+ 3
+}
+
+#[allow(non_snake_case)]
+#[no_mangle]
+pub extern "C" fn GetAttachType() -> AttachType {
+ AttachType::Any
+}
diff --git a/src/addins/tmpl/release.bat b/src/addins/tmpl/release.bat
index 648eb36f3b..62534a5e06 100644
--- a/src/addins/tmpl/release.bat
+++ b/src/addins/tmpl/release.bat
@@ -1,7 +1,8 @@
@echo off
:: Установить переменную
-set LIB_NAME=opi_addin
+set CARGO_NAME=opi_addin
+set LIB_NAME=OPI_AddIn
set OPENSSL_DIR=C:\msys64\mingw64
set OPENSSL_LIB_DIR=%OPENSSL_DIR%\lib
set OPENSSL_INCLUDE_DIR=%OPENSSL_DIR%\include
@@ -31,26 +32,31 @@ cargo zigbuild --release --target i686-unknown-linux-gnu
if errorlevel 1 goto :error
:: Копирование файлов .dll и .so
-copy /y target\x86_64-pc-windows-msvc\release\%LIB_NAME%.dll "%OUTPUT_DIR%\AddIn_x64_windows.dll"
+copy /y target\x86_64-pc-windows-msvc\release\%CARGO_NAME%.dll "%OUTPUT_DIR%\AddIn_x64_windows.dll"
if errorlevel 1 goto :error
-copy /y target\i686-pc-windows-msvc\release\%LIB_NAME%.dll "%OUTPUT_DIR%\AddIn_x86_windows.dll"
+copy /y target\i686-pc-windows-msvc\release\%CARGO_NAME%.dll "%OUTPUT_DIR%\AddIn_x86_windows.dll"
if errorlevel 1 goto :error
-copy /y target\x86_64-unknown-linux-gnu\release\lib%LIB_NAME%.so "%OUTPUT_DIR%\AddIn_x64_linux.so"
+copy /y target\x86_64-unknown-linux-gnu\release\lib%CARGO_NAME%.so "%OUTPUT_DIR%\AddIn_x64_linux.so"
if errorlevel 1 goto :error
-copy /y target\i686-unknown-linux-gnu\release\lib%LIB_NAME%.so "%OUTPUT_DIR%\AddIn_x86_linux.so"
+copy /y target\i686-unknown-linux-gnu\release\lib%CARGO_NAME%.so "%OUTPUT_DIR%\AddIn_x86_linux.so"
if errorlevel 1 goto :error
copy /y MANIFEST.XML "%OUTPUT_DIR%\MANIFEST.XML"
if errorlevel 1 goto :error
:: Архивация
-set ZIP_NAME=addin.zip
-powershell -Command "Compress-Archive -Path '%OUTPUT_DIR%\*' -Force -DestinationPath '%ZIP_NAME%'"
+powershell -Command "Compress-Archive -Path '%OUTPUT_DIR%\*' -Force -DestinationPath '%LIB_NAME%.zip'"
if errorlevel 1 goto :error
+copy /y "%LIB_NAME%.zip" "../../ru/OInt/addins/%LIB_NAME%.zip"
+copy /y "%LIB_NAME%.zip" "../../en/OInt/addins/%LIB_NAME%.zip"
+
+copy /y "%LIB_NAME%.zip" "../../ru/OPI/src/CommonTemplates/%LIB_NAME%/Template.addin"
+copy /y "%LIB_NAME%.zip" "../../en/OPI/src/CommonTemplates/%LIB_NAME%/Template.addin"
+
if exist "%OUTPUT_DIR%" (
rmdir /S /Q "%OUTPUT_DIR%"
)
diff --git a/src/addins/tmpl/src/core/mod.rs b/src/addins/tmpl/src/core/mod.rs
index 1ab84b1e86..9f8e10c39f 100644
--- a/src/addins/tmpl/src/core/mod.rs
+++ b/src/addins/tmpl/src/core/mod.rs
@@ -24,13 +24,13 @@ impl RawAddin for AddIn {
fn get_prop_val(&mut self, num: usize, val: &mut Variant) -> bool {let field: &dyn getset::ValueType = &self[num]; field.get_value(val) }
fn set_prop_val(&mut self, num: usize, val: &Variant) -> bool {let field: &mut dyn getset::ValueType = &mut self[num]; field.set_value(val); true }
fn is_prop_readable(&mut self, _num: usize) -> bool { true }
- fn is_prop_writable(&mut self, num: usize) -> bool { true }
+ fn is_prop_writable(&mut self, _num: usize) -> bool { true }
fn get_n_methods(&mut self) -> usize { METHODS.len() }
fn find_method(&mut self, name: &[u16]) -> Option { METHODS.iter().position(|&x| x == name) }
fn get_method_name(&mut self, num: usize, _alias: usize) -> Option<&'static [u16]> { METHODS.get(num).copied() }
fn get_n_params(&mut self, num: usize) -> usize { get_params_amount(num) }
fn get_param_def_value(&mut self, _method_num: usize, _param_num: usize, _value: Variant, ) -> bool { true }
- fn has_ret_val(&mut self, num: usize) -> bool { true }
+ fn has_ret_val(&mut self, _num: usize) -> bool { true }
fn call_as_proc(&mut self, _num: usize, _params: &mut [Variant]) -> bool { false }
fn call_as_func(&mut self, num: usize, params: &mut [Variant], ret_value: &mut Variant, ) -> bool { cal_func(self, num, params).get_value(ret_value) }
diff --git a/src/addins/tmpl/src/lib.rs b/src/addins/tmpl/src/lib.rs
index d08fdf4a06..f13725c068 100644
--- a/src/addins/tmpl/src/lib.rs
+++ b/src/addins/tmpl/src/lib.rs
@@ -14,7 +14,7 @@ pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1);
#[allow(non_snake_case)]
#[no_mangle]
-pub unsafe extern "C" fn GetClassObject(name: *const u16, component: *mut *mut c_void) -> c_long {
+pub unsafe extern "C" fn GetClassObject(_name: *const u16, component: *mut *mut c_void) -> c_long {
let addin = AddIn::new();
create_component(component, addin)
@@ -35,6 +35,7 @@ pub extern "C" fn GetClassNames() -> *const u16 {
}
#[allow(non_snake_case)]
+#[allow(static_mut_refs)]
#[no_mangle]
pub unsafe extern "C" fn SetPlatformCapabilities(capabilities: c_int) -> c_int {
PLATFORM_CAPABILITIES.store(capabilities, Ordering::Relaxed);
diff --git a/src/en/OInt/addins/OPI_SQLite.zip b/src/en/OInt/addins/OPI_SQLite.zip
new file mode 100644
index 0000000000..6b8624c1ec
Binary files /dev/null and b/src/en/OInt/addins/OPI_SQLite.zip differ
diff --git a/src/ru/OInt/addins/OPI_SQLite.zip b/src/ru/OInt/addins/OPI_SQLite.zip
new file mode 100644
index 0000000000..6b8624c1ec
Binary files /dev/null and b/src/ru/OInt/addins/OPI_SQLite.zip differ
diff --git a/src/ru/OPI/src/CommonTemplates/OPI_SQLite/OPI_SQLite.mdo b/src/ru/OPI/src/CommonTemplates/OPI_SQLite/OPI_SQLite.mdo
new file mode 100644
index 0000000000..145767257c
--- /dev/null
+++ b/src/ru/OPI/src/CommonTemplates/OPI_SQLite/OPI_SQLite.mdo
@@ -0,0 +1,9 @@
+
+
+ OPI_SQLite
+
+ ru
+ SQLite
+
+ AddIn
+
diff --git a/src/ru/OPI/src/CommonTemplates/OPI_SQLite/Template.addin b/src/ru/OPI/src/CommonTemplates/OPI_SQLite/Template.addin
new file mode 100644
index 0000000000..6b8624c1ec
Binary files /dev/null and b/src/ru/OPI/src/CommonTemplates/OPI_SQLite/Template.addin differ
diff --git a/src/ru/OPI/src/Configuration/Configuration.mdo b/src/ru/OPI/src/Configuration/Configuration.mdo
index 0550a7374d..41168b860a 100644
--- a/src/ru/OPI/src/Configuration/Configuration.mdo
+++ b/src/ru/OPI/src/Configuration/Configuration.mdo
@@ -40,6 +40,7 @@
Subsystem.OPI_Интеграция
CommonTemplate.OPI_TCPClient
+ CommonTemplate.OPI_SQLite
CommonModule.OPI_Инструменты
CommonModule.OPI_Криптография
CommonModule.OPI_ПреобразованиеТипов