Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 110 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ itertools = "0.10.3"
prost = { version = "0.13.5", features = ["no-recursion-limit"] }
serde = { version = "1.0.139", features = ["derive"] }
serde_json = "1.0.82"
stacker = "0.1"
thiserror = "1.0.31"

[build-dependencies]
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ pub use node_mut::*;
pub use node_ref::*;
pub use parse_result::*;
pub use query::*;
pub use raw_deparse::deparse_raw;
pub use raw_deparse::{deparse_raw, deparse_raw_with_stack};
pub use raw_fingerprint::fingerprint_raw;
pub use raw_parse::parse_raw;
pub use raw_parse::{parse_raw, parse_raw_with_stack};
pub use raw_scan::scan_raw;
pub use summary::*;
pub use summary_result::*;
Expand Down
21 changes: 21 additions & 0 deletions src/raw_deparse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,27 @@ pub fn deparse_raw(protobuf: &protobuf::ParseResult) -> Result<String> {
}
}

/// Deparses a protobuf ParseResult with a custom stack size.
///
/// This function is useful for deparsing deeply nested queries that might overflow the stack.
/// It uses the `stacker` crate to grow the stack if needed.
///
/// # Arguments
///
/// * `protobuf` - The protobuf ParseResult to deparse
/// * `stack_size` - The stack size in bytes to ensure is available for deparsing
///
/// # Example
///
/// ```rust
/// let result = pg_query::parse("SELECT * FROM users").unwrap();
/// let sql = pg_query::deparse_raw_with_stack(&result.protobuf, 8 * 1024 * 1024).unwrap();
/// assert_eq!(sql, "SELECT * FROM users");
/// ```
pub fn deparse_raw_with_stack(protobuf: &protobuf::ParseResult, stack_size: usize) -> Result<String> {
stacker::maybe_grow(32 * 1024, stack_size, || deparse_raw(protobuf))
}

