MCPcopy Create free account
hub / github.com/MaterializeInc/materialize / fmt_call

Method fmt_call

src/sql-parser/src/ast/defs/expr.rs:1309–1411  ·  view source on GitHub ↗
(&self, f: &mut AstFormatter<W>, allow_special_form: bool)

Source from the content-addressed store, hash-verified

1307 }
1308
1309 fn fmt_call<W: fmt::Write>(&self, f: &mut AstFormatter<W>, allow_special_form: bool) {
1310 // This block handles printing function calls that have special parsing. In stable mode, the
1311 // name is quoted and so won't get the special parsing. We only need to print the special
1312 // formats in non-stable mode.
1313 //
1314 // The special forms (`position(a IN b)`, `extract(field FROM source)`)
1315 // have no syntax for `DISTINCT`, a within-group `ORDER BY`, a `FILTER`,
1316 // or an `OVER` window. A call literally named `"position"`/`"extract"`
1317 // that carries any of those modifiers (only reachable via the quoted
1318 // name — the real special grammar doesn't accept them) must therefore
1319 // fall through to the plain quoted-call form, or the special form
1320 // silently drops them on display.
1321 let has_call_modifiers = self.distinct
1322 || self.filter.is_some()
1323 || self.over.is_some()
1324 || matches!(&self.args, FunctionArgs::Args { order_by, .. } if !order_by.is_empty());
1325 if allow_special_form && !f.stable() && !has_call_modifiers {
1326 let special: Option<(&str, &[Option<Keyword>])> =
1327 match self.name.to_ast_string_stable().as_str() {
1328 // `extract(field FROM source)` parses `field` into a string
1329 // literal, so the special form only round-trips when arg0 is
1330 // a string. A generic `"extract"(a, b)` with a non-string
1331 // first arg must use the plain (quoted) call form.
1332 r#""extract""#
1333 if self.args.len() == Some(2)
1334 && matches!(self.args.first(), Some(Expr::Value(Value::String(_)))) =>
1335 {
1336 Some(("extract", &[None, Some(FROM)]))
1337 }
1338 // `position(<needle> IN <haystack>)` parses the needle at
1339 // `Precedence::Like`, so a low-precedence needle (`NOT`, a
1340 // comparison, `IS`, a boolean connective, a quantified
1341 // comparison, ...) printed bare before the `IN` would swallow
1342 // or stop short of the delimiter. Only use the special form
1343 // with a needle that's safe to sit left of `IN`.
1344 r#""position""#
1345 if self.args.len() == Some(2)
1346 && self.args.first().is_some_and(prints_self_delimiting) =>
1347 {
1348 Some(("position", &[None, Some(IN)]))
1349 }
1350
1351 // "trim" doesn't need to appear here because it changes the function name (to
1352 // "btrim", "ltrim", or "rtrim"), but only "trim" is parsed specially. "substring"
1353 // supports comma-delimited arguments, so doesn't need to be here.
1354 _ => None,
1355 };
1356 if let Some((name, kws)) = special {
1357 f.write_str(name);
1358 f.write_str("(");
1359 self.args.intersperse_function_argument_keywords(f, kws);
1360 f.write_str(")");
1361 return;
1362 }
1363 }
1364
1365 // If the function name clashes with a keyword that has its own special
1366 // parser form, an unquoted name on reparse would trigger the

Callers 2

fmtMethod · 0.80
fmt_table_callMethod · 0.80

Calls 9

is_someMethod · 0.80
stableMethod · 0.80
to_ast_string_stableMethod · 0.80
write_nodeMethod · 0.80
as_strMethod · 0.45
lenMethod · 0.45
firstMethod · 0.45
write_strMethod · 0.45

Tested by

no test coverage detected