package com.chenyang.druid.sql.dialect.kingbase.visitor;

import com.chenyang.druid.DbType;
import com.chenyang.druid.sql.ast.SQLCommentHint;
import com.chenyang.druid.sql.ast.SQLDataType;
import com.chenyang.druid.sql.ast.SQLDataTypeImpl;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLHint;
import com.chenyang.druid.sql.ast.SQLLimit;
import com.chenyang.druid.sql.ast.SQLName;
import com.chenyang.druid.sql.ast.SQLObject;
import com.chenyang.druid.sql.ast.SQLOrderBy;
import com.chenyang.druid.sql.ast.SQLOver;
import com.chenyang.druid.sql.ast.SQLParameter;
import com.chenyang.druid.sql.ast.SQLStatement;
import com.chenyang.druid.sql.ast.SQLWindow;
import com.chenyang.druid.sql.ast.expr.SQLAggregateExpr;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.chenyang.druid.sql.ast.expr.SQLBooleanExpr;
import com.chenyang.druid.sql.ast.expr.SQLCharExpr;
import com.chenyang.druid.sql.ast.expr.SQLDateExpr;
import com.chenyang.druid.sql.ast.expr.SQLIdentifierExpr;
import com.chenyang.druid.sql.ast.expr.SQLIntegerExpr;
import com.chenyang.druid.sql.ast.expr.SQLListExpr;
import com.chenyang.druid.sql.ast.expr.SQLLiteralExpr;
import com.chenyang.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.chenyang.druid.sql.ast.expr.SQLNCharExpr;
import com.chenyang.druid.sql.ast.expr.SQLNullExpr;
import com.chenyang.druid.sql.ast.expr.SQLNumberExpr;
import com.chenyang.druid.sql.ast.expr.SQLPropertyExpr;
import com.chenyang.druid.sql.ast.expr.SQLTimeExpr;
import com.chenyang.druid.sql.ast.expr.SQLTimestampExpr;
import com.chenyang.druid.sql.ast.expr.SQLVariantRefExpr;
import com.chenyang.druid.sql.ast.statement.SQLAssignItem;
import com.chenyang.druid.sql.ast.statement.SQLBlockStatement;
import com.chenyang.druid.sql.ast.statement.SQLCharacterDataType;
import com.chenyang.druid.sql.ast.statement.SQLCommentStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateProcedureStatement;
import com.chenyang.druid.sql.ast.statement.SQLExprTableSource;
import com.chenyang.druid.sql.ast.statement.SQLInsertStatement;
import com.chenyang.druid.sql.ast.statement.SQLSelect;
import com.chenyang.druid.sql.ast.statement.SQLSelectGroupByClause;
import com.chenyang.druid.sql.ast.statement.SQLSelectItem;
import com.chenyang.druid.sql.ast.statement.SQLSelectQuery;
import com.chenyang.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.chenyang.druid.sql.ast.statement.SQLSetStatement;
import com.chenyang.druid.sql.ast.statement.SQLTableSampling;
import com.chenyang.druid.sql.ast.statement.SQLTableSource;
import com.chenyang.druid.sql.ast.statement.SQLUnionQuery;
import com.chenyang.druid.sql.ast.statement.SQLUpdateSetItem;
import com.chenyang.druid.sql.ast.statement.SQLValuesTableSource;
import com.chenyang.druid.sql.ast.statement.SQLWithSubqueryClause;
import com.chenyang.druid.sql.dialect.kingbase.ast.KingbaseValuesTableSource;
import com.chenyang.druid.sql.dialect.kingbase.ast.ValueClause;
import com.chenyang.druid.sql.dialect.kingbase.ast.clause.KingbaseSQLOver;
import com.chenyang.druid.sql.dialect.kingbase.ast.clause.KingbaseWithSubqueryEntry;
import com.chenyang.druid.sql.dialect.kingbase.ast.expression.KingbaseArgumentExpr;
import com.chenyang.druid.sql.dialect.kingbase.ast.expression.KingbaseCaseStatement;
import com.chenyang.druid.sql.dialect.kingbase.ast.expression.KingbaseCharExpr;
import com.chenyang.druid.sql.dialect.kingbase.ast.expression.KingbaseConstantExpr;
import com.chenyang.druid.sql.dialect.kingbase.ast.expression.KingbaseDateTimeExpr;
import com.chenyang.druid.sql.dialect.kingbase.ast.expression.KingbaseExprTableSource;
import com.chenyang.druid.sql.dialect.kingbase.ast.expression.KingbaseForUpdateExpr;
import com.chenyang.druid.sql.dialect.kingbase.ast.expression.KingbaseTypeCastExpr;
import com.chenyang.druid.sql.dialect.kingbase.ast.expression.KingbaseUpdateTableSource;
import com.chenyang.druid.sql.dialect.kingbase.ast.statement.KingbaseDeleteStatement;
import com.chenyang.druid.sql.dialect.kingbase.ast.statement.KingbaseInsertStatement;
import com.chenyang.druid.sql.dialect.kingbase.ast.statement.KingbaseMultiInsertStatement;
import com.chenyang.druid.sql.dialect.kingbase.ast.statement.KingbaseSelectQueryBlock;
import com.chenyang.druid.sql.dialect.kingbase.ast.statement.KingbaseUpdateStatement;
import com.chenyang.druid.sql.visitor.ExportParameterVisitorUtils;
import com.chenyang.druid.sql.visitor.SQLASTOutputVisitor;
import com.chenyang.druid.sql.visitor.VisitorFeature;
import com.chenyang.druid.util.FnvHash;
import java.io.IOException;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class KingbaseOutputVisitor extends SQLASTOutputVisitor implements KingbaseASTVisitor {
   private static boolean shardingSupportChecked = false;

   public KingbaseOutputVisitor(Appendable appender) {
      super(appender);
      this.dbType = DbType.kingbase;
      this.shardingSupport = true;
      this.quote = '"';
   }

   public KingbaseOutputVisitor(Appendable appender, boolean parameterized) {
      super(appender, parameterized);
      this.dbType = DbType.kingbase;
      this.shardingSupport = true;
      this.quote = '"';

      try {
         this.configFromProperty();
      } catch (AccessControlException var4) {
      }

   }

   public void configFromProperty() {
      if (this.parameterized && !shardingSupportChecked) {
         shardingSupportChecked = true;
         String property = System.getProperties().getProperty("fastsql.parameterized.shardingSupport");
         if ("true".equals(property)) {
            this.setShardingSupport(true);
         } else if ("false".equals(property)) {
            this.setShardingSupport(false);
         }
      }

   }

   public boolean isShardingSupport() {
      return this.parameterized && this.shardingSupport;
   }

   public void setShardingSupport(boolean shardingSupport) {
      this.shardingSupport = shardingSupport;
   }

   public boolean visit(SQLSelectQueryBlock select) {
      return select instanceof KingbaseSelectQueryBlock ? this.visit((KingbaseSelectQueryBlock)select) : super.visit(select);
   }

   public boolean visit(KingbaseSelectQueryBlock x) {
      boolean bracket = x.isBracket();
      if (bracket) {
         this.print('(');
      }

      if (!this.isParameterized() && this.isPrettyFormat() && x.hasBeforeComment()) {
         this.printlnComments(x.getBeforeCommentsDirect());
      }

      String cachedSelectList = x.getCachedSelectList();
      if (cachedSelectList != null) {
         if (!this.isEnabled(VisitorFeature.OutputSkipSelectListCacheString)) {
            this.print0(cachedSelectList);
         }
      } else {
         this.print0(this.ucase ? "SELECT " : "select ");
         int i = 0;

         for(int size = x.getHintsSize(); i < size; ++i) {
            SQLCommentHint hint = (SQLCommentHint)x.getHints().get(i);
            hint.accept(this);
            this.print(' ');
         }

         switch (x.getDistionOption()) {
            case 1:
               this.print0(this.ucase ? "ALL " : "all ");
               break;
            case 2:
               this.print0(this.ucase ? "DISTINCT " : "distinct ");
               break;
            case 3:
               this.print0(this.ucase ? "UNIQUE " : "unique ");
               break;
            case 4:
               this.print0(this.ucase ? "DISTINCTROW " : "distinctrow ");
         }

         if (x.isHignPriority()) {
            this.print0(this.ucase ? "HIGH_PRIORITY " : "high_priority ");
         }

         if (x.isStraightJoin()) {
            this.print0(this.ucase ? "STRAIGHT_JOIN " : "straight_join ");
         }

         if (x.isSmallResult()) {
            this.print0(this.ucase ? "SQL_SMALL_RESULT " : "sql_small_result ");
         }

         if (x.isBigResult()) {
            this.print0(this.ucase ? "SQL_BIG_RESULT " : "sql_big_result ");
         }

         if (x.isBufferResult()) {
            this.print0(this.ucase ? "SQL_BUFFER_RESULT " : "sql_buffer_result ");
         }

         if (x.getCache() != null) {
            if (x.getCache()) {
               this.print0(this.ucase ? "SQL_CACHE " : "sql_cache ");
            } else {
               this.print0(this.ucase ? "SQL_NO_CACHE " : "sql_no_cache ");
            }
         }

         if (x.isCalcFoundRows()) {
            this.print0(this.ucase ? "SQL_CALC_FOUND_ROWS " : "sql_calc_found_rows ");
         }

         this.printSelectList(x.getSelectList());
         SQLName forcePartition = x.getForcePartition();
         if (forcePartition != null) {
            this.println();
            this.print0(this.ucase ? "FORCE PARTITION " : "force partition ");
            this.printExpr(forcePartition, this.parameterized);
         }

         SQLExprTableSource into = x.getInto();
         if (into != null) {
            this.println();
            this.print0(this.ucase ? "INTO " : "into ");
            if (x.getIntoOption() != null) {
               this.print0(this.ucase ? x.getIntoOption().name().toUpperCase(Locale.ROOT) : x.getIntoOption().name().toLowerCase(Locale.ROOT));
               this.print(' ');
            }

            this.printTableSource(into);
         }
      }

      SQLTableSource from = x.getFrom();
      if (from != null) {
         this.println();
         this.print0(this.ucase ? "FROM " : "from ");
         this.printTableSource(from);
      }

      SQLExpr where = x.getWhere();
      if (where != null) {
         this.println();
         this.print0(this.ucase ? "WHERE " : "where ");
         this.printExpr(where, this.parameterized);
      }

      this.printHierarchical(x);
      SQLSelectGroupByClause groupBy = x.getGroupBy();
      if (groupBy != null) {
         this.println();
         this.visit((SQLSelectGroupByClause)groupBy);
      }

      List<SQLWindow> windows = x.getWindows();
      if (windows != null && windows.size() > 0) {
         this.println();
         this.print0(this.ucase ? "WINDOW " : "window ");
         this.printAndAccept(windows, ", ");
      }

      SQLOrderBy orderBy = x.getOrderBy();
      if (orderBy != null) {
         this.println();
         this.visit((SQLOrderBy)orderBy);
      }

      SQLLimit limit = x.getLimit();
      if (limit != null) {
         this.println();
         this.printFetchFirst(x);
      }

      SQLName procedureName = x.getProcedureName();
      if (procedureName != null) {
         this.print0(this.ucase ? " PROCEDURE " : " procedure ");
         procedureName.accept(this);
         if (!x.getProcedureArgumentList().isEmpty()) {
            this.print('(');
            this.printAndAccept(x.getProcedureArgumentList(), ", ");
            this.print(')');
         }
      }

      if (x.getForUpdate() != null) {
         x.getForUpdate().accept(this);
      }

      if (x.isLockInShareMode()) {
         this.println();
         this.print0(this.ucase ? "LOCK IN SHARE MODE" : "lock in share mode");
      }

      if (bracket) {
         this.print(')');
      }

      return false;
   }

   public void endVisit(KingbaseSelectQueryBlock x) {
   }

   public boolean visit(KingbaseArgumentExpr x) {
      return true;
   }

   public void endVisit(KingbaseArgumentExpr x) {
   }

   protected void printFetchFirst(KingbaseSelectQueryBlock x) {
      SQLLimit limit = x.getLimit();
      if (limit != null) {
         if (limit.getType() != null && limit.getType() != SQLLimit.Type.FETCH) {
            this.println();
            this.print("LIMIT ");
            if (limit.getOffset() == null) {
               limit.getRowCount().accept(this);
            } else {
               limit.getRowCount().accept(this);
               SQLExpr expr = limit.getOffset();
               if (!expr.toString().equalsIgnoreCase("all")) {
                  this.print(" OFFSET ");
                  limit.getOffset().accept(this);
               }
            }

         } else {
            SQLExpr offset = limit.getOffset();
            SQLExpr first = limit.getRowCount();
            SQLObject parent = x.getParent();
            if (parent instanceof SQLSelect) {
               SQLOrderBy orderBy = ((SQLSelect)parent).getOrderBy();
               if (orderBy != null && orderBy.getItems().size() > 0) {
                  this.println();
                  this.print0(this.ucase ? "ORDER BY " : "order by ");
                  this.printAndAccept(orderBy.getItems(), ", ");
               }
            }

            this.println();
            if (offset != null) {
               this.print0(this.ucase ? "OFFSET " : "offset ");
               offset.accept(this);
               this.print0(this.ucase ? " ROWS" : " rows");
            }

            if (first != null) {
               if (offset != null) {
                  this.print(' ');
               }

               if (DbType.sqlserver == this.dbType && offset != null) {
                  this.print0(this.ucase ? "FETCH NEXT " : "fetch next ");
               } else {
                  this.print0(this.ucase ? "FETCH FIRST " : "fetch first ");
               }

               first.accept(this);
               if (limit.isPercent()) {
                  this.print0(this.ucase ? " PERCENT ROWS ONLY" : " percent rows only");
               } else {
                  this.print0(this.ucase ? " ROWS ONLY" : " rows only");
               }
            }

         }
      }
   }

   public boolean visit(SQLDataType x) {
      this.printDataType(x);
      if (x instanceof SQLDataTypeImpl) {
         SQLDataTypeImpl dataTypeImpl = (SQLDataTypeImpl)x;
         if (dataTypeImpl.isUnsigned()) {
            this.print0(this.ucase ? " UNSIGNED" : " unsigned");
         }

         if (dataTypeImpl.isZerofill()) {
            this.print0(this.ucase ? " ZEROFILL" : " zerofill");
         }

         SQLExpr indexBy = ((SQLDataTypeImpl)x).getIndexBy();
         if (indexBy != null) {
            this.print0(this.ucase ? " INDEX BY " : " index by ");
            indexBy.accept(this);
         }
      }

      if (x instanceof SQLCharacterDataType) {
         SQLCharacterDataType charType = (SQLCharacterDataType)x;
         if (charType.getCharSetName() != null) {
            this.print0(this.ucase ? " CHARACTER SET " : " character set ");
            this.print0(charType.getCharSetName());
            if (charType.getCollate() != null) {
               this.print0(this.ucase ? " COLLATE " : " collate ");
               this.print0(charType.getCollate());
            }
         }

         List<SQLCommentHint> hints = ((SQLCharacterDataType)x).hints;
         if (hints != null) {
            this.print(' ');

            for(SQLCommentHint hint : hints) {
               hint.accept(this);
            }
         }
      }

      return false;
   }

   public boolean visit(SQLCharacterDataType x) {
      this.printDataType(x);
      if (x.isHasBinary()) {
         this.print0(this.ucase ? " BINARY " : " binary ");
      }

      if (x.getCharSetName() != null) {
         this.print0(this.ucase ? " CHARACTER SET " : " character set ");
         this.print0(x.getCharSetName());
         if (x.getCollate() != null) {
            this.print0(this.ucase ? " COLLATE " : " collate ");
            this.print0(x.getCollate());
         }
      } else if (x.getCollate() != null) {
         this.print0(this.ucase ? " COLLATE " : " collate ");
         this.print0(x.getCollate());
      }

      List<SQLCommentHint> hints = x.hints;
      if (hints != null) {
         this.print(' ');

         for(SQLCommentHint hint : hints) {
            hint.accept(this);
         }
      }

      return false;
   }

   public boolean visit(SQLCharExpr x, boolean parameterized) {
      if (this.appender == null) {
         return false;
      } else {
         try {
            if (parameterized) {
               this.appender.append('?');
               this.incrementReplaceCunt();
               if (this.parameters != null) {
                  ExportParameterVisitorUtils.exportParameter(this.parameters, (SQLExpr)x);
               }

               return false;
            } else {
               this.appender.append('\'');
               String text = x.getText();
               boolean hasSpecial = false;

               for(int i = 0; i < text.length(); ++i) {
                  char ch = text.charAt(i);
                  if (ch == '\'' || ch == '\\' || ch == 0) {
                     hasSpecial = true;
                     break;
                  }
               }

               if (hasSpecial) {
                  boolean regForPresto = false;
                  if (this.isEnabled(VisitorFeature.OutputRegForPresto) && x.getParent() instanceof SQLMethodInvokeExpr) {
                     SQLMethodInvokeExpr regCall = (SQLMethodInvokeExpr)x.getParent();
                     long nameHash = regCall.methodNameHashCode64();
                     regForPresto = x == regCall.getArguments().get(1) && (nameHash == FnvHash.Constants.REGEXP_SUBSTR || nameHash == FnvHash.Constants.REGEXP_COUNT || nameHash == FnvHash.Constants.REGEXP_EXTRACT || nameHash == FnvHash.Constants.REGEXP_EXTRACT_ALL || nameHash == FnvHash.Constants.REGEXP_LIKE || nameHash == FnvHash.Constants.REGEXP_REPLACE || nameHash == FnvHash.Constants.REGEXP_SPLIT);
                  }

                  for(int i = 0; i < text.length(); ++i) {
                     char ch = text.charAt(i);
                     if (ch == '\'') {
                        this.appender.append('\'');
                        this.appender.append('\'');
                     } else if (ch == '\\') {
                        this.appender.append('\\');
                        if (!regForPresto && (i >= text.length() - 1 || text.charAt(i + 1) != '_')) {
                           this.appender.append('\\');
                        }
                     } else if (ch == 0) {
                        this.appender.append('\\');
                        this.appender.append('0');
                     } else {
                        this.appender.append(ch);
                     }
                  }
               } else {
                  this.appender.append(text);
               }

               this.appender.append('\'');
               return false;
            }
         } catch (IOException e) {
            throw new RuntimeException("println error", e);
         }
      }
   }

   public boolean visit(SQLVariantRefExpr x) {
      int index = x.getIndex();
      if (this.inputParameters != null && index < this.inputParameters.size()) {
         return super.visit(x);
      } else {
         if (x.isGlobal()) {
            this.print0("@@global.");
         } else if (x.isSession()) {
            this.print0("@@session.");
         }

         String varName = x.getName();

         for(int i = 0; i < varName.length(); ++i) {
            char ch = varName.charAt(i);
            if (ch == '\'') {
               if (varName.startsWith("@@") && i == 2) {
                  this.print(ch);
               } else if (varName.startsWith("@") && i == 1) {
                  this.print(ch);
               } else if (i != 0 && i != varName.length() - 1) {
                  this.print0("\\'");
               } else {
                  this.print(ch);
               }
            } else {
               this.print(ch);
            }
         }

         String collate = (String)x.getAttribute("COLLATE");
         if (collate != null) {
            this.print0(this.ucase ? " COLLATE " : " collate ");
            this.print0(collate);
         }

         return false;
      }
   }

   public boolean visit(KingbaseDeleteStatement x) {
      List<SQLCommentHint> headHints = x.getHeadHintsDirect();
      if (headHints != null) {
         for(SQLCommentHint hint : headHints) {
            hint.accept(this);
            this.println();
         }
      }

      if (this.isPrettyFormat() && x.hasBeforeComment()) {
         this.printlnComments(x.getBeforeCommentsDirect());
      }

      if (x.getWith() != null) {
         x.getWith().accept(this);
         this.println();
      }

      this.print0(this.ucase ? "DELETE " : "delete ");
      int i = 0;

      for(int size = x.getHintsSize(); i < size; ++i) {
         SQLCommentHint hint = (SQLCommentHint)x.getHints().get(i);
         hint.accept(this);
         this.print(' ');
      }

      if (x.isLowPriority()) {
         this.print0(this.ucase ? "LOW_PRIORITY " : "low_priority ");
      }

      if (x.isQuick()) {
         this.print0(this.ucase ? "QUICK " : "quick ");
      }

      if (x.isIgnore()) {
         this.print0(this.ucase ? "IGNORE " : "ignore ");
      }

      if (x.isForceAllPartitions()) {
         this.print0(this.ucase ? "FORCE ALL PARTITIONS " : "force all partitions ");
      } else {
         SQLName partition = x.getForcePartition();
         if (partition != null) {
            this.print0(this.ucase ? "FORCE PARTITION " : "force partition ");
            this.printExpr(partition, this.parameterized);
            this.print(' ');
         }
      }

      SQLTableSource from = x.getFrom();
      if (from == null) {
         this.print0(this.ucase ? "FROM " : "from ");
         if (x.isFulltextDictionary()) {
            this.print0(this.ucase ? "FULLTEXT DICTIONARY " : "fulltext dictionary ");
         }

         if (x.isOnly()) {
            this.print0(this.ucase ? "ONLY " : "only ");
         }

         x.getTableSource().accept(this);
         if (x.isInherit()) {
            this.print(' ');
            this.print0("*");
            this.print(' ');
         }
      } else {
         x.getTableSource().accept(this);
         this.println();
         if (x.isOnly()) {
            this.print0(this.ucase ? "ONLY " : "only ");
         }

         this.print0(this.ucase ? "FROM " : "from ");
         from.accept(this);
         if (x.isInherit()) {
            this.print0("*");
         }
      }

      SQLTableSource using = x.getUsing();
      if (using != null) {
         this.println();
         this.print0(this.ucase ? "USING " : "using ");
         using.accept(this);
      }

      SQLExpr where = x.getWhere();
      if (where != null) {
         this.println();
         ++this.indentCount;
         this.print0(this.ucase ? "WHERE " : "where ");
         this.printExpr(where, this.parameterized);
         --this.indentCount;
      }

      if (x.getOrderBy() != null) {
         this.println();
         x.getOrderBy().accept(this);
      }

      if (x.getLimit() != null) {
         this.println();
         x.getLimit().accept(this);
      }

      this.printReturning(x.getReturnList());
      return false;
   }

   public void endVisit(KingbaseDeleteStatement x) {
   }

   public boolean visit(KingbaseInsertStatement x) {
      List<SQLCommentHint> headHints = x.getHeadHintsDirect();
      if (headHints != null) {
         for(SQLCommentHint hint : headHints) {
            hint.accept(this);
            this.println();
         }
      }

      if (this.isPrettyFormat() && x.hasBeforeComment()) {
         this.printlnComments(x.getBeforeCommentsDirect());
      }

      SQLWithSubqueryClause with = x.getWith();
      if (with != null) {
         this.visit((SQLWithSubqueryClause)with);
         this.println();
      }

      this.print0(this.ucase ? "INSERT " : "insert ");
      int i = 0;

      for(int size = x.getHintsSize(); i < size; ++i) {
         SQLCommentHint hint = (SQLCommentHint)x.getHints().get(i);
         hint.accept(this);
         this.print(' ');
      }

      if (x.isLowPriority()) {
         this.print0(this.ucase ? "LOW_PRIORITY " : "low_priority ");
      }

      if (x.isDelayed()) {
         this.print0(this.ucase ? "DELAYED " : "delayed ");
      }

      if (x.isHighPriority()) {
         this.print0(this.ucase ? "HIGH_PRIORITY " : "high_priority ");
      }

      if (x.isIgnore()) {
         this.print0(this.ucase ? "IGNORE " : "ignore ");
      }

      if (x.isRollbackOnFail()) {
         this.print0(this.ucase ? "ROLLBACK_ON_FAIL " : "rollback_on_fail ");
      }

      i = 1;
      if (x.isOverwrite()) {
         this.print0(this.ucase ? "OVERWRITE " : "overwrite ");
      }

      if (true) {
         this.print0(this.ucase ? "INTO " : "into ");
      }

      if (x.isFulltextDictionary()) {
         this.print0(this.ucase ? "FULLTEXT DICTIONARY " : "fulltext dictionary ");
      }

      SQLExprTableSource tableSource = x.getTableSource();
      if (tableSource != null) {
         if (tableSource.getClass() == SQLExprTableSource.class) {
            this.visit(tableSource);
         } else {
            tableSource.accept(this);
         }
      }

      List<SQLAssignItem> partitions = x.getPartitions();
      if (partitions != null) {
         int partitionsSize = partitions.size();
         if (partitionsSize > 0) {
            this.print0(this.ucase ? " PARTITION (" : " partition (");

            for(int i2 = 0; i2 < partitionsSize; ++i2) {
               if (i2 != 0) {
                  this.print0(", ");
               }

               SQLAssignItem assign = (SQLAssignItem)partitions.get(i2);
               assign.getTarget().accept(this);
               if (assign.getValue() != null) {
                  this.print('=');
                  assign.getValue().accept(this);
               }
            }

            this.print(')');
         }

         if (x.isIfNotExists()) {
            this.print0(this.ucase ? " IF NOT EXISTS " : "if not exists ");
         }
      }

      String columnsString = x.getColumnsString();
      if (columnsString != null) {
         if (!this.isEnabled(VisitorFeature.OutputSkipInsertColumnsString)) {
            this.print0(columnsString);
         }
      } else {
         List<SQLExpr> columns = x.getColumns();
         if (columns.size() > 0) {
            ++this.indentCount;
            this.print0(" (");
            int i3 = 0;

            for(int size = columns.size(); i3 < size; ++i3) {
               if (i3 != 0) {
                  if (i3 % 5 == 0) {
                     this.println();
                  }

                  this.print0(", ");
               }

               SQLExpr column = (SQLExpr)columns.get(i3);
               if (column instanceof SQLIdentifierExpr) {
                  this.printName0(((SQLIdentifierExpr)column).getName());
               } else {
                  this.printExpr(column, this.parameterized);
               }
            }

            this.print(')');
            --this.indentCount;
         }
      }

      this.print0(this.ucase ? " " + x.getOverridingStr().toUpperCase() + " " : " " + x.getOverridingStr().toLowerCase() + " ");
      List<SQLInsertStatement.ValuesClause> valuesList = x.getValuesList();
      if (!valuesList.isEmpty()) {
         this.println();
         this.printValuesList(valuesList);
      }

      if (x.getQuery() != null) {
         this.println();
         x.getQuery().accept(this);
      }

      List<SQLExpr> duplicateKeyUpdate = x.getDuplicateKeyUpdate();
      if (duplicateKeyUpdate.size() != 0) {
         this.println();
         this.print0(this.ucase ? "ON DUPLICATE KEY UPDATE " : "on duplicate key update ");
         int i4 = 0;

         for(int size = duplicateKeyUpdate.size(); i4 < size; ++i4) {
            if (i4 != 0) {
               if (i4 % 5 == 0) {
                  this.println();
               }

               this.print0(", ");
            }

            ((SQLExpr)duplicateKeyUpdate.get(i4)).accept(this);
         }
      }

      if (x.isDefaultValue()) {
         this.print0(this.ucase ? "  DEFAULT VALUES" : " default values");
      }

      if (x.isOnConflict()) {
         this.print0(this.ucase ? "  ON CONFLICT " : " on conflict ");
      }

      if (x.isDoNothing()) {
         this.print0(this.ucase ? "  DO NOTHING " : " do nothing ");
      }

      List<SQLExpr> doUpdateList = x.getDoUpdateList();
      if (doUpdateList.size() > 0) {
         this.print0("  ( ");

         for(int i5 = 0; i5 < doUpdateList.size(); ++i5) {
            if (i5 != 0) {
               this.print0(", ");
            }

            ((SQLExpr)doUpdateList.get(i5)).accept(this);
         }

         this.print0(" ) ");
      }

      if (x.isDoUpdate()) {
         this.print0(this.ucase ? "  DO UPDATE SET " : " do update set ");
         KingbaseInsertStatement doUpdateStatement = x.getDoUpdateStatement();
         List<SQLExpr> columns = doUpdateStatement.getColumns();
         if (columns.size() > 1) {
            this.print0(" (");
         }

         int i6 = 0;

         for(int size = columns.size(); i6 < size; ++i6) {
            if (i6 != 0) {
               this.print0(", ");
            }

            ((SQLExpr)columns.get(i6)).accept(this);
         }

         if (columns.size() > 1) {
            this.print0(" )");
         }

         this.print0(" = ");
         List<SQLInsertStatement.ValuesClause> valList = doUpdateStatement.getValuesList();

         for(int i7 = 0; i7 < valList.size(); ++i7) {
            SQLInsertStatement.ValuesClause valuesClause = (SQLInsertStatement.ValuesClause)valList.get(i7);
            List<SQLExpr> values = valuesClause.getValues();
            if (values.size() > 1) {
               this.print0(" (");
            }

            for(int i1 = 0; i1 < values.size(); ++i1) {
               if (i1 != 0) {
                  this.print0(", ");
               }

               ((SQLExpr)values.get(i1)).accept(this);
            }

            if (values.size() > 1) {
               this.print0(" )");
            }
         }

         SQLExpr where = doUpdateStatement.getDoUpdateWhere();
         if (where != null) {
            this.println();
            ++this.indentCount;
            this.print0(this.ucase ? "WHERE " : "where ");
            this.printExpr(where, this.parameterized);
            --this.indentCount;
         }
      }

      this.printReturning(x.getReturnList());
      return false;
   }

   public void endVisit(KingbaseInsertStatement x) {
   }

   protected void printValuesList(List<SQLInsertStatement.ValuesClause> valuesList) {
      if (this.parameterized && valuesList.size() > 1 && !this.parameterizedQuesUnMergeValuesList) {
         this.print0(this.ucase ? "VALUES " : "values ");
         ++this.indentCount;
         boolean allConst = true;
         if (valuesList.size() > 1) {
            for(int index = 0; index < valuesList.size(); ++index) {
               List<SQLExpr> values = ((SQLInsertStatement.ValuesClause)valuesList.get(index)).getValues();

               for(int i = 0; i < values.size(); ++i) {
                  SQLExpr value = (SQLExpr)values.get(i);
                  if (!(value instanceof SQLLiteralExpr) && !(value instanceof SQLVariantRefExpr) && (!(value instanceof SQLMethodInvokeExpr) || ((SQLMethodInvokeExpr)value).getArguments().size() != 0)) {
                     allConst = false;
                     break;
                  }
               }

               if (!allConst) {
                  break;
               }
            }
         }

         if (!allConst) {
            for(int index = 0; index < valuesList.size(); ++index) {
               if (index != 0) {
                  this.print(',');
                  this.println();
               }

               this.visit((SQLInsertStatement.ValuesClause)valuesList.get(index), this.parameters);
            }
         } else if (valuesList.size() > 1 && this.parameters != null) {
            SQLInsertStatement.ValuesClause first = (SQLInsertStatement.ValuesClause)valuesList.get(0);
            List<Object> valuesParameters = new ArrayList(first.getValues().size());
            this.visit(first, valuesParameters);
            this.parameters.add(valuesParameters);

            for(int index = 1; index < valuesList.size(); ++index) {
               List<SQLExpr> values = ((SQLInsertStatement.ValuesClause)valuesList.get(index)).getValues();
               List<Object> var16 = new ArrayList(values.size());
               int i = 0;

               for(int size = values.size(); i < size; ++i) {
                  SQLExpr expr = (SQLExpr)values.get(i);
                  if (!(expr instanceof SQLIntegerExpr) && !(expr instanceof SQLBooleanExpr) && !(expr instanceof SQLNumberExpr) && !(expr instanceof SQLCharExpr) && !(expr instanceof SQLNCharExpr) && !(expr instanceof SQLTimestampExpr) && !(expr instanceof SQLDateExpr) && !(expr instanceof SQLTimeExpr)) {
                     if (expr instanceof SQLNullExpr) {
                        this.incrementReplaceCunt();
                        var16.add(null);
                     }
                  } else {
                     this.incrementReplaceCunt();
                     ExportParameterVisitorUtils.exportParameter(var16, (SQLExpr)expr);
                  }
               }

               this.parameters.add(var16);
            }

            this.incrementReplaceCunt();
         } else {
            if (valuesList.size() > 1) {
               this.incrementReplaceCunt();
            }

            this.visit((SQLInsertStatement.ValuesClause)valuesList.get(0), this.parameters);
         }

         --this.indentCount;
      } else {
         this.print0(this.ucase ? "VALUES " : "values ");
         if (valuesList.size() > 1) {
            ++this.indentCount;
         }

         int i = 0;

         for(int size = valuesList.size(); i < size; ++i) {
            if (i != 0) {
               this.print(',');
               this.println();
            }

            SQLInsertStatement.ValuesClause item = (SQLInsertStatement.ValuesClause)valuesList.get(i);
            this.visit(item, this.parameters);
         }

         if (valuesList.size() > 1) {
            --this.indentCount;
         }

      }
   }

   public boolean visit(ValueClause x) {
      return true;
   }

   public void endVisit(ValueClause x) {
   }

   public boolean visit(ValueClause.Item x) {
      return true;
   }

   public void endVisit(ValueClause.Item x) {
   }

   public boolean visit(KingbaseValuesTableSource x) {
      return true;
   }

   public void endVisit(KingbaseValuesTableSource x) {
   }

   public boolean visit(KingbaseUpdateStatement x) {
      List<SQLCommentHint> headHints = x.getHeadHintsDirect();
      if (headHints != null) {
         for(SQLCommentHint hint : headHints) {
            hint.accept(this);
            this.println();
         }
      }

      if (x.getWith() != null) {
         x.getWith().accept(this);
         this.println();
      }

      List<SQLExpr> returning = x.getReturning();
      if (returning != null && returning.size() > 0) {
         this.print0(this.ucase ? "SELECT " : "select ");
         this.printAndAccept(returning, ", ");
         this.println();
         this.print0(this.ucase ? "FROM " : "from ");
      }

      this.print0(this.ucase ? "UPDATE " : "update ");
      if (x.isLowPriority()) {
         this.print0(this.ucase ? "LOW_PRIORITY " : "low_priority ");
      }

      if (x.isIgnore()) {
         this.print0(this.ucase ? "IGNORE " : "ignore ");
      }

      if (x.getHints() != null && x.getHints().size() > 0) {
         this.printAndAccept(x.getHints(), " ");
         this.print0(" ");
      }

      if (x.isCommitOnSuccess()) {
         this.print0(this.ucase ? "COMMIT_ON_SUCCESS " : "commit_on_success ");
      }

      if (x.isRollBackOnFail()) {
         this.print0(this.ucase ? "ROLLBACK_ON_FAIL " : "rollback_on_fail ");
      }

      if (x.isQueryOnPk()) {
         this.print0(this.ucase ? "QUEUE_ON_PK " : "queue_on_pk ");
      }

      SQLExpr targetAffectRow = x.getTargetAffectRow();
      if (targetAffectRow != null) {
         this.print0(this.ucase ? "TARGET_AFFECT_ROW " : "target_affect_row ");
         this.printExpr(targetAffectRow, this.parameterized);
         this.print(' ');
      }

      if (x.isForceAllPartitions()) {
         this.print0(this.ucase ? "FORCE ALL PARTITIONS " : "force all partitions ");
      } else {
         SQLName partition = x.getForcePartition();
         if (partition != null) {
            this.print0(this.ucase ? "FORCE PARTITION " : "force partition ");
            this.printExpr(partition, this.parameterized);
            this.print(' ');
         }
      }

      SQLTableSource tableSource = x.getTableSource();
      if (tableSource.getOnly()) {
         this.print0(this.ucase ? "ONLY " : "only ");
      }

      this.printTableSource(x.getTableSource());
      this.println();
      this.print0(this.ucase ? "SET " : "set ");
      List<SQLUpdateSetItem> items = x.getItems();
      int i = 0;

      for(int size = items.size(); i < size; ++i) {
         if (i != 0) {
            this.print0(", ");
         }

         SQLUpdateSetItem item = (SQLUpdateSetItem)items.get(i);
         this.visit((SQLUpdateSetItem)item);
      }

      SQLExpr where = x.getWhere();
      if (where != null) {
         this.println();
         ++this.indentCount;
         this.print0(this.ucase ? "WHERE " : "where ");
         this.printExpr(where, this.parameterized);
         --this.indentCount;
      }

      SQLOrderBy orderBy = x.getOrderBy();
      if (orderBy != null) {
         this.println();
         this.visit((SQLOrderBy)orderBy);
      }

      SQLLimit limit = x.getLimit();
      if (limit != null) {
         this.println();
         this.visit((SQLLimit)limit);
      }

      this.printReturning(x.getReturnList());
      return false;
   }

   public void endVisit(KingbaseUpdateStatement x) {
   }

   private void printReturning(List<SQLSelectItem> returnList) {
      if (returnList != null && returnList.size() > 0) {
         this.print0(this.ucase ? " RETURNING " : " returning ");

         for(int i = 0; i < returnList.size(); ++i) {
            if (i != 0) {
               this.print0(", ");
            }

            SQLSelectItem sqlSelectItem = (SQLSelectItem)returnList.get(i);
            this.visit((SQLSelectItem)sqlSelectItem);
         }
      }

   }

   public boolean visit(SQLExprTableSource x) {
      this.printTableSourceExpr(x.getExpr());
      SQLTableSampling sampling = x.getSampling();
      if (sampling != null) {
         this.print(' ');
         sampling.accept(this);
      }

      String alias = x.getAlias();
      List<SQLName> columns = x.getColumnsDirect();
      if (alias != null) {
         this.print(' ');
         if (columns != null && columns.size() > 0) {
            this.print0(this.ucase ? " AS " : " as ");
         }

         this.print0(alias);
      }

      if (columns != null && columns.size() > 0) {
         this.print(" (");
         this.printAndAccept(columns, ", ");
         this.print(')');
      }

      for(int i = 0; i < x.getHintsSize(); ++i) {
         this.print(' ');
         ((SQLHint)x.getHints().get(i)).accept(this);
      }

      if (x.getPartitionSize() > 0) {
         this.print0(this.ucase ? " PARTITION (" : " partition (");
         this.printlnAndAccept(x.getPartitions(), ", ");
         this.print(')');
      }

      return false;
   }

   public boolean visit(KingbaseCharExpr x) {
      if (this.parameterized) {
         this.print('?');
         this.incrementReplaceCunt();
         if (this.parameters != null) {
            ExportParameterVisitorUtils.exportParameter(this.parameters, (SQLExpr)x);
         }

         return false;
      } else {
         String charset = x.getCharset();
         String collate = x.getCollate();
         String text = x.getText();
         if (charset != null) {
            this.print(charset);
            long charsetHashCode = FnvHash.hashCode64(charset);
            if (charsetHashCode != FnvHash.Constants._UCS2 && charsetHashCode != FnvHash.Constants._UTF16) {
               if (x.getType() != null) {
                  this.print(x.getType());
               }

               this.print(" '");
            } else {
               this.print(" x'");
            }

            this.print(text);
            this.print('\'');
         } else {
            if (x.getType() != null) {
               this.print(x.getType());
            }

            this.print('\'');
            this.print(text);
            this.print('\'');
         }

         if (collate != null) {
            this.print(" COLLATE ");
            this.print(collate);
         }

         return false;
      }
   }

   public void endVisit(KingbaseCharExpr x) {
   }

   public boolean visit(SQLAssignItem x) {
      String tagetString = x.getTarget().toString();
      boolean mysqlSpecial = false;
      if (DbType.mysql == this.dbType) {
         mysqlSpecial = "NAMES".equalsIgnoreCase(tagetString) || "CHARACTER SET".equalsIgnoreCase(tagetString) || "CHARSET".equalsIgnoreCase(tagetString);
      }

      if (!mysqlSpecial) {
         x.getTarget().accept(this);
         this.print0(" = ");
      } else {
         this.print0(this.ucase ? tagetString.toUpperCase() : tagetString.toLowerCase());
         this.print(' ');
      }

      x.getValue().accept(this);
      return false;
   }

   protected void visitAggreateRest(SQLAggregateExpr aggregateExpr) {
       {
           SQLOrderBy value = aggregateExpr.getOrderBy();
           if (value != null) {
               this.print(' ');
               value.accept(this);
           }
       }
       {
           Object value = aggregateExpr.getAttribute("SEPARATOR");
           if (value != null) {
               this.print0(this.ucase ? " SEPARATOR " : " separator ");
               ((SQLObject) value).accept(this);
           }
       }
   }

   public boolean visit(SQLSetStatement x) {
      boolean printSet = x.getAttribute("parser.set") == Boolean.TRUE || DbType.oracle != this.dbType;
      if (printSet) {
         this.print0(this.ucase ? "SET " : "set ");
      }

      SQLSetStatement.Option option = x.getOption();
      if (option != null) {
         this.print(option.name());
         this.print(' ');
      }

      if (option == SQLSetStatement.Option.PASSWORD) {
         this.print0("FOR ");
      }

      this.printAndAccept(x.getItems(), ", ");
      if (x.getHints() != null && x.getHints().size() > 0) {
         this.print(' ');
         this.printAndAccept(x.getHints(), " ");
      }

      return false;
   }

   public boolean visit(SQLBlockStatement x) {
      SQLObject parent = x.getParent();
      String labelName = x.getLabelName();
      if (labelName != null && !labelName.equals("")) {
         this.print0(labelName);
         this.print0(": ");
      }

      List<SQLParameter> parameters = x.getParameters();
      if (parameters.size() != 0) {
         ++this.indentCount;
         if (parent instanceof SQLCreateProcedureStatement) {
            this.printIndent();
         }

         if (!(parent instanceof SQLCreateProcedureStatement)) {
            this.print0(this.ucase ? "DECLARE" : "declare");
            this.println();
         }

         int i = 0;

         for(int size = parameters.size(); i < size; ++i) {
            if (i != 0) {
               this.println();
            }

            SQLParameter param = (SQLParameter)parameters.get(i);
            this.visit((SQLParameter)param);
            this.print(';');
         }

         --this.indentCount;
         this.println();
      }

      this.print0(this.ucase ? "BEGIN" : "begin");
      if (!x.isEndOfCommit()) {
         ++this.indentCount;
      } else {
         this.print(';');
      }

      this.println();
      List<SQLStatement> statementList = x.getStatementList();
      int i = 0;

      for(int size = statementList.size(); i < size; ++i) {
         if (i != 0) {
            this.println();
         }

         SQLStatement stmt = (SQLStatement)statementList.get(i);
         stmt.accept(this);
      }

      if (!x.isEndOfCommit()) {
         --this.indentCount;
         this.println();
         this.print0(this.ucase ? "END" : "end");
         if (labelName != null && !labelName.equals("")) {
            this.print(' ');
            this.print0(labelName);
         }
      }

      return false;
   }

   public boolean visit(KingbaseCaseStatement.KingbaseWhenStatement x) {
      this.print0(this.ucase ? "WHEN " : "when ");
      x.getCondition().accept(this);
      this.print0(" THEN");
      this.println();

      for(int i = 0; i < x.getStatements().size(); ++i) {
         ((SQLStatement)x.getStatements().get(i)).accept(this);
         if (i != x.getStatements().size() - 1) {
            this.println();
         }
      }

      this.println();
      return false;
   }

   public void endVisit(KingbaseCaseStatement.KingbaseWhenStatement x) {
   }

   public boolean visit(KingbaseCaseStatement x) {
      return true;
   }

   public void endVisit(KingbaseCaseStatement x) {
   }

   public boolean visit(KingbaseUpdateTableSource x) {
      KingbaseUpdateStatement update = x.getUpdate();
      if (update != null) {
         update.accept0((KingbaseASTVisitor)this);
      }

      return false;
   }

   public void endVisit(KingbaseUpdateTableSource x) {
   }

   public boolean visit(SQLCommentStatement x) {
      SQLCommentStatement.Type type = x.getType();
      SQLExprTableSource on = x.getOn();
      if (type == SQLCommentStatement.Type.TABLE) {
         this.print0(this.ucase ? "ALTER TABLE " : "alter table ");
         on.accept(this);
         this.print0(this.ucase ? " COMMENT = " : " comment = ");
         x.getComment().accept(this);
      } else {
         SQLPropertyExpr propertyExpr = (SQLPropertyExpr)on.getExpr();
         SQLExpr table = propertyExpr.getOwner();
         String column = propertyExpr.getName();
         this.print0(this.ucase ? "ALTER TABLE " : "alter table ");
         this.printTableSourceExpr(table);
         this.print0(this.ucase ? " MODIFY COLUMN " : " modify column ");
         this.print(column);
         this.print0(this.ucase ? " COMMENT " : " comment ");
         x.getComment().accept(this);
      }

      return false;
   }

   protected void printQuery(SQLSelectQuery x) {
      Class<?> clazz = x.getClass();
      if (clazz == KingbaseSelectQueryBlock.class) {
         this.visit((KingbaseSelectQueryBlock)x);
      } else if (clazz == SQLSelectQueryBlock.class) {
         this.visit((SQLSelectQueryBlock)x);
      } else if (clazz == SQLUnionQuery.class) {
         this.visit((SQLUnionQuery)((SQLUnionQuery)x));
      } else {
         x.accept(this);
      }

   }

   public void printInsertColumns(List<SQLExpr> columns) {
      int size = columns.size();
      if (size > 0) {
         if (size > 5) {
            ++this.indentCount;
            this.print(' ');
         }

         this.print('(');

         for(int i = 0; i < size; ++i) {
            if (i != 0) {
               if (i % 5 == 0) {
                  this.println();
               }

               this.print0(", ");
            }

            SQLExpr column = (SQLExpr)columns.get(i);
            if (column instanceof SQLIdentifierExpr) {
               this.visit((SQLIdentifierExpr)((SQLIdentifierExpr)column));
            } else {
               this.printExpr(column, this.parameterized);
            }

            String dataType = (String)column.getAttribute("dataType");
            if (dataType != null) {
               this.print(' ');
               this.print(dataType);
            }
         }

         this.print(')');
         if (size > 5) {
            --this.indentCount;
         }
      }

   }

   public boolean visit(SQLValuesTableSource x) {
      this.print('(');
      this.incrementIndent();
      this.println();
      this.print0(this.ucase ? "VALUES " : "values ");
      List<SQLListExpr> values = x.getValues();

      for(int i = 0; i < values.size(); ++i) {
         if (i != 0) {
            this.print(", ");
            this.println();
         }

         SQLListExpr list = (SQLListExpr)values.get(i);
         this.visit((SQLListExpr)list);
      }

      this.decrementIndent();
      this.println();
      this.print0(")");
      if (x.getAlias() != null) {
         this.print0(" AS ");
         this.print0(x.getAlias());
         if (x.getColumns().size() > 0) {
            this.print0(" (");
            this.printAndAccept(x.getColumns(), ", ");
            this.print(')');
         }
      }

      return false;
   }

   public boolean visit(KingbaseTypeCastExpr x) {
      SQLExpr expr = x.getExpr();
      SQLDataType dataType = x.getDataType();
      if (dataType.nameHashCode64() == FnvHash.Constants.VARBIT) {
         dataType.accept(this);
         this.print(' ');
         this.printExpr(expr);
         return false;
      } else {
         if (expr != null) {
            if (expr instanceof SQLBinaryOpExpr) {
               this.print('(');
               expr.accept(this);
               this.print(')');
            } else if (expr instanceof KingbaseTypeCastExpr && dataType.getArguments().size() == 0) {
               expr.accept(this);
            } else {
               expr.accept(this);
            }
         }

         this.print0("::");
         dataType.accept(this);
         return false;
      }
   }

   public void endVisit(KingbaseTypeCastExpr x) {
   }

   public boolean visit(KingbaseSQLOver x) {
      this.print0(this.ucase ? "(" : "(");
      if (x.getExistingName() != null) {
         x.getExistingName().accept(this);
         this.print(' ');
      }

      if (x.getPartitionBy().size() > 0) {
         this.print0(this.ucase ? "PARTITION BY " : "partition by ");
         this.printAndAccept(x.getPartitionBy(), ", ");
         this.print(' ');
      }

      SQLOrderBy orderBy = x.getOrderBy();
      if (orderBy != null) {
         orderBy.accept(this);
      }

      SQLExpr windowingBetweenBegin = x.getWindowingBetweenBegin();
      SQLExpr windowingBetweenEnd = x.getWindowingBetweenEnd();
      SQLOver.WindowingBound beginBound = x.getWindowingBetweenBeginBound();
      SQLOver.WindowingBound endBound = x.getWindowingBetweenEndBound();
      SQLOver.WindowingType windowingType = x.getWindowingType();
      if (windowingBetweenEnd == null && endBound == null) {
         if (windowingType != null) {
            this.print(' ');
            this.print0(this.ucase ? windowingType.name : windowingType.name_lower);
         }

         this.printWindowingExpr(windowingBetweenBegin);
         if (beginBound != null) {
            this.print(' ');
            this.print0(this.ucase ? beginBound.name : beginBound.name_lower);
         }
      } else {
         if (windowingType != null) {
            this.print(' ');
            this.print0(this.ucase ? windowingType.name : windowingType.name_lower);
         }

         this.print0(this.ucase ? " BETWEEN" : " between");
         this.printWindowingExpr(windowingBetweenBegin);
         if (beginBound != null) {
            this.print(' ');
            this.print0(this.ucase ? beginBound.name : beginBound.name_lower);
         }

         this.print0(this.ucase ? " AND" : " and");
         this.printWindowingExpr(windowingBetweenEnd);
         if (endBound != null) {
            this.print(' ');
            this.print0(this.ucase ? endBound.name : endBound.name_lower);
         }
      }

      if (x.getExcludeBound() != null) {
         this.print0(this.ucase ? " EXCLUDE " : " exclude");
         this.print0(this.ucase ? x.getExcludeBound().name : x.getExcludeBound().name_lower);
      }

      this.print(')');
      return false;
   }

   public void endVisit(KingbaseSQLOver x) {
   }

   public boolean visit(KingbaseDateTimeExpr x) {
      this.print(x.getTimeType().toString());
      this.print(' ');
      if (x.getPrecision() != null) {
         this.print('(');
         x.getPrecision().accept(this);
         this.print(')');
         this.print(' ');
      }

      if (x.isWithTimezone()) {
         if (x.isLocal()) {
            this.print("WITH LOCAL TIME ZONE ");
         } else {
            this.print("WITH TIME ZONE ");
         }
      }

      if (x.isWithoutTimezone()) {
         this.print("WITHOUT TIME ZONE ");
      }

      x.getValue().accept(this);
      if (x.getIntervalBegin() != null) {
         this.print(' ');
         x.getIntervalBegin().accept(this);
      }

      if (x.getIntervalEnd() != null) {
         this.print(" TO");
         this.print(' ');
         x.getIntervalEnd().accept(this);
      }

      return false;
   }

   public void endVisit(KingbaseDateTimeExpr x) {
   }

   public boolean visit(KingbaseForUpdateExpr x) {
      this.println();
      this.print(this.ucase ? "FOR" : "for");
      this.print(' ');
      this.print(this.ucase ? x.getLockStrength().name : x.getLockStrength().name_lower);
      if (x.getOfTables() != null && x.getOfTables().size() > 0) {
         this.print(' ');
         this.print(this.ucase ? "OF" : "of");
         this.print(' ');
         List<SQLExpr> tables = x.getOfTables();

         for(int i = 0; i < tables.size(); ++i) {
            ((SQLExpr)tables.get(i)).accept(this);
            if (i < tables.size() - 1) {
               this.print(",");
            }
         }
      }

      if (x.getLockType() != null) {
         this.print(' ');
         this.print(this.ucase ? x.getLockType().name : x.getLockType().name_lower);
      }

      return false;
   }

   public void endVisit(KingbaseForUpdateExpr x) {
   }

   public boolean visit(KingbaseExprTableSource x) {
      x.getExpr().accept(this);
      if (x.getDbLink() != null) {
         this.print('@');
         x.getDbLink().accept(this);
      }

      if (x.getSampling() != null) {
         x.getSampling().accept(this);
      }

      if (x.getAlias() != null && x.getAlias().length() > 0) {
         this.print(" ");
         this.print0(x.getAlias());
         this.print(" ");
      }

      return false;
   }

   public void endVisit(KingbaseExprTableSource x) {
   }

   public boolean visit(KingbaseWithSubqueryEntry x) {
      this.print0(x.getAlias());
      if (x.getColumns().size() > 0) {
         this.print0(" (");
         this.printAndAccept(x.getColumns(), ", ");
         this.print(')');
      }

      this.print(' ');
      this.print0(this.ucase ? "AS " : "as ");
      if (x.getType() != null) {
         this.print0(this.ucase ? x.getType().name.toUpperCase(Locale.ROOT) : x.getType().name.toLowerCase(Locale.ROOT));
         this.print(' ');
      }

      this.print('(');
      ++this.indentCount;
      this.println();
      SQLSelect query = x.getSubQuery();
      if (query != null) {
         query.accept(this);
      } else {
         x.getReturningStatement().accept(this);
      }

      --this.indentCount;
      this.println();
      this.print(')');
      return false;
   }

   public void endVisit(KingbaseWithSubqueryEntry x) {
   }

   public boolean visit(KingbaseConstantExpr x) {
      this.print(x.getValue().toString());
      return false;
   }

   public void endVisit(KingbaseConstantExpr x) {
   }

   public boolean visit(KingbaseMultiInsertStatement.InsertIntoClause x) {
      this.print0(this.ucase ? "INTO " : "into ");
      x.getTableSource().accept(this);
      if (x.getColumns().size() > 0) {
         ++this.indentCount;
         this.println();
         this.print('(');
         int i = 0;

         for(int size = x.getColumns().size(); i < size; ++i) {
            if (i != 0) {
               if (i % 5 == 0) {
                  this.println();
               }

               this.print0(", ");
            }

            ((SQLExpr)x.getColumns().get(i)).accept(this);
         }

         this.print(')');
         --this.indentCount;
      }

      if (x.getValues() != null) {
         this.println();
         this.print0(this.ucase ? "VALUES " : "values ");
         x.getValues().accept(this);
      } else if (x.getQuery() != null) {
         this.println();
         x.getQuery().accept(this);
      }

      return false;
   }

   public void endVisit(KingbaseMultiInsertStatement.InsertIntoClause x) {
   }

   public boolean visit(KingbaseMultiInsertStatement x) {
      this.print0(this.ucase ? "INSERT " : "insert ");
      if (x.getOption() != null) {
         this.print0(x.getOption().name());
         this.print(' ');
      }

      int i = 0;

      for(int size = x.getEntries().size(); i < size; ++i) {
         ++this.indentCount;
         this.println();
         ((KingbaseMultiInsertStatement.Entry)x.getEntries().get(i)).accept(this);
         --this.indentCount;
      }

      this.println();
      x.getSubQuery().accept(this);
      return false;
   }

   public void endVisit(KingbaseMultiInsertStatement x) {
   }

   public boolean visit(KingbaseMultiInsertStatement.ConditionalInsertClause x) {
      int i = 0;

      for(int size = x.getItems().size(); i < size; ++i) {
         if (i != 0) {
            this.println();
         }

         KingbaseMultiInsertStatement.ConditionalInsertClauseItem item = (KingbaseMultiInsertStatement.ConditionalInsertClauseItem)x.getItems().get(i);
         item.accept(this);
      }

      if (x.getElseItem() != null) {
         this.println();
         this.print0(this.ucase ? "ELSE" : "else");
         ++this.indentCount;
         this.println();
         x.getElseItem().accept(this);
         --this.indentCount;
      }

      return false;
   }

   public void endVisit(KingbaseMultiInsertStatement.ConditionalInsertClause x) {
   }

   public boolean visit(KingbaseMultiInsertStatement.ConditionalInsertClauseItem x) {
      this.print0(this.ucase ? "WHEN " : "when ");
      x.getWhen().accept(this);
      this.print0(this.ucase ? " THEN" : " then");
      ++this.indentCount;
      this.println();
      x.getThen().accept(this);
      --this.indentCount;
      return false;
   }

   public void endVisit(KingbaseMultiInsertStatement.ConditionalInsertClauseItem x) {
   }
}
