Skip to main content

pg_query/
summary.rs

1use std::ffi::{CStr, CString};
2
3use prost::Message;
4
5use crate::bindings::*;
6use crate::error::*;
7use crate::protobuf;
8use crate::summary_result::SummaryResult;
9
10/// Parses the given SQL statement and provides a summary of it.
11///
12/// It is possible to generate the same data using `pg_query::parse` and
13/// iterating through the parse tree. However, `pg_query::summary` uses a
14/// C implementation to avoid sending as much data over protobuf.
15///
16/// Avoiding sending the parse tree over protobuf can cause as much as an
17/// *order of magnitude* performance improvement. It also prevents some
18/// crashes caused by protobuf handling such a large amount of data.
19///
20/// You can run `cargo bench parse_vs_summary` to run the benchmarks that
21/// comparse the two options.
22///
23/// # Example
24///
25/// ```rust
26/// use pg_query::{Node, NodeEnum, NodeRef};
27///
28/// let result = pg_query::summary("SELECT * FROM contacts", -1);
29/// assert!(result.is_ok());
30/// let result = result.unwrap();
31/// assert_eq!(result.tables(), vec!["contacts"]);
32/// ```
33pub fn summary(statement: &str, truncate_limit: i32) -> Result<SummaryResult> {
34    let input = CString::new(statement)?;
35    let result = unsafe { pg_query_summary(input.as_ptr(), 0, truncate_limit) };
36    let parse_result = if !result.error.is_null() {
37        let message = unsafe { CStr::from_ptr((*result.error).message) }.to_string_lossy().to_string();
38        Err(Error::Parse(message))
39    } else {
40        let data = unsafe { std::slice::from_raw_parts(result.summary.data as *const u8, result.summary.len as usize) };
41        let stderr = unsafe { CStr::from_ptr(result.stderr_buffer) }.to_string_lossy().to_string();
42        protobuf::SummaryResult::decode(data).map_err(Error::Decode).map(|result| SummaryResult::new(result, stderr))
43    };
44    unsafe { pg_query_free_summary_parse_result(result) };
45    parse_result
46}