1 /* 2 * Copyright 2015-2018 HuntLabs.cn 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 module hunt.sql.parser.SQLParser; 17 18 import hunt.sql.ast.statement.SQLCreateTableStatement; 19 // import hunt.sql.dialect.hive.stmt.HiveCreateTableStatement; 20 import hunt.sql.parser.Lexer; 21 import hunt.sql.parser.Token; 22 import hunt.sql.parser.SQLParserFeature; 23 import hunt.sql.parser.ParserException; 24 import hunt.String; 25 //import hunt.lang; 26 import hunt.text; 27 import hunt.Integer; 28 29 public class SQLParser { 30 protected Lexer lexer; 31 protected string dbType; 32 33 public this(string sql, string dbType){ 34 this(new Lexer(sql, null, dbType), dbType); 35 this.lexer.nextToken(); 36 } 37 38 public this(string sql){ 39 this(sql, null); 40 } 41 42 public this(Lexer lexer){ 43 this(lexer, null); 44 } 45 46 public this(Lexer lexer, string dbType){ 47 this.lexer = lexer; 48 this.dbType = dbType; 49 } 50 51 public Lexer getLexer() { 52 return lexer; 53 } 54 55 public string getDbType() { 56 return dbType; 57 } 58 59 protected bool identifierEquals(string text) { 60 return lexer.identifierEquals(text); 61 } 62 63 protected void acceptIdentifier(string text) { 64 if (lexer.identifierEquals(text)) { 65 lexer.nextToken(); 66 } else { 67 setErrorEndPos(lexer.pos()); 68 throw new ParserException("syntax error, expect " ~ text ~ ", actual " ~ lexer.token ~ ", " ~ lexer.info()); 69 } 70 } 71 72 protected string tableAlias() { 73 return tableAlias(false); 74 } 75 76 protected string tableAlias(bool must) { 77 Token token = lexer.token; 78 if (token == Token.CONNECT 79 || token == Token.START 80 || token == Token.SELECT 81 || token == Token.FROM 82 || token == Token.WHERE) { 83 if (must) { 84 throw new ParserException("illegal _alias. " ~ lexer.info()); 85 } 86 return null; 87 } 88 89 if (token == Token.IDENTIFIER) { 90 string ident = lexer.stringVal; 91 if (equalsIgnoreCase(ident, "START") || equalsIgnoreCase(ident, "CONNECT")) { 92 if (must) { 93 throw new ParserException("illegal _alias. " ~ lexer.info()); 94 } 95 return null; 96 } 97 } 98 99 return this.as(); 100 } 101 102 protected string as() { 103 string _alias = null; 104 105 Token token = lexer.token; 106 107 if (token == Token.COMMA) { 108 return null; 109 } 110 111 if (token == Token.AS) { 112 lexer.nextToken(); 113 _alias = lexer.stringVal(); 114 lexer.nextToken(); 115 116 if (_alias !is null) { 117 while (lexer.token == Token.DOT) { 118 lexer.nextToken(); 119 _alias ~= ('.' ~ lexer.token.stringof); //@gxc 120 lexer.nextToken(); 121 } 122 123 return _alias; 124 } 125 126 if (lexer.token == Token.LPAREN) { 127 return null; 128 } 129 130 throw new ParserException("Error : " ~ lexer.info()); 131 } 132 133 if (lexer.token == Token.LITERAL_ALIAS) { 134 _alias = lexer.stringVal(); 135 lexer.nextToken(); 136 } else if (lexer.token == Token.IDENTIFIER) { 137 _alias = lexer.stringVal(); 138 lexer.nextToken(); 139 } else if (lexer.token == Token.LITERAL_CHARS) { 140 _alias = "'" ~ lexer.stringVal() ~ "'"; 141 lexer.nextToken(); 142 } else { 143 switch (lexer.token) { 144 case Token.CASE: 145 case Token.USER: 146 case Token.LOB: 147 case Token.END: 148 case Token.DEFERRED: 149 case Token.OUTER: 150 case Token.DO: 151 case Token.STORE: 152 case Token.MOD: 153 _alias = lexer.stringVal(); 154 lexer.nextToken(); 155 break; 156 default: 157 break; 158 } 159 } 160 161 switch (lexer.token) { 162 case Token.KEY: 163 case Token.INTERVAL: 164 case Token.CONSTRAINT: 165 _alias = lexer.token.stringof; //@gxc 166 lexer.nextToken(); 167 return _alias; 168 default: 169 break; 170 } 171 172 return _alias; 173 } 174 175 protected string alias_f() { 176 string _alias = null; 177 if (lexer.token == Token.LITERAL_ALIAS) { 178 _alias = lexer.stringVal(); 179 lexer.nextToken(); 180 } else if (lexer.token == Token.IDENTIFIER) { 181 _alias = lexer.stringVal(); 182 lexer.nextToken(); 183 } else if (lexer.token == Token.LITERAL_CHARS) { 184 _alias = "'" ~ lexer.stringVal() ~ "'"; 185 lexer.nextToken(); 186 } else { 187 switch (lexer.token) { 188 case Token.KEY: 189 case Token.INDEX: 190 case Token.CASE: 191 case Token.MODEL: 192 case Token.PCTFREE: 193 case Token.INITRANS: 194 case Token.MAXTRANS: 195 case Token.SEGMENT: 196 case Token.CREATION: 197 case Token.IMMEDIATE: 198 case Token.DEFERRED: 199 case Token.STORAGE: 200 case Token.NEXT: 201 case Token.MINEXTENTS: 202 case Token.MAXEXTENTS: 203 case Token.MAXSIZE: 204 case Token.PCTINCREASE: 205 case Token.FLASH_CACHE: 206 case Token.CELL_FLASH_CACHE: 207 case Token.NONE: 208 case Token.LOB: 209 case Token.STORE: 210 case Token.ROW: 211 case Token.CHUNK: 212 case Token.CACHE: 213 case Token.NOCACHE: 214 case Token.LOGGING: 215 case Token.NOCOMPRESS: 216 case Token.KEEP_DUPLICATES: 217 case Token.EXCEPTIONS: 218 case Token.PURGE: 219 case Token.INITIALLY: 220 case Token.END: 221 case Token.COMMENT: 222 case Token.ENABLE: 223 case Token.DISABLE: 224 case Token.SEQUENCE: 225 case Token.USER: 226 case Token.ANALYZE: 227 case Token.OPTIMIZE: 228 case Token.GRANT: 229 case Token.REVOKE: 230 case Token.FULL: 231 case Token.TO: 232 case Token.NEW: 233 case Token.INTERVAL: 234 case Token.LOCK: 235 case Token.LIMIT: 236 case Token.IDENTIFIED: 237 case Token.PASSWORD: 238 case Token.BINARY: 239 case Token.WINDOW: 240 case Token.OFFSET: 241 case Token.SHARE: 242 case Token.START: 243 case Token.CONNECT: 244 case Token.MATCHED: 245 case Token.ERRORS: 246 case Token.REJECT: 247 case Token.UNLIMITED: 248 case Token.BEGIN: 249 case Token.EXCLUSIVE: 250 case Token.MODE: 251 case Token.ADVISE: 252 case Token.TYPE: 253 case Token.CLOSE: 254 case Token.OPEN: 255 _alias = lexer.stringVal(); 256 lexer.nextToken(); 257 return _alias; 258 case Token.QUES: 259 _alias = "?"; 260 lexer.nextToken(); 261 break; 262 default: 263 break; 264 } 265 } 266 return _alias; 267 } 268 269 protected void printError(Token token) { 270 string arround; 271 if (lexer._mark >= 0 && (lexer.text.length > lexer._mark + 30)) { 272 if (lexer._mark - 5 > 0) { 273 arround = lexer.text.substring(lexer._mark - 5, lexer._mark + 30); 274 } else { 275 arround = lexer.text.substring(lexer._mark, lexer._mark + 30); 276 } 277 278 } else if (lexer._mark >= 0) { 279 if (lexer._mark - 5 > 0) { 280 arround = lexer.text.substring(lexer._mark - 5); 281 } else { 282 arround = lexer.text.substring(lexer._mark); 283 } 284 } else { 285 arround = lexer.text; 286 } 287 288 // throw new 289 // ParserException("syntax error, error arround:'"~arround~"',expect " 290 // ~ token ~ ", actual " ~ lexer.token ~ " " 291 // ~ lexer.stringVal() ~ ", pos " ~ this.lexer.pos()); 292 throw new ParserException("syntax error, error in :<" ~ arround ~ ">, expect: <" ~ token ~ 293 ">, actual: <" ~ lexer.token ~ ">, " ~ lexer.info()); 294 } 295 296 public void accept(Token token) { 297 if (lexer.token == token) { 298 lexer.nextToken(); 299 } else { 300 setErrorEndPos(lexer.pos()); 301 printError(token); 302 } 303 } 304 305 public int acceptInteger() { 306 if (lexer.token == Token.LITERAL_INT) { 307 int intVal = (cast(Integer) lexer.integerValue()).intValue(); 308 lexer.nextToken(); 309 return intVal; 310 } else { 311 throw new ParserException("syntax error, expect: <int>, actual: <" ~ lexer.token ~ ">, " 312 ~ lexer.info()); 313 } 314 } 315 316 public void match(Token token) { 317 if (lexer.token != token) { 318 throw new ParserException("syntax error, expect: <" ~ token ~ ">, actual: <" ~ lexer.token ~ ">, " 319 ~ lexer.info()); 320 } 321 } 322 323 private int errorEndPos = -1; 324 325 protected void setErrorEndPos(int errPos) { 326 if (errPos > errorEndPos) { 327 errorEndPos = errPos; 328 } 329 } 330 331 public void config(SQLParserFeature feature, bool state) { 332 this.lexer.config(feature, state); 333 } 334 335 public bool isEnabled(SQLParserFeature feature) { 336 return lexer.isEnabled(feature); 337 } 338 339 protected SQLCreateTableStatement newCreateStatement() { 340 return new SQLCreateTableStatement(getDbType()); 341 } 342 }