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.dialect.postgresql.parser.PGSelectParser; 17 18 import hunt.collection; 19 20 import hunt.sql.ast.SQLExpr; 21 import hunt.sql.ast.SQLLimit; 22 import hunt.sql.ast.SQLParameter; 23 import hunt.sql.ast.SQLSetQuantifier; 24 import hunt.sql.ast.expr.SQLIdentifierExpr; 25 import hunt.sql.ast.statement.SQLExprTableSource; 26 import hunt.sql.ast.statement.SQLSelectQuery; 27 import hunt.sql.ast.statement.SQLSelectQueryBlock; 28 import hunt.sql.ast.statement.SQLTableSource; 29 import hunt.sql.dialect.postgresql.ast.stmt.PGFunctionTableSource; 30 import hunt.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock; 31 // import hunt.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock.IntoOption; 32 import hunt.sql.dialect.postgresql.ast.stmt.PGValuesQuery; 33 import hunt.sql.parser; 34 import hunt.sql.ast.statement.SQLTableSource; 35 import hunt.sql.dialect.postgresql.parser.PGExprParser; 36 37 38 public class PGSelectParser : SQLSelectParser { 39 40 public this(SQLExprParser exprParser){ 41 super(exprParser); 42 } 43 44 public this(SQLExprParser exprParser, SQLSelectListCache selectListCache){ 45 super(exprParser, selectListCache); 46 } 47 48 public this(string sql){ 49 this(new PGExprParser(sql)); 50 } 51 52 protected SQLExprParser createExprParser() { 53 return new PGExprParser(lexer); 54 } 55 56 override 57 public SQLSelectQuery query() { 58 if (lexer.token() == Token.VALUES) { 59 lexer.nextToken(); 60 accept(Token.LPAREN); 61 PGValuesQuery valuesQuery = new PGValuesQuery(); 62 this.exprParser.exprList(valuesQuery.getValues(), valuesQuery); 63 accept(Token.RPAREN); 64 return queryRest(valuesQuery); 65 } 66 67 if (lexer.token() == Token.LPAREN) { 68 lexer.nextToken(); 69 70 SQLSelectQuery select = query(); 71 if (cast(SQLSelectQueryBlock)(select) !is null) { 72 (cast(SQLSelectQueryBlock) select).setParenthesized(true); 73 } 74 accept(Token.RPAREN); 75 76 return queryRest(select); 77 } 78 79 PGSelectQueryBlock queryBlock = new PGSelectQueryBlock(); 80 81 if (lexer.token() == Token.SELECT) { 82 lexer.nextToken(); 83 84 if (lexer.token() == Token.COMMENT) { 85 lexer.nextToken(); 86 } 87 88 if (lexer.token() == Token.DISTINCT) { 89 queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT); 90 lexer.nextToken(); 91 92 if (lexer.token() == Token.ON) { 93 lexer.nextToken(); 94 95 for (;;) { 96 SQLExpr expr = this.createExprParser().expr(); 97 queryBlock.getDistinctOn().add(expr); 98 if (lexer.token() == Token.COMMA) { 99 lexer.nextToken(); 100 continue; 101 } else { 102 break; 103 } 104 } 105 } 106 } else if (lexer.token() == Token.ALL) { 107 queryBlock.setDistionOption(SQLSetQuantifier.ALL); 108 lexer.nextToken(); 109 } 110 111 parseSelectList(queryBlock); 112 113 if (lexer.token() == Token.INTO) { 114 lexer.nextToken(); 115 116 if (lexer.token() == Token.TEMPORARY) { 117 lexer.nextToken(); 118 queryBlock.setIntoOption(PGSelectQueryBlock.IntoOption.TEMPORARY); 119 } else if (lexer.token() == Token.TEMP) { 120 lexer.nextToken(); 121 queryBlock.setIntoOption(PGSelectQueryBlock.IntoOption.TEMP); 122 } else if (lexer.token() == Token.UNLOGGED) { 123 lexer.nextToken(); 124 queryBlock.setIntoOption(PGSelectQueryBlock.IntoOption.UNLOGGED); 125 } 126 127 if (lexer.token() == Token.TABLE) { 128 lexer.nextToken(); 129 } 130 131 SQLExpr name = this.createExprParser().name(); 132 133 queryBlock.setInto(new SQLExprTableSource(name)); 134 } 135 } 136 137 parseFrom(queryBlock); 138 139 parseWhere(queryBlock); 140 141 parseGroupBy(queryBlock); 142 143 if (lexer.token() == Token.WINDOW) { 144 this.parseWindow(queryBlock); 145 } 146 147 queryBlock.setOrderBy(this.createExprParser().parseOrderBy()); 148 149 for (;;) { 150 if (lexer.token() == Token.LIMIT) { 151 SQLLimit limit = new SQLLimit(); 152 153 lexer.nextToken(); 154 if (lexer.token() == Token.ALL) { 155 limit.setRowCount(new SQLIdentifierExpr("ALL")); 156 lexer.nextToken(); 157 } else { 158 limit.setRowCount(expr()); 159 } 160 161 queryBlock.setLimit(limit); 162 } else if (lexer.token() == Token.OFFSET) { 163 SQLLimit limit = queryBlock.getLimit(); 164 if (limit is null) { 165 limit = new SQLLimit(); 166 queryBlock.setLimit(limit); 167 } 168 lexer.nextToken(); 169 SQLExpr offset = expr(); 170 limit.setOffset(offset); 171 172 if (lexer.token() == Token.ROW || lexer.token() == Token.ROWS) { 173 lexer.nextToken(); 174 } 175 } else { 176 break; 177 } 178 } 179 180 if (lexer.token() == Token.FETCH) { 181 lexer.nextToken(); 182 PGSelectQueryBlock.FetchClause fetch = new PGSelectQueryBlock.FetchClause(); 183 184 if (lexer.token() == Token.FIRST) { 185 fetch.setOption(PGSelectQueryBlock.FetchClause.Option.FIRST); 186 } else if (lexer.token() == Token.NEXT) { 187 fetch.setOption(PGSelectQueryBlock.FetchClause.Option.NEXT); 188 } else { 189 throw new ParserException("expect 'FIRST' or 'NEXT'. " ~ lexer.info()); 190 } 191 192 SQLExpr count = expr(); 193 fetch.setCount(count); 194 195 if (lexer.token() == Token.ROW || lexer.token() == Token.ROWS) { 196 lexer.nextToken(); 197 } else { 198 throw new ParserException("expect 'ROW' or 'ROWS'. " ~ lexer.info()); 199 } 200 201 if (lexer.token() == Token.ONLY) { 202 lexer.nextToken(); 203 } else { 204 throw new ParserException("expect 'ONLY'. " ~ lexer.info()); 205 } 206 207 queryBlock.setFetch(fetch); 208 } 209 210 if (lexer.token() == Token.FOR) { 211 lexer.nextToken(); 212 213 PGSelectQueryBlock.ForClause forClause = new PGSelectQueryBlock.ForClause(); 214 215 if (lexer.token() == Token.UPDATE) { 216 forClause.setOption(PGSelectQueryBlock.ForClause.Option.UPDATE); 217 lexer.nextToken(); 218 } else if (lexer.token() == Token.SHARE) { 219 forClause.setOption(PGSelectQueryBlock.ForClause.Option.SHARE); 220 lexer.nextToken(); 221 } else { 222 throw new ParserException("expect 'FIRST' or 'NEXT'. " ~ lexer.info()); 223 } 224 225 if (lexer.token() == Token.OF) { 226 for (;;) { 227 SQLExpr expr = this.createExprParser().expr(); 228 forClause.getOf().add(expr); 229 if (lexer.token() == Token.COMMA) { 230 lexer.nextToken(); 231 continue; 232 } else { 233 break; 234 } 235 } 236 } 237 238 if (lexer.token() == Token.NOWAIT) { 239 lexer.nextToken(); 240 forClause.setNoWait(true); 241 } 242 243 queryBlock.setForClause(forClause); 244 } 245 246 return queryRest(queryBlock); 247 } 248 249 override protected SQLTableSource parseTableSourceRest(SQLTableSource tableSource) { 250 if (lexer.token() == Token.AS && cast(SQLExprTableSource)(tableSource) !is null) { 251 lexer.nextToken(); 252 253 string _alias = null; 254 if (lexer.token() == Token.IDENTIFIER) { 255 _alias = lexer.stringVal(); 256 lexer.nextToken(); 257 } 258 259 if (lexer.token() == Token.LPAREN) { 260 SQLExprTableSource exprTableSource = cast(SQLExprTableSource) tableSource; 261 262 PGFunctionTableSource functionTableSource = new PGFunctionTableSource(exprTableSource.getExpr()); 263 if (_alias !is null) { 264 functionTableSource.setAlias(_alias); 265 } 266 267 lexer.nextToken(); 268 parserParameters(functionTableSource.getParameters()); 269 accept(Token.RPAREN); 270 271 return super.parseTableSourceRest(functionTableSource); 272 } 273 if (_alias !is null) { 274 tableSource.setAlias(_alias); 275 return super.parseTableSourceRest(tableSource); 276 } 277 } 278 279 return super.parseTableSourceRest(tableSource); 280 } 281 282 private void parserParameters(List!(SQLParameter) parameters) { 283 for (;;) { 284 SQLParameter parameter = new SQLParameter(); 285 286 parameter.setName(this.exprParser.name()); 287 parameter.setDataType(this.exprParser.parseDataType()); 288 289 parameters.add(parameter); 290 if (lexer.token() == Token.COMMA || lexer.token() == Token.SEMI) { 291 lexer.nextToken(); 292 } 293 294 if (lexer.token() != Token.BEGIN && lexer.token() != Token.RPAREN) { 295 continue; 296 } 297 298 break; 299 } 300 } 301 }