/// Allocates a C node of the given type.
unsafe fn alloc_node<T>(tag: bindings_raw::NodeTag) -> *mut T {
bindings_raw::pg_query_alloc_node(std::mem::size_of::<T>(), tag as i32) as *mut T
Expand Down
48 changes: 27 additions & 21 deletions src/raw_parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,26 @@ pub fn parse_raw(statement: &str) -> Result<ParseResult> {
parse_result
}

/// Parses a SQL statement with a custom stack size.
///
/// This function is useful for parsing deeply nested queries that might overflow the stack.
/// It uses the `stacker` crate to grow the stack if needed.
///
/// # Arguments
///
/// * `statement` - The SQL statement to parse
/// * `stack_size` - The stack size in bytes to ensure is available for parsing
///
/// # Example
///
/// ```rust
/// let result = pg_query::parse_raw_with_stack("SELECT * FROM users", 8 * 1024 * 1024).unwrap();
/// assert_eq!(result.tables(), vec!["users"]);
/// ```
pub fn parse_raw_with_stack(statement: &str, stack_size: usize) -> Result<ParseResult> {
stacker::maybe_grow(32 * 1024, stack_size, || parse_raw(statement))
}

/// Converts a PostgreSQL List of RawStmt nodes to protobuf RawStmt vector.
unsafe fn convert_list_to_raw_stmts(list: *mut bindings_raw::List) -> Vec<protobuf::RawStmt> {
if list.is_null() {
Expand Down Expand Up @@ -1918,10 +1938,8 @@ unsafe fn convert_discard_stmt(ds: &bindings_raw::DiscardStmt) -> protobuf::Disc
}

unsafe fn convert_coerce_to_domain(ctd: &bindings_raw::CoerceToDomain) -> protobuf::CoerceToDomain {
// xpr is an embedded Expr, convert it as a node pointer
let xpr_ptr = &ctd.xpr as *const bindings_raw::Expr as *mut bindings_raw::Node;
protobuf::CoerceToDomain {
xpr: convert_node_boxed(xpr_ptr),
xpr: None,
arg: convert_node_boxed(ctd.arg as *mut bindings_raw::Node),
resulttype: ctd.resulttype,
resulttypmod: ctd.resulttypmod,
Expand Down Expand Up @@ -2150,9 +2168,8 @@ unsafe fn convert_bit_string(bs: &bindings_raw::BitString) -> protobuf::BitStrin
}

unsafe fn convert_boolean_test(bt: &bindings_raw::BooleanTest) -> protobuf::BooleanTest {
let xpr_ptr = &bt.xpr as *const bindings_raw::Expr as *mut bindings_raw::Node;
protobuf::BooleanTest {
xpr: convert_node_boxed(xpr_ptr),
xpr: None,
arg: convert_node_boxed(bt.arg as *mut bindings_raw::Node),
booltesttype: bt.booltesttype as i32 + 1,
location: bt.location,
Expand Down Expand Up @@ -2751,20 +2768,12 @@ unsafe fn convert_stats_elem(se: &bindings_raw::StatsElem) -> protobuf::StatsEle
}

unsafe fn convert_sql_value_function(svf: &bindings_raw::SQLValueFunction) -> protobuf::SqlValueFunction {
let xpr_ptr = &svf.xpr as *const bindings_raw::Expr as *mut bindings_raw::Node;
protobuf::SqlValueFunction {
xpr: convert_node_boxed(xpr_ptr),
op: svf.op as i32 + 1,
r#type: svf.type_,
typmod: svf.typmod,
location: svf.location,
}
protobuf::SqlValueFunction { xpr: None, op: svf.op as i32 + 1, r#type: svf.type_, typmod: svf.typmod, location: svf.location }
}

unsafe fn convert_xml_expr(xe: &bindings_raw::XmlExpr) -> protobuf::XmlExpr {
let xpr_ptr = &xe.xpr as *const bindings_raw::Expr as *mut bindings_raw::Node;
protobuf::XmlExpr {
xpr: convert_node_boxed(xpr_ptr),
xpr: None,
op: xe.op as i32 + 1,
name: convert_c_string(xe.name),
named_args: convert_list_to_nodes(xe.named_args),
Expand All @@ -2789,9 +2798,8 @@ unsafe fn convert_xml_serialize(xs: &bindings_raw::XmlSerialize) -> protobuf::Xm
}

unsafe fn convert_named_arg_expr(nae: &bindings_raw::NamedArgExpr) -> protobuf::NamedArgExpr {
let xpr_ptr = &nae.xpr as *const bindings_raw::Expr as *mut bindings_raw::Node;
protobuf::NamedArgExpr {
xpr: convert_node_boxed(xpr_ptr),
xpr: None,
arg: convert_node_boxed(nae.arg as *mut bindings_raw::Node),
name: convert_c_string(nae.name),
argnumber: nae.argnumber,
Expand Down Expand Up @@ -2824,9 +2832,8 @@ unsafe fn convert_json_value_expr(jve: &bindings_raw::JsonValueExpr) -> protobuf
}

unsafe fn convert_json_constructor_expr(jce: &bindings_raw::JsonConstructorExpr) -> protobuf::JsonConstructorExpr {
let xpr_ptr = &jce.xpr as *const bindings_raw::Expr as *mut bindings_raw::Node;
protobuf::JsonConstructorExpr {
xpr: convert_node_boxed(xpr_ptr),
xpr: None,
r#type: jce.type_ as i32 + 1,
args: convert_list_to_nodes(jce.args),
func: convert_node_boxed(jce.func as *mut bindings_raw::Node),
Expand All @@ -2853,9 +2860,8 @@ unsafe fn convert_json_behavior(jb: &bindings_raw::JsonBehavior) -> protobuf::Js
}

unsafe fn convert_json_expr(je: &bindings_raw::JsonExpr) -> protobuf::JsonExpr {
let xpr_ptr = &je.xpr as *const bindings_raw::Expr as *mut bindings_raw::Node;
protobuf::JsonExpr {
xpr: convert_node_boxed(xpr_ptr),
xpr: None,
op: je.op as i32 + 1,
column_name: convert_c_string(je.column_name),
formatted_expr: convert_node_boxed(je.formatted_expr as *mut bindings_raw::Node),
Expand Down
Loading