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}