View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shardingsphere.sqlfederation.optimizer.converter.segment.expression.impl;
19  
20  import lombok.AccessLevel;
21  import lombok.NoArgsConstructor;
22  import org.apache.calcite.sql.SqlBasicCall;
23  import org.apache.calcite.sql.SqlFunctionCategory;
24  import org.apache.calcite.sql.SqlIdentifier;
25  import org.apache.calcite.sql.SqlNode;
26  import org.apache.calcite.sql.SqlNodeList;
27  import org.apache.calcite.sql.SqlOperator;
28  import org.apache.calcite.sql.SqlSyntax;
29  import org.apache.calcite.sql.SqlUnresolvedFunction;
30  import org.apache.calcite.sql.fun.SqlStdOperatorTable;
31  import org.apache.calcite.sql.parser.SqlParserPos;
32  import org.apache.calcite.sql.validate.SqlNameMatchers;
33  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
34  import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.FunctionSegment;
35  import org.apache.shardingsphere.sqlfederation.optimizer.converter.segment.expression.ExpressionConverter;
36  
37  import java.util.Collection;
38  import java.util.Collections;
39  import java.util.LinkedList;
40  import java.util.List;
41  import java.util.Optional;
42  
43  /**
44   * Function converter.
45   */
46  @NoArgsConstructor(access = AccessLevel.PRIVATE)
47  public final class FunctionConverter {
48      
49      /**
50       * Convert function segment to sql node.
51       * 
52       * @param segment function segment
53       * @return sql node
54       */
55      public static Optional<SqlNode> convert(final FunctionSegment segment) {
56          SqlIdentifier functionName = new SqlIdentifier(segment.getFunctionName(), SqlParserPos.ZERO);
57          // TODO optimize sql parse logic for select current_user.
58          if ("CURRENT_USER".equalsIgnoreCase(functionName.getSimple())) {
59              return Optional.of(functionName);
60          }
61          if ("TRIM".equalsIgnoreCase(functionName.getSimple())) {
62              return TrimFunctionConverter.convert(segment);
63          }
64          if ("OVER".equalsIgnoreCase(functionName.getSimple())) {
65              return WindowFunctionConverter.convert(segment);
66          }
67          List<SqlOperator> functions = new LinkedList<>();
68          SqlStdOperatorTable.instance().lookupOperatorOverloads(functionName, null, SqlSyntax.FUNCTION, functions, SqlNameMatchers.withCaseSensitive(false));
69          return Optional.of(functions.isEmpty()
70                  ? new SqlBasicCall(
71                          new SqlUnresolvedFunction(functionName, null, null, null, null, SqlFunctionCategory.USER_DEFINED_FUNCTION), getFunctionParameters(segment.getParameters()), SqlParserPos.ZERO)
72                  : new SqlBasicCall(functions.iterator().next(), getFunctionParameters(segment.getParameters()), SqlParserPos.ZERO));
73      }
74      
75      private static List<SqlNode> getFunctionParameters(final Collection<ExpressionSegment> sqlSegments) {
76          List<SqlNode> result = new LinkedList<>();
77          for (ExpressionSegment each : sqlSegments) {
78              ExpressionConverter.convert(each).ifPresent(optional -> result.addAll(optional instanceof SqlNodeList ? ((SqlNodeList) optional).getList() : Collections.singleton(optional)));
79          }
80          return result;
81      }
82  }