Skip to content

Dialect on create_database and no_db_trigger support #152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 10, 2024
Merged
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
2 changes: 2 additions & 0 deletions examples/createdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ fn main() -> Result<(), FbError> {
.user("SYSDBA")
.pass("masterkey")
.page_size(8 * 1024) // Optional
.dialect(rsfbclient::Dialect::D1)
.create_database()?;

#[cfg(feature = "dynamic_loading")]
Expand All @@ -38,6 +39,7 @@ fn main() -> Result<(), FbError> {
.user("SYSDBA")
.pass("masterkey")
.page_size(16 * 1024) // Optional
.dialect(rsfbclient::Dialect::D3)
.create_database()?;

conn.close()?;
Expand Down
6 changes: 5 additions & 1 deletion rsfbclient-core/src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ pub trait FirebirdClientDbOps: Send {
fn attach_database(
&mut self,
config: &Self::AttachmentConfig,
dialect: Dialect,
no_db_triggers: bool,
) -> Result<Self::DbHandle, FbError>;

/// Disconnect from the database
Expand All @@ -50,6 +52,7 @@ pub trait FirebirdClientDbOps: Send {
&mut self,
config: &Self::AttachmentConfig,
page_size: Option<u32>,
dialect: Dialect,
) -> Result<Self::DbHandle, FbError>;
}

Expand Down Expand Up @@ -145,12 +148,13 @@ pub trait FirebirdClientDbEvents: FirebirdClientDbOps {
) -> Result<(), FbError>;
}

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
#[repr(u8)]
/// Firebird sql dialect
pub enum Dialect {
D1 = 1,
D2 = 2,
#[default]
D3 = 3,
}

Expand Down
21 changes: 18 additions & 3 deletions rsfbclient-native/src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,17 @@ impl<T: LinkageMarker> FirebirdClientDbOps for NativeFbClient<T> {
fn attach_database(
&mut self,
config: &Self::AttachmentConfig,
dialect: Dialect,
no_db_triggers: bool,
) -> Result<NativeDbHandle, FbError> {
let (dpb, conn_string) = self.build_dpb(config);
let (mut dpb, conn_string) = self.build_dpb(config, dialect);
let mut handle = 0;

if no_db_triggers {
dpb.extend(&[ibase::isc_dpb_no_db_triggers as u8, 1 as u8]);
dpb.extend(&[1 as u8]);
}

unsafe {
if self.ibase.isc_attach_database()(
&mut self.status[0],
Expand Down Expand Up @@ -162,8 +169,9 @@ impl<T: LinkageMarker> FirebirdClientDbOps for NativeFbClient<T> {
&mut self,
config: &Self::AttachmentConfig,
page_size: Option<u32>,
dialect: Dialect,
) -> Result<NativeDbHandle, FbError> {
let (mut dpb, conn_string) = self.build_dpb(config);
let (mut dpb, conn_string) = self.build_dpb(config, dialect);
let mut handle = 0;

if let Some(ps) = page_size {
Expand Down Expand Up @@ -668,7 +676,11 @@ impl<T: LinkageMarker> NativeFbClient<T> {
/// Build the dpb and the connection string
///
/// Used by attach database operations
fn build_dpb(&mut self, config: &NativeFbAttachmentConfig) -> (Vec<u8>, String) {
fn build_dpb(
&mut self,
config: &NativeFbAttachmentConfig,
dialect: Dialect,
) -> (Vec<u8>, String) {
let user = &config.user;
let mut password = None;
let db_name = &config.db_name;
Expand Down Expand Up @@ -709,6 +721,9 @@ impl<T: LinkageMarker> NativeFbClient<T> {
dpb.extend(role.bytes());
}

dpb.extend(&[ibase::isc_dpb_sql_dialect as u8, 1 as u8]);
dpb.extend(&[dialect as u8]);

dpb
};

Expand Down
18 changes: 15 additions & 3 deletions rsfbclient-rust/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ impl FirebirdClientDbOps for RustFbClient {
fn attach_database(
&mut self,
config: &Self::AttachmentConfig,
dialect: Dialect,
no_db_triggers: bool,
) -> Result<RustDbHandle, FbError> {
let host = config.host.as_str();
let port = config.port;
Expand All @@ -109,7 +111,8 @@ impl FirebirdClientDbOps for RustFbClient {
)?,
};

let attach_result = conn.attach_database(db_name, user, pass, role);
let attach_result =
conn.attach_database(db_name, user, pass, role, dialect, no_db_triggers);

// Put the connection back
self.conn.replace(conn);
Expand All @@ -135,6 +138,7 @@ impl FirebirdClientDbOps for RustFbClient {
&mut self,
config: &Self::AttachmentConfig,
page_size: Option<u32>,
dialect: Dialect,
) -> Result<RustDbHandle, FbError> {
let host = config.host.as_str();
let port = config.port;
Expand All @@ -159,7 +163,7 @@ impl FirebirdClientDbOps for RustFbClient {
)?,
};

let attach_result = conn.create_database(db_name, user, pass, page_size, role);
let attach_result = conn.create_database(db_name, user, pass, page_size, role, dialect);

// Put the connection back
self.conn.replace(conn);
Expand Down Expand Up @@ -391,6 +395,7 @@ impl FirebirdWireConnection {
pass: &str,
page_size: Option<u32>,
role_name: Option<&str>,
dialect: Dialect,
) -> Result<DbHandle, FbError> {
self.socket.write_all(&create(
db_name,
Expand All @@ -400,6 +405,7 @@ impl FirebirdWireConnection {
self.charset.clone(),
page_size,
role_name.clone(),
dialect,
))?;
self.socket.flush()?;

Expand All @@ -415,6 +421,8 @@ impl FirebirdWireConnection {
user: &str,
pass: &str,
role_name: Option<&str>,
dialect: Dialect,
no_db_triggers: bool,
) -> Result<DbHandle, FbError> {
self.socket.write_all(&attach(
db_name,
Expand All @@ -423,6 +431,8 @@ impl FirebirdWireConnection {
self.version,
self.charset.clone(),
role_name.clone(),
dialect,
no_db_triggers,
))?;
self.socket.flush()?;

Expand Down Expand Up @@ -1042,7 +1052,9 @@ fn connection_test() {
let mut conn =
FirebirdWireConnection::connect("127.0.0.1", 3050, db_name, user, pass, UTF_8).unwrap();

let mut db_handle = conn.attach_database(db_name, user, pass, None).unwrap();
let mut db_handle = conn
.attach_database(db_name, user, pass, None, Dialect::D3, false)
.unwrap();

let mut tr_handle = conn
.begin_transaction(&mut db_handle, TransactionConfiguration::default())
Expand Down
30 changes: 27 additions & 3 deletions rsfbclient-rust/src/wire.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
util::*,
xsqlda::{XSqlVar, XSQLDA_DESCRIBE_VARS},
};
use rsfbclient_core::{ibase, Charset, Column, FbError, FreeStmtOp, SqlType, TrOp};
use rsfbclient_core::{ibase, Charset, Column, Dialect, FbError, FreeStmtOp, SqlType, TrOp};

/// Buffer length to use in the connection
pub const BUFFER_LENGTH: u32 = 1024;
Expand Down Expand Up @@ -139,8 +139,19 @@ pub fn attach(
protocol: ProtocolVersion,
charset: Charset,
role_name: Option<&str>,
dialect: Dialect,
no_db_triggers: bool,
) -> Bytes {
let dpb = build_dpb(user, pass, protocol, charset, None, role_name);
let dpb = build_dpb(
user,
pass,
protocol,
charset,
None,
role_name,
dialect,
no_db_triggers,
);

let mut attach = BytesMut::with_capacity(16 + db_name.len() + dpb.len());

Expand All @@ -163,8 +174,11 @@ pub fn create(
charset: Charset,
page_size: Option<u32>,
role_name: Option<&str>,
dialect: Dialect,
) -> Bytes {
let dpb = build_dpb(user, pass, protocol, charset, page_size, role_name);
let dpb = build_dpb(
user, pass, protocol, charset, page_size, role_name, dialect, false,
);

let mut create = BytesMut::with_capacity(16 + db_name.len() + dpb.len());

Expand All @@ -186,6 +200,8 @@ fn build_dpb(
charset: Charset,
page_size: Option<u32>,
role_name: Option<&str>,
dialect: Dialect,
no_db_triggers: bool,
) -> Bytes {
let mut dpb = BytesMut::with_capacity(64);

Expand All @@ -209,6 +225,14 @@ fn build_dpb(
dpb.extend(role.bytes());
}

dpb.extend(&[ibase::isc_dpb_sql_dialect as u8, 1 as u8]);
dpb.extend(&[dialect as u8]);

if no_db_triggers {
dpb.extend(&[ibase::isc_dpb_no_db_triggers as u8, 1 as u8]);
dpb.extend(&[1 as u8]);
}

match protocol {
// Plaintext password
ProtocolVersion::V10 => {
Expand Down
6 changes: 6 additions & 0 deletions src/connection/builders/builder_native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,12 @@ where
self.conn_conf.transaction_conf = builder(&mut transaction_builder()).build();
self
}

/// Disabled the database triggers
pub fn no_db_triggers(&mut self) -> &mut Self {
self.conn_conf.no_db_triggers = true;
self
}
}

impl<A, B> NativeConnectionBuilder<A, B> {
Expand Down
6 changes: 6 additions & 0 deletions src/connection/builders/builder_pure_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ impl PureRustConnectionBuilder {
self
}

/// Disabled the database triggers
pub fn no_db_triggers(&mut self) -> &mut Self {
self.0.no_db_triggers = true;
self
}

/// Default transaction configuration
pub fn transaction(&mut self, conf: TransactionConfiguration) -> &mut Self {
self.0.transaction_conf = conf;
Expand Down
7 changes: 5 additions & 2 deletions src/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub trait FirebirdClientFactory {
pub struct ConnectionConfiguration<A> {
attachment_conf: A,
dialect: Dialect,
no_db_triggers: bool,
stmt_cache_size: usize,
transaction_conf: TransactionConfiguration,
}
Expand All @@ -71,6 +72,7 @@ impl<A: Default> Default for ConnectionConfiguration<A> {
dialect: Dialect::D3,
stmt_cache_size: 20,
transaction_conf: TransactionConfiguration::default(),
no_db_triggers: false,
}
}
}
Expand Down Expand Up @@ -107,7 +109,8 @@ impl<C: FirebirdClient> Connection<C> {
mut cli: C,
conf: &ConnectionConfiguration<C::AttachmentConfig>,
) -> Result<Connection<C>, FbError> {
let handle = cli.attach_database(&conf.attachment_conf)?;
let handle =
cli.attach_database(&conf.attachment_conf, conf.dialect, conf.no_db_triggers)?;
let stmt_cache = StmtCache::new(conf.stmt_cache_size);

Ok(Connection {
Expand All @@ -127,7 +130,7 @@ impl<C: FirebirdClient> Connection<C> {
conf: &ConnectionConfiguration<C::AttachmentConfig>,
page_size: Option<u32>,
) -> Result<Connection<C>, FbError> {
let handle = cli.create_database(&conf.attachment_conf, page_size)?;
let handle = cli.create_database(&conf.attachment_conf, page_size, conf.dialect)?;
let stmt_cache = StmtCache::new(conf.stmt_cache_size);

Ok(Connection {
Expand Down
40 changes: 40 additions & 0 deletions src/tests/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,4 +309,44 @@ mk_tests_default! {

Ok(())
}

#[test]
#[cfg(all(not(feature = "embedded_tests")))]
fn no_db_triggers() -> Result<(), FbError> {

let epoch = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_nanos();

let mut conn = cbuilder()
.connect()?;

conn.execute(&format!("create table log_conn{} (id int);", epoch), ())?;

conn.execute(&format!("create trigger trig_conexao{0} on connect as begin insert into log_conn{0} (id) values (5); end", epoch), ())?;

conn.close()?;

let mut conn2 = cbuilder()
.no_db_triggers()
.connect()?;

let resp: Option<(i32,)> = conn2.query_first(&format!("select * from log_conn{}", epoch), ())?;
assert_eq!(None, resp);

conn2.close()?;

let mut conn3 = cbuilder()
.connect()?;

let resp: Option<(i32,)> = conn3.query_first(&format!("select * from log_conn{}", epoch), ())?;
assert_eq!(Some((5,)), resp);

conn3.execute(&format!("drop trigger trig_conexao{};", epoch), ()).ok();
conn3.execute(&format!("drop table log_conn{};", epoch), ()).ok();
conn3.close()?;

Ok(())
}
}
34 changes: 34 additions & 0 deletions src/tests/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,38 @@ mk_tests_default! {

Ok(())
}

#[test]
#[cfg(all(feature = "linking", not(feature = "embedded_tests"), not(feature = "pure_rust")))]
fn dyn_linking_create_with_invalid_dialect() -> Result<(), FbError> {

let rs = builder_native()
.with_dyn_link()
.with_remote()
.db_name("test_create_db5.fdb")
.user("SYSDBA")
.host("localhost")
.dialect(rsfbclient::Dialect::D2)
.create_database();

assert!(rs.is_err());
assert!(rs.err().unwrap().to_string().contains("Database dialect 2 is not a valid dialec"));

Ok(())
}

#[test]
#[cfg(all(feature = "pure_rust", not(feature = "native_client")))]
fn pure_rust_create_with_invalid_dialect() -> Result<(), FbError> {
let rs = builder_pure_rust()
.db_name("test_create_db55.fdb")
.user("SYSDBA")
.dialect(rsfbclient::Dialect::D2)
.create_database();

assert!(rs.is_err());
assert!(rs.err().unwrap().to_string().contains("Database dialect 2 is not a valid dialec"));

Ok(())
}
}