| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| // Taken from syntax of SqlInsert statement from calcite parser, edited for replace syntax |
| SqlNode DruidSqlReplaceEof() : |
| { |
| final SqlIdentifier destination; |
| SqlNode source; |
| SqlNodeList columnList = null; |
| final Span s; |
| SqlNode tableRef = null; |
| SqlInsert sqlInsert; |
| SqlGranularityLiteral partitionedBy = null; |
| SqlNodeList clusteredBy = null; |
| final Pair<SqlNodeList, SqlNodeList> p; |
| SqlNode replaceTimeQuery = null; |
| SqlIdentifier exportFileFormat = null; |
| } |
| { |
| <REPLACE> { s = span(); } |
| <INTO> |
| ( |
| LOOKAHEAD(2) |
| <EXTERN> <LPAREN> destination = ExternalDestination() <RPAREN> |
| | |
| destination = CompoundTableIdentifier() |
| ( tableRef = TableHints(destination) | { tableRef = destination; } ) |
| [ LOOKAHEAD(5) tableRef = ExtendTable(tableRef) ] |
| ) |
| ( |
| LOOKAHEAD(2) |
| p = ParenthesizedCompoundIdentifierList() { |
| if (p.right.size() > 0) { |
| tableRef = extend(tableRef, p.right); |
| } |
| if (p.left.size() > 0) { |
| columnList = p.left; |
| } else { |
| columnList = null; |
| } |
| } |
| | { columnList = null; } |
| ) |
| [ |
| <AS> exportFileFormat = FileFormat() |
| ] |
| [ |
| <OVERWRITE> |
| [ |
| replaceTimeQuery = ReplaceTimeQuery() |
| ] |
| ] |
| source = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) |
| // PARTITIONED BY is necessary, but is kept optional in the grammar. It is asserted that it is not missing in the |
| // IngestHandler#validate() so that we can return a custom error message. |
| [ |
| <PARTITIONED> <BY> |
| partitionedBy = PartitionGranularity() |
| ] |
| [ |
| clusteredBy = ClusteredBy() |
| ] |
| { |
| |
| } |
| // EOF is also present in SqlStmtEof but EOF is a special case and a single EOF can be consumed multiple times. |
| // The reason for adding EOF here is to ensure that we create a DruidSqlReplace node after the syntax has been |
| // validated and throw SQL syntax errors before performing validations in the DruidSqlReplace which can overshadow the |
| // actual error message. |
| <EOF> |
| { |
| sqlInsert = new SqlInsert(s.end(source), SqlNodeList.EMPTY, destination, source, columnList); |
| return DruidSqlReplace.create(sqlInsert, partitionedBy, clusteredBy, exportFileFormat, replaceTimeQuery); |
| } |
| } |
| |
| SqlNode ReplaceTimeQuery() : |
| { |
| SqlNode replaceQuery; |
| } |
| { |
| ( |
| <ALL> { replaceQuery = SqlLiteral.createCharString("ALL", getPos()); } |
| | |
| // We parse all types of conditions and throw an exception if it is not supported to keep the parsing simple |
| replaceQuery = Where() |
| ) |
| { |
| return replaceQuery; |
| } |
| } |