linkrs_query/parser/parsing/
user_parser.rs1use crate::parser::ast::stmt::*;
6use crate::parser::ast::types::Span;
7use crate::parser::core::error::{ParseError, ParseErrorKind};
8use crate::parser::parsing::parse_context::ParseContext;
9use crate::parser::TokenKind;
10
11pub struct UserParser;
13
14impl UserParser {
15 pub fn new() -> Self {
16 Self
17 }
18
19 pub fn parse_create_user_statement(
21 &mut self,
22 ctx: &mut ParseContext,
23 ) -> Result<Stmt, ParseError> {
24 let start_span = ctx.current_span();
25 ctx.expect_token(TokenKind::CreateUser)?;
26 self.parse_create_user_internal(ctx, start_span)
27 }
28
29 pub fn parse_create_user_statement_after_create(
31 &mut self,
32 ctx: &mut ParseContext,
33 start_span: Span,
34 ) -> Result<Stmt, ParseError> {
35 ctx.expect_token(TokenKind::User)?;
36 self.parse_create_user_internal(ctx, start_span)
37 }
38
39 fn parse_create_user_internal(
41 &mut self,
42 ctx: &mut ParseContext,
43 start_span: Span,
44 ) -> Result<Stmt, ParseError> {
45 let mut if_not_exists = false;
46 if ctx.match_token(TokenKind::If) {
47 ctx.expect_token(TokenKind::Not)?;
48 ctx.expect_token(TokenKind::Exists)?;
49 if_not_exists = true;
50 }
51
52 let username = ctx.expect_dcl_name()?;
53
54 let mut password = String::new();
58 if ctx.match_token(TokenKind::With) {
59 ctx.match_token(TokenKind::Password);
62 password = ctx.expect_string_literal()?;
63 } else if ctx.match_token(TokenKind::Password) {
64 password = ctx.expect_string_literal()?;
65 } else if matches!(ctx.current_token().kind, TokenKind::StringLiteral(_)) {
66 password = ctx.expect_string_literal()?;
68 }
69
70 let span = ctx.span_since(start_span.start);
71
72 Ok(Stmt::CreateUser(CreateUserStmt {
73 span,
74 username,
75 password,
76 if_not_exists,
77 }))
78 }
79
80 pub fn parse_alter_user_statement(
82 &mut self,
83 ctx: &mut ParseContext,
84 ) -> Result<Stmt, ParseError> {
85 let start_span = ctx.current_span();
86 ctx.expect_token(TokenKind::AlterUser)?;
87 self.parse_alter_user_internal(ctx, start_span)
88 }
89
90 pub fn parse_alter_user_internal(
92 &mut self,
93 ctx: &mut ParseContext,
94 start_span: Span,
95 ) -> Result<Stmt, ParseError> {
96 ctx.expect_token(TokenKind::User)?;
97
98 let username = ctx.expect_dcl_name()?;
99
100 let mut password = None;
101 let mut is_locked = None;
102
103 if ctx.match_token(TokenKind::With) {
105 ctx.expect_token(TokenKind::Password)?;
106 password = Some(ctx.expect_string_literal()?);
107 }
108
109 while ctx.match_token(TokenKind::Set) {
111 if ctx.match_token(TokenKind::Locked) {
112 ctx.expect_token(TokenKind::Assign)?;
113 is_locked = Some(ctx.expect_boolean_literal()?);
114 } else {
115 return Err(ParseError::new(
116 ParseErrorKind::SyntaxError,
117 "Expected LOCKED after SET in ALTER USER".to_string(),
118 ctx.current_position(),
119 ));
120 }
121 }
122
123 let span = ctx.span_since(start_span.start);
124
125 Ok(Stmt::AlterUser(AlterUserStmt {
126 span,
127 username,
128 password,
129 is_locked,
130 }))
131 }
132
133 pub fn parse_drop_user_statement(
135 &mut self,
136 ctx: &mut ParseContext,
137 ) -> Result<Stmt, ParseError> {
138 let start_span = ctx.current_span();
139 ctx.expect_token(TokenKind::DropUser)?;
140
141 let mut if_exists = false;
142 if ctx.match_token(TokenKind::If) {
143 ctx.expect_token(TokenKind::Exists)?;
144 if_exists = true;
145 }
146
147 let username = ctx.expect_dcl_name()?;
148
149 let span = ctx.span_since(start_span.start);
150
151 Ok(Stmt::DropUser(DropUserStmt {
152 span,
153 username,
154 if_exists,
155 }))
156 }
157
158 pub fn parse_change_password_statement(
160 &mut self,
161 ctx: &mut ParseContext,
162 ) -> Result<Stmt, ParseError> {
163 let start_span = ctx.current_span();
164 ctx.expect_token(TokenKind::ChangePassword)?;
165
166 self.parse_change_password_internal(ctx, start_span)
167 }
168
169 pub fn parse_change_password_internal(
171 &mut self,
172 ctx: &mut ParseContext,
173 start_span: Span,
174 ) -> Result<Stmt, ParseError> {
175 let username = if matches!(ctx.current_token().kind, TokenKind::StringLiteral(_))
179 || ctx.check_token(TokenKind::From)
180 {
181 None
182 } else {
183 Some(ctx.expect_dcl_name()?)
184 };
185
186 ctx.match_token(TokenKind::From);
189
190 let old_password = ctx.expect_string_literal()?;
191 ctx.expect_token(TokenKind::To)?;
192 let new_password = ctx.expect_string_literal()?;
193
194 let span = ctx.span_since(start_span.start);
195
196 Ok(Stmt::ChangePassword(ChangePasswordStmt {
197 span,
198 username,
199 old_password,
200 new_password,
201 }))
202 }
203
204 pub fn parse_change_statement(&mut self, ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
206 let start_span = ctx.current_span();
207 ctx.expect_token(TokenKind::Change)?;
208
209 if ctx.match_token(TokenKind::Password) {
211 return self.parse_change_password_internal(ctx, start_span);
212 }
213
214 Err(ParseError::new(
215 ParseErrorKind::UnexpectedToken,
216 "Expected PASSWORD after CHANGE".to_string(),
217 ctx.current_position(),
218 ))
219 }
220
221 fn parse_role_type(&mut self, ctx: &mut ParseContext) -> Result<RoleType, ParseError> {
223 let token = ctx.current_token();
224 let role_str = match token.kind {
225 TokenKind::God => {
226 ctx.next_token();
227 "GOD".to_string()
228 }
229 TokenKind::Admin => {
230 ctx.next_token();
231 "ADMIN".to_string()
232 }
233 TokenKind::Dba => {
234 ctx.next_token();
235 "DBA".to_string()
236 }
237 TokenKind::Guest => {
238 ctx.next_token();
239 "GUEST".to_string()
240 }
241 TokenKind::User => {
242 ctx.next_token();
243 "USER".to_string()
244 }
245 _ => ctx.expect_identifier()?,
246 };
247
248 role_str
249 .parse::<RoleType>()
250 .map_err(|e| ParseError::new(ParseErrorKind::SyntaxError, e, ctx.current_position()))
251 }
252
253 pub fn parse_grant_statement(&mut self, ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
256 let start_span = ctx.current_span();
257 ctx.expect_token(TokenKind::Grant)?;
258
259 let _ = ctx.match_token(TokenKind::Role);
261
262 let role = self.parse_role_type(ctx)?;
264
265 ctx.expect_token(TokenKind::On)?;
267
268 let space_name = ctx.expect_dcl_name()?;
270
271 ctx.expect_token(TokenKind::To)?;
273
274 let username = ctx.expect_dcl_name()?;
276
277 let span = ctx.span_since(start_span.start);
278
279 Ok(Stmt::Grant(GrantStmt {
280 span,
281 role,
282 space_name,
283 username,
284 }))
285 }
286
287 pub fn parse_revoke_statement(&mut self, ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
290 let start_span = ctx.current_span();
291 ctx.expect_token(TokenKind::Revoke)?;
292
293 let _ = ctx.match_token(TokenKind::Role);
295
296 let role = self.parse_role_type(ctx)?;
298
299 ctx.expect_token(TokenKind::On)?;
301
302 let space_name = ctx.expect_dcl_name()?;
304
305 ctx.expect_token(TokenKind::From)?;
307
308 let username = ctx.expect_dcl_name()?;
310
311 let span = ctx.span_since(start_span.start);
312
313 Ok(Stmt::Revoke(RevokeStmt {
314 span,
315 role,
316 space_name,
317 username,
318 }))
319 }
320}
321
322impl Default for UserParser {
323 fn default() -> Self {
324 Self::new()
325 }
326}
327
328#[cfg(test)]
331mod tests {
332 use crate::parser::Parser;
333
334 #[test]
335 fn test_parse_create_user_unicode_username() {
336 let query = "CREATE USER ユーザー WITH PASSWORD 'password'";
337 let mut parser = Parser::new(query);
338 let result = parser.parse();
339 assert!(
340 result.is_ok(),
341 "Unicode username should parse: {:?}",
342 result.err()
343 );
344 }
345
346 #[test]
347 fn test_parse_create_user_unicode_password() {
348 let query = "CREATE USER testuser WITH PASSWORD 'パスワード123'";
349 let mut parser = Parser::new(query);
350 let result = parser.parse();
351 assert!(
352 result.is_ok(),
353 "Unicode password should parse: {:?}",
354 result.err()
355 );
356 }
357
358 #[test]
359 fn test_parse_create_user_special_chars_username() {
360 let query = "CREATE USER user_123_test WITH PASSWORD 'password'";
361 let mut parser = Parser::new(query);
362 let result = parser.parse();
363 assert!(
364 result.is_ok(),
365 "Username with numbers and underscores should parse: {:?}",
366 result.err()
367 );
368 }
369
370 #[test]
371 fn test_parse_create_user_special_chars_password() {
372 let query = "CREATE USER user WITH PASSWORD 'P@$$w0rd!#%&*'";
373 let mut parser = Parser::new(query);
374 let result = parser.parse();
375 assert!(
376 result.is_ok(),
377 "Password with special chars should parse: {:?}",
378 result.err()
379 );
380 }
381
382 #[test]
383 fn test_parse_create_user_rejects_with_role() {
384 let query = "CREATE USER testuser WITH PASSWORD 'pass' WITH ROLE ADMIN";
385 let mut parser = Parser::new(query);
386 assert!(
387 parser.parse().is_err(),
388 "WITH ROLE is no longer part of CREATE USER syntax"
389 );
390 }
391
392 #[test]
393 fn test_parse_alter_user_set_locked() {
394 for (value, expected) in [("true", true), ("false", false)] {
395 let query = format!("ALTER USER testuser SET LOCKED = {}", value);
396 let mut parser = Parser::new(&query);
397 let result = parser.parse();
398 assert!(
399 result.is_ok(),
400 "SET LOCKED = {} should parse: {:?}",
401 value,
402 result.err()
403 );
404 match result.expect("parsed").ast.stmt() {
405 crate::parser::ast::Stmt::AlterUser(stmt) => {
406 assert_eq!(stmt.is_locked, Some(expected))
407 }
408 other => panic!("expected AlterUser, got {:?}", other),
409 }
410 }
411 }
412
413 #[test]
414 fn test_parse_alter_user_set_locked_rejects_non_boolean() {
415 for query in [
416 "ALTER USER testuser SET LOCKED = yes",
417 "ALTER USER testuser SET LOCKED = 1",
418 ] {
419 let mut parser = Parser::new(query);
420 assert!(
421 parser.parse().is_err(),
422 "{} should be rejected, not silently treated as false",
423 query
424 );
425 }
426 }
427
428 #[test]
429 fn test_parse_alter_user_set_role_rejected() {
430 let mut parser = Parser::new("ALTER USER testuser SET ROLE = DBA");
431 assert!(
432 parser.parse().is_err(),
433 "SET ROLE is no longer part of ALTER USER syntax"
434 );
435 }
436
437 #[test]
438 fn test_parse_create_user_case_insensitive_keywords() {
439 let query = "create user testuser with password 'pass'";
440 let mut parser = Parser::new(query);
441 let result = parser.parse();
442 assert!(
443 result.is_ok(),
444 "Lowercase keywords should parse: {:?}",
445 result.err()
446 );
447 }
448
449 #[test]
450 fn test_parse_alter_user_unicode() {
451 let query = "ALTER USER ユーザー WITH PASSWORD 'ニューパスワード'";
452 let mut parser = Parser::new(query);
453 let result = parser.parse();
454 assert!(
455 result.is_ok(),
456 "ALTER USER with unicode should parse: {:?}",
457 result.err()
458 );
459 }
460
461 #[test]
462 fn test_parse_drop_user_unicode() {
463 let query = "DROP USER ユーザー";
464 let mut parser = Parser::new(query);
465 let result = parser.parse();
466 assert!(
467 result.is_ok(),
468 "DROP USER with unicode should parse: {:?}",
469 result.err()
470 );
471 }
472
473 #[test]
474 fn test_parse_change_password_unicode() {
475 let query = "CHANGE PASSWORD ユーザー 'オールドパスワード' TO 'ニューパスワード'";
476 let mut parser = Parser::new(query);
477 let result = parser.parse();
478 assert!(
479 result.is_ok(),
480 "CHANGE PASSWORD with unicode should parse: {:?}",
481 result.err()
482 );
483 }
484
485 #[test]
486 fn test_parse_grant_unicode() {
487 let query = "GRANT ADMIN ON スペース TO ユーザー";
488 let mut parser = Parser::new(query);
489 let result = parser.parse();
490 assert!(
491 result.is_ok(),
492 "GRANT with unicode should parse: {:?}",
493 result.err()
494 );
495 }
496
497 #[test]
498 fn test_parse_revoke_unicode() {
499 let query = "REVOKE ADMIN ON スペース FROM ユーザー";
500 let mut parser = Parser::new(query);
501 let result = parser.parse();
502 assert!(
503 result.is_ok(),
504 "REVOKE with unicode should parse: {:?}",
505 result.err()
506 );
507 }
508
509 #[test]
510 fn test_parse_describe_user_unicode() {
511 let query = "DESCRIBE USER ユーザー";
512 let mut parser = Parser::new(query);
513 let result = parser.parse();
514 assert!(
515 result.is_ok(),
516 "DESCRIBE USER with unicode should parse: {:?}",
517 result.err()
518 );
519 }
520
521 #[test]
522 fn test_parse_show_roles_with_unicode_space() {
523 let query = "SHOW ROLES IN スペース";
524 let mut parser = Parser::new(query);
525 let result = parser.parse();
526 assert!(
527 result.is_ok(),
528 "SHOW ROLES IN with unicode space should parse: {:?}",
529 result.err()
530 );
531 }
532
533 #[test]
534 fn test_parse_create_user_long_username() {
535 let long_username = "a".repeat(255);
536 let query = format!("CREATE USER {} WITH PASSWORD 'pass'", long_username);
537 let mut parser = Parser::new(&query);
538 let result = parser.parse();
539 assert!(
540 result.is_ok(),
541 "Long username should parse: {:?}",
542 result.err()
543 );
544 }
545
546 #[test]
547 fn test_parse_create_user_long_password() {
548 let long_password = "a".repeat(1000);
549 let query = format!("CREATE USER user WITH PASSWORD '{}'", long_password);
550 let mut parser = Parser::new(&query);
551 let result = parser.parse();
552 assert!(
553 result.is_ok(),
554 "Long password should parse: {:?}",
555 result.err()
556 );
557 }
558
559 #[test]
560 fn test_parse_create_user_empty_like_password() {
561 let query = "CREATE USER user WITH PASSWORD 'a'";
562 let mut parser = Parser::new(query);
563 let result = parser.parse();
564 assert!(
565 result.is_ok(),
566 "Single char password should parse: {:?}",
567 result.err()
568 );
569 }
570
571 #[test]
572 fn test_parse_grant_case_insensitive_role() {
573 for role_case in ["ADMIN", "Admin", "admin"] {
574 let query = format!("GRANT {} ON space TO user", role_case);
575 let mut parser = Parser::new(&query);
576 let result = parser.parse();
577 assert!(
578 result.is_ok(),
579 "GRANT with role case {} should parse: {:?}",
580 role_case,
581 result.err()
582 );
583 }
584 }
585
586 #[test]
587 fn test_parse_show_roles_with_and_without_space() {
588 let query1 = "SHOW ROLES";
589 let query2 = "SHOW ROLES IN myspace";
590
591 let mut parser1 = Parser::new(query1);
592 let result1 = parser1.parse();
593 assert!(
594 result1.is_ok(),
595 "SHOW ROLES without space should parse: {:?}",
596 result1.err()
597 );
598
599 let mut parser2 = Parser::new(query2);
600 let result2 = parser2.parse();
601 assert!(
602 result2.is_ok(),
603 "SHOW ROLES with space should parse: {:?}",
604 result2.err()
605 );
606 }
607
608 #[test]
609 fn test_parse_whitespace_handling() {
610 let queries = vec![
611 "CREATE USER user WITH PASSWORD 'pass'",
612 "CREATE\tUSER\tuser\tWITH\tPASSWORD\t'pass'",
613 "CREATE\nUSER\nuser\nWITH\nPASSWORD\n'pass'",
614 ];
615
616 for query in queries {
617 let mut parser = Parser::new(query);
618 let result = parser.parse();
619 assert!(
620 result.is_ok(),
621 "Query with extra whitespace should parse: {:?}",
622 result.err()
623 );
624 }
625 }
626}