Skip to content

Commit c67d667

Browse files
committed
only allow to omit referenced columns with PgSQL
1 parent 16f42c1 commit c67d667

File tree

4 files changed

+27
-10
lines changed

4 files changed

+27
-10
lines changed

src/dialect/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,10 @@ pub trait Dialect: Debug {
3838
fn is_identifier_start(&self, ch: char) -> bool;
3939
/// Determine if a character is a valid unquoted identifier character
4040
fn is_identifier_part(&self, ch: char) -> bool;
41+
/// Return whether it is allowed to have a `REFERENCES` option
42+
/// in a column definition without a list (in parentheses)
43+
/// of referenced foreign key columns
44+
fn allow_omit_referenced_columns_in_column_option(&self) -> bool {
45+
false
46+
}
4147
}

src/dialect/postgresql.rs

+4
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,8 @@ impl Dialect for PostgreSqlDialect {
3030
|| ch == '$'
3131
|| ch == '_'
3232
}
33+
34+
fn allow_omit_referenced_columns_in_column_option(&self) -> bool {
35+
true
36+
}
3337
}

src/parser.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -69,23 +69,24 @@ impl fmt::Display for ParserError {
6969
impl Error for ParserError {}
7070

7171
/// SQL Parser
72-
pub struct Parser {
72+
pub struct Parser<'a> {
7373
tokens: Vec<Token>,
7474
/// The index of the first unprocessed token in `self.tokens`
7575
index: usize,
76+
dialect: &'a dyn Dialect,
7677
}
7778

78-
impl Parser {
79+
impl<'a> Parser<'a> {
7980
/// Parse the specified tokens
80-
pub fn new(tokens: Vec<Token>) -> Self {
81-
Parser { tokens, index: 0 }
81+
pub fn new(tokens: Vec<Token>, dialect: &'a dyn Dialect) -> Self {
82+
Parser { tokens, index: 0, dialect }
8283
}
8384

8485
/// Parse a SQL statement and produce an Abstract Syntax Tree (AST)
8586
pub fn parse_sql(dialect: &dyn Dialect, sql: String) -> Result<Vec<Statement>, ParserError> {
8687
let mut tokenizer = Tokenizer::new(dialect, &sql);
8788
let tokens = tokenizer.tokenize()?;
88-
let mut parser = Parser::new(tokens);
89+
let mut parser = Parser::new(tokens, dialect);
8990
let mut stmts = Vec::new();
9091
let mut expecting_statement_delimiter = false;
9192
debug!("Parsing sql '{}'...", sql);
@@ -839,7 +840,7 @@ impl Parser {
839840
/// Parse a comma-separated list of 1+ items accepted by `F`
840841
pub fn parse_comma_separated<T, F>(&mut self, mut f: F) -> Result<Vec<T>, ParserError>
841842
where
842-
F: FnMut(&mut Parser) -> Result<T, ParserError>,
843+
F: FnMut(&mut Parser<'a>) -> Result<T, ParserError>,
843844
{
844845
let mut values = vec![];
845846
loop {
@@ -1019,8 +1020,12 @@ impl Parser {
10191020
ColumnOption::Unique { is_primary: false }
10201021
} else if self.parse_keyword("REFERENCES") {
10211022
let foreign_table = self.parse_object_name()?;
1022-
let referred_columns =
1023-
self.parse_parenthesized_column_list(Optional)?;
1023+
let referred_columns = self.parse_parenthesized_column_list(
1024+
if self.dialect.allow_omit_referenced_columns_in_column_option() {
1025+
Optional
1026+
} else {
1027+
Mandatory
1028+
})?;
10241029
ColumnOption::ForeignKey {
10251030
foreign_table,
10261031
referred_columns,

src/test_utils.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ impl TestedDialects {
5353
self.one_of_identical_results(|dialect| {
5454
let mut tokenizer = Tokenizer::new(dialect, sql);
5555
let tokens = tokenizer.tokenize().unwrap();
56-
f(&mut Parser::new(tokens))
56+
f(&mut Parser::new(tokens, dialect))
5757
})
5858
}
5959

@@ -104,7 +104,9 @@ impl TestedDialects {
104104
/// Ensures that `sql` parses as an expression, and is not modified
105105
/// after a serialization round-trip.
106106
pub fn verified_expr(&self, sql: &str) -> Expr {
107-
let ast = self.run_parser_method(sql, Parser::parse_expr).unwrap();
107+
let ast = self
108+
.run_parser_method(sql, |parser| parser.parse_expr())
109+
.unwrap();
108110
assert_eq!(sql, &ast.to_string(), "round-tripping without changes");
109111
ast
110112
}

0 commit comments

Comments
 (0)