sql/parsers/
cursor_parser.rs1use snafu::{ResultExt, ensure};
16use sqlparser::keywords::Keyword;
17use sqlparser::tokenizer::Token;
18
19use crate::error::{self, Result};
20use crate::parser::ParserContext;
21use crate::statements::cursor::{CloseCursor, DeclareCursor, FetchCursor};
22use crate::statements::statement::Statement;
23
24impl ParserContext<'_> {
25 pub(crate) fn parse_declare_cursor(&mut self) -> Result<Statement> {
26 let _ = self.parser.expect_keyword(Keyword::DECLARE);
27 let cursor_name = self
28 .parser
29 .parse_object_name(false)
30 .context(error::SyntaxSnafu)?;
31 let _ = self
32 .parser
33 .expect_keywords(&[Keyword::CURSOR, Keyword::FOR]);
34
35 let mut is_select = false;
36 if let Token::Word(w) = self.parser.peek_token().token {
37 match w.keyword {
38 Keyword::SELECT | Keyword::WITH => {
39 is_select = true;
40 }
41 _ => {}
42 }
43 };
44 ensure!(
45 is_select,
46 error::InvalidSqlSnafu {
47 msg: "Expect select query in cursor statement".to_string(),
48 }
49 );
50
51 let query_stmt = self.parse_query()?;
52 match query_stmt {
53 Statement::Query(query) => Ok(Statement::DeclareCursor(DeclareCursor {
54 cursor_name: ParserContext::canonicalize_object_name(cursor_name)?,
55 query,
56 })),
57 _ => error::InvalidSqlSnafu {
58 msg: format!("Expect query, found {}", query_stmt),
59 }
60 .fail(),
61 }
62 }
63
64 pub(crate) fn parse_fetch_cursor(&mut self) -> Result<Statement> {
65 let _ = self.parser.expect_keyword(Keyword::FETCH);
66
67 let fetch_size = self
68 .parser
69 .parse_literal_uint()
70 .context(error::SyntaxSnafu)?;
71 let _ = self
72 .parser
73 .parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]);
74
75 let cursor_name = self
76 .parser
77 .parse_object_name(false)
78 .context(error::SyntaxSnafu)?;
79
80 Ok(Statement::FetchCursor(FetchCursor {
81 cursor_name: ParserContext::canonicalize_object_name(cursor_name)?,
82 fetch_size,
83 }))
84 }
85
86 pub(crate) fn parse_close_cursor(&mut self) -> Result<Statement> {
87 let _ = self.parser.expect_keyword(Keyword::CLOSE);
88 let cursor_name = self
89 .parser
90 .parse_object_name(false)
91 .context(error::SyntaxSnafu)?;
92
93 Ok(Statement::CloseCursor(CloseCursor {
94 cursor_name: ParserContext::canonicalize_object_name(cursor_name)?,
95 }))
96 }
97}
98
99#[cfg(test)]
100mod tests {
101
102 use super::*;
103 use crate::dialect::GreptimeDbDialect;
104 use crate::parser::ParseOptions;
105
106 #[test]
107 fn test_parse_declare_cursor() {
108 let sql = "DECLARE c1 CURSOR FOR\nSELECT * FROM numbers";
109 let result =
110 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
111 .unwrap();
112
113 if let Statement::DeclareCursor(dc) = &result[0] {
114 assert_eq!("c1", dc.cursor_name.to_string());
115 assert_eq!(
116 "DECLARE c1 CURSOR FOR SELECT * FROM numbers",
117 dc.to_string()
118 );
119 } else {
120 panic!("Unexpected statement");
121 }
122
123 let sql = "DECLARE c1 CURSOR FOR\nINSERT INTO numbers VALUES (1);";
124 let result =
125 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
126 assert!(result.is_err());
127 }
128
129 #[test]
130 fn test_parese_fetch_cursor() {
131 let sql = "FETCH 1000 FROM c1";
132 let result =
133 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
134 .unwrap();
135
136 if let Statement::FetchCursor(fc) = &result[0] {
137 assert_eq!("c1", fc.cursor_name.to_string());
138 assert_eq!("1000", fc.fetch_size.to_string());
139 assert_eq!(sql, fc.to_string());
140 } else {
141 panic!("Unexpected statement")
142 }
143 }
144
145 #[test]
146 fn test_close_fetch_cursor() {
147 let sql = "CLOSE c1";
148 let result =
149 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
150 .unwrap();
151
152 if let Statement::CloseCursor(cc) = &result[0] {
153 assert_eq!("c1", cc.cursor_name.to_string());
154 assert_eq!(sql, cc.to_string());
155 } else {
156 panic!("Unexpected statement")
157 }
158 }
159}