From: Olaf Wintermann Date: Sat, 18 Jul 2026 06:54:36 +0000 (+0200) Subject: implement dav query exec X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=HEAD;p=note.git implement dav query exec --- diff --git a/dav-rs/src/dav/ffi.rs b/dav-rs/src/dav/ffi.rs index 982296c..2e140aa 100644 --- a/dav-rs/src/dav/ffi.rs +++ b/dav-rs/src/dav/ffi.rs @@ -29,6 +29,23 @@ use std::ffi::{c_char, c_int, c_long, c_void}; use libc::time_t; + +#[repr(C)] +#[derive(Debug)] +pub struct CxString { + pub ptr: *const c_char, + pub len: usize, +} + +impl CxString { + pub fn new(s: &str) -> Self { + Self { + ptr: s.as_ptr() as *const c_char, + len: s.len(), + } + } +} + #[repr(C)] pub struct DavContext { _private: [u8; 0], @@ -135,3 +152,17 @@ pub struct DavXmlAttr { pub value: *mut c_char, pub next: *mut DavXmlAttr, } + + +#[repr(C)] +#[derive(Debug)] +pub struct DavQLStatement { + _private: [u8; 0], +} + +#[repr(C)] +#[derive(Debug)] +pub struct DavResult { + pub result: *mut DavResource, + pub status: c_int, +} diff --git a/dav-rs/src/dav/query.rs b/dav-rs/src/dav/query.rs index 6249440..4a3d648 100644 --- a/dav-rs/src/dav/query.rs +++ b/dav-rs/src/dav/query.rs @@ -27,12 +27,16 @@ */ #![allow(dead_code)] -use crate::dav::session::Session; +use std::ffi::{c_char, c_int, CString}; +use crate::dav::ffi::{CxString, DavQLStatement, DavResult, DavSession}; +use crate::dav::resource::Resource; +use crate::dav::session::{DavError, Session}; +use crate::dav::utils::cstr2str; pub struct DavQuery { pub from: String, pub properties: Vec, - pub filter: Vec, + pub filter: Option, pub depth: u16 } @@ -40,7 +44,7 @@ pub fn query(from: &str) -> DavQuery { DavQuery { from: from.to_string(), properties: Vec::new(), - filter: Vec::new(), + filter: None, depth: 1 } } @@ -56,22 +60,61 @@ impl DavQuery { self } - pub fn filter(&mut self, filter: Cmp) -> &mut Self { - self.filter.push(filter.cmp); + pub fn filter(&mut self, filter: &str) -> &mut Self { + self.filter = Some(filter.to_string()); self } -} + pub fn execute<'a>(&self, session: &Session) -> Result, DavError> { + let query = self.compile(); + let cxstr = CxString::new(query.as_str()); -pub struct Cmp { - cmp: String, -} + unsafe { + let stmt = dav_parse_statement(cxstr); + let errrorcode = dav_sql_statement_get_errorcode(stmt); + let result = if errrorcode != 0 { + let errrorcode = dav_sql_statement_get_errorcode(stmt); + let errormsg = cstr2str(dav_sql_statement_get_errormessage(stmt)); + Err(DavError::QlError(format!("{} {}", errrorcode, errormsg))) + } else { + let stmt_result = dav_statement_exec(session.ptr, stmt); + if stmt_result.status == 0 && !stmt_result.result.is_null() { + Ok(Resource::from_ptr(stmt_result.result)) + } else { + Err(session.get_error()) + } + }; + dav_free_statement(stmt); + result + } + } + + fn compile(&self) -> String { + let properties = self + .properties + .iter() + .map(|p| format!("`{}`", p)) + .collect::>() + .join(", "); + let mut query = format!( + "select {} from {} with depth {}", + properties, self.from, self.depth + ); -impl Cmp { - pub fn eq_str(prop: &str, str: &str) -> Cmp { - Cmp { - cmp: format!("{} = '{}'", prop, str), + if let Some(filter) = &self.filter { + query.push_str(" where "); + query.push_str(filter); } + + query } -} \ No newline at end of file +} + +unsafe extern "C" { + fn dav_parse_statement(stmt: CxString) -> *mut DavQLStatement; + fn dav_free_statement(stmt: *mut DavQLStatement); + fn dav_sql_statement_get_errorcode(stmt: *const DavQLStatement) -> c_int; + fn dav_sql_statement_get_errormessage(stmt: *const DavQLStatement) -> *mut c_char; + fn dav_statement_exec(sn: *mut DavSession, st: *mut DavQLStatement, ...) -> DavResult; +} diff --git a/dav-rs/src/dav/resource.rs b/dav-rs/src/dav/resource.rs index 4a667c5..c0e01f7 100644 --- a/dav-rs/src/dav/resource.rs +++ b/dav-rs/src/dav/resource.rs @@ -42,6 +42,25 @@ pub struct Resource<'a> { pub base: ResourceRef<'a> } +impl Resource<'_> { + pub fn from_ptr<'a>(ptr: *mut ffi::DavResource) -> Resource<'a> { + Resource { + base: ResourceRef { + ptr: ptr, + _marker: PhantomData, + } + } + } + + pub fn new<'a>(sn: &Session, path: &str) -> Resource<'a> { + let path = CString::new(path).unwrap(); + unsafe { + let res = dav_resource_new(sn.ptr, path.as_ptr()); + Resource::from_ptr(res) + } + } +} + pub struct ResourceRef<'a> { pub ptr: *mut ffi::DavResource, _marker: PhantomData<&'a Resource<'a>>, diff --git a/dav-rs/src/dav/session.rs b/dav-rs/src/dav/session.rs index e744746..9e460fa 100644 --- a/dav-rs/src/dav/session.rs +++ b/dav-rs/src/dav/session.rs @@ -147,7 +147,7 @@ pub fn get_session_error(sn: *const ffi::DavSession) -> DavError { ffi::DavError::DavCouldntConnect => DavError::CouldntConnect, ffi::DavError::DavTimeout => DavError::Timeout, ffi::DavError::DavSslError => DavError::SslError, - ffi::DavError::DavQlError => DavError::QlError, + ffi::DavError::DavQlError => DavError::QlError("".to_string()), ffi::DavError::DavContentVerificationError => DavError::ContentVerificationError, ffi::DavError::DavPreconditionFailed => DavError::PreconditionFailed, ffi::DavError::DavRequestEntityTooLarge => DavError::RequestEntityTooLarge, @@ -173,7 +173,7 @@ pub enum DavError { CouldntConnect, Timeout, SslError, - QlError, + QlError(String), ContentVerificationError, PreconditionFailed, RequestEntityTooLarge,