Skip to content

Commit 78a6823

Browse files
Merge branch 'main' into xmlparse
2 parents f9b311e + 2f3b5b8 commit 78a6823

40 files changed

Lines changed: 2695 additions & 619 deletions

.github/workflows/audit.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
name: Security audit
19+
20+
on:
21+
push:
22+
branches-ignore:
23+
- 'gh-readonly-queue/**'
24+
paths:
25+
- '**/Cargo.toml'
26+
- '**/Cargo.lock'
27+
pull_request:
28+
paths:
29+
- '**/Cargo.toml'
30+
- '**/Cargo.lock'
31+
merge_group:
32+
schedule:
33+
# Run every day so newly published advisories are caught even when the
34+
# dependency tree has not changed.
35+
- cron: '0 0 * * *'
36+
37+
permissions:
38+
contents: read
39+
40+
jobs:
41+
audit:
42+
runs-on: ubuntu-latest
43+
steps:
44+
- uses: actions/checkout@v4
45+
- name: Install cargo-audit
46+
run: cargo install cargo-audit --locked
47+
- name: Run cargo audit
48+
run: cargo audit --deny warnings

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ edition = "2021"
3636
name = "sqlparser"
3737
path = "src/lib.rs"
3838

39+
[lints.rust]
40+
unsafe_code = "forbid"
41+
3942
[features]
4043
default = ["std", "recursive-protection"]
4144
std = []

derive/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ edition = "2021"
3535
[lib]
3636
proc-macro = true
3737

38+
[lints.rust]
39+
unsafe_code = "forbid"
40+
3841
[dependencies]
3942
syn = { version = "2.0", default-features = false, features = ["full", "printing", "parsing", "derive", "proc-macro", "clone-impls"] }
4043
proc-macro2 = "1.0"

examples/cli.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ $ cargo run --example cli - [--dialectname]
7171
.expect("failed to read from stdin");
7272
String::from_utf8(buf).expect("stdin content wasn't valid utf8")
7373
} else {
74-
println!("Parsing from file '{}' using {:?}", &filename, dialect);
74+
println!("Parsing from file '{}' using {:?}", filename, dialect);
7575
fs::read_to_string(&filename)
76-
.unwrap_or_else(|_| panic!("Unable to read the file {}", &filename))
76+
.unwrap_or_else(|_| panic!("Unable to read the file {}", filename))
7777
};
7878
let without_bom = if contents.chars().next().unwrap() as u64 != 0xfeff {
7979
contents.as_str()

sqlparser_bench/benches/sqlparser_bench.rs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,58 @@ fn parse_prefix_case_chain(c: &mut Criterion) {
245245
group.finish();
246246
}
247247

248+
/// Benchmark parsing pathological paren chains that previously caused 2^N
249+
/// work in `parse_table_factor`. The input `SELECT 1 FROM ((((...` rejects
250+
/// at EOF, which used to force exponential backtracking through the chain.
251+
fn parse_table_factor_paren_chain(c: &mut Criterion) {
252+
let mut group = c.benchmark_group("parse_table_factor_paren_chain");
253+
let dialect = GenericDialect {};
254+
255+
for &n in &[10usize, 20, 30] {
256+
let mut sql = String::from("SELECT 1 ");
257+
for _ in 0..5 {
258+
sql.push_str("FROM ");
259+
sql.push_str(&"(".repeat(n));
260+
sql.push(' ');
261+
}
262+
263+
group.bench_function(format!("chain_{n}"), |b| {
264+
b.iter(|| {
265+
let _ = Parser::new(&dialect)
266+
.with_recursion_limit(256)
267+
.try_with_sql(std::hint::black_box(&sql))
268+
.and_then(|mut p| p.parse_statements());
269+
});
270+
});
271+
}
272+
273+
group.finish();
274+
}
275+
276+
/// Benchmark parsing pathological `CAST(CASE (CAST(CASE (...` chains that
277+
/// previously caused 2^N work in `parse_function_args` on dialects with
278+
/// expression-named function arguments (the argument expression was parsed
279+
/// once to detect the named form, then re-parsed on the unnamed path).
280+
fn parse_function_arg_call_chain(c: &mut Criterion) {
281+
let mut group = c.benchmark_group("parse_function_arg_call_chain");
282+
let dialect = PostgreSqlDialect {};
283+
284+
for &n in &[10usize, 20, 30] {
285+
let sql = String::from("SELECT ") + &"CAST(CASE (".repeat(n) + &")".repeat(n);
286+
287+
group.bench_function(format!("chain_{n}"), |b| {
288+
b.iter(|| {
289+
let _ = Parser::new(&dialect)
290+
.with_recursion_limit(256)
291+
.try_with_sql(std::hint::black_box(&sql))
292+
.and_then(|mut p| p.parse_statements());
293+
});
294+
});
295+
}
296+
297+
group.finish();
298+
}
299+
248300
criterion_group!(
249301
benches,
250302
basic_queries,
@@ -253,6 +305,8 @@ criterion_group!(
253305
parse_compound_chain,
254306
parse_compound_keyword_chain,
255307
parse_prefix_keyword_call_chain,
256-
parse_prefix_case_chain
308+
parse_prefix_case_chain,
309+
parse_table_factor_paren_chain,
310+
parse_function_arg_call_chain
257311
);
258312
criterion_main!(benches);

src/ast/data_type.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,8 @@ impl fmt::Display for DataType {
720720
ArrayElemTypeDef::SquareBracket(t, Some(size)) => write!(f, "{t}[{size}]"),
721721
ArrayElemTypeDef::AngleBracket(t) => write!(f, "ARRAY<{t}>"),
722722
ArrayElemTypeDef::Parenthesis(t) => write!(f, "Array({t})"),
723+
ArrayElemTypeDef::Qualified(t, None) => write!(f, "{t} ARRAY"),
724+
ArrayElemTypeDef::Qualified(t, Some(size)) => write!(f, "{t} ARRAY[{size}]"),
723725
},
724726
DataType::Custom(ty, modifiers) => {
725727
if modifiers.is_empty() {
@@ -1163,6 +1165,8 @@ pub enum ArrayElemTypeDef {
11631165
SquareBracket(Box<DataType>, Option<u64>),
11641166
/// Parenthesis style, e.g. `Array(Int64)`.
11651167
Parenthesis(Box<DataType>),
1168+
/// Qualified by a data type and optional size, e.g. `INT ARRAY` or `INT ARRAY[4]`.
1169+
Qualified(Box<DataType>, Option<u64>),
11661170
}
11671171

11681172
/// Represents different types of geometric shapes which are commonly used in

0 commit comments

Comments
 (0)