1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use crate::{
ast::CreateDatabaseStmt,
lexer::TokenKind,
parser::{parser::Parser, parser_error::ParserError},
};
impl<'a> Parser<'a> {
/// Parses a `CREATE DATABASE` statement.
///
/// Syntax:
/// ```sql
/// CREATE DATABASE [IF NOT EXISTS] name
/// [OWNER [=] user]
/// [ENCODING [=] 'encoding']
/// [LOCALE [=] 'locale']
/// [TABLESPACE [=] tablespace]
/// [CONNECTION LIMIT [=] n]
/// ```
///
/// The `CREATE DATABASE` keyword is consumed by the caller (`create.rs`).
/// This function starts at `IF NOT EXISTS` or the database name.
pub fn parse_create_database(&mut self) -> Result<CreateDatabaseStmt, ParserError> {
// Parse optional IF NOT EXISTS clause
let if_not_exists = self.parse_if_not_exist()?;
// Database name — required
let name = self.expect_identifier()?;
// Optional clauses — all can appear in any order
let mut owner = None;
let mut encoding = None;
let mut locale = None;
let mut tablespace = None;
let mut connection_limit = None;
loop {
match self.current_token().clone() {
// `OWNER [=] user`
// Specifies the role that owns the database.
// The `=` is optional (PostgreSQL allows both forms).
TokenKind::Owner => {
self.advance();
self.consume(&TokenKind::Eq);
owner = Some(self.expect_identifier()?);
}
// `ENCODING [=] 'UTF8'`
// Sets the character encoding for the database.
// Value must be a string literal e.g. 'UTF8', 'SQL_ASCII'.
TokenKind::Encoding => {
self.advance();
self.consume(&TokenKind::Eq);
encoding = Some(self.expect_string_literal()?);
}
// `LOCALE [=] 'en_US.UTF-8'`
// Sets both LC_COLLATE and LC_CTYPE at once.
// Value must be a string literal.
TokenKind::Locale => {
self.advance();
self.consume(&TokenKind::Eq);
locale = Some(self.expect_string_literal()?);
}
// `TABLESPACE [=] tablespace_name`
// Specifies the default tablespace for the database.
TokenKind::Tablespace => {
self.advance();
self.consume(&TokenKind::Eq);
tablespace = Some(self.expect_identifier()?);
}
// `CONNECTION LIMIT [=] n`
// Limits the number of concurrent connections.
// -1 means no limit.
TokenKind::Connection => {
self.advance();
self.expect(TokenKind::Limit)?;
self.consume(&TokenKind::Eq);
connection_limit = Some(self.expect_int()?);
}
// No more clauses — exit the loop
_ => break,
}
}
Ok(CreateDatabaseStmt {
name,
if_not_exists,
owner,
encoding,
locale,
tablespace,
connection_limit,
})
}
}