MCPcopy Create free account
hub / github.com/NodeDB-Lab/nodedb / parse

Function parse

nodedb-sql/src/ddl_ast/parse/dispatch.rs:21–93  ·  view source on GitHub ↗

Try to parse a DDL statement from raw SQL. Returns `None` for non-DDL queries (SELECT, INSERT, etc.) that should flow through the normal planner. Returns `Some(Err(...))` when the SQL is structurally a DDL command but contains a reserved identifier that would be misrouted by the dispatcher.

(sql: &str)

Source from the content-addressed store, hash-verified

19/// is structurally a DDL command but contains a reserved identifier that
20/// would be misrouted by the dispatcher.
21pub fn parse(sql: &str) -> Option<Result<NodedbStatement, SqlError>> {
22 let trimmed = sql.trim();
23 if trimmed.is_empty() {
24 return None;
25 }
26 let upper = trimmed.to_uppercase();
27 let parts: Vec<&str> = trimmed.split_whitespace().collect();
28 if parts.is_empty() {
29 return None;
30 }
31
32 // Graph DSL (`GRAPH ...`, `MATCH ...`, `OPTIONAL MATCH ...`) has its own
33 // tokenising parser — delegate early using token-aware dispatch so that
34 // leading block/line comments and quoted values containing DSL keywords
35 // are never mistakenly matched.
36 let first = lex::first_sql_word(trimmed).map(|w| w.to_uppercase());
37 let is_graph = match first.as_deref() {
38 Some("GRAPH") | Some("MATCH") => true,
39 Some("OPTIONAL") => lex::second_sql_word(trimmed)
40 .map(|w| w.eq_ignore_ascii_case("MATCH"))
41 .unwrap_or(false),
42 _ => false,
43 };
44 if is_graph {
45 return graph_parse::try_parse(trimmed).map(Ok);
46 }
47
48 // Dispatch by family. Order matters only where prefixes overlap
49 // (e.g. DESCRIBE vs DESCRIBE SEQUENCE — handled inside each
50 // family's `try_parse`). A `Some(Err(...))` from any family
51 // short-circuits the chain — reserved-identifier errors must not
52 // be silently swallowed by the next family's `None` path.
53 macro_rules! try_family {
54 ($result:expr) => {{
55 let r = $result;
56 if r.is_some() {
57 return r;
58 }
59 }};
60 }
61
62 // `SHOW GRAPH STATS` must be checked before the generic collection parser
63 // so its `SHOW` prefix is not consumed by `SHOW COLLECTIONS`/etc.
64 try_family!(graph_stats::try_parse(&upper, &parts, trimmed));
65 // Conflict policy must be checked before the generic collection parser
66 // so "SET ON CONFLICT" does not fall through to the raw-SQL path.
67 try_family!(conflict_policy::try_parse(&upper, &parts, trimmed));
68 try_family!(collection::try_parse(&upper, &parts, trimmed));
69 try_family!(index::try_parse(&upper, &parts, trimmed));
70 try_family!(trigger::try_parse(&upper, &parts, trimmed));
71 try_family!(schedule::try_parse(&upper, &parts, trimmed));
72 try_family!(sequence::try_parse(&upper, &parts, trimmed));
73 try_family!(alert::try_parse(&upper, &parts, trimmed));
74 try_family!(retention::try_parse(&upper, &parts, trimmed));
75 try_family!(cluster_admin::try_parse(&upper, &parts, trimmed));
76 try_family!(maintenance::try_parse(&upper, &parts, trimmed));
77 try_family!(backup::try_parse(&upper, &parts, trimmed));
78 // COPY FROM file-path form — must come after backup so STDIN forms fall through.

Callers 15

okFunction · 0.70
errFunction · 0.70
okFunction · 0.70
errFunction · 0.70
okFunction · 0.70
errFunction · 0.70
okFunction · 0.70
assert_reservedFunction · 0.70

Calls 5

first_sql_wordFunction · 0.85
second_sql_wordFunction · 0.85
collectMethod · 0.80
try_parseFunction · 0.70
is_emptyMethod · 0.45