use std::{ffi::c_void, ops::Deref};
use pg_query::protobuf::{ParseResult, RawStmt};
use crate::bindings::PdStatement;
impl PdStatement {
pub unsafe fn from_proto(value: &ParseResult) -> Self {
Self {
data: value.stmts.as_ptr() as *mut c_void,
version: value.version,
len: value.stmts.len() as u64,
}
}
}
#[derive(Debug)]
pub struct PdParseResult {
parse_result: Option<ParseResult>,
borrowed: bool,
}
impl Clone for PdParseResult {
fn clone(&self) -> Self {
Self {
parse_result: self.parse_result.clone(),
borrowed: false,
}
}
}
impl From<PdStatement> for PdParseResult {
fn from(value: PdStatement) -> Self {
Self {
parse_result: Some(ParseResult {
version: value.version,
stmts: unsafe {
Vec::from_raw_parts(
value.data as *mut RawStmt,
value.len as usize,
value.len as usize,
)
},
}),
borrowed: true,
}
}
}
impl Drop for PdParseResult {
fn drop(&mut self) {
if self.borrowed {
let parse_result = self.parse_result.take();
std::mem::forget(parse_result.unwrap().stmts);
}
}
}
impl Deref for PdParseResult {
type Target = ParseResult;
fn deref(&self) -> &Self::Target {
self.parse_result.as_ref().unwrap()
}
}
impl PdStatement {
pub fn protobuf(&self) -> PdParseResult {
PdParseResult::from(*self)
}
}
#[cfg(test)]
mod test {
use crate::pg_query::NodeEnum;
use super::*;
#[test]
fn test_ast() {
let ast = pg_query::parse("SELECT * FROM users WHERE id = $1").unwrap();
let ffi = unsafe { PdStatement::from_proto(&ast.protobuf) };
match ffi
.protobuf()
.stmts
.first()
.unwrap()
.stmt
.as_ref()
.unwrap()
.node
.as_ref()
.unwrap()
{
NodeEnum::SelectStmt(_) => (),
_ => {
panic!("not a select")
}
};
let _ = ffi.protobuf().clone();
}
}