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) }
38            .to_string_lossy()
39            .to_string();
40        Err(Error::Parse(message))
41    } else {
42        let data = unsafe {
43            std::slice::from_raw_parts(
44                result.summary.data as *const u8,
45                result.summary.len as usize,
46            )
47        };
48        let stderr = unsafe { CStr::from_ptr(result.stderr_buffer) }
49            .to_string_lossy()
50            .to_string();
51        protobuf::SummaryResult::decode(data)
52            .map_err(Error::Decode)
53            .map(|result| SummaryResult::new(result, stderr))
54    };
55    unsafe { pg_query_free_summary_parse_result(result) };
56    parse_result
57}