use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::ptr;
use crate::dialects::Dialect;
unsafe fn cstr_to_option(p: *const c_char) -> Option<&'static str> {
if p.is_null() {
return None;
}
unsafe { CStr::from_ptr(p) }.to_str().ok()
}
fn resolve_dialect(name: Option<&str>) -> Dialect {
name.and_then(Dialect::from_str).unwrap_or(Dialect::Ansi)
}
fn to_c_string(s: String) -> *mut c_char {
CString::new(s)
.map(CString::into_raw)
.unwrap_or(ptr::null_mut())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn sqlglot_parse(
sql: *const c_char,
dialect: *const c_char,
) -> *mut c_char {
let sql_str = match unsafe { cstr_to_option(sql) } {
Some(s) => s,
None => return ptr::null_mut(),
};
let dialect_enum = resolve_dialect(unsafe { cstr_to_option(dialect) });
match crate::parse(sql_str, dialect_enum) {
Ok(ast) => match serde_json::to_string(&ast) {
Ok(json) => to_c_string(json),
Err(_) => ptr::null_mut(),
},
Err(_) => ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn sqlglot_transpile(
sql: *const c_char,
from_dialect: *const c_char,
to_dialect: *const c_char,
) -> *mut c_char {
let sql_str = match unsafe { cstr_to_option(sql) } {
Some(s) => s,
None => return ptr::null_mut(),
};
let from = resolve_dialect(unsafe { cstr_to_option(from_dialect) });
let to = resolve_dialect(unsafe { cstr_to_option(to_dialect) });
match crate::transpile(sql_str, from, to) {
Ok(result) => to_c_string(result),
Err(_) => ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn sqlglot_generate(
ast_json: *const c_char,
dialect: *const c_char,
) -> *mut c_char {
let json_str = match unsafe { cstr_to_option(ast_json) } {
Some(s) => s,
None => return ptr::null_mut(),
};
let dialect_enum = resolve_dialect(unsafe { cstr_to_option(dialect) });
match serde_json::from_str::<crate::ast::Statement>(json_str) {
Ok(ast) => to_c_string(crate::generate(&ast, dialect_enum)),
Err(_) => ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub extern "C" fn sqlglot_version() -> *const c_char {
concat!(env!("CARGO_PKG_VERSION"), "\0").as_ptr() as *const c_char
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn sqlglot_free(ptr: *mut c_char) {
if !ptr.is_null() {
drop(unsafe { CString::from_raw(ptr) });
}
}