content: /*
   * 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.
   */
  package org.apache.calcite.sql;
  
  import org.apache.calcite.sql.fun.SqlStdOperatorTable;
  import org.apache.calcite.sql.util.SqlString;
  
  import org.checkerframework.checker.nullness.qual.Nullable;
  import org.checkerframework.dataflow.qual.Pure;
  
  import java.util.function.Consumer;
  
  /**
   * A <code>SqlWriter</code> is the target to construct a SQL statement from a
   * parse tree. It deals with dialect differences; for example, Oracle quotes
   * identifiers as <code>"scott"</code>, while SQL Server quotes them as <code>
   * [scott]</code>.
   */
  public interface SqlWriter {
    //~ Enums ------------------------------------------------------------------
  
    /**
     * Style of formatting sub-queries.
     */
    enum SubQueryStyle {
      /**
       * Julian's style of sub-query nesting. Like this:
       *
       * <blockquote><pre>SELECT *
       * FROM (
       *     SELECT *
       *     FROM t
       * )
       * WHERE condition</pre></blockquote>
       */
      HYDE,
  
      /**
       * Damian's style of sub-query nesting. Like this:
       *
       * <blockquote><pre>SELECT *
       * FROM
       * (   SELECT *
       *     FROM t
       * )
       * WHERE condition</pre></blockquote>
       */
      BLACK
    }
  
    /**
     * Enumerates the types of frame.
     */
    enum FrameTypeEnum implements FrameType {
      /**
       * SELECT query (or UPDATE or DELETE). The items in the list are the
       * clauses: FROM, WHERE, etc.
       */
      SELECT,
  
      /**
       * Simple list.
       */
      SIMPLE,
  
      /**
       * Comma-separated list surrounded by parentheses.
       * The parentheses are present even if the list is empty.
       */
      PARENTHESES,
  
      /**
       * The SELECT clause of a SELECT statement.
       */
      SELECT_LIST,
  
      /**
       * The WINDOW clause of a SELECT statement.
       */
      WINDOW_DECL_LIST,
  
      /**
       * The SET clause of an UPDATE statement.
       */
      UPDATE_SET_LIST,
  
      /**
       * Function declaration.
       */
      FUN_DECL,
  
      /**
       * Function call or datatype declaration.
       *
       * <p>Examples:
       * <ul>
       * <li><code>SUBSTRING('foobar' FROM 1 + 2 TO 4)</code></li>
       * <li><code>DECIMAL(10, 5)</code></li>
       * </ul>
       */
      FUN_CALL,
  
      /**
       * Window specification.
       *
       * <p>Examples:
       * <ul>
       * <li><code>SUM(x) OVER (ORDER BY hireDate ROWS 3 PRECEDING)</code></li>
       * <li><code>WINDOW w1 AS (ORDER BY hireDate), w2 AS (w1 PARTITION BY gender
       * RANGE BETWEEN INTERVAL '1' YEAR PRECEDING AND '2' MONTH
       * PRECEDING)</code></li>
       * </ul>
       */
      WINDOW,
  
      /**
       * ORDER BY clause of a SELECT statement. The "list" has only two items:
       * the query and the order by clause, with ORDER BY as the separator.
       */
      ORDER_BY,
  
      /**
       * ORDER BY list.
       *
       * <p>Example:
       * <ul>
       * <li><code>ORDER BY x, y DESC, z</code></li>
       * </ul>
       */
      ORDER_BY_LIST,
  
      /**
       * WITH clause of a SELECT statement. The "list" has only two items:
       * the WITH clause and the query, with AS as the separator.
       */
      WITH,
  
      /**
       * The body query of WITH.
       */
      WITH_BODY,
  
      /**
       * OFFSET clause.
       *
       * <p>Example:
       * <ul>
       * <li><code>OFFSET 10 ROWS</code></li>
       * </ul>
       */
      OFFSET,
  
      /**
       * FETCH clause.
       *
       * <p>Example:
       * <ul>
       * <li><code>FETCH FIRST 3 ROWS ONLY</code></li>
       * </ul>
       */
      FETCH,
  
      /**
       * GROUP BY list.
       *
       * <p>Example:
       * <ul>
       * <li><code>GROUP BY x, FLOOR(y)</code></li>
       * </ul>
       */
      GROUP_BY_LIST,
  
      /**
       * Sub-query list. Encloses a SELECT, UNION, EXCEPT, INTERSECT query
       * with optional ORDER BY.
       *
       * <p>Example:
       * <ul>
       * <li><code>GROUP BY x, FLOOR(y)</code></li>
       * </ul>
       */
      SUB_QUERY(true),
  
      /**
       * Set operation.
       *
       * <p>Example:
       * <ul>
       * <li><code>SELECT * FROM a UNION SELECT * FROM b</code></li>
       * </ul>
       */
      SETOP,
  
      /**
       * VALUES clause.
       *
       * <p>Example:
       *
       * <blockquote><pre>VALUES (1, 'a'),
       *   (2, 'b')</pre></blockquote>
       */
      VALUES,
  
      /**
       * FROM clause (containing various kinds of JOIN).
       */
      FROM_LIST,
  
      /**
       * Pair-wise join.
       */
      JOIN(false),
  
      /**
       * WHERE clause.
       */
      WHERE_LIST,
  
      /**
       * Compound identifier.
       *
       * <p>Example:
       * <ul>
       * <li><code>"A"."B"."C"</code></li>
       * </ul>
       */
      IDENTIFIER(false),
  
      /**
       * Alias ("AS"). No indent.
       */
      AS(false),
  
      /**
       * CASE expression.
       */
      CASE,
  
      /**
       * Same behavior as user-defined frame type.
       */
      OTHER;
  
      private final boolean needsIndent;
  
      /**
       * Creates a list type.
       */
      FrameTypeEnum() {
        this(true);
      }
  
      /**
       * Creates a list type.
       */
      FrameTypeEnum(boolean needsIndent) {
        this.needsIndent = needsIndent;
      }
  
      @Override public boolean needsIndent() {
        return needsIndent;
      }
  
      /**
       * Creates a frame type.
       *
       * @param name Name
       * @return frame type
       */
      public static FrameType create(final String name) {
        return new FrameType() {
          @Override public String getName() {
            return name;
          }
  
          @Override public boolean needsIndent() {
            return true;
          }
        };
      }
  
      @Override public String getName() {
        return name();
      }
    }
  
    /** Comma operator.
     *
     * <p>Defined in {@code SqlWriter} because it is only used while converting
     * {@link SqlNode} to SQL;
     * see {@link SqlWriter#list(FrameTypeEnum, SqlBinaryOperator, SqlNodeList)}.
     *
     * <p>The precedence of the comma operator is low but not zero. For
     * instance, this ensures parentheses in
     * {@code select x, (select * from foo order by z), y from t}. */
    SqlBinaryOperator COMMA =
        new SqlBinaryOperator(",", SqlKind.OTHER, 2, false, null, null, null);
  
    //~ Methods ----------------------------------------------------------------
  
    /**
     * Resets this writer so that it can format another expression. Does not
     * affect formatting preferences (see {@link #resetSettings()}
     */
    void reset();
  
    /**
     * Resets all properties to their default values.
     */
    void resetSettings();
  
    /**
     * Returns the dialect of SQL.
     *
     * @return SQL dialect
     */
    SqlDialect getDialect();
  
    /**
     * Returns the contents of this writer as a 'certified kocher' SQL string.
     *
     * @return SQL string
     */
    SqlString toSqlString();
  
    /**
     * Prints a literal, exactly as provided. Does not attempt to indent or
     * convert to upper or lower case. Does not add quotation marks. Adds
     * preceding whitespace if necessary.
     */
    @Pure
    void literal(String s);
  
    /**
     * Prints a sequence of keywords. Must not start or end with space, but may
     * contain a space. For example, <code>keyword("SELECT")</code>, <code>
     * keyword("CHARACTER SET")</code>.
     */
    @Pure
    void keyword(String s);
  
    /**
     * Prints a string, preceded by whitespace if necessary.
     */
    @Pure
    void print(String s);
  
    /**
     * Prints an integer.
     *
     * @param x Integer
     */
    @Pure
    void print(int x);
  
    /**
     * Prints an identifier, quoting as necessary.
     *
     * @param name   The identifier name
     * @param quoted Whether this identifier was quoted in the original sql statement,
     *               this may not be the only factor to decide whether this identifier
     *               should be quoted
     */
    void identifier(String name, boolean quoted);
  
    /**
     * Prints a dynamic parameter (e.g. {@code ?} for default JDBC)
     */
    void dynamicParam(int index);
  
    /**
     * Prints the OFFSET/FETCH clause.
     */
    void fetchOffset(@Nullable SqlNode fetch, @Nullable SqlNode offset);
  
    /**
     * Prints the TOP(n) clause.
     *
     * @see #fetchOffset
     */
    void topN(@Nullable SqlNode fetch, @Nullable SqlNode offset);
  
    /**
     * Prints a new line, and indents.
     */
    void newlineAndIndent();
  
    /**
     * Returns whether this writer should quote all identifiers, even those
     * that do not contain mixed-case identifiers or punctuation.
     *
     * @return whether to quote all identifiers
     */
    boolean isQuoteAllIdentifiers();
  
    /**
     * Returns whether this writer should start each clause (e.g. GROUP BY) on
     * a new line.
     *
     * @return whether to start each clause on a new line
     */
    boolean isClauseStartsLine();
  
    /**
     * Returns whether the items in the SELECT clause should each be on a
     * separate line.
     *
     * @return whether to put each SELECT clause item on a new line
     */
    boolean isSelectListItemsOnSeparateLines();
  
    /**
     * Returns whether to output all keywords (e.g. SELECT, GROUP BY) in lower
     * case.
     *
     * @return whether to output SQL keywords in lower case
     */
    boolean isKeywordsLowerCase();
  
    /**
     * Starts a list which is a call to a function.
     *
     * @see #endFunCall(Frame)
     */
    @Pure
    Frame startFunCall(String funName);
  
    /**
     * Ends a list which is a call to a function.
     *
     * @param frame Frame
     * @see #startFunCall(String)
     */
    @Pure
    void endFunCall(Frame frame);
  
    /**
     * Starts a list.
     */
    @Pure
    Frame startList(String open, String close);
  
    /**
     * Starts a list with no opening string.
     *
     * @param frameType Type of list. For example, a SELECT list will be
     * governed according to SELECT-list formatting preferences.
     */
    @Pure
    Frame startList(FrameTypeEnum frameType);
  
    /**
     * Starts a list.
     *
     * @param frameType Type of list. For example, a SELECT list will be
     *                  governed according to SELECT-list formatting preferences.
     * @param open      String to start the list; typically "(" or the empty
     *                  string.
     * @param close     String to close the list
     */
    @Pure
    Frame startList(FrameType frameType, String open, String close);
  
    /**
     * Ends a list.
     *
     * @param frame The frame which was created by {@link #startList}.
     */
    @Pure
    void endList(@Nullable Frame frame);
  
    /**
     * Writes a list.
     */
    @Pure
    SqlWriter list(FrameTypeEnum frameType, Consumer<SqlWriter> action);
  
    /**
     * Writes a list separated by a binary operator
     * ({@link SqlStdOperatorTable#AND AND},
     * {@link SqlStdOperatorTable#OR OR}, or
     * {@link #COMMA COMMA}).
     */
    @Pure
    SqlWriter list(FrameTypeEnum frameType, SqlBinaryOperator sepOp,
        SqlNodeList list);
  
    /**
     * Writes a list separator, unless the separator is "," and this is the
     * first occurrence in the list.
     *
     * @param sep List separator, typically ",".
     */
    @Pure
    void sep(String sep);
  
    /**
     * Writes a list separator.
     *
     * @param sep        List separator, typically ","
     * @param printFirst Whether to print the first occurrence of the separator
     */
    @Pure
    void sep(String sep, boolean printFirst);
  
    /**
     * Sets whether whitespace is needed before the next token.
     */
    @Pure
    void setNeedWhitespace(boolean needWhitespace);
  
    /**
     * Returns the offset for each level of indentation. Default 4.
     */
    int getIndentation();
  
    /**
     * Returns whether to enclose all expressions in parentheses, even if the
     * operator has high enough precedence that the parentheses are not
     * required.
     *
     * <p>For example, the parentheses are required in the expression <code>(a +
     * b) * c</code> because the '*' operator has higher precedence than the '+'
     * operator, and so without the parentheses, the expression would be
     * equivalent to <code>a + (b * c)</code>. The fully-parenthesized
     * expression, <code>((a + b) * c)</code> is unambiguous even if you don't
     * know the precedence of every operator.
     */
    boolean isAlwaysUseParentheses();
  
    /**
     * Returns whether we are currently in a query context (SELECT, INSERT,
     * UNION, INTERSECT, EXCEPT, and the ORDER BY operator).
     */
    boolean inQuery();
  
    //~ Inner Interfaces -------------------------------------------------------
  
    /**
     * A Frame is a piece of generated text which shares a common indentation
     * level.
     *
     * <p>Every frame has a beginning, a series of clauses and separators, and
     * an end. A typical frame is a comma-separated list. It begins with a "(",
     * consists of expressions separated by ",", and ends with a ")".
     *
     * <p>A select statement is also a kind of frame. The beginning and end are
     * empty strings, but it consists of a sequence of clauses. "SELECT",
     * "FROM", "WHERE" are separators.
     *
     * <p>A frame is current between a call to one of the
     * {@link SqlWriter#startList} methods and the call to
     * {@link SqlWriter#endList(Frame)}. If other code starts a frame in the meantime,
     * the sub-frame is put onto a stack.
     */
    interface Frame {
    }
  
    /** Frame type. */
    interface FrameType {
      /**
       * Returns the name of this frame type.
       *
       * @return name
       */
      String getName();
  
      /**
       * Returns whether this frame type should cause the code be further
       * indented.
       *
       * @return whether to further indent code within a frame of this type
       */
      boolean needsIndent();
    }
  }
  