package com.chenyang.druid.sql.visitor;

import com.chenyang.druid.DbType;
import com.chenyang.druid.sql.SQLUtils;
import com.chenyang.druid.sql.ast.AutoIncrementType;
import com.chenyang.druid.sql.ast.SQLAdhocTableSource;
import com.chenyang.druid.sql.ast.SQLAnnIndex;
import com.chenyang.druid.sql.ast.SQLArgument;
import com.chenyang.druid.sql.ast.SQLArrayDataType;
import com.chenyang.druid.sql.ast.SQLCommentHint;
import com.chenyang.druid.sql.ast.SQLCurrentTimeExpr;
import com.chenyang.druid.sql.ast.SQLCurrentUserExpr;
import com.chenyang.druid.sql.ast.SQLDataType;
import com.chenyang.druid.sql.ast.SQLDataTypeImpl;
import com.chenyang.druid.sql.ast.SQLDeclareItem;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLExprImpl;
import com.chenyang.druid.sql.ast.SQLHint;
import com.chenyang.druid.sql.ast.SQLIndexDefinition;
import com.chenyang.druid.sql.ast.SQLIndexOptions;
import com.chenyang.druid.sql.ast.SQLKeep;
import com.chenyang.druid.sql.ast.SQLLimit;
import com.chenyang.druid.sql.ast.SQLMapDataType;
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.SQLOrderingSpecification;
import com.chenyang.druid.sql.ast.SQLOver;
import com.chenyang.druid.sql.ast.SQLParameter;
import com.chenyang.druid.sql.ast.SQLPartition;
import com.chenyang.druid.sql.ast.SQLPartitionBy;
import com.chenyang.druid.sql.ast.SQLPartitionByHash;
import com.chenyang.druid.sql.ast.SQLPartitionByList;
import com.chenyang.druid.sql.ast.SQLPartitionByRange;
import com.chenyang.druid.sql.ast.SQLPartitionByValue;
import com.chenyang.druid.sql.ast.SQLPartitionSpec;
import com.chenyang.druid.sql.ast.SQLPartitionValue;
import com.chenyang.druid.sql.ast.SQLRecordDataType;
import com.chenyang.druid.sql.ast.SQLRowDataType;
import com.chenyang.druid.sql.ast.SQLStatement;
import com.chenyang.druid.sql.ast.SQLStructDataType;
import com.chenyang.druid.sql.ast.SQLSubPartition;
import com.chenyang.druid.sql.ast.SQLSubPartitionByHash;
import com.chenyang.druid.sql.ast.SQLSubPartitionByList;
import com.chenyang.druid.sql.ast.SQLSubPartitionByRange;
import com.chenyang.druid.sql.ast.SQLUnionDataType;
import com.chenyang.druid.sql.ast.SQLWindow;
import com.chenyang.druid.sql.ast.expr.SQLAggregateExpr;
import com.chenyang.druid.sql.ast.expr.SQLAggregateOption;
import com.chenyang.druid.sql.ast.expr.SQLAllColumnExpr;
import com.chenyang.druid.sql.ast.expr.SQLAllExpr;
import com.chenyang.druid.sql.ast.expr.SQLAnyExpr;
import com.chenyang.druid.sql.ast.expr.SQLArrayExpr;
import com.chenyang.druid.sql.ast.expr.SQLBetweenExpr;
import com.chenyang.druid.sql.ast.expr.SQLBigIntExpr;
import com.chenyang.druid.sql.ast.expr.SQLBinaryExpr;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOpExprGroup;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOperator;
import com.chenyang.druid.sql.ast.expr.SQLBooleanExpr;
import com.chenyang.druid.sql.ast.expr.SQLCaseExpr;
import com.chenyang.druid.sql.ast.expr.SQLCaseStatement;
import com.chenyang.druid.sql.ast.expr.SQLCastExpr;
import com.chenyang.druid.sql.ast.expr.SQLCharExpr;
import com.chenyang.druid.sql.ast.expr.SQLContainsExpr;
import com.chenyang.druid.sql.ast.expr.SQLCurrentOfCursorExpr;
import com.chenyang.druid.sql.ast.expr.SQLDateExpr;
import com.chenyang.druid.sql.ast.expr.SQLDateTimeExpr;
import com.chenyang.druid.sql.ast.expr.SQLDbLinkExpr;
import com.chenyang.druid.sql.ast.expr.SQLDecimalExpr;
import com.chenyang.druid.sql.ast.expr.SQLDefaultExpr;
import com.chenyang.druid.sql.ast.expr.SQLDoubleExpr;
import com.chenyang.druid.sql.ast.expr.SQLExistsExpr;
import com.chenyang.druid.sql.ast.expr.SQLExprUtils;
import com.chenyang.druid.sql.ast.expr.SQLExtractExpr;
import com.chenyang.druid.sql.ast.expr.SQLFlashbackExpr;
import com.chenyang.druid.sql.ast.expr.SQLFloatExpr;
import com.chenyang.druid.sql.ast.expr.SQLGroupingSetExpr;
import com.chenyang.druid.sql.ast.expr.SQLHexExpr;
import com.chenyang.druid.sql.ast.expr.SQLIdentifierExpr;
import com.chenyang.druid.sql.ast.expr.SQLInListExpr;
import com.chenyang.druid.sql.ast.expr.SQLInSubQueryExpr;
import com.chenyang.druid.sql.ast.expr.SQLIntegerExpr;
import com.chenyang.druid.sql.ast.expr.SQLIntervalExpr;
import com.chenyang.druid.sql.ast.expr.SQLIntervalUnit;
import com.chenyang.druid.sql.ast.expr.SQLJSONExpr;
import com.chenyang.druid.sql.ast.expr.SQLListExpr;
import com.chenyang.druid.sql.ast.expr.SQLLiteralExpr;
import com.chenyang.druid.sql.ast.expr.SQLMatchAgainstExpr;
import com.chenyang.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.chenyang.druid.sql.ast.expr.SQLNCharExpr;
import com.chenyang.druid.sql.ast.expr.SQLNotExpr;
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.SQLQueryExpr;
import com.chenyang.druid.sql.ast.expr.SQLRealExpr;
import com.chenyang.druid.sql.ast.expr.SQLSequenceExpr;
import com.chenyang.druid.sql.ast.expr.SQLSizeExpr;
import com.chenyang.druid.sql.ast.expr.SQLSmallIntExpr;
import com.chenyang.druid.sql.ast.expr.SQLSomeExpr;
import com.chenyang.druid.sql.ast.expr.SQLTimeExpr;
import com.chenyang.druid.sql.ast.expr.SQLTimestampExpr;
import com.chenyang.druid.sql.ast.expr.SQLTinyIntExpr;
import com.chenyang.druid.sql.ast.expr.SQLUnaryExpr;
import com.chenyang.druid.sql.ast.expr.SQLValuesExpr;
import com.chenyang.druid.sql.ast.expr.SQLVariantRefExpr;
import com.chenyang.druid.sql.ast.statement.SQLAlterCharacter;
import com.chenyang.druid.sql.ast.statement.SQLAlterDatabaseItem;
import com.chenyang.druid.sql.ast.statement.SQLAlterDatabaseStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterFunctionStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterIndexStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterMaterializedViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterOutlineStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterSequenceStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterSetDateFormatStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterSetNlsDateLanguageStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterSystemGetConfigStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterSystemSetConfigStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterSystemStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableAddColumn;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableAddConstraint;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableAddExtPartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableAddIndex;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableAddPartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableAddSupplemental;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableAlterColumn;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableAnalyzePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableArchivePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableBlockSize;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableCheckPartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableCoalescePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableConvertCharSet;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDeleteByCondition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDisableConstraint;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDisableKeys;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDisableLifecycle;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDiscardPartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDropColumnItem;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDropConstraint;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDropExtPartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDropForeignKey;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDropIndex;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDropKey;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDropPartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDropPrimaryKey;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableEnableConstraint;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableEnableKeys;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableEnableLifecycle;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableExchangePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableGroupStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableImportPartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableItem;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableMergePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableModifyClusteredBy;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableOptimizePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTablePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTablePartitionCount;
import com.chenyang.druid.sql.ast.statement.SQLAlterTablePartitionSetProperties;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableReOrganizePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableRebuildPartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableRecoverPartitions;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableRename;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableRenameColumn;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableRenameIndex;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableRenamePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableRepairPartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableReplaceColumn;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableSetComment;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableSetLifecycle;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableSetLocation;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableSetOption;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableSubpartitionAvailablePartitionNum;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableTouch;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableTruncatePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableUnarchivePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTablespaceAddDatafile;
import com.chenyang.druid.sql.ast.statement.SQLAlterTablespaceCache;
import com.chenyang.druid.sql.ast.statement.SQLAlterTablespaceDatafile;
import com.chenyang.druid.sql.ast.statement.SQLAlterTablespaceRename;
import com.chenyang.druid.sql.ast.statement.SQLAlterTablespaceRenameDatafile;
import com.chenyang.druid.sql.ast.statement.SQLAlterTablespaceResizeDatafile;
import com.chenyang.druid.sql.ast.statement.SQLAlterTablespaceStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterTypeStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterUserStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterViewRenameStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLAnalyzeTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLArchiveTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLAssignItem;
import com.chenyang.druid.sql.ast.statement.SQLBackupStatement;
import com.chenyang.druid.sql.ast.statement.SQLBlockStatement;
import com.chenyang.druid.sql.ast.statement.SQLBuildTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLCallStatement;
import com.chenyang.druid.sql.ast.statement.SQLCancelJobStatement;
import com.chenyang.druid.sql.ast.statement.SQLCharacterDataType;
import com.chenyang.druid.sql.ast.statement.SQLCheck;
import com.chenyang.druid.sql.ast.statement.SQLCloseStatement;
import com.chenyang.druid.sql.ast.statement.SQLColumnCheck;
import com.chenyang.druid.sql.ast.statement.SQLColumnConstraint;
import com.chenyang.druid.sql.ast.statement.SQLColumnDefinition;
import com.chenyang.druid.sql.ast.statement.SQLColumnPrimaryKey;
import com.chenyang.druid.sql.ast.statement.SQLColumnReference;
import com.chenyang.druid.sql.ast.statement.SQLColumnUniqueKey;
import com.chenyang.druid.sql.ast.statement.SQLCommentStatement;
import com.chenyang.druid.sql.ast.statement.SQLCommitStatement;
import com.chenyang.druid.sql.ast.statement.SQLCopyFromStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateContextStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateDatabaseStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateDirectoryStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateDomainStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateFunctionStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateIndexStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateMaterializedViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateOutlineStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateProcedureStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateRoleStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateSequenceStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateTableGroupStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateTablespaceStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateTriggerStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateUserStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLDeclareStatement;
import com.chenyang.druid.sql.ast.statement.SQLDefault;
import com.chenyang.druid.sql.ast.statement.SQLDeleteStatement;
import com.chenyang.druid.sql.ast.statement.SQLDescribeStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropCatalogStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropContextStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropDatabaseStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropDirectoryStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropDomainStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropEventStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropFunctionStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropIndexStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropLogFileGroupStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropMaterializedViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropOutlineStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropProcedureStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropResourceGroupStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropResourceStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropRoleStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropSequenceStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropServerStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropSynonymStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropTableGroupStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropTableSpaceStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropTriggerStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropTypeStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropUserStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLDumpStatement;
import com.chenyang.druid.sql.ast.statement.SQLErrorLoggingClause;
import com.chenyang.druid.sql.ast.statement.SQLExplainAnalyzeStatement;
import com.chenyang.druid.sql.ast.statement.SQLExplainStatement;
import com.chenyang.druid.sql.ast.statement.SQLExportDatabaseStatement;
import com.chenyang.druid.sql.ast.statement.SQLExportTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLExprHint;
import com.chenyang.druid.sql.ast.statement.SQLExprStatement;
import com.chenyang.druid.sql.ast.statement.SQLExprTableSource;
import com.chenyang.druid.sql.ast.statement.SQLExternalRecordFormat;
import com.chenyang.druid.sql.ast.statement.SQLFetchStatement;
import com.chenyang.druid.sql.ast.statement.SQLForStatement;
import com.chenyang.druid.sql.ast.statement.SQLForeignKeyConstraint;
import com.chenyang.druid.sql.ast.statement.SQLForeignKeyImpl;
import com.chenyang.druid.sql.ast.statement.SQLGrantStatement;
import com.chenyang.druid.sql.ast.statement.SQLIfStatement;
import com.chenyang.druid.sql.ast.statement.SQLImportDatabaseStatement;
import com.chenyang.druid.sql.ast.statement.SQLImportTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLInsertStatement;
import com.chenyang.druid.sql.ast.statement.SQLJoinTableSource;
import com.chenyang.druid.sql.ast.statement.SQLLateralViewTableSource;
import com.chenyang.druid.sql.ast.statement.SQLLoadIndexIntoCacheStatement;
import com.chenyang.druid.sql.ast.statement.SQLLoopStatement;
import com.chenyang.druid.sql.ast.statement.SQLMergeStatement;
import com.chenyang.druid.sql.ast.statement.SQLNotNullConstraint;
import com.chenyang.druid.sql.ast.statement.SQLNullConstraint;
import com.chenyang.druid.sql.ast.statement.SQLObjectType;
import com.chenyang.druid.sql.ast.statement.SQLOpenStatement;
import com.chenyang.druid.sql.ast.statement.SQLPartitionRef;
import com.chenyang.druid.sql.ast.statement.SQLPrimaryKey;
import com.chenyang.druid.sql.ast.statement.SQLPrimaryKeyImpl;
import com.chenyang.druid.sql.ast.statement.SQLPrivilegeItem;
import com.chenyang.druid.sql.ast.statement.SQLPurgeLogsStatement;
import com.chenyang.druid.sql.ast.statement.SQLPurgeRecyclebinStatement;
import com.chenyang.druid.sql.ast.statement.SQLPurgeTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLRefreshMaterializedViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLReleaseSavePointStatement;
import com.chenyang.druid.sql.ast.statement.SQLRenameUserStatement;
import com.chenyang.druid.sql.ast.statement.SQLRestoreStatement;
import com.chenyang.druid.sql.ast.statement.SQLReturnStatement;
import com.chenyang.druid.sql.ast.statement.SQLRevokeStatement;
import com.chenyang.druid.sql.ast.statement.SQLRollbackStatement;
import com.chenyang.druid.sql.ast.statement.SQLSavePointStatement;
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.SQLSelectOrderByItem;
import com.chenyang.druid.sql.ast.statement.SQLSelectQuery;
import com.chenyang.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.chenyang.druid.sql.ast.statement.SQLSelectStatement;
import com.chenyang.druid.sql.ast.statement.SQLSetSchemaStatement;
import com.chenyang.druid.sql.ast.statement.SQLSetStatement;
import com.chenyang.druid.sql.ast.statement.SQLSetTimeZoneStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowCatalogsStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowColumnsStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowCreateMaterializedViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowCreateTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowCreateViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowDatabasesStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowErrorsStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowFunctionsStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowGrantsStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowIndexesStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowMaterializedViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowOutlinesStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowPackagesStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowPartitionsStmt;
import com.chenyang.druid.sql.ast.statement.SQLShowProcessListStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowQueryTaskStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowRecylebinStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowSessionStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowStatisticListStmt;
import com.chenyang.druid.sql.ast.statement.SQLShowStatisticStmt;
import com.chenyang.druid.sql.ast.statement.SQLShowTableGroupsStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowTablesStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowUsersStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowViewsStatement;
import com.chenyang.druid.sql.ast.statement.SQLSubmitJobStatement;
import com.chenyang.druid.sql.ast.statement.SQLSubqueryTableSource;
import com.chenyang.druid.sql.ast.statement.SQLSyncMetaStatement;
import com.chenyang.druid.sql.ast.statement.SQLTableElement;
import com.chenyang.druid.sql.ast.statement.SQLTableLike;
import com.chenyang.druid.sql.ast.statement.SQLTableSampling;
import com.chenyang.druid.sql.ast.statement.SQLTableSource;
import com.chenyang.druid.sql.ast.statement.SQLTruncateStatement;
import com.chenyang.druid.sql.ast.statement.SQLUnionOperator;
import com.chenyang.druid.sql.ast.statement.SQLUnionQuery;
import com.chenyang.druid.sql.ast.statement.SQLUnionQueryTableSource;
import com.chenyang.druid.sql.ast.statement.SQLUnique;
import com.chenyang.druid.sql.ast.statement.SQLUniqueConstraint;
import com.chenyang.druid.sql.ast.statement.SQLUnnestTableSource;
import com.chenyang.druid.sql.ast.statement.SQLUpdateSetItem;
import com.chenyang.druid.sql.ast.statement.SQLUpdateStatement;
import com.chenyang.druid.sql.ast.statement.SQLUseStatement;
import com.chenyang.druid.sql.ast.statement.SQLValuesQuery;
import com.chenyang.druid.sql.ast.statement.SQLValuesTableSource;
import com.chenyang.druid.sql.ast.statement.SQLWhileStatement;
import com.chenyang.druid.sql.ast.statement.SQLWhoamiStatement;
import com.chenyang.druid.sql.ast.statement.SQLWithSubqueryClause;
import com.chenyang.druid.sql.dialect.hive.ast.stmt.HiveCreateTableStatement;
import com.chenyang.druid.sql.dialect.mysql.ast.MySqlPrimaryKey;
import com.chenyang.druid.sql.dialect.mysql.ast.clause.MySqlTableTableSource;
import com.chenyang.druid.sql.dialect.mysql.ast.expr.MySqlOrderingExpr;
import com.chenyang.druid.sql.dialect.mysql.ast.statement.MySqlAlterDatabaseKillJob;
import com.chenyang.druid.sql.dialect.mysql.ast.statement.MySqlAlterDatabaseSetOption;
import com.chenyang.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
import com.chenyang.druid.sql.dialect.mysql.ast.statement.MySqlExtPartition;
import com.chenyang.druid.sql.dialect.mysql.ast.statement.MySqlKillStatement;
import com.chenyang.druid.sql.dialect.mysql.ast.statement.SQLAlterResourceGroupStatement;
import com.chenyang.druid.sql.dialect.mysql.ast.statement.SQLCreateResourceGroupStatement;
import com.chenyang.druid.sql.dialect.mysql.ast.statement.SQLListResourceGroupStatement;
import com.chenyang.druid.sql.dialect.oracle.ast.OracleSegmentAttributes;
import com.chenyang.druid.sql.dialect.oracle.ast.expr.OracleCursorExpr;
import com.chenyang.druid.sql.dialect.oracle.ast.expr.OracleDatetimeExpr;
import com.chenyang.druid.sql.dialect.oracle.ast.stmt.OracleCreatePackageStatement;
import com.chenyang.druid.sql.dialect.oracle.ast.stmt.OracleForStatement;
import com.chenyang.druid.sql.dialect.oracle.ast.stmt.OracleSelectPivot;
import com.chenyang.druid.sql.dialect.oracle.parser.OracleFunctionDataType;
import com.chenyang.druid.sql.dialect.oracle.parser.OracleProcedureDataType;
import com.chenyang.druid.util.FnvHash;
import com.chenyang.druid.util.JdbcUtils;
import com.chenyang.druid.util.Utils;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.NClob;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;

public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements ParameterizedVisitor, PrintableVisitor {
   public static Boolean defaultPrintStatementAfterSemi;
   protected final Appendable appender;
   protected int indentCount = 0;
   protected boolean ucase = true;
   protected int selectListNumberOfLine = 5;
   protected boolean groupItemSingleLine = false;
   protected List<Object> parameters;
   protected List<Object> inputParameters;
   protected Set<String> tables;
   protected String table;
   protected boolean exportTables = false;
   protected DbType dbType;
   protected Map<String, String> tableMapping;
   protected int replaceCount;
   protected boolean parameterizedMergeInList = false;
   protected boolean parameterizedQuesUnMergeInList = false;
   protected boolean parameterizedQuesUnMergeValuesList = false;
   protected boolean printNameQuote = false;
   protected char quote = '"';
   protected boolean parameterized = false;
   protected boolean shardingSupport = false;
   protected transient int lines = 0;
   private TimeZone timeZone;
   protected Boolean printStatementAfterSemi;
   private static final Integer ONE;
   static String[] variantValuesCache_1;
   static String[] variantValuesCache;

   public SQLASTOutputVisitor(Appendable appender) {
      this.printStatementAfterSemi = defaultPrintStatementAfterSemi;
      this.features |= VisitorFeature.OutputPrettyFormat.mask;
      this.appender = appender;
   }

   public SQLASTOutputVisitor(Appendable appender, DbType dbType) {
      this.printStatementAfterSemi = defaultPrintStatementAfterSemi;
      this.features |= VisitorFeature.OutputPrettyFormat.mask;
      this.appender = appender;
      this.dbType = dbType;
   }

   public SQLASTOutputVisitor(Appendable appender, boolean parameterized) {
      this.printStatementAfterSemi = defaultPrintStatementAfterSemi;
      this.features |= VisitorFeature.OutputPrettyFormat.mask;
      this.appender = appender;
      this.config(VisitorFeature.OutputParameterized, parameterized);
   }

   public int getReplaceCount() {
      return this.replaceCount;
   }

   public void incrementReplaceCunt() {
      ++this.replaceCount;
   }

   public TimeZone getTimeZone() {
      return this.timeZone;
   }

   public void setTimeZone(TimeZone timeZone) {
      this.timeZone = timeZone;
   }

   public void addTableMapping(String srcTable, String destTable) {
      if (this.tableMapping == null) {
         this.tableMapping = new HashMap();
      }

      if (srcTable.indexOf(46) >= 0) {
         SQLExpr expr = SQLUtils.toSQLExpr(srcTable, this.dbType);
         if (expr instanceof SQLPropertyExpr) {
            srcTable = ((SQLPropertyExpr)expr).simplify().toString();
         }
      } else {
         srcTable = SQLUtils.normalize(srcTable);
      }

      this.tableMapping.put(srcTable, destTable);
   }

   public void setTableMapping(Map<String, String> tableMapping) {
      this.tableMapping = tableMapping;
   }

   public List<Object> getParameters() {
      if (this.parameters == null) {
         this.parameters = new ArrayList();
      }

      return this.parameters;
   }

   public boolean isDesensitize() {
      return this.isEnabled(VisitorFeature.OutputDesensitize);
   }

   public void setDesensitize(boolean desensitize) {
      this.config(VisitorFeature.OutputDesensitize, desensitize);
   }

   public Set<String> getTables() {
      return this.table != null && this.tables == null ? Collections.singleton(this.table) : this.tables;
   }

   /** @deprecated */
   @Deprecated
   public void setParameters(List<Object> parameters) {
      if (parameters != null && parameters.size() > 0) {
         this.inputParameters = parameters;
      } else {
         this.parameters = parameters;
      }

   }

   public void setInputParameters(List<Object> parameters) {
      this.inputParameters = parameters;
   }

   public void setOutputParameters(List<Object> parameters) {
      this.parameters = parameters;
   }

   public int getIndentCount() {
      return this.indentCount;
   }

   public Appendable getAppender() {
      return this.appender;
   }

   public boolean isPrettyFormat() {
      return this.isEnabled(VisitorFeature.OutputPrettyFormat);
   }

   public void setPrettyFormat(boolean prettyFormat) {
      this.config(VisitorFeature.OutputPrettyFormat, prettyFormat);
   }

   public void decrementIndent() {
      --this.indentCount;
   }

   public void incrementIndent() {
      ++this.indentCount;
   }

   public boolean isParameterized() {
      return this.isEnabled(VisitorFeature.OutputParameterized);
   }

   public void setParameterized(boolean parameterized) {
      this.config(VisitorFeature.OutputParameterized, parameterized);
   }

   public boolean isParameterizedMergeInList() {
      return this.parameterizedMergeInList;
   }

   public void setParameterizedMergeInList(boolean parameterizedMergeInList) {
      this.parameterizedMergeInList = parameterizedMergeInList;
   }

   public boolean isParameterizedQuesUnMergeInList() {
      return this.parameterizedQuesUnMergeInList;
   }

   public void setParameterizedQuesUnMergeInList(boolean parameterizedQuesUnMergeInList) {
      this.config(VisitorFeature.OutputParameterizedQuesUnMergeInList, parameterizedQuesUnMergeInList);
   }

   public boolean isExportTables() {
      return this.exportTables;
   }

   public void setExportTables(boolean exportTables) {
      this.exportTables = exportTables;
   }

   public void print(char value) {
      if (this.appender != null) {
         try {
            this.appender.append(value);
         } catch (IOException e) {
            throw new RuntimeException("print error", e);
         }
      }
   }

   public void print(int value) {
      if (this.appender != null) {
         if (this.appender instanceof StringBuffer) {
            ((StringBuffer)this.appender).append(value);
         } else if (this.appender instanceof StringBuilder) {
            ((StringBuilder)this.appender).append(value);
         } else {
            this.print0(Integer.toString(value));
         }

      }
   }

   public void print(long value) {
      if (this.appender != null) {
         if (this.appender instanceof StringBuilder) {
            ((StringBuilder)this.appender).append(value);
         } else if (this.appender instanceof StringBuffer) {
            ((StringBuffer)this.appender).append(value);
         } else {
            this.print0(Long.toString(value));
         }

      }
   }

   public void print(float value) {
      if (this.appender != null) {
         if (this.appender instanceof StringBuilder) {
            ((StringBuilder)this.appender).append(value);
         } else if (this.appender instanceof StringBuffer) {
            ((StringBuffer)this.appender).append(value);
         } else {
            this.print0(Float.toString(value));
         }

      }
   }

   public void print(double value) {
      if (this.appender != null) {
         if (this.appender instanceof StringBuilder) {
            ((StringBuilder)this.appender).append(value);
         } else if (this.appender instanceof StringBuffer) {
            ((StringBuffer)this.appender).append(value);
         } else {
            this.print0(Double.toString(value));
         }

      }
   }

   public void print(Date date) {
      if (this.appender != null) {
         SimpleDateFormat dateFormat;
         if (date instanceof java.sql.Date) {
            dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            this.print0("DATE ");
         } else {
            dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
            this.print0("TIMESTAMP ");
         }

         if (this.timeZone != null) {
            dateFormat.setTimeZone(this.timeZone);
         }

         this.print0("'" + dateFormat.format(date) + "'");
      }
   }

   public void print(String text) {
      if (this.appender != null) {
         this.print0(text);
      }
   }

   protected void print0(String text) {
      if (this.appender != null) {
         try {
            this.appender.append(text);
         } catch (IOException e) {
            throw new RuntimeException("println error", e);
         }
      }
   }

   protected void printUcase(String text) {
      this.print0(this.ucase ? text.toUpperCase() : text.toLowerCase());
   }

   protected void printName0(String text) {
      if (this.appender != null && text != null && text.length() != 0) {
         try {
            if (this.printNameQuote) {
               char c0 = text.charAt(0);
               if (c0 == this.quote) {
                  this.appender.append(text);
               } else if (c0 == '"' && text.charAt(text.length() - 1) == '"') {
                  this.appender.append(this.quote);
                  this.appender.append(text.substring(1, text.length() - 1));
                  this.appender.append(this.quote);
               } else if (c0 == '`' && text.charAt(text.length() - 1) == '`') {
                  this.appender.append(this.quote);
                  this.appender.append(text.substring(1, text.length() - 1));
                  this.appender.append(this.quote);
               } else {
                  this.appender.append(this.quote);
                  this.appender.append(text);
                  this.appender.append(this.quote);
               }
            } else {
               this.appender.append(text);
            }

         } catch (IOException e) {
            throw new RuntimeException("println error", e);
         }
      }
   }

   protected void printAlias(String alias) {
      if (alias != null && alias.length() != 0) {
         this.print(' ');

         try {
            this.appender.append(alias);
         } catch (IOException e) {
            throw new RuntimeException("println error", e);
         }
      }
   }

   protected void printAndAccept(List<? extends SQLObject> nodes, String seperator) {
      int i = 0;

      for(int size = nodes.size(); i < size; ++i) {
         if (i != 0) {
            this.print0(seperator);
         }

         ((SQLObject)nodes.get(i)).accept(this);
      }

   }

   protected void printAndAccept(List<? extends SQLExpr> nodes, String seperator, boolean parameterized) {
      int i = 0;

      for(int size = nodes.size(); i < size; ++i) {
         if (i != 0) {
            this.print0(seperator);
         }

         this.printExpr((SQLExpr)nodes.get(i), parameterized);
      }

   }

   private static int paramCount(SQLExpr x) {
      if (x instanceof SQLName) {
         return 1;
      } else if (x instanceof SQLAggregateExpr) {
         SQLAggregateExpr aggregateExpr = (SQLAggregateExpr)x;
         List<SQLExpr> args = aggregateExpr.getArguments();
         int paramCount = 1;

         for(SQLExpr arg : args) {
            paramCount += paramCount(arg);
         }

         if (aggregateExpr.getOver() != null) {
            ++paramCount;
         }

         return paramCount;
      } else if (!(x instanceof SQLMethodInvokeExpr)) {
         if (x instanceof SQLBinaryOpExpr) {
            return paramCount(((SQLBinaryOpExpr)x).getLeft()) + paramCount(((SQLBinaryOpExpr)x).getRight());
         } else {
            return x instanceof SQLCaseExpr ? 10 : 1;
         }
      } else {
         List<SQLExpr> params = ((SQLMethodInvokeExpr)x).getArguments();
         int paramCount = 1;

         for(SQLExpr param : params) {
            paramCount += paramCount(param);
         }

         return paramCount;
      }
   }

   protected void printSelectList(List<SQLSelectItem> selectList) {
      ++this.indentCount;
      int i = 0;
      int lineItemCount = 0;

      for(int size = selectList.size(); i < size; ++lineItemCount) {
         SQLSelectItem selectItem = (SQLSelectItem)selectList.get(i);
         SQLExpr selectItemExpr = selectItem.getExpr();
         int paramCount = paramCount(selectItemExpr);
         boolean methodOrBinary = !(selectItemExpr instanceof SQLName) && (selectItemExpr instanceof SQLMethodInvokeExpr || selectItemExpr instanceof SQLAggregateExpr || selectItemExpr instanceof SQLBinaryOpExpr);
         if (methodOrBinary) {
            lineItemCount += paramCount - 1;
         }

         if (i != 0) {
            SQLSelectItem preSelectItem = (SQLSelectItem)selectList.get(i - 1);
            if (preSelectItem.getAfterCommentsDirect() != null) {
               lineItemCount = 0;
               this.println();
            } else if (methodOrBinary) {
               if (lineItemCount >= this.selectListNumberOfLine) {
                  lineItemCount = paramCount;
                  this.println();
               }
            } else if (lineItemCount >= this.selectListNumberOfLine || selectItemExpr instanceof SQLQueryExpr || selectItemExpr instanceof SQLCaseExpr || selectItemExpr instanceof SQLCharExpr && ((SQLCharExpr)selectItemExpr).getText().length() > 20) {
               lineItemCount = 0;
               this.println();
            }

            this.print0(", ");
         }

         if (selectItem.getClass() == SQLSelectItem.class) {
            this.visit(selectItem);
         } else {
            selectItem.accept(this);
         }

         if (selectItem.hasAfterComment()) {
            this.print(' ');
            this.printlnComment(selectItem.getAfterCommentsDirect());
         }

         ++i;
      }

      --this.indentCount;
   }

   protected void printlnAndAccept(List<? extends SQLObject> nodes, String seperator) {
      int i = 0;

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

         ((SQLObject)nodes.get(i)).accept(this);
      }

   }

   protected void printIndent() {
      if (this.appender != null) {
         try {
            for(int i = 0; i < this.indentCount; ++i) {
               this.appender.append('\t');
            }

         } catch (IOException e) {
            throw new RuntimeException("print error", e);
         }
      }
   }

   public void println() {
      if (!this.isPrettyFormat()) {
         this.print(' ');
      } else {
         this.print('\n');
         ++this.lines;
         this.printIndent();
      }
   }

   public void println(String text) {
      this.print(text);
      this.println();
   }

   public boolean visit(SQLBetweenExpr x) {
      SQLExpr testExpr = x.getTestExpr();
      SQLExpr beginExpr = x.getBeginExpr();
      SQLExpr endExpr = x.getEndExpr();
      boolean quote = false;
      if (testExpr instanceof SQLBinaryOpExpr) {
         SQLBinaryOperator operator = ((SQLBinaryOpExpr)testExpr).getOperator();
         switch (operator) {
            case BooleanAnd:
            case BooleanOr:
            case BooleanXor:
            case Assignment:
               quote = true;
               break;
            default:
               quote = ((SQLBinaryOpExpr)testExpr).isBracket();
         }
      } else if (testExpr instanceof SQLInListExpr || testExpr instanceof SQLBetweenExpr || testExpr instanceof SQLNotExpr || testExpr instanceof SQLUnaryExpr || testExpr instanceof SQLCaseExpr || testExpr instanceof SQLBinaryOpExprGroup) {
         quote = true;
      }

      if (testExpr != null) {
         if (quote) {
            this.print('(');
            this.printExpr(testExpr, this.parameterized);
            this.print(')');
         } else {
            this.printExpr(testExpr, this.parameterized);
         }
      }

      if (x.isNot()) {
         this.print0(this.ucase ? " NOT BETWEEN " : " not between ");
      } else {
         this.print0(this.ucase ? " BETWEEN " : " between ");
      }

      int lines = this.lines;
      if (beginExpr instanceof SQLBinaryOpExpr) {
         SQLBinaryOpExpr binaryOpBegin = (SQLBinaryOpExpr)beginExpr;
         this.incrementIndent();
         if (!binaryOpBegin.isBracket() && !binaryOpBegin.getOperator().isLogical() && !binaryOpBegin.getOperator().isRelational()) {
            this.printExpr(beginExpr, this.parameterized);
         } else {
            this.print('(');
            this.printExpr(beginExpr, this.parameterized);
            this.print(')');
         }

         this.decrementIndent();
      } else if (!(beginExpr instanceof SQLInListExpr) && !(beginExpr instanceof SQLBetweenExpr) && !(beginExpr instanceof SQLNotExpr) && !(beginExpr instanceof SQLUnaryExpr) && !(beginExpr instanceof SQLCaseExpr) && !(beginExpr instanceof SQLBinaryOpExprGroup)) {
         this.printExpr(beginExpr, this.parameterized);
      } else {
         this.print('(');
         this.printExpr(beginExpr, this.parameterized);
         this.print(')');
      }

      if (lines != this.lines) {
         this.println();
         this.print0(this.ucase ? "AND " : "and ");
      } else {
         this.print0(this.ucase ? " AND " : " and ");
      }

      if (endExpr instanceof SQLBinaryOpExpr) {
         SQLBinaryOpExpr binaryOpEnd = (SQLBinaryOpExpr)endExpr;
         this.incrementIndent();
         if (!binaryOpEnd.isBracket() && !binaryOpEnd.getOperator().isLogical() && !binaryOpEnd.getOperator().isRelational()) {
            this.printExpr(endExpr, this.parameterized);
         } else {
            this.print('(');
            this.printExpr(endExpr, this.parameterized);
            this.print(')');
         }

         this.decrementIndent();
      } else if (!(endExpr instanceof SQLInListExpr) && !(endExpr instanceof SQLBetweenExpr) && !(endExpr instanceof SQLNotExpr) && !(endExpr instanceof SQLUnaryExpr) && !(endExpr instanceof SQLCaseExpr) && !(endExpr instanceof SQLBinaryOpExprGroup)) {
         this.printExpr(endExpr, this.parameterized);
      } else {
         this.print('(');
         this.printExpr(endExpr, this.parameterized);
         this.print(')');
      }

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

      return false;
   }

   public boolean visit(SQLBinaryOpExprGroup x) {
      SQLObject parent = x.getParent();
      SQLBinaryOperator operator = x.getOperator();
      boolean isRoot = parent instanceof SQLSelectQueryBlock || parent instanceof SQLBinaryOpExprGroup;
      List<SQLExpr> items = x.getItems();
      if (items.size() == 0) {
         this.print("true");
         return false;
      } else {
         if (isRoot) {
            ++this.indentCount;
         }

         if (this.parameterized) {
            SQLExpr firstLeft = null;
            SQLBinaryOperator firstOp = null;
            List<Object> parameters = new ArrayList(items.size());
            List<SQLBinaryOpExpr> literalItems = null;
            if ((operator != SQLBinaryOperator.BooleanOr || !this.isEnabled(VisitorFeature.OutputParameterizedQuesUnMergeOr)) && (operator != SQLBinaryOperator.BooleanAnd || !this.isEnabled(VisitorFeature.OutputParameterizedQuesUnMergeAnd))) {
               for(int i = 0; i < items.size(); ++i) {
                  SQLExpr item = (SQLExpr)items.get(i);
                  if (!(item instanceof SQLBinaryOpExpr)) {
                     firstLeft = null;
                     break;
                  }

                  SQLBinaryOpExpr binaryItem = (SQLBinaryOpExpr)item;
                  SQLExpr left = binaryItem.getLeft();
                  SQLExpr right = binaryItem.getRight();
                  if (right instanceof SQLLiteralExpr && !(right instanceof SQLNullExpr)) {
                     if (left instanceof SQLLiteralExpr) {
                        if (literalItems == null) {
                           literalItems = new ArrayList();
                        }

                        literalItems.add(binaryItem);
                        continue;
                     }

                     if (this.parameters != null) {
                        ExportParameterVisitorUtils.exportParameter(parameters, right);
                     }
                  } else if (!(right instanceof SQLVariantRefExpr)) {
                     firstLeft = null;
                     break;
                  }

                  if (firstLeft == null) {
                     firstLeft = binaryItem.getLeft();
                     firstOp = binaryItem.getOperator();
                  } else if (firstOp != binaryItem.getOperator() || !SQLExprUtils.equals(firstLeft, left)) {
                     firstLeft = null;
                     break;
                  }
               }
            }

            if (firstLeft != null) {
               if (literalItems != null) {
                  for(SQLBinaryOpExpr literalItem : literalItems) {
                     this.visit(literalItem);
                     this.println();
                     this.printOperator(operator);
                     this.print(' ');
                  }
               }

               this.printExpr(firstLeft, this.parameterized);
               this.print(' ');
               this.printOperator(firstOp);
               this.print0(" ?");
               if (this.parameters != null && parameters.size() > 0) {
                  this.parameters.addAll(parameters);
               }

               this.incrementReplaceCunt();
               if (isRoot) {
                  --this.indentCount;
               }

               return false;
            }
         }

         for(int i = 0; i < items.size(); ++i) {
            SQLExpr item = (SQLExpr)items.get(i);
            if (i != 0) {
               this.println();
               this.printOperator(operator);
               this.print(' ');
            }

            if (item.hasBeforeComment()) {
               this.printlnComments(item.getBeforeCommentsDirect());
            }

            if (item instanceof SQLBinaryOpExpr) {
               SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr)item;
               SQLExpr binaryOpExprRight = binaryOpExpr.getRight();
               SQLBinaryOperator itemOp = binaryOpExpr.getOperator();
               boolean isLogic = itemOp.isLogical();
               if (isLogic) {
                  ++this.indentCount;
               }

               boolean bracket;
               if (itemOp.priority > operator.priority) {
                  bracket = true;
               } else {
                  bracket = binaryOpExpr.isBracket() & !this.parameterized;
               }

               if (bracket) {
                  this.print('(');
                  this.visit(binaryOpExpr);
                  this.print(')');
               } else {
                  this.visit(binaryOpExpr);
               }

               if (item.hasAfterComment() && !this.parameterized) {
                  this.print(' ');
                  this.printlnComment(item.getAfterCommentsDirect());
               }

               if (isLogic) {
                  --this.indentCount;
               }
            } else if (item instanceof SQLBinaryOpExprGroup) {
               this.print('(');
               this.visit((SQLBinaryOpExprGroup)item);
               this.print(')');
            } else {
               this.printExpr(item, this.parameterized);
            }
         }

         if (isRoot) {
            --this.indentCount;
         }

         return false;
      }
   }

   public boolean visit(SQLBinaryOpExpr x) {
      SQLBinaryOperator operator = x.getOperator();
      if (this.parameterized && operator == SQLBinaryOperator.BooleanOr && !this.isEnabled(VisitorFeature.OutputParameterizedQuesUnMergeOr)) {
         x = SQLBinaryOpExpr.merge(this, x);
         operator = x.getOperator();
      }

      if (this.inputParameters != null && this.inputParameters.size() > 0 && operator == SQLBinaryOperator.Equality && x.getRight() instanceof SQLVariantRefExpr) {
         SQLVariantRefExpr right = (SQLVariantRefExpr)x.getRight();
         int index = right.getIndex();
         if (index >= 0 && index < this.inputParameters.size()) {
            Object param = this.inputParameters.get(index);
            if (param instanceof Collection) {
               x.getLeft().accept(this);
               this.print0(" IN (");
               right.accept(this);
               this.print(')');
               return false;
            }
         }
      }

      SQLObject parent = x.getParent();
      boolean isRoot = parent instanceof SQLSelectQueryBlock;
      boolean relational = operator == SQLBinaryOperator.BooleanAnd || operator == SQLBinaryOperator.BooleanOr;
      if (isRoot && relational) {
         ++this.indentCount;
      }

      List<SQLExpr> groupList = new ArrayList();
      SQLExpr left = x.getLeft();
      SQLExpr right = x.getRight();
      if (this.inputParameters != null && operator != SQLBinaryOperator.Equality) {
         int varIndex = -1;
         if (right instanceof SQLVariantRefExpr) {
            varIndex = ((SQLVariantRefExpr)right).getIndex();
         }

         Object param = null;
         if (varIndex >= 0 && varIndex < this.inputParameters.size()) {
            param = this.inputParameters.get(varIndex);
         }

         if (param instanceof Collection) {
            Collection values = (Collection)param;
            if (values.size() > 0) {
               this.print('(');
               int valIndex = 0;

               for(Object value : values) {
                  if (valIndex++ != 0) {
                     this.print0(this.ucase ? " OR " : " or ");
                  }

                  this.printExpr(left, this.parameterized);
                  this.print(' ');
                  if (operator == SQLBinaryOperator.Is) {
                     this.print('=');
                  } else {
                     this.printOperator(operator);
                  }

                  this.print(' ');
                  this.printParameter(value);
               }

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

      if (operator.isRelational() && left instanceof SQLIntegerExpr && right instanceof SQLIntegerExpr) {
         this.print(((SQLIntegerExpr)left).getNumber().longValue());
         this.print(' ');
         this.printOperator(operator);
         this.print(' ');
         Number number = ((SQLIntegerExpr)right).getNumber();
         if (number instanceof BigInteger) {
            this.print0(((BigInteger)number).toString());
         } else {
            this.print(number.longValue());
         }

         return false;
      } else {
         while(left instanceof SQLBinaryOpExpr && ((SQLBinaryOpExpr)left).getOperator() == operator && operator != SQLBinaryOperator.IsNot && operator != SQLBinaryOperator.Is) {
            SQLBinaryOpExpr binaryLeft = (SQLBinaryOpExpr)left;
            groupList.add(binaryLeft.getRight());
            left = binaryLeft.getLeft();
         }

         groupList.add(left);

         for(int var19 = groupList.size() - 1; var19 >= 0; --var19) {
            SQLExpr item = (SQLExpr)groupList.get(var19);
            if (relational && this.isPrettyFormat() && item.hasBeforeComment() && !this.parameterized) {
               this.printlnComments(item.getBeforeCommentsDirect());
            }

            if (this.isPrettyFormat() && item.hasBeforeComment() && !this.parameterized) {
               this.printlnComments(item.getBeforeCommentsDirect());
            }

            this.visitBinaryLeft(item, operator);
            if (this.isPrettyFormat() && item.hasAfterComment()) {
               this.print(' ');
               this.printlnComment(item.getAfterCommentsDirect());
            }

            if (var19 != groupList.size() - 1 && this.isPrettyFormat() && item.getParent() != null && item.getParent().hasAfterComment() && !this.parameterized) {
               this.print(' ');
               this.printlnComment(item.getParent().getAfterCommentsDirect());
            }

            boolean printOpSpace = true;
            if (relational) {
               this.println();
            } else {
               if (operator == SQLBinaryOperator.Modulus && DbType.oracle == this.dbType && left instanceof SQLIdentifierExpr && right instanceof SQLIdentifierExpr && ((SQLIdentifierExpr)right).getName().equalsIgnoreCase("NOTFOUND")) {
                  printOpSpace = false;
               }

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

            this.printOperator(operator);
            if (printOpSpace) {
               this.print(' ');
            }
         }

         this.visitorBinaryRight(x);
         if (isRoot && relational) {
            --this.indentCount;
         }

         return false;
      }
   }

   protected void printOperator(SQLBinaryOperator operator) {
      this.print0(this.ucase ? operator.name : operator.name_lcase);
   }

   private void visitorBinaryRight(SQLBinaryOpExpr x) {
      SQLExpr right = x.getRight();
      SQLBinaryOperator op = x.getOperator();
      if (this.isPrettyFormat() && right.hasBeforeComment()) {
         this.printlnComments(right.getBeforeCommentsDirect());
      }

      if (right instanceof SQLBinaryOpExpr) {
         SQLBinaryOpExpr binaryRight = (SQLBinaryOpExpr)right;
         SQLBinaryOperator rightOp = binaryRight.getOperator();
         boolean rightRational = rightOp == SQLBinaryOperator.BooleanAnd || rightOp == SQLBinaryOperator.BooleanOr;
         if (rightOp.priority >= op.priority || binaryRight.isBracket() && rightOp != op && rightOp.isLogical() && op.isLogical()) {
            if (rightRational) {
               ++this.indentCount;
            }

            this.print('(');
            this.printExpr(binaryRight, this.parameterized);
            this.print(')');
            if (rightRational) {
               --this.indentCount;
            }
         } else {
            this.printExpr(binaryRight, this.parameterized);
         }
      } else if (right instanceof SQLBinaryOpExprGroup) {
         SQLBinaryOpExprGroup group = (SQLBinaryOpExprGroup)right;
         if (group.getOperator() == x.getOperator()) {
            this.visit(group);
         } else {
            ++this.indentCount;
            this.print('(');
            this.visit(group);
            this.print(')');
            --this.indentCount;
         }
      } else if (SQLBinaryOperator.Equality.priority < op.priority || !(right instanceof SQLInListExpr) && !(right instanceof SQLBetweenExpr) && !(right instanceof SQLNotExpr)) {
         this.printExpr(right, this.parameterized);
      } else {
         ++this.indentCount;
         this.print('(');
         this.printExpr(right, this.parameterized);
         this.print(')');
         --this.indentCount;
      }

      if (right.hasAfterComment() && this.isPrettyFormat()) {
         this.print(' ');
         this.printlnComment(right.getAfterCommentsDirect());
      }

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

   }

   private void visitBinaryLeft(SQLExpr left, SQLBinaryOperator op) {
      if (left instanceof SQLBinaryOpExpr) {
         SQLBinaryOpExpr binaryLeft = (SQLBinaryOpExpr)left;
         SQLBinaryOperator leftOp = binaryLeft.getOperator();
         SQLObject parent = left.getParent();
         boolean leftRational = leftOp == SQLBinaryOperator.BooleanAnd || leftOp == SQLBinaryOperator.BooleanOr;
         boolean bracket;
         if (leftOp.priority > op.priority) {
            bracket = true;
         } else if (leftOp.priority == op.priority && parent instanceof SQLBinaryOpExpr && parent.getParent() instanceof SQLBinaryOpExpr && leftOp.priority == ((SQLBinaryOpExpr)parent.getParent()).getOperator().priority && left == ((SQLBinaryOpExpr)parent).getRight()) {
            bracket = true;
         } else if ((leftOp == SQLBinaryOperator.Is || leftOp == SQLBinaryOperator.IsNot) && !op.isLogical()) {
            bracket = true;
         } else if (!binaryLeft.isBracket()) {
            bracket = false;
         } else if (leftOp == op || (!leftOp.isLogical() || !op.isLogical()) && op != SQLBinaryOperator.Is) {
            bracket = false;
         } else {
            bracket = true;
         }

         if (bracket) {
            if (leftRational) {
               ++this.indentCount;
            }

            this.print('(');
            this.printExpr(left, this.parameterized);
            this.print(')');
            if (leftRational) {
               --this.indentCount;
            }
         } else {
            this.printExpr(left, this.parameterized);
         }
      } else if (left instanceof SQLBinaryOpExprGroup) {
         SQLBinaryOpExprGroup group = (SQLBinaryOpExprGroup)left;
         if (group.getOperator() == op) {
            this.visit(group);
         } else {
            ++this.indentCount;
            this.print('(');
            this.visit(group);
            this.print(')');
            --this.indentCount;
         }
      } else if (left instanceof SQLInListExpr) {
         SQLInListExpr inListExpr = (SQLInListExpr)left;
         boolean quote;
         if (inListExpr.isNot()) {
            quote = op.priority <= SQLBinaryOperator.Equality.priority;
         } else {
            quote = op.priority < SQLBinaryOperator.Equality.priority;
         }

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

         this.visit(inListExpr);
         if (quote) {
            this.print(')');
         }
      } else if (left instanceof SQLBetweenExpr) {
         SQLBetweenExpr betweenExpr = (SQLBetweenExpr)left;
         boolean quote;
         if (betweenExpr.isNot()) {
            quote = op.priority <= SQLBinaryOperator.Equality.priority;
         } else {
            quote = op.priority < SQLBinaryOperator.Equality.priority;
         }

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

         this.visit(betweenExpr);
         if (quote) {
            this.print(')');
         }
      } else if (left instanceof SQLNotExpr) {
         this.print('(');
         this.printExpr(left);
         this.print(')');
      } else if (left instanceof SQLUnaryExpr) {
         SQLUnaryExpr unary = (SQLUnaryExpr)left;
         boolean quote = true;
         switch (unary.getOperator()) {
            case BINARY:
               quote = false;
               break;
            case Plus:
            case Negative:
               quote = op.priority < SQLBinaryOperator.Add.priority;
         }

         if (quote) {
            this.print('(');
            this.printExpr(left);
            this.print(')');
         } else {
            this.printExpr(left);
         }
      } else {
         this.printExpr(left, this.parameterized);
      }

   }

   protected void printTableSource(SQLTableSource x) {
      Class<?> clazz = x.getClass();
      if (clazz == SQLJoinTableSource.class) {
         this.visit((SQLJoinTableSource)x);
      } else if (clazz == SQLExprTableSource.class) {
         this.visit((SQLExprTableSource)x);
      } else if (clazz == SQLSubqueryTableSource.class) {
         this.visit((SQLSubqueryTableSource)x);
      } else {
         x.accept(this);
      }

   }

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

   }

   protected final void printExpr(SQLExpr x) {
      this.printExpr(x, this.parameterized);
   }

   protected final void printExpr(SQLExpr x, boolean parameterized) {
      Class<?> clazz = x.getClass();
      if (clazz == SQLIdentifierExpr.class) {
         this.visit((SQLIdentifierExpr)x);
      } else if (clazz == SQLPropertyExpr.class) {
         this.visit((SQLPropertyExpr)x);
      } else if (clazz == SQLAllColumnExpr.class) {
         this.print('*');
      } else if (clazz == SQLAggregateExpr.class) {
         this.visit((SQLAggregateExpr)x);
      } else if (clazz == SQLBinaryOpExpr.class) {
         this.visit((SQLBinaryOpExpr)x);
      } else if (clazz == SQLCharExpr.class) {
         this.visit((SQLCharExpr)x, parameterized);
      } else if (clazz == SQLNullExpr.class) {
         this.visit((SQLNullExpr)x);
      } else if (clazz == SQLIntegerExpr.class) {
         this.printInteger((SQLIntegerExpr)x, parameterized);
      } else if (clazz == SQLNumberExpr.class) {
         this.visit((SQLNumberExpr)x);
      } else if (clazz == SQLMethodInvokeExpr.class) {
         this.visit((SQLMethodInvokeExpr)x);
      } else if (clazz == SQLVariantRefExpr.class) {
         this.visit((SQLVariantRefExpr)x);
      } else if (clazz == SQLBinaryOpExprGroup.class) {
         this.visit((SQLBinaryOpExprGroup)x);
      } else if (clazz == SQLCaseExpr.class) {
         this.visit((SQLCaseExpr)x);
      } else if (clazz == SQLInListExpr.class) {
         this.visit((SQLInListExpr)x);
      } else if (clazz == SQLNotExpr.class) {
         this.visit((SQLNotExpr)x);
      } else {
         x.accept(this);
      }

   }

   public boolean visit(SQLCaseExpr x) {
      ++this.indentCount;
      this.print0(this.ucase ? "CASE " : "case ");
      SQLExpr valueExpr = x.getValueExpr();
      if (valueExpr != null) {
         this.printExpr(valueExpr, this.parameterized);
      }

      List<SQLCaseExpr.Item> items = x.getItems();
      int i = 0;

      for(int size = items.size(); i < size; ++i) {
         this.println();
         this.visit((SQLCaseExpr.Item)items.get(i));
      }

      SQLExpr elExpr = x.getElseExpr();
      if (elExpr != null) {
         this.println();
         this.print0(this.ucase ? "ELSE " : "else ");
         if (elExpr instanceof SQLCaseExpr) {
            ++this.indentCount;
            this.println();
            this.visit((SQLCaseExpr)elExpr);
            --this.indentCount;
         } else {
            this.printExpr(elExpr, this.parameterized);
         }
      }

      --this.indentCount;
      this.println();
      this.print0(this.ucase ? "END" : "end");
      return false;
   }

   public boolean visit(SQLCaseExpr.Item x) {
      this.print0(this.ucase ? "WHEN " : "when ");
      SQLExpr conditionExpr = x.getConditionExpr();
      int lines = this.lines;
      ++this.indentCount;
      this.printExpr(conditionExpr, this.parameterized);
      --this.indentCount;
      if (lines != this.lines) {
         this.println();
      } else {
         this.print(' ');
      }

      this.print0(this.ucase ? "THEN " : "then ");
      SQLExpr valueExpr = x.getValueExpr();
      if (valueExpr instanceof SQLCaseExpr) {
         ++this.indentCount;
         this.println();
         this.visit((SQLCaseExpr)valueExpr);
         --this.indentCount;
      } else {
         ++this.indentCount;
         this.printExpr(valueExpr, this.parameterized);
         --this.indentCount;
      }

      return false;
   }

   public boolean visit(SQLCaseStatement x) {
      this.print0(this.ucase ? "CASE" : "case");
      SQLExpr valueExpr = x.getValueExpr();
      if (valueExpr != null) {
         this.print(' ');
         this.printExpr(valueExpr, this.parameterized);
      }

      ++this.indentCount;
      this.println();
      this.printlnAndAccept(x.getItems(), " ");
      if (x.getElseStatements().size() > 0) {
         this.println();
         this.print0(this.ucase ? "ELSE " : "else ");
         this.printlnAndAccept(x.getElseStatements(), "");
      }

      --this.indentCount;
      this.println();
      this.print0(this.ucase ? "END CASE" : "end case");
      if (DbType.oracle == this.dbType) {
         this.print(';');
      }

      return false;
   }

   public boolean visit(SQLCaseStatement.Item x) {
      this.print0(this.ucase ? "WHEN " : "when ");
      this.printExpr(x.getConditionExpr(), this.parameterized);
      this.print0(this.ucase ? " THEN " : " then ");
      SQLStatement stmt = x.getStatement();
      if (stmt != null) {
         stmt.accept(this);
         this.print(';');
      }

      return false;
   }

   public boolean visit(SQLCastExpr x) {
      if (x.isTry()) {
         this.print0(this.ucase ? "TRY_CAST(" : "try_cast(");
      } else {
         this.print0(this.ucase ? "CAST(" : "cast(");
      }

      x.getExpr().accept(this);
      this.print0(this.ucase ? " AS " : " as ");
      x.getDataType().accept(this);
      this.print0(")");
      return false;
   }

   public boolean visit(SQLCharExpr x) {
      return this.visit(x, this.parameterized);
   }

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

         return false;
      } else {
         this.printChars(x.getText());
         return false;
      }
   }

   protected void printChars(String text) {
      if (text == null) {
         this.print0(this.ucase ? "NULL" : "null");
      } else {
         this.print('\'');
         int index = text.indexOf(39);
         if (index >= 0) {
            text = text.replaceAll("'", "''");
         }

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

   }

   public boolean visit(SQLDataType x) {
      this.printDataType(x);
      return false;
   }

   protected void printDataType(SQLDataType x) {
      boolean parameterized = this.parameterized;
      this.parameterized = false;
      this.print0(x.getName());
      List<SQLExpr> arguments = x.getArguments();
      if (arguments.size() > 0) {
         this.print('(');
         int i = 0;

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

            this.printExpr((SQLExpr)arguments.get(i), false);
         }

         this.print(')');
      }

      Boolean withTimeZone = x.getWithTimeZone();
      if (withTimeZone != null) {
         if (withTimeZone) {
            if (x.isWithLocalTimeZone()) {
               this.print0(this.ucase ? " WITH LOCAL TIME ZONE" : " with local time zone");
            } else {
               this.print0(this.ucase ? " WITH TIME ZONE" : " with time zone");
            }
         } else {
            this.print0(this.ucase ? " WITHOUT TIME ZONE" : " without time zone");
         }
      }

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

      this.parameterized = parameterized;
   }

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

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

      return false;
   }

   public boolean visit(SQLExistsExpr x) {
      if (x.isNot()) {
         this.print0(this.ucase ? "NOT EXISTS (" : "not exists (");
      } else {
         this.print0(this.ucase ? "EXISTS (" : "exists (");
      }

      ++this.indentCount;
      this.println();
      this.visit(x.getSubQuery());
      --this.indentCount;
      this.println();
      this.print(')');
      SQLCommentHint hint = x.getHint();
      if (hint != null) {
         this.print(' ');
         hint.accept(this);
      }

      return false;
   }

   public boolean visit(SQLIdentifierExpr x) {
      this.printName0(x.getName());
      return false;
   }

   private boolean printName(SQLName x, String name) {
      boolean shardingSupport = this.shardingSupport && this.parameterized;
      return this.printName(x, name, shardingSupport);
   }

   public String unwrapShardingTable(String name) {
      char c0 = name.charAt(0);
      char c_last = name.charAt(name.length() - 1);
      boolean quote = c0 == '`' && c_last == '`' || c0 == '"' && c_last == '"';
      int end = name.length();
      if (quote) {
         --end;
      }

      int num_cnt = 0;
      int postfixed_cnt = 0;

      for(int i = end - 1; i > 0; ++postfixed_cnt) {
         char ch = name.charAt(i);
         if (ch >= '0' && ch <= '9') {
            ++num_cnt;
         }

         if (ch != '_' && (ch < '0' || ch > '9')) {
            break;
         }

         --i;
      }

      if (num_cnt >= 1 && postfixed_cnt >= 2) {
         int start = end - postfixed_cnt;
         if (start < 1) {
            return name;
         } else {
            String realName = name.substring(quote ? 1 : 0, start);
            return realName;
         }
      } else {
         return name;
      }
   }

   private boolean printName(SQLName x, String name, boolean shardingSupport) {
      if (shardingSupport) {
         SQLObject parent = x.getParent();
         shardingSupport = parent instanceof SQLExprTableSource || parent instanceof SQLPropertyExpr;
         if (parent instanceof SQLPropertyExpr && parent.getParent() instanceof SQLExprTableSource) {
            shardingSupport = false;
         }
      }

      if (shardingSupport) {
         boolean quote = name.charAt(0) == '`' && name.charAt(name.length() - 1) == '`';
         String unwrappedName = this.unwrapShardingTable(name);
         if (unwrappedName != name) {
            boolean isAlias = false;

            for(SQLObject parent = x.getParent(); parent != null; parent = parent.getParent()) {
               if (parent instanceof SQLSelectQueryBlock) {
                  SQLTableSource from = ((SQLSelectQueryBlock)parent).getFrom();
                  if (quote) {
                     String name2 = name.substring(1, name.length() - 1);
                     if (this.isTableSourceAlias(from, name, name2)) {
                        isAlias = true;
                     }
                  } else if (this.isTableSourceAlias(from, name)) {
                     isAlias = true;
                  }
                  break;
               }
            }

            if (!isAlias) {
               this.print0(unwrappedName);
               this.incrementReplaceCunt();
               return false;
            }

            this.printName0(name);
            return false;
         }
      }

      this.printName0(name);
      return false;
   }

   public boolean visit(SQLInListExpr x) {
      SQLExpr expr = x.getExpr();
      boolean quote = false;
      if (expr instanceof SQLBinaryOpExpr) {
         SQLBinaryOperator operator = ((SQLBinaryOpExpr)expr).getOperator();
         switch (operator) {
            case BooleanAnd:
            case BooleanOr:
            case BooleanXor:
            case Assignment:
               quote = true;
               break;
            default:
               quote = ((SQLBinaryOpExpr)expr).isBracket();
         }
      } else if (expr instanceof SQLNotExpr || expr instanceof SQLBetweenExpr || expr instanceof SQLInListExpr || expr instanceof SQLUnaryExpr || expr instanceof SQLBinaryOpExprGroup) {
         quote = true;
      }

      if (this.parameterized) {
         List<SQLExpr> targetList = x.getTargetList();
         boolean allLiteral = true;

         for(SQLExpr item : targetList) {
            if (!(item instanceof SQLLiteralExpr) && !(item instanceof SQLVariantRefExpr)) {
               if (!(item instanceof SQLListExpr)) {
                  allLiteral = false;
                  break;
               }

               SQLListExpr list = (SQLListExpr)item;

               for(SQLExpr listItem : list.getItems()) {
                  if (!(listItem instanceof SQLLiteralExpr) && !(listItem instanceof SQLVariantRefExpr)) {
                     allLiteral = false;
                     break;
                  }
               }

               if (allLiteral) {
                  break;
               }
            }
         }

         if (allLiteral) {
            boolean changed = true;
            if (targetList.size() == 1 && targetList.get(0) instanceof SQLVariantRefExpr) {
               changed = false;
            }

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

            this.printExpr(expr, this.parameterized);
            if (quote) {
               this.print(')');
            }

            if (x.isNot()) {
               this.print(this.ucase ? " NOT IN" : " not in");
            } else {
               this.print(this.ucase ? " IN" : " in");
            }

            if (this.parameterizedQuesUnMergeInList && (targetList.size() != 1 || targetList.get(0) instanceof SQLListExpr)) {
               this.print(" (");

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

                  SQLExpr item = (SQLExpr)targetList.get(i);
                  if (item instanceof SQLListExpr) {
                     this.visit((SQLListExpr)item);
                     changed = false;
                  } else {
                     this.print("?");
                  }
               }

               this.print(")");
            } else {
               this.print(" (?)");
            }

            if (changed) {
               this.incrementReplaceCunt();
               if (this.parameters != null) {
                  if (this.parameterizedMergeInList) {
                     List<Object> subList = new ArrayList(x.getTargetList().size());

                     for(SQLExpr target : x.getTargetList()) {
                        ExportParameterVisitorUtils.exportParameter(subList, target);
                     }

                     if (subList != null) {
                        this.parameters.add(subList);
                     }
                  } else {
                     for(SQLExpr target : x.getTargetList()) {
                        ExportParameterVisitorUtils.exportParameter(this.parameters, target);
                     }
                  }
               }
            }

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

            return false;
         }
      }

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

      this.printExpr(expr, this.parameterized);
      if (quote) {
         this.print(')');
      }

      if (x.isNot()) {
         this.print0(this.ucase ? " NOT IN (" : " not in (");
      } else {
         this.print0(this.ucase ? " IN (" : " in (");
      }

      List<SQLExpr> list = x.getTargetList();
      boolean printLn = false;
      if (list.size() > 5) {
         printLn = true;
         int i = 0;

         for(int size = list.size(); i < size; ++i) {
            if (!(list.get(i) instanceof SQLCharExpr)) {
               printLn = false;
               break;
            }
         }
      }

      if (printLn) {
         ++this.indentCount;
         this.println();
         int i = 0;

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

            SQLExpr item = (SQLExpr)list.get(i);
            this.printExpr(item, this.parameterized);
         }

         --this.indentCount;
         this.println();
      } else {
         List<SQLExpr> targetList = x.getTargetList();

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

            this.printExpr((SQLExpr)targetList.get(i), this.parameterized);
         }
      }

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

      return false;
   }

   public boolean visit(SQLContainsExpr x) {
      SQLExpr expr = x.getExpr();
      if (expr != null) {
         this.printExpr(expr, this.parameterized);
         this.print(' ');
      }

      if (x.isNot()) {
         this.print0(this.ucase ? "NOT CONTAINS (" : " not contains (");
      } else {
         this.print0(this.ucase ? "CONTAINS (" : " contains (");
      }

      List<SQLExpr> list = x.getTargetList();
      boolean printLn = false;
      if (list.size() > 5) {
         printLn = true;
         int i = 0;

         for(int size = list.size(); i < size; ++i) {
            if (!(list.get(i) instanceof SQLCharExpr)) {
               printLn = false;
               break;
            }
         }
      }

      if (printLn) {
         ++this.indentCount;
         this.println();
         int i = 0;

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

            SQLExpr item = (SQLExpr)list.get(i);
            this.printExpr(item, this.parameterized);
         }

         --this.indentCount;
         this.println();
      } else {
         List<SQLExpr> targetList = x.getTargetList();

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

            this.printExpr((SQLExpr)targetList.get(i), this.parameterized);
         }
      }

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

   public boolean visit(SQLIntegerExpr x) {
      boolean parameterized = this.parameterized;
      this.printInteger(x, parameterized);
      return false;
   }

   protected void printInteger(SQLIntegerExpr x, boolean parameterized) {
      Number number = x.getNumber();
      if (number.equals(ONE) && DbType.oracle.equals(this.dbType)) {
         SQLObject parent = x.getParent();
         if (parent instanceof SQLBinaryOpExpr) {
            SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr)parent;
            SQLExpr left = binaryOpExpr.getLeft();
            SQLBinaryOperator op = binaryOpExpr.getOperator();
            if (left instanceof SQLIdentifierExpr && op == SQLBinaryOperator.Equality) {
               String name = ((SQLIdentifierExpr)left).getName();
               if ("rownum".equals(name)) {
                  this.print((int)1);
                  return;
               }
            }
         }
      }

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

      } else {
         if (!(number instanceof BigDecimal) && !(number instanceof BigInteger)) {
            this.print(number.longValue());
         } else {
            this.print(number.toString());
         }

      }
   }

   public boolean visit(SQLMethodInvokeExpr x) {
      SQLExpr owner = x.getOwner();
      if (owner != null) {
         this.printMethodOwner(owner);
      }

      if (this.parameterized) {
         List<SQLExpr> arguments = x.getArguments();
         if (x.methodNameHashCode64() == FnvHash.Constants.TRIM && arguments.size() == 1 && arguments.get(0) instanceof SQLCharExpr && x.getTrimOption() == null && x.getFrom() == null) {
            this.print('?');
            if (this.parameters != null) {
               SQLCharExpr charExpr = (SQLCharExpr)arguments.get(0);
               this.parameters.add(charExpr.getText().trim());
            }

            ++this.replaceCount;
            return false;
         }
      }

      String function = x.getMethodName();
      this.printFunctionName(function);
      this.printMethodParameters(x);
      return false;
   }

   protected void printMethodParameters(SQLMethodInvokeExpr x) {
      String function = x.getMethodName();
      List<SQLExpr> parameters = x.getArguments();
      this.print('(');
      String trimOption = x.getTrimOption();
      if (trimOption != null) {
         this.print0(trimOption);
         if (parameters.size() > 0) {
            this.print(' ');
         }
      }

      int i = 0;

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

         SQLExpr param = (SQLExpr)parameters.get(i);
         if (this.parameterized && size == 2 && i == 1 && param instanceof SQLCharExpr) {
            if (DbType.oracle == this.dbType) {
               if ("TO_CHAR".equalsIgnoreCase(function) || "TO_DATE".equalsIgnoreCase(function)) {
                  this.printChars(((SQLCharExpr)param).getText());
                  continue;
               }
            } else if (DbType.mysql == this.dbType && "DATE_FORMAT".equalsIgnoreCase(function)) {
               this.printChars(((SQLCharExpr)param).getText());
               continue;
            }
         }

         if (param instanceof SQLBinaryOpExpr) {
            SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr)param;
            SQLBinaryOperator op = binaryOpExpr.getOperator();
            if (op == SQLBinaryOperator.BooleanAnd || op == SQLBinaryOperator.BooleanOr) {
               ++this.indentCount;
               this.printExpr(param, this.parameterized);
               --this.indentCount;
               continue;
            }
         }

         this.printExpr(param, this.parameterized);
      }

      SQLExpr from = x.getFrom();
      if (from != null) {
         this.print0(this.ucase ? " FROM " : " from ");
         this.printExpr(from, this.parameterized);
         SQLExpr _for = x.getFor();
         if (_for != null) {
            this.print0(this.ucase ? " FOR " : " for ");
            this.printExpr(_for, this.parameterized);
         }
      }

      SQLExpr using = x.getUsing();
      boolean odpsTransformUsing = false;
      if (using != null) {
         odpsTransformUsing = x.methodNameHashCode64() == FnvHash.Constants.TRANSFORM;
         if (!odpsTransformUsing) {
            this.print0(this.ucase ? " USING " : " using ");
            this.printExpr(using, this.parameterized);
         }
      }

      if (x.methodNameHashCode64() == FnvHash.Constants.WEIGHT_STRING) {
         SQLDataType as = (SQLDataType)x.getAttribute("as");
         if (as != null) {
            this.print0(this.ucase ? " AS " : " as ");
            as.accept(this);
         }

         List<SQLSelectOrderByItem> levels = (List)x.getAttribute("levels");
         if (levels != null && levels.size() > 0) {
            this.print0(this.ucase ? " LEVEL " : " level ");
            this.printAndAccept(levels, ", ");
         }

         Boolean reverse = (Boolean)x.getAttribute("reverse");
         if (reverse != null) {
            this.print0(this.ucase ? " REVERSE" : " reverse");
         }
      }

      this.print(')');
      if (odpsTransformUsing) {
         this.print0(this.ucase ? " USING " : " using ");
         this.printExpr(using, this.parameterized);
      }

   }

   protected void printMethodOwner(SQLExpr owner) {
      this.printExpr(owner, this.parameterized);
      this.print('.');
   }

   protected void printFunctionName(String name) {
      this.print0(name);
   }

   public boolean visit(SQLAggregateExpr x) {
      boolean parameterized = this.parameterized;
      if (x.methodNameHashCode64() == FnvHash.Constants.GROUP_CONCAT) {
         this.parameterized = false;
      }

      if (x.methodNameHashCode64() == FnvHash.Constants.COUNT) {
         List<SQLExpr> arguments = x.getArguments();
         if (arguments.size() == 1) {
            SQLExpr arg0 = (SQLExpr)arguments.get(0);
            if (arg0 instanceof SQLLiteralExpr) {
               this.parameterized = false;
            }
         }
      }

      if (x.getOwner() != null) {
         this.printExpr(x.getOwner());
         this.print(".");
      }

      String methodName = x.getMethodName();
      this.print0(this.ucase ? methodName : methodName.toLowerCase());
      this.print('(');
      SQLAggregateOption option = x.getOption();
      if (option != null) {
         this.print0(option.toString());
         this.print(' ');
      }

      List<SQLExpr> arguments = x.getArguments();
      int i = 0;

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

         this.printExpr((SQLExpr)arguments.get(i), false);
      }

      boolean i1 = x.isWithinGroup();
      if (i1) {
         this.print0(this.ucase ? ") WITHIN GROUP (" : " within group (");
      }

      this.visitAggreateRest(x);
      this.print(')');
      if (x.isIgnoreNulls()) {
         this.print0(this.ucase ? " IGNORE NULLS" : " ignore nulls");
      }

      SQLKeep keep = x.getKeep();
      if (keep != null) {
         this.print(' ');
         this.visit(keep);
      }

      SQLOver over = x.getOver();
      if (over != null) {
         this.print0(this.ucase ? " OVER " : " over ");
         over.accept(this);
      }

      SQLName overRef = x.getOverRef();
      if (overRef != null) {
         this.print0(this.ucase ? " OVER " : " over ");
         overRef.accept(this);
      }

      SQLExpr filter = x.getFilter();
      if (filter != null) {
         this.print0(this.ucase ? " FILTER (WHERE " : " filter (where ");
         this.printExpr(filter);
         this.print(')');
      }

      this.parameterized = parameterized;
      return false;
   }

   protected void visitAggreateRest(SQLAggregateExpr x) {
      SQLOrderBy orderBy = x.getOrderBy();
      if (orderBy != null) {
         if (!x.isWithinGroup()) {
            this.print(' ');
         }

         orderBy.accept(this);
      }

   }

   public boolean visit(SQLAllColumnExpr x) {
      this.print('*');
      return true;
   }

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

         return false;
      } else {
         if (x.getText() != null && x.getText().length() != 0) {
            this.print0(this.ucase ? "N'" : "n'");
            this.print0(x.getText().replace("'", "''"));
            this.print('\'');
         } else {
            this.print0(this.ucase ? "NULL" : "null");
         }

         return false;
      }
   }

   public boolean visit(SQLNotExpr x) {
      this.print0(this.ucase ? "NOT " : "not ");
      SQLExpr expr = x.getExpr();
      boolean needQuote = false;
      if (expr instanceof SQLBinaryOpExpr) {
         SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr)expr;
         needQuote = binaryOpExpr.getOperator().isLogical();
      } else if (expr instanceof SQLInListExpr || expr instanceof SQLNotExpr || expr instanceof SQLBinaryOpExprGroup) {
         needQuote = true;
      }

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

      this.printExpr(expr, this.parameterized);
      if (needQuote) {
         this.print(')');
      }

      SQLCommentHint hint = x.getHint();
      if (hint != null) {
         hint.accept(this);
      }

      return false;
   }

   public boolean visit(SQLNullExpr x) {
      SQLObject parent = x.getParent();
      if (!this.parameterized || !(parent instanceof SQLInsertStatement.ValuesClause) && !(parent instanceof SQLInListExpr) && (!(parent instanceof SQLBinaryOpExpr) || ((SQLBinaryOpExpr)parent).getOperator() != SQLBinaryOperator.Equality)) {
         this.print0(this.ucase ? "NULL" : "null");
         return false;
      } else {
         this.print('?');
         this.incrementReplaceCunt();
         if (this.parameters != null) {
            if (parent instanceof SQLBinaryOpExpr) {
               ExportParameterVisitorUtils.exportParameter(this.getParameters(), (SQLExpr)x);
            } else {
               this.getParameters().add(null);
            }
         }

         return false;
      }
   }

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

         return false;
      } else {
         if (this.appender instanceof StringBuilder) {
            x.output((StringBuilder)this.appender);
         } else if (this.appender instanceof StringBuilder) {
            x.output((StringBuilder)this.appender);
         } else {
            this.print0(x.getNumber().toString());
         }

         return false;
      }
   }

   public boolean visit(SQLPropertyExpr x) {
      SQLExpr owner = x.getOwner();
      String mapTableName = null;
      String ownerName = null;
      if (owner instanceof SQLIdentifierExpr) {
         ownerName = ((SQLIdentifierExpr)owner).getName();
         if (this.tableMapping != null) {
            mapTableName = (String)this.tableMapping.get(ownerName);
            if (mapTableName == null && ownerName.length() > 2 && ownerName.charAt(0) == '`' && ownerName.charAt(ownerName.length() - 1) == '`') {
               ownerName = ownerName.substring(1, ownerName.length() - 1);
               mapTableName = (String)this.tableMapping.get(ownerName);
            }
         }
      }

      if (mapTableName != null) {
         for(SQLObject parent = x.getParent(); parent != null; parent = parent.getParent()) {
            if (parent instanceof SQLSelectQueryBlock) {
               SQLTableSource from = ((SQLSelectQueryBlock)parent).getFrom();
               if (this.isTableSourceAlias(from, mapTableName, ownerName)) {
                  mapTableName = null;
               }
               break;
            }
         }
      }

      if (mapTableName != null) {
         this.printName0(mapTableName);
      } else if (owner instanceof SQLIdentifierExpr) {
         SQLIdentifierExpr ownerIdent = (SQLIdentifierExpr)owner;
         this.printName(ownerIdent, ownerIdent.getName(), this.shardingSupport && this.parameterized);
      } else {
         this.printExpr(owner, this.parameterized);
      }

      this.print('.');
      String name = x.getName();
      if ("*".equals(name)) {
         this.print0(name);
      } else {
         this.printName0(name);
      }

      return false;
   }

   protected boolean isTableSourceAlias(SQLTableSource from, String... tableNames) {
      String alias = from.getAlias();
      if (alias != null) {
         for(String tableName : tableNames) {
            if (alias.equalsIgnoreCase(tableName)) {
               return true;
            }
         }

         if (alias.length() > 2 && alias.charAt(0) == '`' && alias.charAt(alias.length() - 1) == '`') {
            alias = alias.substring(1, alias.length() - 1);

            for(String tableName : tableNames) {
               if (alias.equalsIgnoreCase(tableName)) {
                  return true;
               }
            }
         }
      }

      if (!(from instanceof SQLJoinTableSource)) {
         return false;
      } else {
         SQLJoinTableSource join = (SQLJoinTableSource)from;
         return this.isTableSourceAlias(join.getLeft(), tableNames) || this.isTableSourceAlias(join.getRight(), tableNames);
      }
   }

   public boolean visit(SQLQueryExpr x) {
      SQLObject parent = x.getParent();
      if (parent instanceof SQLSelect) {
         parent = parent.getParent();
      }

      SQLSelect subQuery = x.getSubQuery();
      if (parent instanceof SQLInsertStatement.ValuesClause) {
         this.println();
         this.print('(');
         this.visit(subQuery);
         this.print(')');
         this.println();
      } else if ((!(parent instanceof SQLStatement) || parent instanceof OracleForStatement) && !(parent instanceof OracleSelectPivot.Item)) {
         if (parent instanceof SQLOpenStatement) {
            this.visit(subQuery);
         } else if (parent instanceof SQLDeclareItem && DbType.dm == this.dbType) {
            this.visit(subQuery);
         } else {
            this.print('(');
            ++this.indentCount;
            this.println();
            this.visit(subQuery);
            --this.indentCount;
            this.println();
            this.print(')');
         }
      } else {
         ++this.indentCount;
         this.println();
         this.visit(subQuery);
         --this.indentCount;
      }

      return false;
   }

   public boolean visit(SQLSelectGroupByClause x) {
      boolean paren = DbType.oracle == this.dbType || x.isParen();
      boolean rollup = x.isWithRollUp();
      boolean cube = x.isWithCube();
      List<SQLExpr> items = x.getItems();
      int itemSize = items.size();
      if (itemSize > 0) {
         this.print0(this.ucase ? "GROUP BY " : "group by ");
         if (x.isAll()) {
            this.print0(this.ucase ? "ALL " : "all ");
         }

         if (x.isDistinct()) {
            this.print0(this.ucase ? "DISTINCT " : "distinct ");
         }

         if (paren && rollup) {
            this.print0(this.ucase ? "ROLLUP (" : "rollup (");
         } else if (paren && cube) {
            this.print0(this.ucase ? "CUBE (" : "cube (");
         }

         ++this.indentCount;

         for(int i = 0; i < itemSize; ++i) {
            SQLExpr item = (SQLExpr)items.get(i);
            if (i != 0) {
               if (this.groupItemSingleLine) {
                  this.println(", ");
               } else if (item instanceof SQLGroupingSetExpr) {
                  this.println();
               } else {
                  this.print(", ");
               }
            }

            if (item instanceof SQLIntegerExpr) {
               this.printInteger((SQLIntegerExpr)item, false);
            } else if (item instanceof MySqlOrderingExpr && ((MySqlOrderingExpr)item).getExpr() instanceof SQLIntegerExpr) {
               MySqlOrderingExpr orderingExpr = (MySqlOrderingExpr)item;
               this.printInteger((SQLIntegerExpr)orderingExpr.getExpr(), false);
               this.print(' ' + orderingExpr.getType().name);
            } else {
               item.accept(this);
            }

            SQLCommentHint hint = null;
            if (item instanceof SQLExprImpl) {
               hint = ((SQLExprImpl)item).getHint();
            }

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

         if (paren && (rollup || cube)) {
            this.print(')');
         }

         --this.indentCount;
      }

      if (x.getHaving() != null) {
         this.println();
         this.print0(this.ucase ? "HAVING " : "having ");
         x.getHaving().accept(this);
      }

      if (x.isWithRollUp() && !paren) {
         this.print0(this.ucase ? " WITH ROLLUP" : " with rollup");
      }

      if (x.isWithCube() && !paren) {
         this.print0(this.ucase ? " WITH CUBE" : " with cube");
      }

      return false;
   }

   public boolean visit(SQLSelect x) {
      SQLHint headHint = x.getHeadHint();
      if (headHint != null) {
         headHint.accept(this);
         this.println();
      }

      SQLWithSubqueryClause withSubQuery = x.getWithSubQuery();
      if (withSubQuery != null) {
         withSubQuery.accept(this);
         this.println();
      }

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

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

      if (x.getHintsSize() > 0) {
         this.printAndAccept(x.getHints(), "");
      }

      return false;
   }

   public boolean visit(SQLSelectQueryBlock x) {
      if (this.isPrettyFormat() && x.hasBeforeComment()) {
         this.printlnComments(x.getBeforeCommentsDirect());
      }

      this.print0(this.ucase ? "SELECT " : "select ");
      if (x.getHintsSize() > 0) {
         this.printAndAccept(x.getHints(), ", ");
         this.print(' ');
      }

      boolean informix = DbType.informix == this.dbType;
      if (informix) {
         this.printFetchFirst(x);
      }

      int distinctOption = x.getDistionOption();
      if (1 == distinctOption) {
         this.print0(this.ucase ? "ALL " : "all ");
      } else if (2 == distinctOption) {
         this.print0(this.ucase ? "DISTINCT " : "distinct ");
      } else if (3 == distinctOption) {
         this.print0(this.ucase ? "UNIQUE " : "unique ");
      }

      this.printSelectList(x.getSelectList());
      SQLExprTableSource into = x.getInto();
      if (into != null) {
         this.println();
         this.print0(this.ucase ? "INTO " : "into ");
         into.accept(this);
      }

      SQLTableSource from = x.getFrom();
      if (from != null) {
         this.println();
         boolean printFrom = from instanceof SQLLateralViewTableSource && ((SQLLateralViewTableSource)from).getTableSource() == null;
         if (!printFrom) {
            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);
         if (where.hasAfterComment() && this.isPrettyFormat()) {
            this.print(' ');
            this.printlnComment(x.getWhere().getAfterCommentsDirect());
         }
      }

      this.printHierarchical(x);
      SQLSelectGroupByClause groupBy = x.getGroupBy();
      if (groupBy != null) {
         this.println();
         this.visit(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();
         orderBy.accept(this);
      }

      List<SQLSelectOrderByItem> distributeBy = x.getDistributeByDirect();
      if (distributeBy != null && distributeBy.size() > 0) {
         this.println();
         this.print0(this.ucase ? "DISTRIBUTE BY " : "distribute by ");
         this.printAndAccept(distributeBy, ", ");
      }

      List<SQLSelectOrderByItem> sortBy = x.getSortByDirect();
      if (sortBy != null && sortBy.size() > 0) {
         this.println();
         this.print0(this.ucase ? "SORT BY " : "sort by ");
         this.printAndAccept(sortBy, ", ");
      }

      List<SQLSelectOrderByItem> clusterBy = x.getClusterByDirect();
      if (clusterBy != null && clusterBy.size() > 0) {
         this.println();
         this.print0(this.ucase ? "CLUSTER BY " : "cluster by ");
         this.printAndAccept(clusterBy, ", ");
      }

      if (!informix) {
         this.printFetchFirst(x);
      }

      if (x.isForUpdate()) {
         this.println();
         this.print0(this.ucase ? "FOR UPDATE" : "for update");
      }

      return false;
   }

   protected void printFetchFirst(SQLSelectQueryBlock x) {
      SQLLimit limit = x.getLimit();
      if (limit != null) {
         SQLExpr offset = limit.getOffset();
         SQLExpr first = limit.getRowCount();
         if (DbType.informix == this.dbType) {
            if (offset != null) {
               this.print0(this.ucase ? "SKIP " : "skip ");
               offset.accept(this);
            }

            this.print0(this.ucase ? " FIRST " : " first ");
            first.accept(this);
            this.print(' ');
         } else if (DbType.db2 != this.dbType && DbType.oracle != this.dbType && DbType.sqlserver != this.dbType) {
            this.println();
            limit.accept(this);
         } else {
            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 (DbType.oracle == this.dbType && limit.isPercent()) {
                  this.print0(this.ucase ? " PERCENT ROWS ONLY" : " percent rows only");
               } else {
                  this.print0(this.ucase ? " ROWS ONLY" : " rows only");
               }
            }
         }

      }
   }

   public boolean visit(SQLSelectItem x) {
      if (x.isConnectByRoot()) {
         this.print0(this.ucase ? "CONNECT_BY_ROOT " : "connect_by_root ");
      }

      SQLExpr expr = x.getExpr();
      if (expr instanceof SQLIdentifierExpr) {
         this.printName0(((SQLIdentifierExpr)expr).getName());
      } else if (expr instanceof SQLPropertyExpr) {
         this.visit((SQLPropertyExpr)expr);
      } else {
         this.printExpr(expr, this.parameterized);
      }

      String alias = x.getAlias();
      if (alias != null && alias.length() > 0) {
         this.print0(this.ucase ? " AS " : " as ");
         char c0 = alias.charAt(0);
         boolean special = false;
         if (c0 != '"' && c0 != '\'' && c0 != '`' && c0 != '[') {
            for(int i = 1; i < alias.length(); ++i) {
               char ch = alias.charAt(i);
               if (ch < 256 && (ch < '0' || ch > '9') && (ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') && ch != '_' && ch != '$') {
                  special = true;
               }
            }
         }

         if (!this.printNameQuote && !special) {
            this.print0(alias);
         } else {
            this.print(this.quote);
            String unquoteAlias = null;
            if (c0 == '`' && alias.charAt(alias.length() - 1) == '`') {
               unquoteAlias = alias.substring(1, alias.length() - 1);
            } else if (c0 == '\'' && alias.charAt(alias.length() - 1) == '\'') {
               unquoteAlias = alias.substring(1, alias.length() - 1);
            } else if (c0 == '"' && alias.charAt(alias.length() - 1) == '"') {
               unquoteAlias = alias.substring(1, alias.length() - 1);
            } else {
               this.print0(alias);
            }

            if (unquoteAlias != null) {
               this.print0(unquoteAlias);
            }

            this.print(this.quote);
         }

         return false;
      } else {
         List<String> aliasList = x.getAliasList();
         if (aliasList == null) {
            return false;
         } else {
            this.println();
            this.print0(this.ucase ? "AS (" : "as (");
            int aliasSize = aliasList.size();
            if (aliasSize > 5) {
               ++this.indentCount;
               this.println();
            }

            for(int i = 0; i < aliasSize; ++i) {
               if (i != 0) {
                  if (aliasSize > 5) {
                     this.println(",");
                  } else {
                     this.print0(", ");
                  }
               }

               this.print0((String)aliasList.get(i));
            }

            if (aliasSize > 5) {
               --this.indentCount;
               this.println();
            }

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

   public boolean visit(SQLOrderBy x) {
      List<SQLSelectOrderByItem> items = x.getItems();
      if (items.size() > 0) {
         if (x.isSibings()) {
            this.print0(this.ucase ? "ORDER SIBLINGS BY " : "order siblings by ");
         } else {
            this.print0(this.ucase ? "ORDER BY " : "order by ");
         }

         int i = 0;

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

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

      return false;
   }

   public boolean visit(SQLSelectOrderByItem x) {
      SQLExpr expr = x.getExpr();
      if (expr instanceof SQLIntegerExpr) {
         this.print(((SQLIntegerExpr)expr).getNumber().longValue());
      } else {
         this.printExpr(expr, this.parameterized);
      }

      SQLOrderingSpecification type = x.getType();
      if (type != null) {
         this.print(' ');
         this.print0(this.ucase ? type.name : type.name_lcase);
      }

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

      SQLSelectOrderByItem.NullsOrderType nullsOrderType = x.getNullsOrderType();
      if (nullsOrderType != null) {
         this.print(' ');
         this.print0(nullsOrderType.toFormalString());
      }

      SQLCommentHint hint = x.getHint();
      if (hint != null) {
         this.visit(hint);
      }

      return false;
   }

   protected void addTable(String table) {
      if (this.tables == null) {
         if (this.table == null) {
            this.table = table;
            return;
         }

         this.tables = new LinkedHashSet();
         this.tables.add(this.table);
      }

      this.tables.add(table);
   }

   protected void printTableSourceExpr(SQLExpr expr) {
      if (this.exportTables) {
         this.addTable(expr.toString());
      }

      if (this.isEnabled(VisitorFeature.OutputDesensitize)) {
         String ident = null;
         if (expr instanceof SQLIdentifierExpr) {
            ident = ((SQLIdentifierExpr)expr).getName();
         } else if (expr instanceof SQLPropertyExpr) {
            SQLPropertyExpr propertyExpr = (SQLPropertyExpr)expr;
            propertyExpr.getOwner().accept(this);
            this.print('.');
            ident = propertyExpr.getName();
         }

         if (ident != null) {
            String desensitizeTable = SQLUtils.desensitizeTable(ident);
            this.print0(desensitizeTable);
            return;
         }
      }

      if (this.tableMapping != null && expr instanceof SQLName) {
         String tableName;
         if (expr instanceof SQLIdentifierExpr) {
            tableName = ((SQLIdentifierExpr)expr).normalizedName();
         } else if (expr instanceof SQLPropertyExpr) {
            tableName = ((SQLPropertyExpr)expr).normalizedName();
         } else {
            tableName = expr.toString();
         }

         String destTableName = (String)this.tableMapping.get(tableName);
         if (destTableName == null) {
            if (expr instanceof SQLPropertyExpr) {
               SQLPropertyExpr propertyExpr = (SQLPropertyExpr)expr;
               String propName = propertyExpr.getName();
               destTableName = (String)this.tableMapping.get(propName);
               if (destTableName == null && propName.length() > 2 && propName.charAt(0) == '`' && propName.charAt(propName.length() - 1) == '`') {
                  destTableName = (String)this.tableMapping.get(propName.substring(1, propName.length() - 1));
               }

               if (destTableName != null) {
                  propertyExpr.getOwner().accept(this);
                  this.print('.');
                  this.print(destTableName);
                  return;
               }
            } else if (expr instanceof SQLIdentifierExpr) {
               boolean quote = tableName.length() > 2 && tableName.charAt(0) == '`' && tableName.charAt(tableName.length() - 1) == '`';
               if (quote) {
                  destTableName = (String)this.tableMapping.get(tableName.substring(1, tableName.length() - 1));
               }
            }
         }

         if (destTableName != null) {
            this.printName0(destTableName);
            return;
         }
      }

      if (expr instanceof SQLIdentifierExpr) {
         SQLIdentifierExpr identifierExpr = (SQLIdentifierExpr)expr;
         String name = identifierExpr.getName();
         if (!this.parameterized) {
            this.printName0(name);
            return;
         }

         boolean shardingSupport = this.shardingSupport && this.parameterized;
         if (shardingSupport) {
            String nameUnwrappe = this.unwrapShardingTable(name);
            if (!name.equals(nameUnwrappe)) {
               this.incrementReplaceCunt();
            }

            this.printName0(nameUnwrappe);
         } else {
            this.printName0(name);
         }
      } else if (expr instanceof SQLPropertyExpr) {
         SQLPropertyExpr propertyExpr = (SQLPropertyExpr)expr;
         SQLExpr owner = propertyExpr.getOwner();
         if (owner instanceof SQLIdentifierExpr) {
            SQLIdentifierExpr identOwner = (SQLIdentifierExpr)owner;
            String ownerName = identOwner.getName();
            if (!this.parameterized) {
               this.printName0(identOwner.getName());
            } else {
               if (this.shardingSupport) {
                  ownerName = this.unwrapShardingTable(ownerName);
               }

               this.printName0(ownerName);
            }
         } else {
            this.printExpr(owner);
         }

         this.print('.');
         String name = propertyExpr.getName();
         if (!this.parameterized) {
            this.printName0(propertyExpr.getName());
            return;
         }

         boolean shardingSupport = this.shardingSupport && this.parameterized;
         if (shardingSupport) {
            String nameUnwrappe = this.unwrapShardingTable(name);
            if (!name.equals(nameUnwrappe)) {
               this.incrementReplaceCunt();
            }

            this.printName0(nameUnwrappe);
         } else {
            this.printName0(name);
         }
      } else if (expr instanceof SQLMethodInvokeExpr) {
         this.visit((SQLMethodInvokeExpr)expr);
      } else {
         expr.accept(this);
      }

   }

   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(')');
      }

      if (this.isPrettyFormat() && x.hasAfterComment()) {
         this.print(' ');
         this.printlnComment(x.getAfterCommentsDirect());
      }

      return false;
   }

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

      SQLSelect select = stmt.getSelect();
      if (select != null) {
         this.visit(select);
      }

      return false;
   }

   public boolean visit(SQLVariantRefExpr x) {
      int index = x.getIndex();
      if (index >= 0 && this.inputParameters != null && index < this.inputParameters.size()) {
         Object param = this.inputParameters.get(index);
         SQLObject parent = x.getParent();
         boolean in;
         if (parent instanceof SQLInListExpr) {
            in = true;
         } else if (parent instanceof SQLBinaryOpExpr) {
            SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr)parent;
            if (binaryOpExpr.getOperator() == SQLBinaryOperator.Equality) {
               in = true;
            } else {
               in = false;
            }
         } else {
            in = false;
         }

         if (in && param instanceof Collection) {
            boolean first = true;

            for(Object item : (Collection)param) {
               if (!first) {
                  this.print0(", ");
               }

               this.printParameter(item);
               first = false;
            }
         } else {
            this.printParameter(param);
         }

         return false;
      } else {
         this.print0(x.getName());
         return false;
      }
   }

   public void printParameter(Object param) {
      if (param == null) {
         this.print0(this.ucase ? "NULL" : "null");
      } else if (!(param instanceof Number) && !(param instanceof Boolean) && !(param instanceof Date)) {
         if (param instanceof String) {
            SQLCharExpr charExpr = new SQLCharExpr((String)param);
            this.visit(charExpr);
         } else if (param instanceof Date) {
            this.print((Date)param);
         } else if (param instanceof InputStream) {
            this.print0("'<InputStream>'");
         } else if (param instanceof Reader) {
            this.print0("'<Reader>'");
         } else if (param instanceof Blob) {
            this.print0("'<Blob>'");
         } else if (param instanceof NClob) {
            this.print0("'<NClob>'");
         } else if (param instanceof Clob) {
            this.print0("'<Clob>'");
         } else if (param instanceof byte[]) {
            byte[] bytes = (byte[])param;
            int bytesLen = bytes.length;
            char[] chars = new char[bytesLen * 2 + 3];
            chars[0] = 'x';
            chars[1] = '\'';

            for(int i = 0; i < bytes.length; ++i) {
               int a = bytes[i] & 255;
               int b0 = a >> 4;
               int b1 = a & 15;
               chars[i * 2 + 2] = (char)(b0 + (b0 < 10 ? 48 : 55));
               chars[i * 2 + 3] = (char)(b1 + (b1 < 10 ? 48 : 55));
            }

            chars[chars.length - 1] = '\'';
            this.print0(new String(chars));
         } else if (param instanceof Character) {
            this.print('\'');
            this.print((Character)param);
            this.print('\'');
         } else {
            this.print0("'" + param.getClass().getName() + "'");
         }
      } else {
         this.print0(param.toString());
      }
   }

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

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

      this.print0(this.ucase ? "DROP " : "drop ");
      List<SQLCommentHint> hints = x.getHints();
      if (hints != null) {
         this.printAndAccept(hints, " ");
         this.print(' ');
      }

      if (x.isExternal()) {
         this.print0(this.ucase ? "EXTERNAL " : "external ");
      }

      if (x.isDropPartition()) {
         this.print0(this.ucase ? "PARTITIONED " : "partitioned ");
      }

      if (x.isTemporary()) {
         this.print0(this.ucase ? "TEMPORARY TABLE " : "temporary table ");
      } else {
         this.print0(this.ucase ? "TABLE " : "table ");
      }

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

      this.printAndAccept(x.getTableSources(), ", ");
      if (x.isCascade()) {
         this.printCascade();
      }

      if (x.isRestrict()) {
         this.print0(this.ucase ? " RESTRICT" : " restrict");
      }

      if (x.isPurge()) {
         this.print0(this.ucase ? " PURGE" : " purge");
      }

      if (x.getWhere() != null) {
         this.print0(this.ucase ? " WHERE " : " where ");
         x.getWhere().accept(this);
      }

      return false;
   }

   protected void printCascade() {
      this.print0(this.ucase ? " CASCADE" : " cascade");
   }

   protected void printRestrict() {
      this.printUcase(" RESTRICT");
   }

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

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

      this.print0(this.ucase ? "DROP VIEW " : "drop view ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      this.printAndAccept(x.getTableSources(), ", ");
      if (x.isCascade()) {
         this.printCascade();
      }

      if (x.isRestrict()) {
         this.printRestrict();
      }

      return false;
   }

   public boolean visit(SQLDropEventStatement x) {
      this.print0(this.ucase ? "DROP EVENT " : "drop event ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      this.printExpr(x.getName(), this.parameterized);
      return false;
   }

   public boolean visit(SQLDropResourceStatement x) {
      this.print0(this.ucase ? "DROP RESOURCE " : "drop resource ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      this.printExpr(x.getName(), this.parameterized);
      return false;
   }

   public boolean visit(SQLDropResourceGroupStatement x) {
      this.print0(this.ucase ? "DROP RESOURCE GROUP " : "drop resource group ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      this.printExpr(x.getName(), this.parameterized);
      return false;
   }

   public boolean visit(SQLListResourceGroupStatement x) {
      this.print0(this.ucase ? "LIST RESOURCE GROUP" : "list resource group");
      return false;
   }

   public boolean visit(SQLColumnDefinition x) {
      boolean parameterized = this.parameterized;
      this.parameterized = false;
      x.getName().accept(this);
      SQLDataType dataType = x.getDataType();
      if (dataType != null) {
         this.print(' ');
         dataType.accept(this);
      }

      if (x.getDefaultExpr() != null) {
         this.visitColumnDefault(x);
      }

      if (x.isAutoIncrement()) {
         this.print0(this.ucase ? " AUTO_INCREMENT" : " auto_increment");
      }

      AutoIncrementType sequenceType = x.getSequenceType();
      if (sequenceType != null) {
         this.print0(" ");
         this.print0(this.ucase ? sequenceType.getKeyword() : sequenceType.getKeyword().toLowerCase());
      }

      for(SQLColumnConstraint item : x.getConstraints()) {
         boolean newLine = item instanceof SQLForeignKeyConstraint || item instanceof SQLPrimaryKey || item instanceof SQLColumnCheck || item instanceof SQLColumnCheck || item.getName() != null;
         if (newLine) {
            ++this.indentCount;
            this.println();
         } else {
            this.print(' ');
         }

         item.accept(this);
         if (newLine) {
            --this.indentCount;
         }
      }

      SQLExpr generatedAlawsAs = x.getGeneratedAlawsAs();
      if (generatedAlawsAs != null) {
         this.print0(this.ucase ? " GENERATED ALWAYS AS " : " generated always as ");
         this.printExpr(generatedAlawsAs, parameterized);
      }

      SQLColumnDefinition.Identity identity = x.getIdentity();
      if (identity != null) {
         if (this.dbType == DbType.h2) {
            this.print0(this.ucase ? " AS " : " as ");
         } else {
            this.print(' ');
         }

         identity.accept(this);
      }

      if (x.isVirtual()) {
         this.print0(this.ucase ? " VIRTUAL" : " virtual");
      }

      if (x.isVisible()) {
         this.print0(this.ucase ? " VISIBLE" : " visible");
      }

      Boolean enable = x.getEnable();
      if (enable != null && enable) {
         this.print0(this.ucase ? " ENABLE" : " enable");
      }

      if (x.getComment() != null) {
         this.print0(this.ucase ? " COMMENT " : " comment ");
         x.getComment().accept(this);
      }

      List<SQLAssignItem> mappedBy = x.getMappedByDirect();
      if (mappedBy != null && mappedBy.size() > 0) {
         this.print0(this.ucase ? " MAPPED BY (" : " mapped by (");
         this.printAndAccept(mappedBy, ", ");
         this.print0(this.ucase ? ")" : ")");
      }

      List<SQLAssignItem> colProperties = x.getColPropertiesDirect();
      if (colProperties != null && colProperties.size() > 0) {
         this.print0(this.ucase ? " COLPROPERTIES (" : " colproperties (");
         this.printAndAccept(colProperties, ", ");
         this.print0(this.ucase ? ")" : ")");
      }

      if (x.getEncode() != null) {
         this.print0(this.ucase ? " ENCODE=" : " encode=");
         x.getEncode().accept(this);
      }

      if (x.getCompression() != null) {
         this.print0(this.ucase ? " COMPRESSION=" : " compression=");
         x.getCompression().accept(this);
      }

      this.parameterized = parameterized;
      return false;
   }

   public boolean visit(SQLColumnDefinition.Identity x) {
      this.print0(this.ucase ? "IDENTITY" : "identity");
      Integer seed = x.getSeed();
      if (seed != null) {
         this.print0(" (");
         this.print(seed);
         this.print0(", ");
         this.print(x.getIncrement());
         this.print(')');
      }

      return false;
   }

   protected void visitColumnDefault(SQLColumnDefinition x) {
      this.print0(this.ucase ? " DEFAULT " : " default ");
      this.printExpr(x.getDefaultExpr(), false);
   }

   public boolean visit(SQLDeleteStatement x) {
      SQLTableSource from = x.getFrom();
      String alias = x.getAlias();
      if (x.getWith() != null) {
         x.getWith().accept(this);
         this.println();
      }

      if (from == null) {
         this.print0(this.ucase ? "DELETE FROM " : "delete from ");
         this.printTableSourceExpr(x.getTableName());
         if (alias != null) {
            this.print(' ');
            this.print0(alias);
         }
      } else {
         this.print0(this.ucase ? "DELETE " : "delete ");
         this.printTableSourceExpr(x.getTableName());
         this.print0(this.ucase ? " FROM " : " from ");
         from.accept(this);
      }

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

      return false;
   }

   public boolean visit(SQLCurrentOfCursorExpr x) {
      this.print0(this.ucase ? "CURRENT OF " : "current of ");
      this.printExpr(x.getCursorName(), this.parameterized);
      return false;
   }

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

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

      if (x.isUpsert()) {
         this.print0(this.ucase ? "UPSERT INTO " : "upsert into ");
      } else if (x.isOverwrite() && this.dbType == DbType.odps) {
         this.print0(this.ucase ? "INSERT OVERWRITE " : "insert overwrite ");
      } else {
         this.print0(this.ucase ? "INSERT INTO " : "insert into ");
      }

      x.getTableSource().accept(this);
      String columnsString = x.getColumnsString();
      if (columnsString != null) {
         this.print0(columnsString);
      } else {
         this.printInsertColumns(x.getColumns());
      }

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

      return false;
   }

   public void printInsertColumns(List<SQLExpr> columns) {
      int size = columns.size();
      if (size > 0) {
         if (size > 5) {
            ++this.indentCount;
            this.println();
         } else {
            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)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(SQLUpdateSetItem x) {
      this.printExpr(x.getColumn(), this.parameterized);
      this.print0(" = ");
      this.printExpr(x.getValue(), this.parameterized);
      return false;
   }

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

      this.print0(this.ucase ? "UPDATE " : "update ");
      this.printTableSource(x.getTableSource());
      this.println();
      this.print0(this.ucase ? "SET " : "set ");
      int i = 0;

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

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

      if (x.getFrom() != null) {
         this.println();
         this.print0(this.ucase ? "FROM " : "from ");
         x.getFrom().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;
      }

      return false;
   }

   protected void printTableElements(List<SQLTableElement> tableElementList) {
      int size = tableElementList.size();
      if (size != 0) {
         this.print0(" (");
         ++this.indentCount;
         this.println();

         for(int i = 0; i < size; ++i) {
            SQLTableElement element = (SQLTableElement)tableElementList.get(i);
            element.accept(this);
            if (i != size - 1) {
               this.print(',');
            }

            if (this.isPrettyFormat() && element.hasAfterComment()) {
               this.print(' ');
               this.printlnComment(element.getAfterCommentsDirect());
            }

            if (i != size - 1) {
               this.println();
            }
         }

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

   public boolean visit(SQLCreateTableStatement x) {
      this.printCreateTable(x, true);
      SQLPartitionBy partitionBy = x.getPartitioning();
      if (partitionBy != null) {
         this.println();
         this.print0(this.ucase ? "PARTITION BY " : "partition by ");
         partitionBy.accept(this);
      }

      List<SQLAssignItem> options = x.getTableOptions();
      if (options.size() > 0) {
         this.println();
         this.print0(this.ucase ? "WITH (" : "with (");
         this.printAndAccept(options, ", ");
         this.print(')');
      }

      SQLName tablespace = x.getTablespace();
      if (tablespace != null) {
         this.println();
         this.print0(this.ucase ? "TABLESPACE " : "tablespace ");
         tablespace.accept(this);
      }

      SQLExpr engine = x.getEngine();
      if (engine != null) {
         this.print0(this.ucase ? " ENGINE = " : " engine = ");
         engine.accept(this);
      }

      return false;
   }

   protected void printCreateTable(SQLCreateTableStatement x, boolean printSelect) {
      this.print0(this.ucase ? "CREATE " : "create ");
      if (x.isExternal()) {
         this.print0(this.ucase ? "EXTERNAL " : "external ");
      }

      SQLCreateTableStatement.Type tableType = x.getType();
      if (SQLCreateTableStatement.Type.GLOBAL_TEMPORARY.equals(tableType)) {
         this.print0(this.ucase ? "GLOBAL TEMPORARY " : "global temporary ");
      } else if (SQLCreateTableStatement.Type.LOCAL_TEMPORARY.equals(tableType)) {
         this.print0(this.ucase ? "LOCAL TEMPORARY " : "local temporary ");
      } else if (SQLCreateTableStatement.Type.SHADOW.equals(tableType)) {
         this.print0(this.ucase ? "SHADOW " : "shadow ");
      }

      if (x.isDimension()) {
         this.print0(this.ucase ? "DIMENSION " : "dimension ");
      }

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

      this.printTableSourceExpr(x.getName());
      this.printTableElements(x.getTableElementList());
      SQLExprTableSource inherits = x.getInherits();
      if (inherits != null) {
         this.print0(this.ucase ? " INHERITS (" : " inherits (");
         inherits.accept(this);
         this.print(')');
      }

      SQLExpr storedAs = x.getStoredAs();
      if (storedAs != null) {
         this.print0(this.ucase ? " STORE AS " : " store as ");
         this.printExpr(storedAs, this.parameterized);
      }

      SQLSelect select = x.getSelect();
      if (printSelect && select != null) {
         this.println();
         this.print0(this.ucase ? "AS" : "as");
         this.println();
         this.visit(select);
      }

   }

   public boolean visit(SQLUniqueConstraint x) {
      if (x.getName() != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         x.getName().accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "UNIQUE (" : "unique (");
      List<SQLSelectOrderByItem> columns = x.getColumns();
      int i = 0;

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

         this.visit((SQLSelectOrderByItem)columns.get(i));
      }

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

   public boolean visit(SQLNotNullConstraint x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "NOT NULL" : "not null");
      List<SQLCommentHint> hints = x.hints;
      if (hints != null) {
         this.print(' ');

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

      return false;
   }

   public boolean visit(SQLNullConstraint x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "NULL" : "null");
      return false;
   }

   public boolean visit(SQLUnionQuery x) {
      SQLUnionOperator operator = x.getOperator();
      List<SQLSelectQuery> relations = x.getRelations();
      if (relations.size() > 2) {
         for(int i = 0; i < relations.size(); ++i) {
            if (i != 0) {
               this.println();
               this.print0(this.ucase ? operator.name : operator.name_lcase);
               this.println();
            }

            SQLSelectQuery item = (SQLSelectQuery)relations.get(i);
            item.accept(this);
         }

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

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

         return false;
      } else {
         SQLSelectQuery left = x.getLeft();
         SQLSelectQuery right = x.getRight();
         boolean bracket = x.isBracket() && !(x.getParent() instanceof SQLUnionQueryTableSource);
         SQLOrderBy orderBy = x.getOrderBy();
         if (!bracket && left instanceof SQLUnionQuery && ((SQLUnionQuery)left).getOperator() == operator && !right.isBracket() && x.getLimit() == null && orderBy == null) {
            SQLUnionQuery leftUnion = (SQLUnionQuery)left;
            if (right instanceof SQLSelectQueryBlock) {
               SQLSelectQueryBlock rightQueryBlock = (SQLSelectQueryBlock)right;
               if (rightQueryBlock.getOrderBy() != null || rightQueryBlock.getLimit() != null) {
                  rightQueryBlock.setBracket(true);
               }
            }

            List<SQLSelectQuery> rights = new ArrayList();
            rights.add(right);

            while(true) {
               SQLSelectQuery leftLeft = leftUnion.getLeft();
               SQLSelectQuery leftRight = leftUnion.getRight();
               if (leftRight instanceof SQLSelectQueryBlock) {
                  SQLSelectQueryBlock leftRightQueryBlock = (SQLSelectQueryBlock)leftRight;
                  if (leftRightQueryBlock.getOrderBy() != null || leftRightQueryBlock.getLimit() != null) {
                     leftRightQueryBlock.setBracket(true);
                  }
               }

               if (leftUnion.isBracket() || leftUnion.getOrderBy() != null || leftLeft.isBracket() || leftRight.isBracket() || !(leftLeft instanceof SQLUnionQuery) || ((SQLUnionQuery)leftLeft).getOperator() != operator) {
                  rights.add(leftRight);
                  rights.add(leftLeft);

                  for(int leftRigt = rights.size() - 1; leftRigt >= 0; --leftRigt) {
                     leftRight = (SQLSelectQuery)rights.get(leftRigt);
                     leftRight.accept(this);
                     if (leftRigt > 0) {
                        this.println();
                        this.print0(this.ucase ? operator.name : operator.name_lcase);
                        this.println();
                     }
                  }

                  return false;
               }

               rights.add(leftRight);
               leftUnion = (SQLUnionQuery)leftLeft;
            }
         } else {
            if (bracket) {
               this.print('(');
            }

            if (left != null) {
               if (left.getClass() == SQLUnionQuery.class) {
                  SQLUnionQuery leftUnion = (SQLUnionQuery)left;
                  if (leftUnion.getRelations().size() > 2) {
                     this.visit(leftUnion);
                  } else {
                     SQLSelectQuery leftLeft = leftUnion.getLeft();
                     SQLSelectQuery leftRigt = leftUnion.getRight();
                     if (!leftUnion.isBracket() && leftUnion.getRight() instanceof SQLSelectQueryBlock && leftUnion.getLeft() != null && leftUnion.getLimit() == null && leftUnion.getOrderBy() == null) {
                        if (leftLeft.getClass() == SQLUnionQuery.class) {
                           this.visit((SQLUnionQuery)leftLeft);
                        } else {
                           this.printQuery(leftLeft);
                        }

                        this.println();
                        this.print0(this.ucase ? leftUnion.getOperator().name : leftUnion.getOperator().name_lcase);
                        this.println();
                        leftRigt.accept(this);
                     } else {
                        this.visit(leftUnion);
                     }
                  }
               } else {
                  left.accept(this);
               }
            }

            if (right == null) {
               return false;
            } else {
               this.println();
               this.print0(this.ucase ? operator.name : operator.name_lcase);
               this.println();
               boolean needParen = false;
               if (!right.isBracket() && right instanceof SQLSelectQueryBlock) {
                  SQLSelectQueryBlock rightQuery = (SQLSelectQueryBlock)right;
                  if (rightQuery.getOrderBy() != null || rightQuery.getLimit() != null) {
                     needParen = true;
                  }
               }

               if (needParen) {
                  this.print('(');
                  right.accept(this);
                  this.print(')');
               } else {
                  right.accept(this);
               }

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

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

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

               return false;
            }
         }
      }
   }

   public boolean visit(SQLUnaryExpr x) {
      switch (x.getOperator()) {
         case IsNotASet:
         case IsEmpty:
         case IsNotEmpty:
         case FactorialSuffix:
            x.getExpr().accept(this);
            this.print(' ');
            this.print0(x.getOperator().name);
            return false;
         default:
            this.print0(x.getOperator().name);
            SQLExpr expr = x.getExpr();
            switch (x.getOperator()) {
               case BINARY:
               case Prior:
               case ConnectByRoot:
                  this.print(' ');
                  expr.accept(this);
                  return false;
               default:
                  if (!(expr instanceof SQLBinaryOpExpr) && !(expr instanceof SQLBinaryOpExprGroup) && !(expr instanceof SQLUnaryExpr) && !(expr instanceof SQLNotExpr) && !(expr instanceof SQLBetweenExpr) && !(expr instanceof SQLInListExpr) && !(expr instanceof SQLInSubQueryExpr)) {
                     expr.accept(this);
                  } else {
                     this.incrementIndent();
                     this.print('(');
                     expr.accept(this);
                     this.print(')');
                     this.decrementIndent();
                  }

                  return false;
            }
      }
   }

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

         return false;
      } else {
         this.print0("0x");
         this.print0(x.getHex());
         String charset = (String)x.getAttribute("USING");
         if (charset != null) {
            this.print0(this.ucase ? " USING " : " using ");
            this.print0(charset);
         }

         return false;
      }
   }

   public boolean visit(SQLSetStatement x) {
      if (x.getHeadHintsDirect() != null) {
         for(SQLCommentHint hint : x.getHeadHintsDirect()) {
            hint.accept(this);
         }
      }

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

      boolean printSet = x.getAttribute("parser.set") == Boolean.TRUE || !JdbcUtils.isOracleDbType(this.dbType) && !JdbcUtils.isDmDbType(this.dbType);
      if (printSet) {
         this.print0(this.ucase ? "SET " : "set ");
      }

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

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

      return false;
   }

   public boolean visit(SQLAssignItem x) {
      x.getTarget().accept(this);
      SQLExpr value = x.getValue();
      if (value != null) {
         this.print0(" = ");
         value.accept(this);
      } else if (this.dbType == DbType.odps) {
         this.print0(" = ");
      }

      return false;
   }

   public boolean visit(SQLCallStatement x) {
      if (x.isBrace()) {
         this.print('{');
      }

      if (x.getOutParameter() != null) {
         x.getOutParameter().accept(this);
         this.print0(" = ");
      }

      this.print0(this.ucase ? "CALL " : "call ");
      x.getProcedureName().accept(this);
      this.print('(');
      this.printAndAccept(x.getParameters(), ", ");
      this.print(')');
      if (x.isBrace()) {
         this.print('}');
      }

      return false;
   }

   public boolean visit(SQLJoinTableSource x) {
      SQLCommentHint hint = x.getHint();
      if (hint != null) {
         hint.accept(this);
      }

      SQLTableSource left = x.getLeft();
      String alias = x.getAlias();
      if (alias != null) {
         this.print('(');
      }

      if (left instanceof SQLJoinTableSource && ((SQLJoinTableSource)left).getJoinType() == SQLJoinTableSource.JoinType.COMMA && x.getJoinType() != SQLJoinTableSource.JoinType.COMMA && DbType.postgresql != this.dbType && ((SQLJoinTableSource)left).getAttribute("ads.comma_join") == null) {
         this.print('(');
         this.printTableSource(left);
         this.print(')');
      } else {
         this.printTableSource(left);
      }

      ++this.indentCount;
      if (x.getJoinType() == SQLJoinTableSource.JoinType.COMMA) {
         this.print(',');
      } else {
         this.println();
         boolean asof = x.isAsof();
         if (asof) {
            this.print0(this.ucase ? " ASOF " : " asof");
         }

         if (x.isNatural()) {
            this.print0(this.ucase ? "NATURAL " : "natural ");
         }

         this.printJoinType(x.getJoinType());
      }

      this.print(' ');
      SQLTableSource right = x.getRight();
      if (right instanceof SQLJoinTableSource) {
         this.print('(');
         this.printTableSource(right);
         this.print(')');
      } else {
         this.printTableSource(right);
      }

      SQLExpr condition = x.getCondition();
      if (condition != null) {
         boolean newLine = false;
         if (right instanceof SQLSubqueryTableSource) {
            newLine = true;
         } else if (condition instanceof SQLBinaryOpExpr) {
            SQLBinaryOperator op = ((SQLBinaryOpExpr)condition).getOperator();
            if (op == SQLBinaryOperator.BooleanAnd || op == SQLBinaryOperator.BooleanOr) {
               newLine = true;
            }
         } else if (condition instanceof SQLBinaryOpExprGroup) {
            newLine = true;
         }

         if (newLine) {
            this.println();
         } else {
            this.print(' ');
         }

         ++this.indentCount;
         this.print0(this.ucase ? "ON " : "on ");
         this.printExpr(condition, this.parameterized);
         --this.indentCount;
      }

      if (x.getUsing().size() > 0) {
         this.print0(this.ucase ? " USING (" : " using (");
         this.printAndAccept(x.getUsing(), ", ");
         this.print(')');
      }

      if (alias != null) {
         this.print0(this.ucase ? ") AS " : ") as ");
         this.print0(alias);
      }

      SQLJoinTableSource.UDJ udj = x.getUdj();
      if (udj != null) {
         this.println();
         udj.accept(this);
      }

      --this.indentCount;
      return false;
   }

   public boolean visit(SQLJoinTableSource.UDJ x) {
      this.print0(this.ucase ? "USING " : "using ");
      this.print0(x.getFunction());
      this.print('(');
      this.printAndAccept(x.getArguments(), ", ");
      this.print0(") ");
      this.print0(x.getAlias());
      this.print0(this.ucase ? " AS (" : " as (");
      this.printAndAccept(x.getColumns(), ", ");
      this.print0(")");
      return false;
   }

   protected void printJoinType(SQLJoinTableSource.JoinType joinType) {
      this.print0(this.ucase ? joinType.name : joinType.name_lcase);
   }

   public boolean visit(SQLInsertStatement.ValuesClause x) {
      return this.visit(x, this.parameters);
   }

   public boolean visit(SQLInsertStatement.ValuesClause x, List<Object> parameters) {
      if (!this.parameterized && this.isEnabled(VisitorFeature.OutputUseInsertValueClauseOriginalString) && x.getOriginalString() != null) {
         this.print0(x.getOriginalString());
         return false;
      } else {
         int xReplaceCount = x.getReplaceCount();
         List<SQLExpr> values = x.getValues();
         this.replaceCount += xReplaceCount;
         if (xReplaceCount == values.size() && xReplaceCount < variantValuesCache.length) {
            String variantValues;
            if (this.indentCount == 0) {
               variantValues = variantValuesCache_1[xReplaceCount];
            } else {
               variantValues = variantValuesCache[xReplaceCount];
            }

            this.print0(variantValues);
            return false;
         } else if (this.inputParameters != null && this.inputParameters.size() > 0 && this.inputParameters.get(0) instanceof Collection && ((Collection)this.inputParameters.get(0)).size() == x.getValues().size()) {
            this.incrementIndent();

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

               this.print('(');
               int j = 0;

               for(Object item : params) {
                  if (j != 0) {
                     if (j % 5 == 0) {
                        this.println();
                     }

                     this.print0(", ");
                  }

                  this.printParameter(item);
                  ++j;
               }

               this.print(')');
            }

            this.decrementIndent();
            return false;
         } else {
            this.print('(');
            ++this.indentCount;
            int i = 0;

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

                  this.print0(", ");
               }

               Object value = values.get(i);
               if (value instanceof SQLExpr) {
                  SQLExpr expr = (SQLExpr)values.get(i);
                  if (!this.parameterized || !(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 (this.parameterized && expr instanceof SQLNullExpr) {
                        this.print('?');
                        if (parameters != null) {
                           parameters.add(null);
                        }

                        this.incrementReplaceCunt();
                     } else if (expr instanceof SQLVariantRefExpr) {
                        this.visit((SQLVariantRefExpr)expr);
                     } else {
                        expr.accept(this);
                     }
                  } else {
                     this.print('?');
                     this.incrementReplaceCunt();
                     if (parameters != null) {
                        ExportParameterVisitorUtils.exportParameter(parameters, expr);
                     }
                  }
               } else if (value instanceof Integer) {
                  this.print((Integer)value);
               } else if (value instanceof Long) {
                  this.print((Long)value);
               } else if (value instanceof String) {
                  this.printChars((String)value);
               } else if (value instanceof Float) {
                  this.print((Float)value);
               } else if (value instanceof Double) {
                  this.print((Double)value);
               } else if (value instanceof Date) {
                  this.print((Date)value);
               } else if (value instanceof BigDecimal) {
                  this.print(value.toString());
               } else {
                  if (value != null) {
                     throw new UnsupportedOperationException();
                  }

                  this.print0(this.ucase ? "NULL" : "null");
               }
            }

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

   public boolean visit(SQLSomeExpr x) {
      this.print0(this.ucase ? "SOME (" : "some (");
      ++this.indentCount;
      this.println();
      x.getSubQuery().accept(this);
      --this.indentCount;
      this.println();
      this.print(')');
      return false;
   }

   public boolean visit(SQLAnyExpr x) {
      this.print0(this.ucase ? "ANY (" : "any (");
      ++this.indentCount;
      this.println();
      x.getSubQuery().accept(this);
      --this.indentCount;
      this.println();
      this.print(')');
      return false;
   }

   public boolean visit(SQLAllExpr x) {
      this.print0(this.ucase ? "ALL (" : "all (");
      ++this.indentCount;
      this.println();
      x.getSubQuery().accept(this);
      --this.indentCount;
      this.println();
      this.print(')');
      return false;
   }

   public boolean visit(SQLInSubQueryExpr x) {
      x.getExpr().accept(this);
      if (x.isNot()) {
         this.print0(this.ucase ? " NOT IN (" : " not in (");
      } else if (x.isGlobal()) {
         this.print0(this.ucase ? " GLOBAL IN (" : " global in (");
      } else {
         this.print0(this.ucase ? " IN (" : " in (");
      }

      ++this.indentCount;
      this.println();
      x.getSubQuery().accept(this);
      --this.indentCount;
      this.println();
      this.print(')');
      if (x.getHint() != null) {
         x.getHint().accept(this);
      }

      return false;
   }

   public boolean visit(SQLListExpr x) {
      this.print('(');
      this.printAndAccept(x.getItems(), ", ");
      this.print(')');
      return false;
   }

   public boolean visit(SQLSubqueryTableSource x) {
      this.print('(');
      ++this.indentCount;
      this.println();
      if (x.getHintsSize() > 0) {
         this.printAndAccept(x.getHints(), " ");
         this.println();
      }

      this.visit(x.getSelect());
      --this.indentCount;
      this.println();
      this.print(')');
      List<SQLName> columns = x.getColumns();
      String alias = x.getAlias();
      if (alias != null) {
         if (columns.size() > 0) {
            this.print0(" AS ");
         } else {
            this.print(' ');
         }

         this.print0(alias);
      }

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

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

            this.printExpr((SQLExpr)columns.get(i));
         }

         this.print(')');
      }

      return false;
   }

   public boolean visit(SQLUnnestTableSource x) {
      this.print0(this.ucase ? "UNNEST(" : "unnest(");
      List<SQLExpr> items = x.getItems();
      this.printAndAccept(items, ", ");
      this.print(')');
      if (x.isOrdinality()) {
         this.print0(this.ucase ? " WITH ORDINALITY" : " with ordinality");
      }

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

         this.print0(alias);
      }

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

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

            this.printExpr((SQLExpr)columns.get(i));
         }

         this.print(')');
      }

      return false;
   }

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

      this.print0(this.ucase ? "TRUNCATE TABLE " : "truncate table ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

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

      if (x.isPartitionAll()) {
         this.print0(this.ucase ? " PARTITION ALL" : " partition all");
      } else if (x.getPartitionsForADB().size() > 0) {
         this.print0(this.ucase ? " PARTITION " : " partition ");
         this.printAndAccept(x.getPartitionsForADB(), ", ");
      }

      if (x.isDropStorage()) {
         this.print0(this.ucase ? " DROP STORAGE" : " drop storage");
      }

      if (x.isReuseStorage()) {
         this.print0(this.ucase ? " REUSE STORAGE" : " reuse storage");
      }

      if (x.isIgnoreDeleteTriggers()) {
         this.print0(this.ucase ? " IGNORE DELETE TRIGGERS" : " ignore delete triggers");
      }

      if (x.isRestrictWhenDeleteTriggers()) {
         this.print0(this.ucase ? " RESTRICT WHEN DELETE TRIGGERS" : " restrict when delete triggers");
      }

      if (x.isContinueIdentity()) {
         this.print0(this.ucase ? " CONTINUE IDENTITY" : " continue identity");
      }

      if (x.isImmediate()) {
         this.print0(this.ucase ? " IMMEDIATE" : " immediate");
      }

      return false;
   }

   public boolean visit(SQLDefaultExpr x) {
      this.print0(this.ucase ? "DEFAULT" : "default");
      return false;
   }

   public void endVisit(SQLCommentStatement x) {
   }

   public boolean visit(SQLCommentStatement x) {
      this.print0(this.ucase ? "COMMENT ON " : "comment on ");
      if (x.getType() != null) {
         this.print0(x.getType().name());
         this.print(' ');
      }

      x.getOn().accept(this);
      this.print0(this.ucase ? " IS " : " is ");
      x.getComment().accept(this);
      return false;
   }

   public boolean visit(SQLUseStatement x) {
      this.print0(this.ucase ? "USE " : "use ");
      x.getDatabase().accept(this);
      return false;
   }

   protected boolean isOdps() {
      return DbType.odps == this.dbType;
   }

   public boolean visit(SQLAlterTableAddColumn x) {
      if (DbType.odps != this.dbType && DbType.hive != this.dbType) {
         this.print0(this.ucase ? "ADD (" : "add (");
      } else {
         this.print0(this.ucase ? "ADD COLUMNS (" : "add columns (");
      }

      this.printAndAccept(x.getColumns(), ", ");
      this.print(')');
      Boolean restrict = x.getRestrict();
      if (restrict != null && restrict) {
         this.print0(this.ucase ? " RESTRICT" : " restrict");
      }

      if (x.isCascade()) {
         this.print0(this.ucase ? " CASCADE" : " cascade");
      }

      return false;
   }

   public boolean visit(SQLAlterTableReplaceColumn x) {
      this.print0(this.ucase ? "REPLACE COLUMNS (" : "replace columns (");
      this.printAndAccept(x.getColumns(), ", ");
      this.print(')');
      return false;
   }

   public boolean visit(SQLAlterTableDropColumnItem x) {
      this.print0(this.ucase ? "DROP COLUMN " : "drop column ");
      this.printAndAccept(x.getColumns(), ", ");
      if (x.isCascade()) {
         this.print0(this.ucase ? " CASCADE" : " cascade");
      }

      return false;
   }

   public boolean visit(SQLAlterTableDeleteByCondition x) {
      this.printUcase("DELETE WHERE ");
      x.getWhere().accept(this);
      return false;
   }

   public void endVisit(SQLAlterTableAddColumn x) {
   }

   public boolean visit(SQLDropIndexStatement x) {
      this.print0(this.ucase ? "DROP INDEX " : "drop index ");
      if (x.isIfExists()) {
         this.printUcase("IF EXISTS ");
      }

      x.getIndexName().accept(this);
      this.print0(" ");
      SQLExprTableSource table = x.getTableName();
      if (table != null) {
         this.print0(this.ucase ? " ON " : " on ");
         table.accept(this);
      }

      SQLExpr algorithm = x.getAlgorithm();
      if (algorithm != null) {
         this.print0(this.ucase ? " ALGORITHM " : " algorithm ");
         algorithm.accept(this);
      }

      SQLExpr lockOption = x.getLockOption();
      if (lockOption != null) {
         this.print0(this.ucase ? " LOCK " : " lock ");
         lockOption.accept(this);
      }

      if (x.isCascade()) {
         this.printUcase("CASCADE ");
      }

      if (x.isRestrict()) {
         this.printUcase("RESTRICT ");
      }

      return false;
   }

   public boolean visit(SQLDropLogFileGroupStatement x) {
      this.print0(this.ucase ? "DROP LOGFILE GROUP " : "drop logfile group ");
      x.getName().accept(this);
      return false;
   }

   public boolean visit(SQLDropServerStatement x) {
      this.print0(this.ucase ? "DROP SERVER " : "drop server ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

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

   public boolean visit(SQLDropTypeStatement x) {
      this.print0(this.ucase ? "DROP TYPE " : "drop type ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

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

   public boolean visit(SQLDropSynonymStatement x) {
      if (x.isPublic()) {
         this.print0(this.ucase ? "DROP PUBLIC SYNONYM " : "drop public synonym ");
      } else {
         this.print0(this.ucase ? "DROP SYNONYM " : "drop synonym ");
      }

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

      x.getName().accept(this);
      if (x.isForce()) {
         this.print0(this.ucase ? " FORCE" : " force");
      }

      if (x.isCascade()) {
         this.printUcase(" CASCADE ");
      } else if (x.isRestrict()) {
         this.printUcase(" RESTRICT ");
      }

      return false;
   }

   public boolean visit(SQLSavePointStatement x) {
      this.print0(this.ucase ? "SAVEPOINT" : "savepoint");
      SQLExpr name = x.getName();
      if (name != null) {
         this.print(' ');
         name.accept(this);
      }

      return false;
   }

   public boolean visit(SQLReleaseSavePointStatement x) {
      this.print0(this.ucase ? "RELEASE SAVEPOINT " : "release savepoint ");
      x.getName().accept(this);
      return false;
   }

   public boolean visit(SQLRollbackStatement x) {
      this.print0(this.ucase ? "ROLLBACK" : "rollback");
      if (x.isWork()) {
         this.print0(this.ucase ? " WORK" : " work");
      }

      if (x.getTo() != null) {
         this.print0(this.ucase ? " TO " : " to ");
         if (this.dbType == DbType.dm) {
            this.print0(this.ucase ? "SAVEPOINT " : "savepoint ");
         }

         x.getTo().accept(this);
      }

      return false;
   }

   public boolean visit(SQLCommentHint x) {
      if (x.hasBeforeComment() && !this.parameterized) {
         this.printlnComment(x.getBeforeCommentsDirect());
         this.println();
      }

      this.print0("/*");
      this.print0(x.getText());
      this.print0("*/");
      return false;
   }

   public boolean visit(SQLCreateDatabaseStatement x) {
      if (x.getHeadHintsDirect() != null) {
         for(SQLCommentHint hint : x.getHeadHintsDirect()) {
            hint.accept(this);
         }
      }

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

      this.print0(this.ucase ? "CREATE " : "create ");
      if (x.isPhysical()) {
         this.print0(this.ucase ? "PHYSICAL " : "physical ");
      }

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

      x.getName().accept(this);
      if (x.getCharacterSet() != null) {
         this.print0(this.ucase ? " CHARACTER SET " : " character set ");
         this.print0(x.getCharacterSet());
      }

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

      SQLExpr comment = x.getComment();
      if (comment != null) {
         this.print0(this.ucase ? " COMMENT " : " comment ");
         this.printExpr(comment, false);
      }

      SQLExpr location = x.getLocation();
      if (location != null) {
         this.print0(this.ucase ? " LOCATION " : " location ");
         this.printExpr(location, false);
      }

      if (x.getDbProperties().size() > 0) {
         if (this.dbType != DbType.mysql && this.dbType != DbType.presto && this.dbType != DbType.ads && this.dbType != DbType.mariadb) {
            if (this.dbType == DbType.hive) {
               this.println();
               this.print0(this.ucase ? "WITH DBPROPERTIES (" : "with dbproperties (");
            } else {
               this.println();
               this.print0(this.ucase ? "WITH PROPERTIES (" : "with properties (");
            }
         } else {
            this.println();
            this.print0(this.ucase ? "WITH (" : "with (");
         }

         this.incrementIndent();
         this.println();
         this.printlnAndAccept(x.getDbProperties(), ",");
         this.decrementIndent();
         this.println();
         this.print(')');
      }

      if (x.getUser() != null) {
         this.print0(this.ucase ? " FOR " : " for ");
         this.print0("'" + x.getUser() + "'");
      }

      if (x.getOptions().size() > 0) {
         this.print0(this.ucase ? " OPTIONS (" : " options (");

         for(Map.Entry<String, SQLExpr> option : x.getOptions().entrySet()) {
            this.print0((String)option.getKey());
            this.print0("=");
            this.printExpr((SQLExpr)option.getValue(), false);
            this.print0(" ");
         }

         this.print(')');
      }

      List<List<SQLAssignItem>> storedBy = x.getStoredBy();
      if (storedBy.size() != 0) {
         this.println();
         this.print0(this.ucase ? "STORED BY " : "stored by ");
         this.incrementIndent();

         for(int i = 0; i < storedBy.size(); ++i) {
            List<SQLAssignItem> items = (List)storedBy.get(i);
            if (i != 0) {
               this.print(',');
               this.println();
            }

            this.print('(');
            this.printAndAccept(items, ", ");
            this.print(')');
         }

         this.decrementIndent();
      }

      SQLExpr storedIn = x.getStoredIn();
      if (storedIn != null) {
         this.println();
         this.print0(this.ucase ? "STORED IN " : "stored in ");
         this.printExpr(storedIn);
         List<SQLAssignItem> storedOn = x.getStoredOn();
         if (storedOn.size() > 0) {
            this.print0(this.ucase ? " ON (" : " ON (");
            this.printAndAccept(storedOn, ", ");
            this.print(')');
         }
      }

      SQLExpr storedAs = x.getStoredAs();
      if (storedAs != null) {
         this.println();
         this.print0(this.ucase ? "STORED AS " : "stored as ");
         this.printExpr(storedAs);
      }

      return false;
   }

   public boolean visit(SQLCreateTableGroupStatement x) {
      this.print0(this.ucase ? "CREATE TABLEGROUP " : "create tablegroup ");
      if (x.isIfNotExists()) {
         this.print0(this.ucase ? "IF NOT EXISTS " : "if not exists ");
      }

      x.getName().accept(this);
      SQLExpr partitionNum = x.getPartitionNum();
      if (partitionNum != null) {
         this.print0(this.ucase ? " PARTITION NUM " : " partition num ");
         this.printExpr(partitionNum);
      }

      return false;
   }

   public boolean visit(SQLDropTableGroupStatement x) {
      this.print0(this.ucase ? "DROP TABLEGROUP " : "drop tablegroup ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF NOT EXISTS " : "if not exists ");
      }

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

   public boolean visit(SQLAlterTableGroupStatement x) {
      this.print0(this.ucase ? "ALTER TABLEGROUP " : "alter tablegroup ");
      x.getName().accept(this);
      this.print0(" ");
      this.printAndAccept(x.getOptions(), " ");
      return false;
   }

   public boolean visit(SQLAlterSystemGetConfigStatement x) {
      this.print0(this.ucase ? "ALTER SYSTEM GET CONFIG " : "alter system get config ");
      x.getName().accept(this);
      return false;
   }

   public boolean visit(SQLAlterSystemSetConfigStatement x) {
      this.print0(this.ucase ? "ALTER SYSTEM SET COFNIG " : "alter system set config ");
      this.printAndAccept(x.getOptions(), " ");
      return false;
   }

   public boolean visit(SQLAlterViewStatement x) {
      this.print0(this.ucase ? "ALTER " : "alter ");
      ++this.indentCount;
      String algorithm = x.getAlgorithm();
      if (algorithm != null && algorithm.length() > 0) {
         this.print0(this.ucase ? "ALGORITHM = " : "algorithm = ");
         this.print0(algorithm);
         this.println();
      }

      SQLName definer = x.getDefiner();
      if (definer != null) {
         this.print0(this.ucase ? "DEFINER = " : "definer = ");
         definer.accept(this);
         this.println();
      }

      String sqlSecurity = x.getSqlSecurity();
      if (sqlSecurity != null && sqlSecurity.length() > 0) {
         this.print0(this.ucase ? "SQL SECURITY " : "sql security ");
         this.print0(sqlSecurity);
         this.println();
      }

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

      x.getTableSource().accept(this);
      List<SQLTableElement> columns = x.getColumns();
      if (columns.size() > 0) {
         this.print0(" (");
         ++this.indentCount;
         this.println();

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

            ((SQLTableElement)columns.get(i)).accept(this);
         }

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

      if (x.getComment() != null) {
         this.println();
         this.print0(this.ucase ? "COMMENT " : "comment ");
         x.getComment().accept(this);
      }

      this.println();
      this.print0(this.ucase ? "AS" : "as");
      this.println();
      x.getSubQuery().accept(this);
      if (x.isWithCheckOption()) {
         this.println();
         this.print0(this.ucase ? "WITH CHECK OPTION" : "with check option");
      }

      return false;
   }

   public boolean visit(SQLCreateViewStatement x) {
      this.print0(this.ucase ? "CREATE " : "create ");
      if (x.isOrReplace()) {
         this.print0(this.ucase ? "OR REPLACE " : "or replace ");
      }

      ++this.indentCount;
      String algorithm = x.getAlgorithm();
      if (algorithm != null && algorithm.length() > 0) {
         this.print0(this.ucase ? "ALGORITHM = " : "algorithm = ");
         this.print0(algorithm);
         this.println();
      }

      SQLName definer = x.getDefiner();
      if (definer != null) {
         this.print0(this.ucase ? "DEFINER = " : "definer = ");
         definer.accept(this);
         this.println();
      }

      String sqlSecurity = x.getSqlSecurity();
      if (sqlSecurity != null && sqlSecurity.length() > 0) {
         this.print0(this.ucase ? "SQL SECURITY = " : "sql security = ");
         this.print0(sqlSecurity);
         this.println();
      }

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

      x.getTableSource().accept(this);
      List<SQLTableElement> columns = x.getColumns();
      if (columns.size() > 0) {
         this.print0(" (");
         ++this.indentCount;
         this.println();

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

            ((SQLTableElement)columns.get(i)).accept(this);
         }

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

      SQLLiteralExpr comment = x.getComment();
      if (comment != null) {
         this.println();
         this.print0(this.ucase ? "COMMENT " : "comment ");
         comment.accept(this);
      }

      this.println();
      this.print0(this.ucase ? "AS" : "as");
      this.println();
      x.getSubQuery().accept(this);
      if (x.isWithLocal()) {
         this.println();
         this.print0(this.ucase ? "WITH LOCAL" : "with local");
      }

      if (x.isWithCascaded()) {
         this.println();
         this.print0(this.ucase ? "WITH CASCADED" : "with cascaded");
      }

      if (x.isWithCheckOption()) {
         if (!x.isWithLocal() && !x.isWithCascaded()) {
            this.println();
            this.print0(this.ucase ? "WITH" : "with");
         }

         this.print0(this.ucase ? " CHECK OPTION" : " check option");
      }

      if (x.isWithReadOnly()) {
         this.println();
         this.print0(this.ucase ? "WITH READ ONLY" : "with read only");
      }

      return false;
   }

   public boolean visit(SQLCreateViewStatement.Column x) {
      x.getExpr().accept(this);
      SQLCharExpr comment = x.getComment();
      if (comment != null) {
         this.print0(this.ucase ? " COMMENT " : " comment ");
         comment.accept(this);
      }

      return false;
   }

   public boolean visit(SQLAlterTableDropIndex x) {
      this.print0(this.ucase ? "DROP INDEX " : "drop index ");
      x.getIndexName().accept(this);
      return false;
   }

   public boolean visit(SQLOver x) {
      this.print0(this.ucase ? "(" : "(");
      this.printSQLOVER(x);
      this.print(')');
      return false;
   }

   public void printSQLOVER(SQLOver x) {
      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);
      }

      SQLOrderBy distributeBy = x.getDistributeBy();
      if (distributeBy != null) {
         List<SQLSelectOrderByItem> items = distributeBy.getItems();
         if (items.size() > 0) {
            this.print0(this.ucase ? "DISTRIBUTE BY " : "distribute by ");
            int i = 0;

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

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

      SQLOrderBy sortBy = x.getDistributeBy();
      if (sortBy != null) {
         List<SQLSelectOrderByItem> items = sortBy.getItems();
         if (items.size() > 0) {
            this.print0(this.ucase ? "SORT BY " : "sort by ");
            int i = 0;

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

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

      if (x.getOf() != null) {
         this.print0(this.ucase ? " OF " : " of ");
         x.getOf().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);
         }
      }

   }

   protected void printWindowingExpr(SQLExpr expr) {
      if (expr != null) {
         this.print(' ');
         if (expr instanceof SQLIdentifierExpr) {
            String ident = ((SQLIdentifierExpr)expr).getName();
            this.print0(this.ucase ? ident : ident.toLowerCase());
         } else {
            expr.accept(this);
         }

      }
   }

   public boolean visit(SQLKeep x) {
      if (x.getDenseRank() == SQLKeep.DenseRank.FIRST) {
         this.print0(this.ucase ? "KEEP (DENSE_RANK FIRST " : "keep (dense_rank first ");
      } else {
         this.print0(this.ucase ? "KEEP (DENSE_RANK LAST " : "keep (dense_rank last ");
      }

      x.getOrderBy().accept(this);
      this.print(')');
      return false;
   }

   public boolean visit(SQLColumnPrimaryKey x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "PRIMARY KEY" : "primary key");
      return false;
   }

   public boolean visit(SQLColumnUniqueKey x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "UNIQUE" : "unique");
      return false;
   }

   public boolean visit(SQLColumnCheck x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "CHECK (" : "check (");
      x.getExpr().accept(this);
      this.print(')');
      if (x.getEnable() != null) {
         if (x.getEnable()) {
            this.print0(this.ucase ? " ENABLE" : " enable");
         } else {
            this.print0(this.ucase ? " DISABLE" : " disable");
         }
      }

      return false;
   }

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

      this.print0(this.ucase ? "WITH " : "with ");
      if (x.getRecursive() == Boolean.TRUE) {
         this.print0(this.ucase ? "RECURSIVE " : "recursive ");
      }

      ++this.indentCount;
      this.printlnAndAccept(x.getEntries(), ", ");
      --this.indentCount;
      return false;
   }

   public boolean visit(SQLWithSubqueryClause.Entry 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 ");
      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 boolean visit(SQLAlterTableModifyClusteredBy x) {
      this.print0(this.ucase ? "CLUSTERED BY " : "clustered by ");
      if (!x.getClusterColumns().isEmpty()) {
         this.printAndAccept(x.getClusterColumns(), ", ");
      } else {
         this.print0("()");
      }

      return false;
   }

   public boolean visit(SQLAlterTableAlterColumn x) {
      if (DbType.odps == this.dbType) {
         this.print0(this.ucase ? "CHANGE COLUMN " : "change column ");
      } else if (DbType.hive == this.dbType) {
         this.print0(this.ucase ? "CHANGE " : "change ");
      } else {
         this.print0(this.ucase ? "ALTER COLUMN " : "alter column ");
      }

      SQLName originColumn = x.getOriginColumn();
      if (originColumn != null) {
         originColumn.accept(this);
         this.print(' ');
      }

      x.getColumn().accept(this);
      if (x.isSetNotNull()) {
         this.print0(this.ucase ? " SET NOT NULL" : " set not null");
      }

      if (x.isDropNotNull()) {
         this.print0(this.ucase ? " DROP NOT NULL" : " drop not null");
      }

      if (x.getSetDefault() != null) {
         this.print0(this.ucase ? " SET DEFAULT " : " set default ");
         x.getSetDefault().accept(this);
      }

      if (x.isDropDefault()) {
         this.print0(this.ucase ? " DROP DEFAULT" : " drop default");
      }

      SQLDataType dataType = x.getDataType();
      if (dataType != null) {
         this.print0(this.ucase ? " SET DATA TYPE " : " set data type ");
         dataType.accept(this);
      }

      SQLName after = x.getAfter();
      if (after != null) {
         this.print0(this.ucase ? " AFTER " : " after ");
         after.accept(this);
      }

      return false;
   }

   public boolean visit(SQLCheck x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "CHECK (" : "check (");
      ++this.indentCount;
      x.getExpr().accept(this);
      --this.indentCount;
      this.print(')');
      Boolean enforced = x.getEnforced();
      if (enforced != null) {
         if (enforced) {
            this.print0(this.ucase ? " ENFORCED" : " enforced");
         } else {
            this.print0(this.ucase ? " NOT ENFORCED" : " not enforced");
         }
      }

      return false;
   }

   public boolean visit(SQLDefault x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "DEFAULT " : "default ");
      ++this.indentCount;
      x.getExpr().accept(this);
      --this.indentCount;
      this.print0(this.ucase ? " FOR " : " for ");
      ++this.indentCount;
      x.getColumn().accept(this);
      --this.indentCount;
      if (x.isWithValues()) {
         this.print0(this.ucase ? " WITH VALUES" : " with values");
      }

      return false;
   }

   public boolean visit(SQLAlterTableDropForeignKey x) {
      this.print0(this.ucase ? "DROP FOREIGN KEY " : "drop foreign key ");
      x.getIndexName().accept(this);
      return false;
   }

   public boolean visit(SQLAlterTableDropPrimaryKey x) {
      this.print0(this.ucase ? "DROP PRIMARY KEY" : "drop primary key");
      return false;
   }

   public boolean visit(SQLAlterTableDropKey x) {
      this.print0(this.ucase ? "DROP KEY " : "drop key ");
      x.getKeyName().accept(this);
      return false;
   }

   public boolean visit(SQLAlterTablePartitionCount x) {
      this.print0(this.ucase ? "PARTITIONS " : "partitons ");
      x.getCount().accept(this);
      return false;
   }

   public boolean visit(SQLAlterTableBlockSize x) {
      this.print0(this.ucase ? "BLOCK_SIZE " : "block_size ");
      x.getSize().accept(this);
      return false;
   }

   public boolean visit(SQLAlterTableEnableKeys x) {
      this.print0(this.ucase ? "ENABLE KEYS" : "enable keys");
      return false;
   }

   public boolean visit(SQLAlterTableDisableKeys x) {
      this.print0(this.ucase ? "DISABLE KEYS" : "disable keys");
      return false;
   }

   public boolean visit(SQLAlterTableDisableConstraint x) {
      this.print0(this.ucase ? "DISABLE CONSTRAINT " : "disable constraint ");
      x.getConstraintName().accept(this);
      if (x.getCascade() != null) {
         this.print0(this.ucase ? " CASCADE " : " cascade ");
      }

      if (x.getRestrict() != null) {
         this.print0(this.ucase ? " RESTRICT " : " restrict ");
      }

      return false;
   }

   public boolean visit(SQLAlterTableEnableConstraint x) {
      this.print0(this.ucase ? "ENABLE CONSTRAINT " : "enable constraint ");
      x.getConstraintName().accept(this);
      if (x.getCheck() != null && x.getCheck()) {
         this.print0(this.ucase ? " CHECK " : " check ");
      }

      if (x.getCheck() != null && !x.getCheck()) {
         this.print0(this.ucase ? " NOT CHECK " : " not check ");
      }

      return false;
   }

   public boolean visit(SQLAlterTableDropConstraint x) {
      this.print0(this.ucase ? "DROP CONSTRAINT " : "drop constraint ");
      x.getConstraintName().accept(this);
      if (x.isCascade()) {
         this.print0(this.ucase ? " CASCADE" : " cascade");
      } else if (x.isRestrict()) {
         this.print0(this.ucase ? " RESTRICT" : " restrict");
      }

      return false;
   }

   public boolean visit(SQLAlterTableStatement x) {
      this.print0(this.ucase ? "ALTER TABLE " : "alter table ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      this.printTableSourceExpr(x.getName());
      ++this.indentCount;

      for(int i = 0; i < x.getItems().size(); ++i) {
         SQLAlterTableItem item = (SQLAlterTableItem)x.getItems().get(i);
         if (i != 0) {
            SQLAlterTableItem former = (SQLAlterTableItem)x.getItems().get(i - 1);
            if (this.dbType != DbType.hive || !(former instanceof SQLAlterTableAddPartition) || !(item instanceof SQLAlterTableAddPartition)) {
               this.print(',');
            }
         }

         this.println();
         item.accept(this);
      }

      --this.indentCount;
      if (x.isMergeSmallFiles()) {
         this.print0(this.ucase ? " MERGE SMALLFILES" : " merge smallfiles");
      }

      List<SQLSelectOrderByItem> clusteredBy = x.getClusteredBy();
      if (clusteredBy.size() > 0) {
         this.println();
         this.print0(this.ucase ? "CLUSTERED BY (" : "clustered by (");
         this.printAndAccept(clusteredBy, ",");
         this.print0(")");
      }

      List<SQLSelectOrderByItem> sortedBy = x.getSortedBy();
      if (sortedBy.size() > 0) {
         this.println();
         this.print0(this.ucase ? "SORTED BY (" : "sorted by (");
         this.printAndAccept(sortedBy, ", ");
         this.print(')');
      }

      int buckets = x.getBuckets();
      if (buckets > 0) {
         this.println();
         this.print0(this.ucase ? "INTO " : "into ");
         this.print(buckets);
         this.print0(this.ucase ? " BUCKETS" : " buckets");
      }

      int shards = x.getShards();
      if (shards > 0) {
         this.println();
         this.print0(this.ucase ? "INTO " : "into ");
         this.print(shards);
         this.print0(this.ucase ? " SHARDS" : " shards");
      }

      return false;
   }

   public boolean visit(SQLExprHint x) {
      x.getExpr().accept(this);
      return false;
   }

   public boolean visit(SQLCreateIndexStatement x) {
      this.print0(this.ucase ? "CREATE " : "create ");
      String type = x.getType();
      if (type != null) {
         this.print0(this.ucase ? type.toUpperCase() : type.toLowerCase());
         this.print(' ');
      }

      if (x.isGlobal()) {
         this.print0(this.ucase ? "GLOBAL " : "global ");
      }

      if (x.isLocal()) {
         this.print0(this.ucase ? "LOCAL " : "local ");
      }

      this.print0(this.ucase ? "INDEX " : "index ");
      x.getName().accept(this);
      this.print0(this.ucase ? " ON " : " on ");
      x.getTable().accept(this);
      this.print0(" (");
      this.printAndAccept(x.getItems(), ", ");
      this.print(')');
      List<SQLName> covering = x.getCovering();
      if (covering.size() > 0) {
         this.print0(this.ucase ? " COVERING (" : " covering (");
         this.printAndAccept(covering, ", ");
         this.print(')');
      }

      SQLExpr dbPartitionBy = x.getDbPartitionBy();
      if (dbPartitionBy != null) {
         this.print0(this.ucase ? " DBPARTITION BY " : " dbpartition by ");
         dbPartitionBy.accept(this);
      }

      SQLExpr tablePartitionBy = x.getTablePartitionBy();
      if (tablePartitionBy != null) {
         this.print0(this.ucase ? " TBPARTITION BY " : " tbpartition by ");
         tablePartitionBy.accept(this);
      }

      SQLExpr tablePartitions = x.getTablePartitions();
      if (tablePartitions != null) {
         this.print0(this.ucase ? " TBPARTITIONS " : " tbpartitions ");
         tablePartitions.accept(this);
      }

      if (x.getIndexDefinition().hasOptions()) {
         String using = x.getIndexDefinition().getOptions().getIndexType();
         if (using != null) {
            this.print0(this.ucase ? " USING " : " using ");
            this.print0(this.ucase ? using.toUpperCase() : using.toLowerCase());
         }

         x.getIndexDefinition().getOptions().accept(this);
      }

      return false;
   }

   public boolean visit(SQLUnique x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "UNIQUE (" : "unique (");
      this.printAndAccept(x.getColumns(), ", ");
      this.print(')');
      return false;
   }

   public boolean visit(SQLPrimaryKeyImpl x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "PRIMARY KEY " : "primary key ");
      if (x.isClustered()) {
         this.print0(this.ucase ? "CLUSTERED " : "clustered ");
      }

      this.print('(');
      this.printAndAccept(x.getColumns(), ", ");
      this.print(')');
      if (x.isDisableNovalidate()) {
         this.print0(this.ucase ? " DISABLE NOVALIDATE" : " disable novalidate");
      }

      return false;
   }

   public boolean visit(SQLAlterTableRenameColumn x) {
      this.print0(this.ucase ? "RENAME COLUMN " : "rename column ");
      x.getColumn().accept(this);
      this.print0(this.ucase ? " TO " : " to ");
      x.getTo().accept(this);
      return false;
   }

   public boolean visit(SQLColumnReference x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "REFERENCES " : "references ");
      x.getTable().accept(this);
      this.print0(" (");
      this.printAndAccept(x.getColumns(), ", ");
      this.print(')');
      SQLForeignKeyImpl.Match match = x.getReferenceMatch();
      if (match != null) {
         this.print0(this.ucase ? " MATCH " : " match ");
         this.print0(this.ucase ? match.name : match.name_lcase);
      }

      if (x.getOnDelete() != null) {
         this.print0(this.ucase ? " ON DELETE " : " on delete ");
         this.print0(this.ucase ? x.getOnDelete().name : x.getOnDelete().name_lcase);
      }

      if (x.getOnUpdate() != null) {
         this.print0(this.ucase ? " ON UPDATE " : " on update ");
         this.print0(this.ucase ? x.getOnUpdate().name : x.getOnUpdate().name_lcase);
      }

      return false;
   }

   public boolean visit(SQLForeignKeyImpl x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "FOREIGN KEY (" : "foreign key (");
      this.printAndAccept(x.getReferencingColumns(), ", ");
      this.print(')');
      ++this.indentCount;
      this.println();
      this.print0(this.ucase ? "REFERENCES " : "references ");
      x.getReferencedTableName().accept(this);
      if (x.getReferencedColumns().size() > 0) {
         this.print0(" (");
         this.printAndAccept(x.getReferencedColumns(), ", ");
         this.print(')');
      }

      if (x.isOnDeleteCascade()) {
         this.println();
         this.print0(this.ucase ? "ON DELETE CASCADE" : "on delete cascade");
      } else if (x.isOnDeleteSetNull()) {
         this.print0(this.ucase ? "ON DELETE SET NULL" : "on delete set null");
      }

      if (x.isDisableNovalidate()) {
         this.print0(this.ucase ? " DISABLE NOVALIDATE" : " disable novalidate");
      }

      --this.indentCount;
      return false;
   }

   public boolean visit(SQLDropSequenceStatement x) {
      this.print0(this.ucase ? "DROP SEQUENCE " : "drop sequence ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

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

   public void endVisit(SQLDropSequenceStatement x) {
   }

   public boolean visit(SQLDropTriggerStatement x) {
      this.print0(this.ucase ? "DROP TRIGGER " : "drop trigger ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

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

   public void endVisit(SQLDropUserStatement x) {
   }

   public boolean visit(SQLDropUserStatement x) {
      this.print0(this.ucase ? "DROP USER " : "drop user ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      this.printAndAccept(x.getUsers(), ", ");
      if (x.isCascade()) {
         this.print0(this.ucase ? " CASCADE " : " cascade ");
      }

      if (x.isRestrict()) {
         this.print0(this.ucase ? " RESTRICT " : " restrict ");
      }

      return false;
   }

   public boolean visit(SQLCancelJobStatement x) {
      this.print0(this.ucase ? "CANCEL JOB " : "cancel job ");
      x.getJobName().accept(this);
      return false;
   }

   public boolean visit(SQLExplainAnalyzeStatement x) {
      this.print0(this.ucase ? "EXPLAIN ANALYZE " : "explain analyze ");
      this.println();
      x.getSelect().accept(this);
      return false;
   }

   public boolean visit(SQLExplainStatement x) {
      this.print0(this.ucase ? "EXPLAIN" : "explain");
      if (x.getHints() != null && x.getHints().size() > 0) {
         this.print(' ');
         this.printAndAccept(x.getHints(), " ");
      }

      if (x.isExtended()) {
         this.print0(this.ucase ? " EXTENDED" : " extended");
      }

      if (x.isDependency()) {
         this.print0(this.ucase ? " DEPENDENCY" : " dependency");
      }

      if (x.isAuthorization()) {
         this.print0(this.ucase ? " AUTHORIZATION" : " authorization");
      }

      String type = x.getType();
      if (type != null) {
         this.print(' ');
         if (type.indexOf(32) >= 0) {
            this.print('(');
            this.print0(type);
            this.print(')');
         } else {
            this.print0(type);
         }
      }

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

   protected void printGrantPrivileges(SQLGrantStatement x) {
   }

   public boolean visit(SQLGrantStatement x) {
      this.print0(this.ucase ? "GRANT " : "grant ");
      this.printAndAccept(x.getPrivileges(), ", ");
      this.printGrantOn(x);
      if (x.getUsers() != null) {
         this.print0(this.ucase ? " TO " : " to ");
         this.printAndAccept(x.getUsers(), ",");
      }

      if (x.getWithGrantOption()) {
         this.print0(this.ucase ? " WITH GRANT OPTION" : " with grant option");
      }

      boolean with = false;
      SQLExpr maxQueriesPerHour = x.getMaxQueriesPerHour();
      if (maxQueriesPerHour != null) {
         if (!with) {
            this.print0(this.ucase ? " WITH" : " with");
            with = true;
         }

         this.print0(this.ucase ? " MAX_QUERIES_PER_HOUR " : " max_queries_per_hour ");
         maxQueriesPerHour.accept(this);
      }

      SQLExpr maxUpdatesPerHour = x.getMaxUpdatesPerHour();
      if (maxUpdatesPerHour != null) {
         if (!with) {
            this.print0(this.ucase ? " WITH" : " with");
            with = true;
         }

         this.print0(this.ucase ? " MAX_UPDATES_PER_HOUR " : " max_updates_per_hour ");
         maxUpdatesPerHour.accept(this);
      }

      SQLExpr maxConnectionsPerHour = x.getMaxConnectionsPerHour();
      if (maxConnectionsPerHour != null) {
         if (!with) {
            this.print0(this.ucase ? " WITH" : " with");
            with = true;
         }

         this.print0(this.ucase ? " MAX_CONNECTIONS_PER_HOUR " : " max_connections_per_hour ");
         maxConnectionsPerHour.accept(this);
      }

      SQLExpr maxUserConnections = x.getMaxUserConnections();
      if (maxUserConnections != null) {
         if (!with) {
            this.print0(this.ucase ? " WITH" : " with");
            with = true;
         }

         this.print0(this.ucase ? " MAX_USER_CONNECTIONS " : " max_user_connections ");
         maxUserConnections.accept(this);
      }

      if (x.isAdminOption()) {
         if (!with) {
            this.print0(this.ucase ? " WITH" : " with");
            with = true;
         }

         this.print0(this.ucase ? " ADMIN OPTION" : " admin option");
      }

      if (x.getIdentifiedBy() != null) {
         this.print0(this.ucase ? " IDENTIFIED BY " : " identified by ");
         x.getIdentifiedBy().accept(this);
      }

      return false;
   }

   protected void printGrantOn(SQLGrantStatement x) {
      if (x.getResource() != null) {
         this.print0(this.ucase ? " ON " : " on ");
         SQLObjectType resourceType = x.getResourceType();
         if (resourceType != null) {
            this.print0(this.ucase ? resourceType.name : resourceType.name_lcase);
            this.print(' ');
         }

         x.getResource().accept(this);
      }

   }

   protected void printRevokeOn(SQLRevokeStatement x) {
      if (x.getResource() != null) {
         this.print0(this.ucase ? " ON " : " on ");
         SQLObjectType resourceType = x.getResourceType();
         if (resourceType != null) {
            this.print0(this.ucase ? resourceType.name : resourceType.name_lcase);
            this.print(' ');
         }

         x.getResource().accept(this);
      }

   }

   public boolean visit(SQLRevokeStatement x) {
      this.print0(this.ucase ? "REVOKE " : "revoke ");
      if (x.isGrantOption()) {
         this.print0(this.ucase ? "GRANT OPTION" : "grant option");
         if (x.getPrivileges().size() > 0) {
            this.print0(this.ucase ? " FOR " : " for ");
         }
      }

      this.printAndAccept(x.getPrivileges(), ", ");
      if (x.getResource() != null) {
         this.print0(this.ucase ? " ON " : " on ");
         if (x.getResourceType() != null) {
            this.print0(x.getResourceType().name());
            this.print(' ');
         }

         x.getResource().accept(this);
      }

      if (x.getUsers() != null) {
         this.print0(this.ucase ? " FROM " : " from ");
         if (this.dbType == DbType.odps) {
            this.print0(this.ucase ? "USER " : "user ");
         }

         this.printAndAccept(x.getUsers(), ", ");
      }

      if (x.isCascade()) {
         this.print0(this.ucase ? " CASCADE " : " cascade ");
      }

      if (x.isRestrict()) {
         this.print0(this.ucase ? " RESTRICT " : " restrict ");
      }

      return false;
   }

   public boolean visit(SQLDropDatabaseStatement x) {
      this.print0(this.ucase ? "DROP " : "drop ");
      if (x.isPhysical()) {
         this.print0(this.ucase ? "PHYSICAL " : "physical ");
      }

      this.print0(this.ucase ? "DATABASE " : "database ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      x.getDatabase().accept(this);
      Boolean restrict = x.getRestrict();
      if (restrict != null && restrict) {
         this.print0(this.ucase ? " RESTRICT" : " restrict");
      }

      if (x.isCascade()) {
         this.print0(this.ucase ? " CASCADE" : " cascade");
      }

      return false;
   }

   public boolean visit(SQLDropCatalogStatement x) {
      if (x.isExternal()) {
         this.print0(this.ucase ? "DROP EXTERNAL CATALOG " : "drop external catalog ");
      } else {
         this.print0(this.ucase ? "DROP CATALOG " : "drop catalog ");
      }

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

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

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

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

      if (x.isTemporary()) {
         this.print0(this.ucase ? "DROP TEMPORARY FUNCTION " : "drop temporary function ");
      } else {
         this.print0(this.ucase ? "DROP FUNCTION " : "drop function ");
      }

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

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

   public boolean visit(SQLDropTableSpaceStatement x) {
      this.print0(this.ucase ? "DROP TABLESPACE " : "drop tablespace ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      x.getName().accept(this);
      SQLExpr engine = x.getEngine();
      if (engine != null) {
         this.print0(this.ucase ? " ENGINE " : " engine ");
         engine.accept(this);
      }

      if (x.isIncludingContents()) {
         this.printUcase(" IDENTIFIER INCLUDING ");
      }

      return false;
   }

   public boolean visit(SQLDropProcedureStatement x) {
      this.print0(this.ucase ? "DROP PROCEDURE " : "drop procedure ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

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

   public boolean visit(SQLIndexOptions x) {
      SQLExpr keyBlockSize = x.getKeyBlockSize();
      if (keyBlockSize != null) {
         this.print0(this.ucase ? " KEY_BLOCK_SIZE = " : " key_block_size = ");
         this.printExpr(keyBlockSize, this.parameterized);
      }

      String parserName = x.getParserName();
      if (parserName != null) {
         this.print0(this.ucase ? " WITH PARSER " : " with parser ");
         this.print0(parserName);
      }

      SQLExpr comment = x.getComment();
      if (comment != null) {
         this.print0(this.ucase ? " COMMENT " : " comment ");
         this.printExpr(comment, this.parameterized);
      }

      String algorithm = x.getAlgorithm();
      if (algorithm != null) {
         this.print0(this.ucase ? " ALGORITHM = " : " algorithm = ");
         this.print0(algorithm);
      }

      String lock = x.getLock();
      if (lock != null) {
         this.print0(this.ucase ? " LOCK = " : " lock = ");
         this.print0(lock);
      }

      List<SQLAssignItem> options = x.getOtherOptions();
      if (options.size() > 0) {
         for(SQLAssignItem option : options) {
            this.print(' ');
            option.accept(this);
         }
      }

      return false;
   }

   public boolean visit(SQLIndexDefinition x) {
      boolean var10000 = DbType.mysql == this.dbType;
      String type = x.getType();
      if (type != null) {
         this.print0(this.ucase ? type.toUpperCase() : type.toLowerCase());
         this.print(' ');
      }

      if (x.isGlobal()) {
         this.print0(this.ucase ? "GLOBAL " : "global ");
      } else if (x.isLocal()) {
         this.print0(this.ucase ? "LOCAL " : "local ");
      }

      if (x.isIndex()) {
         this.print0(this.ucase ? "INDEX " : "index ");
      }

      if (x.isKey()) {
         this.print0(this.ucase ? "KEY " : "key ");
      }

      if (x.getName() != null && (type == null || !type.equalsIgnoreCase("primary"))) {
         x.getName().accept(this);
         this.print(' ');
      }

      String using = x.getOptions().getIndexType();
      if (using != null) {
         this.print0(this.ucase ? "USING " : "using ");
         this.print0(using);
         this.print(' ');
      }

      if (x.isHashMapType()) {
         this.print0(this.ucase ? "HASHMAP " : "hashmap ");
      }

      this.print('(');
      this.printAndAccept(x.getColumns(), ", ");
      this.print(')');
      if (x.getAnalyzerName() != null) {
         this.print0(this.ucase ? " WITH ANALYZER " : " with analyzer ");
         x.getAnalyzerName().accept(this);
      } else {
         if (x.getIndexAnalyzerName() != null) {
            this.print0(this.ucase ? " WITH INDEX ANALYZER " : " with index analyzer ");
            x.getIndexAnalyzerName().accept(this);
         }

         if (x.getQueryAnalyzerName() != null) {
            this.print0(this.ucase ? " WITH QUERY ANALYZER " : " with query analyzer ");
            x.getQueryAnalyzerName().accept(this);
         }

         if (x.getWithDicName() != null) {
            this.printUcase(" WITH DICT ");
            x.getWithDicName().accept(this);
         }
      }

      List<SQLName> covering = x.getCovering();
      if (covering.size() > 0) {
         this.print0(this.ucase ? " COVERING (" : " covering (");
         this.printAndAccept(covering, ", ");
         this.print(')');
      }

      SQLExpr dbPartitionBy = x.getDbPartitionBy();
      if (dbPartitionBy != null) {
         this.print0(this.ucase ? " DBPARTITION BY " : " dbpartition by ");
         dbPartitionBy.accept(this);
      }

      SQLExpr tablePartitionBy = x.getTbPartitionBy();
      if (tablePartitionBy != null) {
         this.print0(this.ucase ? " TBPARTITION BY " : " tbpartition by ");
         tablePartitionBy.accept(this);
      }

      SQLExpr tablePartitions = x.getTbPartitions();
      if (tablePartitions != null) {
         this.print0(this.ucase ? " TBPARTITIONS " : " tbpartitions ");
         tablePartitions.accept(this);
      }

      if (x.hasOptions()) {
         x.getOptions().accept(this);
      }

      return false;
   }

   public boolean visit(SQLAlterTableAddIndex x) {
      this.print0(this.ucase ? "ADD " : "add ");
      this.visit(x.getIndexDefinition());
      return false;
   }

   public boolean visit(SQLAlterTableAddConstraint x) {
      if (x.isWithNoCheck()) {
         this.print0(this.ucase ? "WITH NOCHECK " : "with nocheck ");
      }

      this.print0(this.ucase ? "ADD " : "add ");
      x.getConstraint().accept(this);
      return false;
   }

   public boolean visit(SQLCreateTriggerStatement x) {
      this.print0(this.ucase ? "CREATE " : "create ");
      if (x.isOrReplace()) {
         this.print0(this.ucase ? "OR REPLACE " : "or replace ");
      }

      this.print0(this.ucase ? "TRIGGER " : "trigger ");
      x.getName().accept(this);
      ++this.indentCount;
      this.println();
      if (SQLCreateTriggerStatement.TriggerType.INSTEAD_OF.equals(x.getTriggerType())) {
         this.print0(this.ucase ? "INSTEAD OF" : "instead of");
      } else {
         String triggerTypeName = x.getTriggerType().name();
         this.print0(this.ucase ? triggerTypeName : triggerTypeName.toLowerCase());
      }

      if (x.isInsert()) {
         this.print0(this.ucase ? " INSERT" : " insert");
      }

      if (x.isDelete()) {
         if (x.isInsert()) {
            this.print0(this.ucase ? " OR" : " or");
         }

         this.print0(this.ucase ? " DELETE" : " delete");
      }

      if (x.isUpdate()) {
         if (x.isInsert() || x.isDelete()) {
            this.print0(this.ucase ? " OR" : " or");
         }

         this.print0(this.ucase ? " UPDATE" : " update");

         for(SQLName colum : x.getUpdateOfColumns()) {
            this.print(' ');
            colum.accept(this);
         }
      }

      this.println();
      this.print0(this.ucase ? "ON " : "on ");
      x.getOn().accept(this);
      if (x.isForEachRow()) {
         this.println();
         this.print0(this.ucase ? "FOR EACH ROW" : "for each row");
      }

      SQLExpr when = x.getWhen();
      if (when != null) {
         this.println();
         this.print0(this.ucase ? "WHEN " : "when ");
         when.accept(this);
      }

      --this.indentCount;
      this.println();
      x.getBody().accept(this);
      return false;
   }

   public boolean visit(SQLBooleanExpr x) {
      this.print0(x.getBooleanValue() ? "true" : "false");
      return false;
   }

   public void endVisit(SQLBooleanExpr x) {
   }

   public boolean visit(SQLUnionQueryTableSource x) {
      this.print('(');
      ++this.indentCount;
      this.println();
      x.getUnion().accept(this);
      --this.indentCount;
      this.println();
      this.print(')');
      if (x.getAlias() != null) {
         this.print(' ');
         this.print0(x.getAlias());
      }

      return false;
   }

   public boolean visit(SQLTimestampExpr x) {
      if (this.parameterized) {
         this.print('?');
         this.incrementReplaceCunt();
         if (this.parameters != null) {
            ExportParameterVisitorUtils.exportParameter(this.parameters, (SQLExpr)x);
         }
      } else {
         this.print0(this.ucase ? "TIMESTAMP " : "timestamp ");
         if (x.isWithTimeZone()) {
            this.print0(this.ucase ? " WITH TIME ZONE " : " with time zone ");
         }

         this.print('\'');
         this.print0(x.getLiteral());
         this.print('\'');
         if (x.getTimeZone() != null) {
            this.print0(this.ucase ? " AT TIME ZONE '" : " at time zone '");
            this.print0(x.getTimeZone());
            this.print('\'');
         }
      }

      return false;
   }

   public boolean visit(SQLBinaryExpr x) {
      this.print0("b'");
      this.print0(x.getText());
      this.print('\'');
      return false;
   }

   public boolean visit(SQLAlterTableRename x) {
      this.print0(this.ucase ? "RENAME TO " : "rename to ");
      x.getTo().accept(this);
      return false;
   }

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

      if (x.isFull()) {
         this.print0(this.ucase ? "SHOW FULL TABLES" : "show full tables");
      } else {
         this.print0(this.ucase ? "SHOW TABLES" : "show tables");
      }

      if (x.isExtended()) {
         this.print0(this.ucase ? " EXTENDED" : " extended");
      }

      if (x.getDatabase() != null) {
         this.print0(this.ucase ? " FROM " : " from ");
         x.getDatabase().accept(this);
      }

      if (x.getLike() != null) {
         this.print0(this.ucase ? " LIKE " : " like ");
         x.getLike().accept(this);
      } else if (x.getWhere() != null) {
         this.print0(this.ucase ? " WHERE " : " where ");
         x.getWhere().accept(this);
      }

      return false;
   }

   protected void printlnComment(List<String> comments) {
      if (comments != null) {
         for(int i = 0; i < comments.size(); ++i) {
            String comment = (String)comments.get(i);
            if (i != 0 && comment.startsWith("--")) {
               this.println();
            }

            this.printComment(comment);
         }
      }

   }

   public void printComment(String comment) {
      if (comment != null) {
         if (comment.startsWith("--") && comment.length() > 2 && comment.charAt(2) != ' ') {
            this.print0("-- ");
            this.print0(comment.substring(2));
         } else {
            this.print0(comment);
         }

      }
   }

   protected void printlnComments(List<String> comments) {
      if (comments != null) {
         for(int i = 0; i < comments.size(); ++i) {
            String comment = (String)comments.get(i);
            this.printComment(comment);
            this.println();
         }
      }

   }

   public boolean visit(SQLAlterViewRenameStatement x) {
      this.print0(this.ucase ? "ALTER VIEW " : "alter view ");
      x.getName().accept(this);
      this.print0(this.ucase ? " RENAME TO " : " rename to ");
      x.getTo().accept(this);
      return false;
   }

   public boolean visit(SQLAlterTableAddPartition x) {
      boolean printAdd = true;
      if (x.getParent() instanceof SQLAlterTableStatement) {
         SQLAlterTableStatement stmt = (SQLAlterTableStatement)x.getParent();
         int p = stmt.getChildren().indexOf(x);
         if (p > 0 && stmt.getChildren().get(p - 1) instanceof SQLAlterTableAddPartition) {
            printAdd = false;
         }
      }

      if (printAdd) {
         this.print0(this.ucase ? "ADD " : "add ");
         if (x.isIfNotExists()) {
            this.print0(this.ucase ? "IF NOT EXISTS " : "if not exists ");
         }
      } else {
         this.print('\t');
         ++this.indentCount;
      }

      if (x.getPartitionCount() != null) {
         this.print0(this.ucase ? "PARTITION PARTITIONS " : "partition partitions ");
         x.getPartitionCount().accept(this);
      }

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

      SQLExpr location = x.getLocation();
      if (location != null) {
         this.print0(this.ucase ? " LOCATION " : " locationn ");
         location.accept(this);
      }

      if (!printAdd) {
         --this.indentCount;
      }

      return false;
   }

   public boolean visit(SQLAlterTableAddExtPartition x) {
      this.print0(this.ucase ? "ADD " : "add ");
      MySqlExtPartition extPartition = x.getExtPartition();
      if (extPartition != null) {
         this.println();
         extPartition.accept(this);
      }

      return false;
   }

   public boolean visit(SQLAlterTableDropExtPartition x) {
      this.print0(this.ucase ? "DROP " : "drop ");
      MySqlExtPartition extPartition = x.getExtPartition();
      if (extPartition != null) {
         this.println();
         extPartition.accept(this);
      }

      return false;
   }

   public boolean visit(SQLAlterTableReOrganizePartition x) {
      this.print0(this.ucase ? "REORGANIZE " : "reorganize ");
      this.printAndAccept(x.getNames(), ", ");
      this.print0(this.ucase ? " INTO (" : " into (");
      this.printAndAccept(x.getPartitions(), ", ");
      this.print(')');
      return false;
   }

   public boolean visit(SQLAlterTableDropPartition x) {
      boolean printDrop = true;
      if (x.getParent() instanceof SQLAlterTableStatement) {
         SQLAlterTableStatement stmt = (SQLAlterTableStatement)x.getParent();
         int p = stmt.getChildren().indexOf(x);
         if (p > 0 && stmt.getChildren().get(p - 1) instanceof SQLAlterTableDropPartition) {
            printDrop = false;
         }
      }

      if (printDrop) {
         this.print0(this.ucase ? "DROP " : "drop ");
         if (x.isIfExists()) {
            this.print0(this.ucase ? "IF EXISTS " : "if exists ");
         }
      } else {
         this.print('\t');
         ++this.indentCount;
      }

      if (x.getAttribute("SIMPLE") != null) {
         this.print0(this.ucase ? "PARTITION " : "partition ");
         this.printAndAccept(x.getPartitions(), ",");
      } else {
         this.print0(this.ucase ? "PARTITION (" : "partition (");
         this.printAndAccept(x.getPartitions(), ", ");
         this.print(')');
      }

      if (x.isPurge()) {
         this.print0(this.ucase ? " PURGE" : " purge");
      }

      return false;
   }

   public boolean visit(SQLAlterTableRenamePartition x) {
      this.print0(this.ucase ? "PARTITION (" : "partition (");
      this.printAndAccept(x.getPartition(), ", ");
      this.print0(this.ucase ? ") RENAME TO PARTITION(" : ") rename to partition(");
      this.printAndAccept(x.getTo(), ", ");
      this.print(')');
      return false;
   }

   public boolean visit(SQLAlterTableSetComment x) {
      this.print0(this.ucase ? "SET COMMENT " : "set comment ");
      x.getComment().accept(this);
      return false;
   }

   public boolean visit(SQLPrivilegeItem x) {
      this.printExpr(x.getAction());
      if (!x.getColumns().isEmpty()) {
         this.print0("(");
         this.printAndAccept(x.getColumns(), ", ");
         this.print0(")");
      }

      return false;
   }

   public void endVisit(SQLPrivilegeItem x) {
   }

   public boolean visit(SQLAlterTableSetLifecycle x) {
      this.print0(this.ucase ? "SET LIFECYCLE " : "set lifecycle ");
      x.getLifecycle().accept(this);
      return false;
   }

   public boolean visit(SQLAlterTableSetLocation x) {
      this.print0(this.ucase ? "SET LOCATION " : "set location ");
      x.getLocation().accept(this);
      return false;
   }

   public boolean visit(SQLAlterTableEnableLifecycle x) {
      if (x.getPartition().size() != 0) {
         this.print0(this.ucase ? "PARTITION (" : "partition (");
         this.printAndAccept(x.getPartition(), ", ");
         this.print0(") ");
      }

      this.print0(this.ucase ? "ENABLE LIFECYCLE" : "enable lifecycle");
      return false;
   }

   public boolean visit(SQLAlterTableDisableLifecycle x) {
      if (x.getPartition().size() != 0) {
         this.print0(this.ucase ? "PARTITION (" : "partition (");
         this.printAndAccept(x.getPartition(), ", ");
         this.print0(") ");
      }

      this.print0(this.ucase ? "DISABLE LIFECYCLE" : "disable lifecycle");
      return false;
   }

   public boolean visit(SQLAlterTablePartition x) {
      if (x.getPartition().size() != 0) {
         this.print0(this.ucase ? "PARTITION (" : "partition (");
         this.printAndAccept(x.getPartition(), ", ");
         this.print0(") ");
      }

      return false;
   }

   public boolean visit(SQLAlterTablePartitionSetProperties x) {
      if (x.getPartition().size() != 0) {
         this.print0(this.ucase ? "PARTITION (" : "partition (");
         this.printAndAccept(x.getPartition(), ", ");
         this.print0(") ");
      }

      if (x.getPartitionProperties().size() != 0) {
         this.print0(this.ucase ? "SET PARTITIONPROPERTIES (" : "set partitionproperties (");
         this.printAndAccept(x.getPartitionProperties(), ", ");
         this.print0(") ");
      }

      return false;
   }

   public boolean visit(SQLAlterTableTouch x) {
      this.print0(this.ucase ? "TOUCH" : "touch");
      if (x.getPartition().size() != 0) {
         this.print0(this.ucase ? " PARTITION (" : " partition (");
         this.printAndAccept(x.getPartition(), ", ");
         this.print(')');
      }

      return false;
   }

   public boolean visit(SQLArrayExpr x) {
      SQLExpr expr = x.getExpr();
      if (expr instanceof SQLIdentifierExpr && ((SQLIdentifierExpr)expr).nameHashCode64() == FnvHash.Constants.ARRAY && this.printNameQuote) {
         this.print0(((SQLIdentifierExpr)expr).getName());
      } else if (expr != null) {
         expr.accept(this);
      }

      this.print('[');
      this.printAndAccept(x.getValues(), ", ");
      this.print(']');
      return false;
   }

   public boolean visit(SQLOpenStatement x) {
      this.print0(this.ucase ? "OPEN " : "open ");
      this.printExpr(x.getCursorName(), this.parameterized);
      List<SQLName> columns = x.getColumns();
      if (columns.size() > 0) {
         this.print('(');
         this.printAndAccept(columns, ", ");
         this.print(')');
      }

      SQLExpr forExpr = x.getFor();
      if (forExpr != null) {
         this.print0(this.ucase ? " FOR " : " for ");
         forExpr.accept(this);
      }

      List<SQLExpr> using = x.getUsing();
      if (using.size() > 0) {
         this.print0(this.ucase ? " USING " : " using ");
         this.printAndAccept(using, ", ");
      }

      return false;
   }

   public boolean visit(SQLFetchStatement x) {
      this.print0(this.ucase ? "FETCH " : "fetch ");
      x.getCursorName().accept(this);
      if (x.isBulkCollect()) {
         this.print0(this.ucase ? " BULK COLLECT INTO " : " bulk collect into ");
      } else {
         this.print0(this.ucase ? " INTO " : " into ");
      }

      this.printAndAccept(x.getInto(), ", ");
      SQLLimit limit = x.getLimit();
      if (limit != null) {
         this.print(' ');
         limit.accept(this);
      }

      return false;
   }

   public boolean visit(SQLCloseStatement x) {
      this.print0(this.ucase ? "CLOSE " : "close ");
      this.printExpr(x.getCursorName(), this.parameterized);
      return false;
   }

   public boolean visit(SQLGroupingSetExpr x) {
      this.print0(this.ucase ? "GROUPING SETS" : "grouping sets");
      this.print0(" (");
      this.printAndAccept(x.getParameters(), ", ");
      this.print(')');
      return false;
   }

   public boolean visit(SQLIfStatement x) {
      this.print0(this.ucase ? "IF " : "if ");
      x.getCondition().accept(this);
      ++this.indentCount;
      this.println();
      int i = 0;

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

      --this.indentCount;

      for(SQLIfStatement.ElseIf elseIf : x.getElseIfList()) {
         this.println();
         elseIf.accept(this);
      }

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

      return false;
   }

   public boolean visit(SQLIfStatement.Else x) {
      this.print0(this.ucase ? "ELSE" : "else");
      ++this.indentCount;
      this.println();
      int i = 0;

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

         SQLStatement item = (SQLStatement)x.getStatements().get(i);
         item.accept(this);
      }

      --this.indentCount;
      return false;
   }

   public boolean visit(SQLIfStatement.ElseIf x) {
      this.print0(this.ucase ? "ELSE IF" : "else if");
      x.getCondition().accept(this);
      this.print0(this.ucase ? " THEN" : " then");
      ++this.indentCount;
      this.println();
      int i = 0;

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

         SQLStatement item = (SQLStatement)x.getStatements().get(i);
         item.accept(this);
      }

      --this.indentCount;
      return false;
   }

   public boolean visit(SQLLoopStatement x) {
      this.print0(this.ucase ? "LOOP" : "loop");
      ++this.indentCount;
      this.println();
      int i = 0;

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

      --this.indentCount;
      this.println();
      this.print0(this.ucase ? "END LOOP" : "end loop");
      if (x.getLabelName() != null) {
         this.print(' ');
         this.print0(x.getLabelName());
      }

      return false;
   }

   public boolean visit(OracleFunctionDataType x) {
      if (x.isStatic()) {
         this.print0(this.ucase ? "STATIC " : "static ");
      }

      this.print0(this.ucase ? "FUNCTION " : "function ");
      this.print0(x.getName());
      this.print(" (");
      this.printAndAccept(x.getParameters(), ", ");
      this.print(")");
      this.print0(this.ucase ? " RETURN " : " return ");
      x.getReturnDataType().accept(this);
      SQLStatement block = x.getBlock();
      if (block != null) {
         this.println();
         this.print0(this.ucase ? "IS" : "is");
         this.println();
         block.accept(this);
      }

      return false;
   }

   public boolean visit(OracleProcedureDataType x) {
      if (x.isStatic()) {
         this.print0(this.ucase ? "STATIC " : "static ");
      }

      this.print0(this.ucase ? "PROCEDURE " : "procedure ");
      this.print0(x.getName());
      if (x.getParameters().size() > 0) {
         this.print(" (");
         this.printAndAccept(x.getParameters(), ", ");
         this.print(")");
      }

      SQLStatement block = x.getBlock();
      if (block != null) {
         this.println();
         this.print0(this.ucase ? "IS" : "is");
         this.println();
         block.accept(this);
      }

      return false;
   }

   public boolean visit(SQLParameter x) {
      SQLName name = x.getName();
      if (x.getDataType().getName().equalsIgnoreCase("CURSOR")) {
         this.print0(this.ucase ? "CURSOR " : "cursor ");
         x.getName().accept(this);
         this.print0(this.ucase ? " IS" : " is");
         ++this.indentCount;
         this.println();
         SQLSelect select = ((SQLQueryExpr)x.getDefaultValue()).getSubQuery();
         select.accept(this);
         --this.indentCount;
      } else {
         if (x.isMap()) {
            this.print0(this.ucase ? "MAP MEMBER " : "map member ");
         } else if (x.isOrder()) {
            this.print0(this.ucase ? "ORDER MEMBER " : "order member ");
         } else if (x.isMember()) {
            this.print0(this.ucase ? "MEMBER " : "member ");
         }

         SQLDataType dataType = x.getDataType();
         if (DbType.oracle != this.dbType && !(dataType instanceof OracleFunctionDataType) && !(dataType instanceof OracleProcedureDataType)) {
            if (x.getParamType() != SQLParameter.ParameterType.IN) {
               if (x.getParamType() == SQLParameter.ParameterType.OUT) {
                  this.print0(this.ucase ? "OUT " : "out ");
               } else if (x.getParamType() == SQLParameter.ParameterType.INOUT) {
                  this.print0(this.ucase ? "INOUT " : "inout ");
               }
            } else {
               boolean skip = DbType.mysql == this.dbType && x.getParent() instanceof SQLCreateFunctionStatement;
               if (!skip) {
                  this.print0(this.ucase ? "IN " : "in ");
               }
            }

            x.getName().accept(this);
            this.print(' ');
         } else {
            if (dataType instanceof OracleFunctionDataType) {
               OracleFunctionDataType functionDataType = (OracleFunctionDataType)dataType;
               this.visit(functionDataType);
               return false;
            }

            if (dataType instanceof OracleProcedureDataType) {
               OracleProcedureDataType procedureDataType = (OracleProcedureDataType)dataType;
               this.visit(procedureDataType);
               return false;
            }

            String dataTypeName = dataType.getName();
            boolean printType = dataTypeName.startsWith("TABLE OF") && x.getDefaultValue() == null || dataTypeName.equalsIgnoreCase("REF CURSOR") || dataTypeName.startsWith("VARRAY(");
            if (printType) {
               this.print0(this.ucase ? "TYPE " : "type ");
            }

            name.accept(this);
            if (x.getParamType() == SQLParameter.ParameterType.IN) {
               this.print0(this.ucase ? " IN " : " in ");
            } else if (x.getParamType() == SQLParameter.ParameterType.OUT) {
               this.print0(this.ucase ? " OUT " : " out ");
            } else if (x.getParamType() == SQLParameter.ParameterType.INOUT) {
               this.print0(this.ucase ? " IN OUT " : " in out ");
            } else {
               this.print(' ');
            }

            if (x.isNoCopy()) {
               this.print0(this.ucase ? "NOCOPY " : "nocopy ");
            }

            if (x.isConstant()) {
               this.print0(this.ucase ? "CONSTANT " : "constant ");
            }

            if (printType) {
               this.print0(this.ucase ? "IS " : "is ");
            }
         }

         dataType.accept(this);
         this.printParamDefaultValue(x);
      }

      return false;
   }

   protected void printParamDefaultValue(SQLParameter x) {
      if (x.getDefaultValue() != null) {
         this.print0(" := ");
         x.getDefaultValue().accept(this);
      }

   }

   public boolean visit(SQLDeclareItem x) {
      SQLDataType dataType = x.getDataType();
      if (dataType instanceof SQLRecordDataType) {
         this.print0(this.ucase ? "TYPE " : "type ");
      }

      x.getName().accept(this);
      if (x.getType() == SQLDeclareItem.Type.TABLE) {
         this.print0(this.ucase ? " TABLE" : " table");
         int size = x.getTableElementList().size();
         if (size > 0) {
            this.print0(" (");
            ++this.indentCount;
            this.println();

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

               ((SQLTableElement)x.getTableElementList().get(i)).accept(this);
            }

            --this.indentCount;
            this.println();
            this.print(')');
         }
      } else if (x.getType() == SQLDeclareItem.Type.CURSOR) {
         this.print0(this.ucase ? " CURSOR" : " cursor");
      } else {
         if (dataType != null) {
            if (dataType instanceof SQLRecordDataType) {
               this.print0(this.ucase ? " IS " : " is ");
            } else {
               this.print(' ');
            }

            dataType.accept(this);
         }

         if (x.getValue() != null) {
            if (DbType.dm == this.getDbType() && "EXCEPTION".equalsIgnoreCase(dataType.toString())) {
               this.print0(this.ucase ? " FOR " : " for ");
            } else if (DbType.dm == this.getDbType() && "CURSOR".equalsIgnoreCase(dataType.toString())) {
               this.print0(this.ucase ? " FOR " : " for ");
            } else if (DbType.mysql != this.getDbType() && DbType.dm != this.getDbType()) {
               this.print0(" = ");
            } else {
               this.print0(this.ucase ? " DEFAULT " : " default ");
            }

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

      return false;
   }

   public boolean visit(SQLPartitionValue x) {
      if (x.getOperator() == SQLPartitionValue.Operator.LessThan && DbType.oracle != this.getDbType() && DbType.dm != this.getDbType() && x.getItems().size() == 1 && x.getItems().get(0) instanceof SQLIdentifierExpr) {
         SQLIdentifierExpr ident = (SQLIdentifierExpr)x.getItems().get(0);
         if ("MAXVALUE".equalsIgnoreCase(ident.getName())) {
            this.print0(this.ucase ? "VALUES LESS THAN MAXVALUE" : "values less than maxvalue");
            return false;
         }
      }

      if (x.getOperator() == SQLPartitionValue.Operator.LessThan) {
         this.print0(this.ucase ? "VALUES LESS THAN (" : "values less than (");
      } else if (x.getOperator() == SQLPartitionValue.Operator.In) {
         this.print0(this.ucase ? "VALUES IN (" : "values in (");
      } else if (x.getOperator() == SQLPartitionValue.Operator.EquorLessThan) {
         this.print0(this.ucase ? "VALUES EQU OR LESS THAN (" : "values equ or less than (");
      } else {
         this.print(this.ucase ? "VALUES (" : "values (");
      }

      this.printAndAccept(x.getItems(), ", ", false);
      this.print(')');
      return false;
   }

   public DbType getDbType() {
      return this.dbType;
   }

   public boolean isUppCase() {
      return this.ucase;
   }

   public void setUppCase(boolean val) {
      this.config(VisitorFeature.OutputUCase, true);
   }

   public boolean visit(SQLPartition x) {
      boolean isDbPartiton = false;
      boolean isTbPartition = false;
      SQLObject parent = x.getParent();
      if (parent != null) {
         SQLObject parent2 = parent.getParent();
         if (parent2 instanceof MySqlCreateTableStatement) {
            MySqlCreateTableStatement stmt = (MySqlCreateTableStatement)parent2;
            isDbPartiton = parent == stmt.getDbPartitionBy();
            isTbPartition = parent == stmt.getTablePartitionBy();
         }
      }

      if (isDbPartiton) {
         this.print0(this.ucase ? "DBPARTITION " : "dbpartition ");
      } else if (isTbPartition) {
         this.print0(this.ucase ? "TBPARTITION " : "tbpartition ");
      } else {
         this.print0(this.ucase ? "PARTITION " : "partition ");
      }

      x.getName().accept(this);
      if (x.getValues() != null) {
         this.print(' ');
         x.getValues().accept(this);
      }

      if (x.getDataDirectory() != null) {
         ++this.indentCount;
         this.println();
         this.print0(this.ucase ? "DATA DIRECTORY " : "data directory ");
         x.getDataDirectory().accept(this);
         --this.indentCount;
      }

      if (x.getIndexDirectory() != null) {
         ++this.indentCount;
         this.println();
         this.print0(this.ucase ? "INDEX DIRECTORY " : "index directory ");
         x.getIndexDirectory().accept(this);
         --this.indentCount;
      }

      ++this.indentCount;
      this.printOracleSegmentAttributes(x);
      if (x.getEngine() != null) {
         this.println();
         this.print0(this.ucase ? "STORAGE ENGINE " : "storage engine ");
         x.getEngine().accept(this);
      }

      --this.indentCount;
      if (x.getMaxRows() != null) {
         this.print0(this.ucase ? " MAX_ROWS " : " max_rows ");
         x.getMaxRows().accept(this);
      }

      if (x.getMinRows() != null) {
         this.print0(this.ucase ? " MIN_ROWS " : " min_rows ");
         x.getMinRows().accept(this);
      }

      if (x.getComment() != null) {
         this.print0(this.ucase ? " COMMENT " : " comment ");
         x.getComment().accept(this);
      }

      if (x.getSubPartitionsCount() != null) {
         ++this.indentCount;
         this.println();
         this.print0(this.ucase ? "SUBPARTITIONS " : "subpartitions ");
         x.getSubPartitionsCount().accept(this);
         --this.indentCount;
      }

      if (x.getSubPartitions().size() > 0) {
         this.print(" (");
         ++this.indentCount;

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

            this.println();
            ((SQLSubPartition)x.getSubPartitions().get(i)).accept(this);
         }

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

      return false;
   }

   public boolean visit(SQLPartitionByRange x) {
      SQLExpr interval = x.getInterval();
      if (x.getColumns().size() != 0 || !(interval instanceof SQLBetweenExpr) && !(interval instanceof SQLMethodInvokeExpr)) {
         this.print0(this.ucase ? "RANGE" : "range");
         boolean columns = true;

         for(SQLExpr column : x.getColumns()) {
            if (!(column instanceof SQLName)) {
               columns = false;
               break;
            }
         }

         if (x.getColumns().size() == 1) {
            if (DbType.mysql == this.getDbType() && columns) {
               this.print0(this.ucase ? " COLUMNS (" : " columns (");
            } else {
               this.print0(" (");
            }

            ((SQLExpr)x.getColumns().get(0)).accept(this);
            this.print(')');
         } else {
            if (DbType.mysql == this.getDbType() && columns) {
               this.print0(this.ucase ? " COLUMNS (" : " columns (");
            } else {
               this.print0(" (");
            }

            this.printAndAccept(x.getColumns(), ", ");
            this.print(')');
         }

         if (interval != null) {
            this.print0(this.ucase ? " INTERVAL (" : " interval (");
            interval.accept(this);
            this.print(')');
         }
      } else {
         interval.accept(this);
      }

      this.printPartitionsCountAndSubPartitions(x);
      if (x.getPartitions().size() > 0) {
         this.print(" (");
         ++this.indentCount;
         int i = 0;

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

            this.println();
            ((SQLPartition)x.getPartitions().get(i)).accept(this);
         }

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

      return false;
   }

   public boolean visit(SQLPartitionByList x) {
      this.print0(this.ucase ? "LIST " : "list ");
      if (x.getColumns().size() == 1) {
         this.print('(');
         ((SQLExpr)x.getColumns().get(0)).accept(this);
         this.print0(")");
      } else {
         this.print0(this.ucase ? "COLUMNS (" : "columns (");
         this.printAndAccept(x.getColumns(), ", ");
         this.print0(")");
      }

      this.printPartitionsCountAndSubPartitions(x);
      this.printSQLPartitions(x.getPartitions());
      return false;
   }

   public boolean visit(SQLPartitionByHash x) {
      if (x.isLinear()) {
         this.print0(this.ucase ? "LINEAR HASH " : "linear hash ");
      } else if (x.isUnique()) {
         this.print0(this.ucase ? "UNI_HASH " : "uni_hash ");
      } else {
         this.print0(this.ucase ? "HASH " : "hash ");
      }

      if (x.isKey()) {
         this.print0(this.ucase ? "KEY" : "key");
      }

      this.print('(');
      this.printAndAccept(x.getColumns(), ", ");
      this.print(')');
      this.printPartitionsCountAndSubPartitions(x);
      this.printSQLPartitions(x.getPartitions());
      return false;
   }

   public boolean visit(SQLPartitionByValue x) {
      this.print0(this.ucase ? "VALUE " : "value ");
      this.print('(');
      this.printAndAccept(x.getColumns(), ", ");
      this.print(')');
      this.printPartitionsCountAndSubPartitions(x);
      this.printSQLPartitions(x.getPartitions());
      return false;
   }

   protected void printSQLPartitions(List<SQLPartition> partitions) {
      int partitionsSize = partitions.size();
      if (partitionsSize > 0) {
         this.print0(" (");
         ++this.indentCount;

         for(int i = 0; i < partitionsSize; ++i) {
            this.println();
            ((SQLPartition)partitions.get(i)).accept(this);
            if (i != partitionsSize - 1) {
               this.print0(", ");
            }
         }

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

   }

   protected void printPartitionsCountAndSubPartitions(SQLPartitionBy x) {
      SQLExpr partitionsCount = x.getPartitionsCount();
      if (partitionsCount != null) {
         boolean isDbPartiton = false;
         boolean isTbPartition = false;
         if (x.getParent() instanceof MySqlCreateTableStatement) {
            MySqlCreateTableStatement stmt = (MySqlCreateTableStatement)x.getParent();
            isDbPartiton = x == stmt.getDbPartitionBy();
            isTbPartition = x == stmt.getTablePartitionBy();
         }

         if (Boolean.TRUE.equals(x.getAttribute("ads.partition"))) {
            this.print0(this.ucase ? " PARTITION NUM " : " partition num ");
         } else if (isDbPartiton) {
            this.print0(this.ucase ? " DBPARTITIONS " : " dbpartitions ");
         } else if (isTbPartition) {
            this.print0(this.ucase ? " TBPARTITIONS " : " tbpartitions ");
         } else {
            this.print0(this.ucase ? " PARTITIONS " : " partitions ");
         }

         partitionsCount.accept(this);
      }

      if (x.getLifecycle() != null) {
         this.print0(this.ucase ? " LIFECYCLE " : " lifecycle ");
         x.getLifecycle().accept(this);
      }

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

      if (x.getStoreIn().size() > 0) {
         this.println();
         this.print0(this.ucase ? "STORE IN (" : "store in (");
         this.printAndAccept(x.getStoreIn(), ", ");
         this.print(')');
      }

   }

   public boolean visit(SQLSubPartitionByHash x) {
      if (x.isLinear()) {
         this.print0(this.ucase ? "SUBPARTITION BY LINEAR HASH " : "subpartition by linear hash ");
      } else {
         this.print0(this.ucase ? "SUBPARTITION BY HASH " : "subpartition by hash ");
      }

      if (x.isKey()) {
         this.print0(this.ucase ? "KEY" : "key");
      }

      this.print('(');
      x.getExpr().accept(this);
      this.print(')');
      if (x.getSubPartitionsCount() != null) {
         this.print0(this.ucase ? " SUBPARTITIONS " : " subpartitions ");
         x.getSubPartitionsCount().accept(this);
      }

      if (x.getStoreIn().size() > 0) {
         this.println();
         this.print0(this.ucase ? "STORE IN (" : "store in (");
         this.printAndAccept(x.getStoreIn(), ", ");
         this.print(')');
      }

      if (x.getSubPartitionTemplate().size() > 0) {
         ++this.indentCount;
         this.println();
         this.print0(this.ucase ? "SUBPARTITION TEMPLATE (" : "subpartition template (");
         ++this.indentCount;
         this.println();
         this.printlnAndAccept(x.getSubPartitionTemplate(), ",");
         --this.indentCount;
         this.println();
         this.print(')');
         --this.indentCount;
      }

      return false;
   }

   public boolean visit(SQLSubPartitionByRange x) {
      this.print0(this.ucase ? "SUBPARTITION BY RANGE " : "subpartition by range ");
      SQLExpr subPartitionsCount = x.getSubPartitionsCount();
      if (subPartitionsCount != null) {
         this.print0(this.ucase ? " SUBPARTITIONS " : " subpartitions ");
         subPartitionsCount.accept(this);
      }

      if (x.getSubPartitionTemplate().size() > 0) {
         ++this.indentCount;
         this.println();
         this.print0(this.ucase ? "SUBPARTITION TEMPLATE (" : "subpartition template (");
         ++this.indentCount;
         this.println();
         this.printlnAndAccept(x.getSubPartitionTemplate(), ",");
         --this.indentCount;
         this.println();
         this.print(')');
         --this.indentCount;
      }

      return false;
   }

   public boolean visit(SQLSubPartitionByList x) {
      if (x.isLinear()) {
         this.print0(this.ucase ? "SUBPARTITION BY LINEAR HASH " : "subpartition by linear hash ");
      } else {
         this.print0(this.ucase ? "SUBPARTITION BY HASH " : "subpartition by hash ");
      }

      this.print('(');
      x.getColumn().accept(this);
      this.print(')');
      if (x.getSubPartitionsCount() != null) {
         this.print0(this.ucase ? " SUBPARTITIONS " : " subpartitions ");
         x.getSubPartitionsCount().accept(this);
      }

      if (x.getSubPartitionTemplate().size() > 0) {
         ++this.indentCount;
         this.println();
         this.print0(this.ucase ? "SUBPARTITION TEMPLATE (" : "subpartition template (");
         ++this.indentCount;
         this.println();
         this.printlnAndAccept(x.getSubPartitionTemplate(), ",");
         --this.indentCount;
         this.println();
         this.print(')');
         --this.indentCount;
      }

      if (x.getLifecycle() != null) {
         this.print0(this.ucase ? " LIFECYCLE " : " lifecycle ");
         x.getLifecycle().accept(this);
      }

      return false;
   }

   public boolean visit(SQLSubPartition x) {
      this.print0(this.ucase ? "SUBPARTITION " : "subpartition ");
      x.getName().accept(this);
      if (x.getValues() != null) {
         this.print(' ');
         x.getValues().accept(this);
      }

      SQLName tableSpace = x.getTableSpace();
      if (tableSpace != null) {
         this.print0(this.ucase ? " TABLESPACE " : " tablespace ");
         tableSpace.accept(this);
      }

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

      return false;
   }

   public boolean visit(SQLAlterDatabaseStatement x) {
      this.print0(this.ucase ? "ALTER DATABASE " : "alter database ");
      x.getName().accept(this);
      if (x.isUpgradeDataDirectoryName()) {
         this.print0(this.ucase ? " UPGRADE DATA DIRECTORY NAME" : " upgrade data directory name");
      }

      if (x.getProperties().size() > 0) {
         this.print0(this.ucase ? " SET DBPROPERTIES (" : "set dbproperties (");
         this.printAndAccept(x.getProperties(), ", ");
         this.print(')');
      }

      SQLAlterDatabaseItem item = x.getItem();
      if (item instanceof MySqlAlterDatabaseSetOption) {
         MySqlAlterDatabaseSetOption setOption = (MySqlAlterDatabaseSetOption)item;
         this.print0(this.ucase ? " SET " : " set ");
         this.printAndAccept(setOption.getOptions(), ", ");
         SQLName on = setOption.getOn();
         if (on != null) {
            this.print0(this.ucase ? " ON " : " on ");
            on.accept(this);
         }
      }

      if (item instanceof MySqlAlterDatabaseKillJob) {
         this.print0(this.ucase ? " KILL " : " kill ");
         MySqlAlterDatabaseKillJob kill = (MySqlAlterDatabaseKillJob)item;
         kill.getJobType().accept(this);
         this.print0(" ");
         kill.getJobId().accept(this);
      }

      SQLAlterCharacter character = x.getCharacter();
      if (character != null) {
         this.print(' ');
         character.accept(this);
      }

      return false;
   }

   public boolean visit(SQLAlterTableConvertCharSet x) {
      this.print0(this.ucase ? "CONVERT TO CHARACTER SET " : "convertToSqlNode to character set ");
      x.getCharset().accept(this);
      if (x.getCollate() != null) {
         this.print0(this.ucase ? " COLLATE " : " collate ");
         x.getCollate().accept(this);
      }

      return false;
   }

   public boolean visit(SQLAlterTableCoalescePartition x) {
      this.print0(this.ucase ? "COALESCE PARTITION " : "coalesce partition ");
      x.getCount().accept(this);
      return false;
   }

   public boolean visit(SQLAlterTableTruncatePartition x) {
      this.print0(this.ucase ? "TRUNCATE PARTITION " : "truncate partition ");
      this.printPartitions(x.getPartitions());
      return false;
   }

   public boolean visit(SQLAlterTableDiscardPartition x) {
      this.print0(this.ucase ? "DISCARD PARTITION " : "discard partition ");
      this.printPartitions(x.getPartitions());
      if (x.isTablespace()) {
         this.print0(this.ucase ? " TABLESPACE" : " tablespace");
      }

      return false;
   }

   public boolean visit(SQLAlterTableExchangePartition x) {
      this.print0(this.ucase ? "EXCHANGE PARTITION " : "exchange partition ");
      this.printAndAccept(x.getPartitions(), ", ");
      this.print0(this.ucase ? " WITH TABLE " : " with table ");
      x.getTable().accept(this);
      Boolean validation = x.getValidation();
      if (validation != null) {
         if (validation) {
            this.print0(this.ucase ? " WITH VALIDATION" : " with validation");
         } else {
            this.print0(this.ucase ? " WITHOUT VALIDATION" : " without validation");
         }
      }

      return false;
   }

   public boolean visit(SQLAlterTableImportPartition x) {
      this.print0(this.ucase ? "IMPORT PARTITION " : "import partition ");
      this.printPartitions(x.getPartitions());
      if (x.isTablespace()) {
         this.print0(this.ucase ? " TABLESPACE" : " tablespace");
      }

      return false;
   }

   public boolean visit(SQLAlterTableAnalyzePartition x) {
      this.print0(this.ucase ? "ANALYZE PARTITION " : "analyze partition ");
      this.printPartitions(x.getPartitions());
      return false;
   }

   protected void printPartitions(List<SQLName> partitions) {
      if (partitions.size() == 1 && "ALL".equalsIgnoreCase(((SQLName)partitions.get(0)).getSimpleName())) {
         this.print0(this.ucase ? "ALL" : "all");
      } else {
         this.printAndAccept(partitions, ", ");
      }

   }

   public boolean visit(SQLAlterTableCheckPartition x) {
      this.print0(this.ucase ? "CHECK PARTITION " : "check partition ");
      this.printPartitions(x.getPartitions());
      return false;
   }

   public boolean visit(SQLAlterTableOptimizePartition x) {
      this.print0(this.ucase ? "OPTIMIZE PARTITION " : "optimize partition ");
      this.printPartitions(x.getPartitions());
      return false;
   }

   public boolean visit(SQLAlterTableRebuildPartition x) {
      this.print0(this.ucase ? "REBUILD PARTITION " : "rebuild partition ");
      this.printPartitions(x.getPartitions());
      return false;
   }

   public boolean visit(SQLAlterTableRepairPartition x) {
      this.print0(this.ucase ? "REPAIR PARTITION " : "repair partition ");
      this.printPartitions(x.getPartitions());
      return false;
   }

   public boolean visit(SQLSequenceExpr x) {
      x.getSequence().accept(this);
      this.print('.');
      this.print0(this.ucase ? x.getFunction().name : x.getFunction().name_lcase);
      return false;
   }

   public boolean visit(SQLMergeStatement x) {
      this.print0(this.ucase ? "MERGE " : "merge ");
      if (x.getHints().size() > 0) {
         this.printAndAccept(x.getHints(), ", ");
         this.print(' ');
      }

      this.print0(this.ucase ? "INTO " : "into ");
      x.getInto().accept(this);
      this.println();
      this.print0(this.ucase ? "USING " : "using ");
      x.getUsing().accept(this);
      this.print0(this.ucase ? " ON (" : " on (");
      x.getOn().accept(this);
      this.print0(") ");
      if (x.getUpdateClause() != null) {
         this.println();
         x.getUpdateClause().accept(this);
      }

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

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

      return false;
   }

   public boolean visit(SQLMergeStatement.MergeUpdateClause x) {
      this.print0(this.ucase ? "WHEN MATCHED THEN UPDATE SET " : "when matched then update set ");
      this.printAndAccept(x.getItems(), ", ");
      SQLExpr where = x.getWhere();
      if (where != null) {
         ++this.indentCount;
         this.println();
         this.print0(this.ucase ? "WHERE " : "where ");
         this.printExpr(where, this.parameterized);
         --this.indentCount;
      }

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

      return false;
   }

   public boolean visit(SQLMergeStatement.MergeInsertClause x) {
      this.print0(this.ucase ? "WHEN NOT MATCHED THEN INSERT" : "when not matched then insert");
      if (x.getColumns().size() > 0) {
         this.print(" (");
         this.printAndAccept(x.getColumns(), ", ");
         this.print(')');
      }

      this.print0(this.ucase ? " VALUES (" : " values (");
      this.printAndAccept(x.getValues(), ", ");
      this.print(')');
      if (x.getWhere() != null) {
         ++this.indentCount;
         this.println();
         this.print0(this.ucase ? "WHERE " : "where ");
         x.getWhere().accept(this);
         --this.indentCount;
      }

      return false;
   }

   public boolean visit(SQLErrorLoggingClause x) {
      this.print0(this.ucase ? "LOG ERRORS " : "log errors ");
      if (x.getInto() != null) {
         this.print0(this.ucase ? "INTO " : "into ");
         x.getInto().accept(this);
         this.print(' ');
      }

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

      if (x.getLimit() != null) {
         this.print0(this.ucase ? " REJECT LIMIT " : " reject limit ");
         x.getLimit().accept(this);
      }

      return false;
   }

   public boolean visit(SQLCreateSequenceStatement x) {
      this.print0(this.ucase ? "CREATE " : "create ");
      if (x.isGroup()) {
         this.print0(this.ucase ? "GROUP " : "group ");
      } else if (x.isSimple()) {
         this.print0(this.ucase ? "SIMPLE " : "simple ");
         Boolean cache = x.getWithCache();
         if (cache != null && cache) {
            this.print0(this.ucase ? "WITH CACHE " : "with cache ");
         }
      } else if (x.isTime()) {
         this.print0(this.ucase ? "TIME " : "time ");
      }

      this.print0(this.ucase ? "SEQUENCE " : "sequence ");
      x.getName().accept(this);
      if (x.getStartWith() != null) {
         this.print0(this.ucase ? " START WITH " : " start with ");
         x.getStartWith().accept(this);
      }

      if (x.getIncrementBy() != null) {
         this.print0(this.ucase ? " INCREMENT BY " : " increment by ");
         x.getIncrementBy().accept(this);
      }

      if (x.getMaxValue() != null) {
         this.print0(this.ucase ? " MAXVALUE " : " maxvalue ");
         x.getMaxValue().accept(this);
      }

      if (x.isNoMaxValue()) {
         if (DbType.postgresql == this.dbType) {
            this.print0(this.ucase ? " NO MAXVALUE" : " no maxvalue");
         } else {
            this.print0(this.ucase ? " NOMAXVALUE" : " nomaxvalue");
         }
      }

      if (x.getMinValue() != null) {
         this.print0(this.ucase ? " MINVALUE " : " minvalue ");
         x.getMinValue().accept(this);
      }

      if (x.isNoMinValue()) {
         if (DbType.postgresql == this.dbType) {
            this.print0(this.ucase ? " NO MINVALUE" : " no minvalue");
         } else {
            this.print0(this.ucase ? " NOMINVALUE" : " nominvalue");
         }
      }

      if (x.getGlobal() != null && x.getGlobal()) {
         this.print0(this.ucase ? " GLOBAL" : " global");
      }

      if (x.getLocal() != null && x.getLocal()) {
         this.print0(this.ucase ? " LOCAL" : " local");
      }

      if (x.getCycle() != null) {
         if (x.getCycle()) {
            this.print0(this.ucase ? " CYCLE" : " cycle");
         } else if (DbType.postgresql == this.dbType) {
            this.print0(this.ucase ? " NO CYCLE" : " no cycle");
         } else {
            this.print0(this.ucase ? " NOCYCLE" : " nocycle");
         }
      }

      Boolean cache = x.getCache();
      if (cache != null) {
         if (cache) {
            this.print0(this.ucase ? " CACHE" : " cache");
            SQLExpr cacheValue = x.getCacheValue();
            if (cacheValue != null) {
               this.print(' ');
               cacheValue.accept(this);
            }
         } else {
            this.print0(this.ucase ? " NOCACHE" : " nocache");
         }
      }

      Boolean order = x.getOrder();
      if (order != null) {
         if (order) {
            this.print0(this.ucase ? " ORDER" : " order");
         } else {
            this.print0(this.ucase ? " NOORDER" : " noorder");
         }
      }

      SQLExpr unitCount = x.getUnitCount();
      if (unitCount != null) {
         this.print0(this.ucase ? " UNIT COUNT " : " unit count ");
         this.printExpr(unitCount);
      }

      SQLExpr unitIndex = x.getUnitIndex();
      if (unitIndex != null) {
         this.print0(this.ucase ? " INDEX " : " index ");
         this.printExpr(unitIndex);
      }

      if (x.getStep() != null) {
         this.print0(this.ucase ? " STEP " : " STEP ");
         this.printExpr(x.getStep());
      }

      return false;
   }

   public boolean visit(SQLAlterSequenceStatement x) {
      this.print0(this.ucase ? "ALTER SEQUENCE " : "alter sequence ");
      x.getName().accept(this);
      if (x.isChangeToSimple()) {
         this.print0(this.ucase ? " CHANGE TO SIMPLE" : " change to simple");
         Boolean cache = x.getWithCache();
         if (cache != null && cache) {
            this.print0(this.ucase ? " WITH CACHE" : "  WITH CACHE");
         }
      } else if (x.isChangeToGroup()) {
         this.print0(this.ucase ? " CHANGE TO GROUP" : " change to group");
      } else if (x.isChangeToTime()) {
         this.print0(this.ucase ? " CHANGE TO TIME" : " change to time");
      }

      if (x.getStartWith() != null) {
         this.print0(this.ucase ? " START WITH " : " start with ");
         x.getStartWith().accept(this);
      }

      if (x.getIncrementBy() != null) {
         this.print0(this.ucase ? " INCREMENT BY " : " increment by ");
         x.getIncrementBy().accept(this);
      }

      if (x.getMaxValue() != null) {
         this.print0(this.ucase ? " MAXVALUE " : " maxvalue ");
         x.getMaxValue().accept(this);
      }

      if (x.isNoMaxValue()) {
         if (DbType.postgresql == this.dbType) {
            this.print0(this.ucase ? " NO MAXVALUE" : " no maxvalue");
         } else {
            this.print0(this.ucase ? " NOMAXVALUE" : " nomaxvalue");
         }
      }

      if (x.getMinValue() != null) {
         this.print0(this.ucase ? " MINVALUE " : " minvalue ");
         x.getMinValue().accept(this);
      }

      if (x.isNoMinValue()) {
         if (DbType.postgresql == this.dbType) {
            this.print0(this.ucase ? " NO MINVALUE" : " no minvalue");
         } else {
            this.print0(this.ucase ? " NOMINVALUE" : " nominvalue");
         }
      }

      if (x.getCycle() != null) {
         if (x.getCycle()) {
            this.print0(this.ucase ? " CYCLE" : " cycle");
         } else if (DbType.postgresql == this.dbType) {
            this.print0(this.ucase ? " NO CYCLE" : " no cycle");
         } else {
            this.print0(this.ucase ? " NOCYCLE" : " nocycle");
         }
      }

      Boolean cache = x.getCache();
      if (cache != null) {
         if (cache) {
            this.print0(this.ucase ? " CACHE" : " cache");
            SQLExpr cacheValue = x.getCacheValue();
            if (cacheValue != null) {
               this.print(' ');
               cacheValue.accept(this);
            }
         } else {
            this.print0(this.ucase ? " NOCACHE" : " nocache");
         }
      }

      Boolean order = x.getOrder();
      if (order != null) {
         if (order) {
            this.print0(this.ucase ? " ORDER" : " order");
         } else {
            this.print0(this.ucase ? " NOORDER" : " noorder");
         }
      }

      if (x.isRestart()) {
         this.print0(this.ucase ? " RESTART" : " restart");
         SQLExpr restartWith = x.getRestartWith();
         if (restartWith != null) {
            this.print0(this.ucase ? " WITH " : " with ");
            restartWith.accept(this);
         }
      }

      if (x.getCurrentValue() != null) {
         this.print0(this.ucase ? " CURRENT VALUE " : " CURRENT VALUE");
         x.getCurrentValue().accept(this);
      }

      return false;
   }

   public boolean visit(SQLDateExpr x) {
      String literal = x.getLiteral();
      this.print0(this.ucase ? "DATE '" : "date '");
      this.print0(literal);
      this.print('\'');
      return false;
   }

   public boolean visit(SQLTimeExpr x) {
      SQLExpr literal = x.getLiteral();
      this.print0(this.ucase ? "TIME " : "time ");
      this.printExpr(literal, this.parameterized);
      return false;
   }

   public boolean visit(SQLDateTimeExpr x) {
      SQLExpr literal = x.getLiteral();
      this.print0(this.ucase ? "DATETIME " : "datetime ");
      this.printExpr(literal, this.parameterized);
      return false;
   }

   public boolean visit(SQLRealExpr x) {
      Float value = x.getValue();
      this.print0(this.ucase ? "REAL '" : "real '");
      this.print(value);
      this.print('\'');
      return false;
   }

   public boolean visit(SQLDecimalExpr x) {
      BigDecimal value = x.getValue();
      this.print0(this.ucase ? "DECIMAL '" : "decimal '");
      this.print(value.toString());
      this.print('\'');
      return false;
   }

   public boolean visit(SQLDoubleExpr x) {
      Double value = x.getValue();
      this.print0(this.ucase ? "DOUBLE '" : "double '");
      this.print(value.toString());
      this.print('\'');
      return false;
   }

   public boolean visit(SQLFloatExpr x) {
      Float value = x.getValue();
      this.print0(this.ucase ? "FLOAT '" : "float '");
      this.print(value.toString());
      this.print('\'');
      return false;
   }

   public boolean visit(SQLSmallIntExpr x) {
      Short value = x.getValue();
      this.print0(this.ucase ? "SMALLINT '" : "smallint '");
      this.print(value.toString());
      this.print('\'');
      return false;
   }

   public boolean visit(SQLTinyIntExpr x) {
      Byte value = x.getValue();
      this.print0(this.ucase ? "TINYINT '" : "tinyint '");
      this.print(value.toString());
      this.print('\'');
      return false;
   }

   public boolean visit(SQLBigIntExpr x) {
      Long value = x.getValue();
      this.print0(this.ucase ? "BIGINT '" : "bigint '");
      this.print(value.toString());
      this.print('\'');
      return false;
   }

   public boolean visit(SQLLimit x) {
      this.print0(this.ucase ? "LIMIT " : "limit ");
      SQLExpr offset = x.getOffset();
      if (offset != null) {
         this.printExpr(offset, this.parameterized);
         this.print0(", ");
      }

      SQLExpr rowCount = x.getRowCount();
      if (rowCount != null) {
         this.printExpr(rowCount, this.parameterized);
      }

      List<SQLExpr> by = x.getBy();
      if (by != null) {
         this.print0(this.ucase ? " BY " : " by ");

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

            ((SQLExpr)by.get(i)).accept(this);
         }
      }

      return false;
   }

   public boolean visit(SQLDescribeStatement x) {
      this.print0(this.ucase ? "DESC " : "desc ");
      if (x.getObjectType() != null) {
         this.print0(x.getObjectType().name());
         this.print(' ');
      }

      if (x.isExtended()) {
         this.print0(this.ucase ? "EXTENDED " : "extended ");
      }

      if (x.isFormatted()) {
         this.print0(this.ucase ? "FORMATTED " : "formatted ");
      }

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

      SQLName column = x.getColumn();
      if (column != null) {
         this.print(' ');
         column.accept(this);
      }

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

      return false;
   }

   protected void printHierarchical(SQLSelectQueryBlock x) {
      SQLExpr startWith = x.getStartWith();
      SQLExpr connectBy = x.getConnectBy();
      if (startWith != null || connectBy != null) {
         this.println();
         if (x.getStartWith() != null) {
            this.print0(this.ucase ? "START WITH " : "start with ");
            x.getStartWith().accept(this);
            this.println();
         }

         this.print0(this.ucase ? "CONNECT BY " : "connect by ");
         if (x.isNoCycle()) {
            this.print0(this.ucase ? "NOCYCLE " : "nocycle ");
         }

         if (x.isPrior()) {
            this.print0(this.ucase ? "PRIOR " : "prior ");
         }

         x.getConnectBy().accept(this);
      }

   }

   public void printOracleSegmentAttributes(OracleSegmentAttributes x) {
      if (x.getPctfree() != null) {
         this.println();
         this.print0(this.ucase ? "PCTFREE " : "pctfree ");
         this.print(x.getPctfree());
      }

      if (x.getPctused() != null) {
         this.println();
         this.print0(this.ucase ? "PCTUSED " : "pctused ");
         this.print(x.getPctused());
      }

      if (x.getInitrans() != null) {
         this.println();
         this.print0(this.ucase ? "INITRANS " : "initrans ");
         this.print(x.getInitrans());
      }

      if (x.getMaxtrans() != null) {
         this.println();
         this.print0(this.ucase ? "MAXTRANS " : "maxtrans ");
         this.print(x.getMaxtrans());
      }

      if (x.getCompress() == Boolean.FALSE) {
         this.println();
         this.print0(this.ucase ? "NOCOMPRESS" : "nocompress");
      } else if (x.getCompress() == Boolean.TRUE) {
         this.println();
         this.print0(this.ucase ? "COMPRESS" : "compress");
         if (x.getCompressLevel() != null) {
            this.print(' ');
            this.print(x.getCompressLevel());
         }
      }

      if (x.getLogging() == Boolean.TRUE) {
         this.println();
         this.print0(this.ucase ? "LOGGING" : "logging");
      } else if (x.getLogging() == Boolean.FALSE) {
         this.println();
         this.print0(this.ucase ? "NOLOGGING" : "nologging");
      }

      if (x.getTablespace() != null) {
         this.println();
         this.print0(this.ucase ? "TABLESPACE " : "tablespace ");
         x.getTablespace().accept(this);
      }

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

   }

   public boolean visit(SQLWhileStatement x) {
      String label = x.getLabelName();
      if (label != null && label.length() != 0) {
         this.print0(x.getLabelName());
         this.print0(": ");
      }

      this.print0(this.ucase ? "WHILE " : "while ");
      x.getCondition().accept(this);
      this.print0(this.ucase ? " DO" : " do");
      this.println();
      int i = 0;

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

      this.println();
      this.print0(this.ucase ? "END WHILE" : "end while");
      if (label != null && label.length() != 0) {
         this.print(' ');
         this.print0(label);
      }

      return false;
   }

   public boolean visit(SQLDeclareStatement x) {
      boolean printDeclare = !(x.getParent() instanceof OracleCreatePackageStatement);
      if (printDeclare) {
         this.print0(this.ucase ? "DECLARE " : "declare ");
      }

      this.printAndAccept(x.getItems(), ", ");
      return false;
   }

   public boolean visit(SQLReturnStatement x) {
      this.print0(this.ucase ? "RETURN" : "return");
      if (x.getExpr() != null) {
         this.print(' ');
         x.getExpr().accept(this);
      }

      return false;
   }

   public void postVisit(SQLObject x) {
      if (x instanceof SQLStatement) {
         SQLStatement stmt = (SQLStatement)x;
         boolean printSemi = this.printStatementAfterSemi == null ? stmt.isAfterSemi() : this.printStatementAfterSemi;
         if (printSemi) {
            this.print(';');
         }
      }

   }

   public boolean visit(SQLArgument x) {
      SQLParameter.ParameterType type = x.getType();
      if (type != null) {
         this.print0(type.name());
         this.print(' ');
      }

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

   public boolean visit(SQLCommitStatement x) {
      this.print0(this.ucase ? "COMMIT" : "commit");
      if (x.isWrite()) {
         this.print0(this.ucase ? " WRITE" : " write");
         if (x.getWait() != null) {
            if (x.getWait()) {
               this.print0(this.ucase ? " WAIT" : " wait");
            } else {
               this.print0(this.ucase ? " NOWAIT" : " nowait");
            }
         }

         if (x.getImmediate() != null) {
            if (x.getImmediate()) {
               this.print0(this.ucase ? " IMMEDIATE" : " immediate");
            } else {
               this.print0(this.ucase ? " BATCH" : " batch");
            }
         }
      }

      if (x.isWork()) {
         this.print0(this.ucase ? " WORK" : " work");
      }

      if (x.getChain() != null) {
         if (x.getChain()) {
            this.print0(this.ucase ? " AND CHAIN" : " and chain");
         } else {
            this.print0(this.ucase ? " AND NO CHAIN" : " and no chain");
         }
      }

      if (x.getRelease() != null) {
         if (x.getRelease()) {
            this.print0(this.ucase ? " AND RELEASE" : " and release");
         } else {
            this.print0(this.ucase ? " AND NO RELEASE" : " and no release");
         }
      }

      return false;
   }

   public boolean visit(SQLFlashbackExpr x) {
      this.print0(x.getType().name());
      this.print(' ');
      SQLExpr expr = x.getExpr();
      if (expr instanceof SQLBinaryOpExpr) {
         this.print('(');
         expr.accept(this);
         this.print(')');
      } else {
         expr.accept(this);
      }

      return false;
   }

   public boolean visit(SQLDropMaterializedViewStatement x) {
      this.print0(this.ucase ? "DROP MATERIALIZED VIEW " : "drop materialized view ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      this.printAndAccept(x.getViewNameList().getItems(), ", ");
      if (x.isCascade()) {
         this.print0(this.ucase ? " CASCADE" : " CASCADE");
      }

      if (x.isRestrict()) {
         this.print0(this.ucase ? " RESTRICT" : " restrict");
      }

      return false;
   }

   public boolean visit(SQLShowMaterializedViewStatement x) {
      this.print0(this.ucase ? "SHOW MATERIALIZED VIEWS" : "show materialized views");
      if (x.getLike() != null) {
         this.printUcase(" LIKE ");
         x.getLike().accept(this);
      }

      return false;
   }

   public boolean visit(SQLShowCreateMaterializedViewStatement x) {
      this.print0(this.ucase ? "SHOW CREATE MATERIALIZED VIEW " : "show create materialized view ");
      x.getName().accept(this);
      return false;
   }

   public boolean visit(SQLRefreshMaterializedViewStatement x) {
      this.print0(this.ucase ? "REFRESH MATERIALIZED VIEW " : "refresh materialized view ");
      x.getName().accept(this);
      return false;
   }

   public boolean visit(SQLAlterMaterializedViewStatement x) {
      this.print0(this.ucase ? "ALTER MATERIALIZED VIEW " : "alter materialized view ");
      x.getName().accept(this);
      if (x.isRefresh()) {
         this.println();
         this.print(this.ucase ? "REFRESH" : "refresh");
         if (x.isRefreshFast()) {
            this.print(this.ucase ? " FAST" : " fast");
         } else if (x.isRefreshComplete()) {
            this.print(this.ucase ? " COMPLETE" : " complete");
         } else if (x.isRefreshForce()) {
            this.print(this.ucase ? " FORCE" : " force");
         }

         if (x.isRefreshOnCommit()) {
            this.print(this.ucase ? " ON COMMIT" : " on commit");
         } else if (x.isRefreshOnDemand()) {
            this.print(this.ucase ? " ON DEMAND" : " on demand");
         } else if (x.isRefreshOnOverWrite()) {
            this.print(this.ucase ? " ON OVERWRITE" : " on overwrite");
         }

         if (x.getStartWith() != null) {
            this.println();
            this.print(this.ucase ? "START WITH " : "start with ");
            x.getStartWith().accept(this);
         }

         if (x.getNext() != null) {
            this.print(this.ucase ? " NEXT " : " next ");
            x.getNext().accept(this);
         }
      }

      Boolean enableQueryRewrite = x.getEnableQueryRewrite();
      if (enableQueryRewrite != null) {
         this.println();
         if (enableQueryRewrite) {
            this.print(this.ucase ? "ENABLE QUERY REWRITE" : "enable query rewrite");
         } else {
            this.print(this.ucase ? "DISABLE QUERY REWRITE" : "disable query rewrite");
         }
      }

      return false;
   }

   public void endVisit(SQLAlterMaterializedViewStatement x) {
   }

   public boolean visit(SQLCreateMaterializedViewStatement x) {
      this.print0(this.ucase ? "CREATE MATERIALIZED VIEW " : "create materialized view ");
      x.getName().accept(this);
      if (this.dbType == DbType.mysql) {
         this.printTableElements(x.getTableElementList());
         if (x.getDistributedByType() != null) {
            this.println();
            if (this.isEnabled(VisitorFeature.OutputDistributedLiteralInCreateTableStmt)) {
               this.print0(this.ucase ? "DISTRIBUTED BY " : "distributed by ");
            } else {
               this.print0(this.ucase ? "DISTRIBUTE BY " : "distribute by ");
            }

            SQLName distributeByType = x.getDistributedByType();
            if ("HASH".equalsIgnoreCase(distributeByType.getSimpleName())) {
               this.print0(this.ucase ? "HASH(" : "hash(");
               this.printAndAccept(x.getDistributedBy(), ",");
               this.print0(")");
            } else if ("BROADCAST".equalsIgnoreCase(distributeByType.getSimpleName())) {
               this.print0(this.ucase ? "BROADCAST " : "broadcast ");
            }
         }

         for(SQLAssignItem option : x.getTableOptions()) {
            String key = ((SQLIdentifierExpr)option.getTarget()).getName();
            this.print(' ');
            this.print0(this.ucase ? key : key.toLowerCase());
            if ("TABLESPACE".equals(key)) {
               this.print(' ');
               option.getValue().accept(this);
            } else {
               this.print0(" = ");
               option.getValue().accept(this);
            }
         }

         if (x.getComment() != null) {
            this.println();
            this.print0(this.ucase ? "COMMENT " : "comment ");
            x.getComment().accept(this);
         }
      }

      SQLPartitionBy partitionBy = x.getPartitionBy();
      if (partitionBy != null) {
         this.println();
         this.print0(this.ucase ? "PARTITION BY " : "partition by ");
         partitionBy.accept(this);
      }

      this.printOracleSegmentAttributes(x);
      this.println();
      Boolean cache = x.getCache();
      if (cache != null) {
         this.print(cache ? "CACHE" : "NOCACHE");
         this.println();
      }

      Boolean parallel = x.getParallel();
      if (parallel != null) {
         if (parallel) {
            this.print(this.ucase ? "PARALLEL" : "parallel");
            Integer parallelValue = x.getParallelValue();
            if (parallelValue != null) {
               this.print(' ');
               this.print(parallelValue);
            }
         } else {
            this.print(this.ucase ? "NOPARALLEL" : "noparallel");
         }

         this.println();
      }

      if (x.isBuildImmediate()) {
         this.println(this.ucase ? "BUILD IMMEDIATE" : "build immediate");
      }

      if (x.isRefresh()) {
         this.print(this.ucase ? "REFRESH" : "refresh");
         if (x.isRefreshFast()) {
            this.print(this.ucase ? " FAST" : " fast");
         } else if (x.isRefreshComplete()) {
            this.print(this.ucase ? " COMPLETE" : " complete");
         } else if (x.isRefreshForce()) {
            this.print(this.ucase ? " FORCE" : " force");
         }

         if (x.isRefreshOnCommit()) {
            this.print(this.ucase ? " ON COMMIT" : " on commit");
         } else if (x.isRefreshOnDemand()) {
            this.print(this.ucase ? " ON DEMAND" : " on demand");
         } else if (x.isRefreshOnOverWrite()) {
            this.print(this.ucase ? " ON OVERWRITE" : " on overwrite");
         }

         if (x.getStartWith() != null) {
            this.println();
            this.print(this.ucase ? "START WITH " : "start with ");
            x.getStartWith().accept(this);
         }

         if (x.getNext() != null) {
            this.print(this.ucase ? " NEXT " : " next ");
            x.getNext().accept(this);
         }

         this.println();
      }

      Boolean enableQueryRewrite = x.getEnableQueryRewrite();
      if (enableQueryRewrite != null) {
         if (enableQueryRewrite) {
            this.print(this.ucase ? "ENABLE QUERY REWRITE" : "enable query rewrite");
         } else {
            this.print(this.ucase ? "DISABLE QUERY REWRITE" : "disable query rewrite");
         }

         this.println();
      }

      this.println(this.ucase ? "AS" : "as");
      x.getQuery().accept(this);
      return false;
   }

   public boolean visit(SQLCreateUserStatement x) {
      this.print0(this.ucase ? "CREATE USER " : "create user ");
      x.getUser().accept(this);
      this.print0(this.ucase ? " IDENTIFIED BY " : " identified by ");
      x.getPassword().accept(this);
      if (x.getDefaultTableSpace() != null) {
         this.print0(this.ucase ? " DEFAULT TABLESPACE " : " default tablespace ");
         x.getDefaultTableSpace().accept(this);
      }

      return false;
   }

   public boolean visit(SQLAlterUserStatement x) {
      this.print0(this.ucase ? "ALTER USER " : "alter user ");
      x.getUser().accept(this);
      this.print0(this.ucase ? " IDENTIFIED BY " : " identified by ");
      x.getPassword().accept(this);
      if (x.getDefaultTableSpace() != null) {
         this.print0(this.ucase ? " DEFAULT TABLESPACE " : " default tablespace ");
         x.getDefaultTableSpace().accept(this);
      }

      return false;
   }

   public boolean visit(SQLAlterFunctionStatement x) {
      this.print0(this.ucase ? "ALTER FUNCTION " : "alter function ");
      x.getName().accept(this);
      if (x.isDebug()) {
         this.print0(this.ucase ? " DEBUG" : " debug");
      }

      if (x.isReuseSettings()) {
         this.print0(this.ucase ? " REUSE SETTINGS" : " reuse settings");
      }

      return false;
   }

   public boolean visit(SQLAlterTypeStatement x) {
      this.print0(this.ucase ? "ALTER TYPE " : "alter type ");
      x.getName().accept(this);
      if (x.isCompile()) {
         this.print0(this.ucase ? " COMPILE" : " compile");
      }

      if (x.isBody()) {
         this.print0(this.ucase ? " BODY" : " body");
      }

      if (x.isDebug()) {
         this.print0(this.ucase ? " DEBUG" : " debug");
      }

      if (x.isReuseSettings()) {
         this.print0(this.ucase ? " REUSE SETTINGS" : " reuse settings");
      }

      return false;
   }

   public boolean visit(SQLIntervalExpr x) {
      this.print0(this.ucase ? "INTERVAL " : "interval ");
      SQLExpr value = x.getValue();
      value.accept(this);
      SQLIntervalUnit unit = x.getUnit();
      if (unit != null) {
         this.print(' ');
         this.print0(this.ucase ? unit.name : unit.name_lcase);
      }

      return false;
   }

   public Boolean getPrintStatementAfterSemi() {
      return this.printStatementAfterSemi;
   }

   public void setPrintStatementAfterSemi(Boolean printStatementAfterSemi) {
      this.printStatementAfterSemi = printStatementAfterSemi;
   }

   public void config(VisitorFeature feature, boolean state) {
      super.config(feature, state);
      if (feature == VisitorFeature.OutputUCase) {
         this.ucase = state;
      } else if (feature == VisitorFeature.OutputParameterized) {
         this.parameterized = state;
      } else if (feature == VisitorFeature.OutputParameterizedQuesUnMergeInList) {
         this.parameterizedQuesUnMergeInList = state;
      } else if (feature == VisitorFeature.OutputParameterizedQuesUnMergeValuesList) {
         this.parameterizedQuesUnMergeValuesList = state;
      } else if (feature == VisitorFeature.OutputParameterizedUnMergeShardingTable) {
         this.shardingSupport = !state;
         this.parameterizedQuesUnMergeValuesList = state;
      } else if (feature == VisitorFeature.OutputNameQuote) {
         this.printNameQuote = state;
      }

   }

   public void setFeatures(int features) {
      super.setFeatures(features);
      this.ucase = this.isEnabled(VisitorFeature.OutputUCase);
      this.parameterized = this.isEnabled(VisitorFeature.OutputParameterized);
      this.parameterizedQuesUnMergeInList = this.isEnabled(VisitorFeature.OutputParameterizedQuesUnMergeInList);
      this.parameterizedQuesUnMergeValuesList = this.isEnabled(VisitorFeature.OutputParameterizedQuesUnMergeValuesList);
      this.shardingSupport = !this.isEnabled(VisitorFeature.OutputParameterizedUnMergeShardingTable);
      this.printNameQuote = this.isEnabled(VisitorFeature.OutputNameQuote);
   }

   public boolean visit(OracleCursorExpr x) {
      this.print0(this.ucase ? "CURSOR(" : "cursor(");
      ++this.indentCount;
      this.println();
      x.getQuery().accept(this);
      --this.indentCount;
      this.println();
      this.print(')');
      return false;
   }

   public boolean visit(OracleDatetimeExpr x) {
      x.getExpr().accept(this);
      SQLExpr timeZone = x.getTimeZone();
      if (timeZone instanceof SQLIdentifierExpr && ((SQLIdentifierExpr)timeZone).getName().equalsIgnoreCase("LOCAL")) {
         this.print0(this.ucase ? " AT LOCAL" : "alter session set ");
         return false;
      } else {
         this.print0(this.ucase ? " AT TIME ZONE " : " at time zone ");
         timeZone.accept(this);
         return false;
      }
   }

   public boolean visit(SQLLateralViewTableSource x) {
      SQLTableSource tableSource = x.getTableSource();
      if (tableSource != null) {
         tableSource.accept(this);
      }

      ++this.indentCount;
      this.println();
      this.print0(this.ucase ? "LATERAL VIEW " : "lateral view ");
      if (x.isOuter()) {
         this.print0(this.ucase ? "OUTER " : "outer ");
      }

      x.getMethod().accept(this);
      this.print(' ');
      this.print0(x.getAlias());
      if (x.getColumns() != null && x.getColumns().size() > 0) {
         this.print0(this.ucase ? " AS " : " as ");
         this.printAndAccept(x.getColumns(), ", ");
      }

      --this.indentCount;
      return false;
   }

   public boolean visit(SQLShowErrorsStatement x) {
      this.print0(this.ucase ? "SHOW ERRORS" : "show errors");
      return false;
   }

   public boolean visit(SQLShowRecylebinStatement x) {
      this.print0(this.ucase ? "SHOW RECYCLEBIN" : "show recyclebin");
      return false;
   }

   public boolean visit(SQLShowCatalogsStatement x) {
      this.print0(this.ucase ? "SHOW CATALOGS" : "show catalogs");
      SQLExpr like = x.getLike();
      if (like != null) {
         this.print0(this.ucase ? " LIKE " : " like ");
         this.printExpr(like);
      }

      return false;
   }

   public boolean visit(SQLShowFunctionsStatement x) {
      this.print0(this.ucase ? "SHOW FUNCTIONS" : "show functions");
      SQLExpr like = x.getLike();
      if (like != null) {
         this.print0(this.ucase ? " LIKE " : " like ");
         this.printExpr(like);
      }

      return false;
   }

   public boolean visit(SQLShowSessionStatement x) {
      this.print0(this.ucase ? "SHOW SESSION" : "show session");
      SQLExpr like = x.getLike();
      if (like != null) {
         this.print0(this.ucase ? " LIKE " : " like ");
         this.printExpr(like);
      }

      return false;
   }

   public boolean visit(SQLAlterCharacter x) {
      if (x.getCharacterSet() != null) {
         this.print0(this.ucase ? "CHARACTER SET = " : "character set = ");
         x.getCharacterSet().accept(this);
      }

      if (x.getCollate() != null) {
         if (x.getCharacterSet() != null) {
            this.print0(", ");
         }

         this.print0(this.ucase ? "COLLATE = " : "collate = ");
         x.getCollate().accept(this);
      }

      return false;
   }

   public boolean visit(SQLRecordDataType x) {
      this.print0(this.ucase ? "RECORD (" : "record (");
      ++this.indentCount;
      this.println();
      List<SQLColumnDefinition> columns = x.getColumns();

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

         ((SQLColumnDefinition)columns.get(i)).accept(this);
         if (i != columns.size() - 1) {
            this.print0(", ");
         }
      }

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

   public boolean visit(SQLExprStatement x) {
      x.getExpr().accept(this);
      return false;
   }

   public boolean visit(SQLBlockStatement x) {
      if (x.getParameters().size() != 0) {
         ++this.indentCount;
         if (x.getParent() instanceof SQLCreateProcedureStatement) {
            SQLCreateProcedureStatement procedureStatement = (SQLCreateProcedureStatement)x.getParent();
            if (procedureStatement.isCreate()) {
               this.printIndent();
            }
         }

         if (!(x.getParent() instanceof SQLCreateProcedureStatement) && !(x.getParent() instanceof SQLCreateFunctionStatement) && !(x.getParent() instanceof OracleFunctionDataType) && !(x.getParent() instanceof OracleProcedureDataType)) {
            this.print0(this.ucase ? "DECLARE" : "declare");
            this.println();
         }

         int i = 0;

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

            SQLParameter param = (SQLParameter)x.getParameters().get(i);
            param.accept(this);
            this.print(';');
         }

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

      this.print0(this.ucase ? "BEGIN" : "begin");
      ++this.indentCount;
      int i = 0;

      for(int size = x.getStatementList().size(); i < size; ++i) {
         this.println();
         SQLStatement stmt = (SQLStatement)x.getStatementList().get(i);
         stmt.accept(this);
      }

      --this.indentCount;
      SQLStatement exception = x.getException();
      if (exception != null) {
         this.println();
         exception.accept(this);
      }

      this.println();
      this.print0(this.ucase ? "END;" : "end;");
      return false;
   }

   public boolean visit(SQLCreateProcedureStatement x) {
      boolean create = x.isCreate();
      if (!create) {
         this.print0(this.ucase ? "PROCEDURE " : "procedure ");
      } else if (x.isOrReplace()) {
         this.print0(this.ucase ? "CREATE OR REPLACE PROCEDURE " : "create or replace procedure ");
      } else {
         this.print0(this.ucase ? "CREATE PROCEDURE " : "create procedure ");
      }

      x.getName().accept(this);
      int paramSize = x.getParameters().size();
      if (paramSize > 0) {
         this.print0(" (");
         ++this.indentCount;
         this.println();

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

            SQLParameter param = (SQLParameter)x.getParameters().get(i);
            param.accept(this);
         }

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

      SQLName authid = x.getAuthid();
      if (authid != null) {
         this.print(this.ucase ? " AUTHID " : " authid ");
         authid.accept(this);
      }

      SQLStatement block = x.getBlock();
      String wrappedSource = x.getWrappedSource();
      if (wrappedSource != null) {
         this.print0(this.ucase ? " WRAPPED " : " wrapped ");
         this.print0(wrappedSource);
      } else {
         if (block != null && !create) {
            this.println();
            this.print("IS");
            this.println();
         } else {
            this.println();
            if (block instanceof SQLBlockStatement) {
               SQLBlockStatement blockStatement = (SQLBlockStatement)block;
               if (blockStatement.getParameters().size() <= 0 && authid == null) {
                  this.println(this.ucase ? "IS" : "is");
               } else {
                  this.println(this.ucase ? "AS" : "as");
               }
            }
         }

         String javaCallSpec = x.getJavaCallSpec();
         if (javaCallSpec != null) {
            this.print0(this.ucase ? "LANGUAGE JAVA NAME '" : "language java name '");
            this.print0(javaCallSpec);
            this.print('\'');
            return false;
         }
      }

      boolean afterSemi = false;
      if (block != null) {
         block.accept(this);
         if (block instanceof SQLBlockStatement && ((SQLBlockStatement)block).getStatementList().size() > 0) {
            afterSemi = ((SQLStatement)((SQLBlockStatement)block).getStatementList().get(0)).isAfterSemi();
         }
      }

      if (!afterSemi && x.getParent() instanceof OracleCreatePackageStatement) {
         this.print(';');
      }

      return false;
   }

   protected boolean hiveVisit(SQLExternalRecordFormat x) {
      ++this.indentCount;
      if (x.getDelimitedBy() != null) {
         this.println();
         this.print0(this.ucase ? "LINES TERMINATED BY " : "lines terminated by ");
         x.getDelimitedBy().accept(this);
      }

      SQLExpr terminatedBy = x.getTerminatedBy();
      if (terminatedBy != null) {
         this.println();
         this.print0(this.ucase ? "FIELDS TERMINATED BY " : "fields terminated by ");
         terminatedBy.accept(this);
      }

      SQLExpr escapedBy = x.getEscapedBy();
      if (escapedBy != null) {
         this.println();
         this.print0(this.ucase ? "ESCAPED BY " : "escaped by ");
         escapedBy.accept(this);
      }

      SQLExpr collectionItemsTerminatedBy = x.getCollectionItemsTerminatedBy();
      if (collectionItemsTerminatedBy != null) {
         this.println();
         this.print0(this.ucase ? "COLLECTION ITEMS TERMINATED BY " : "collection items terminated by ");
         collectionItemsTerminatedBy.accept(this);
      }

      SQLExpr mapKeysTerminatedBy = x.getMapKeysTerminatedBy();
      if (mapKeysTerminatedBy != null) {
         this.println();
         this.print0(this.ucase ? "MAP KEYS TERMINATED BY " : "map keys terminated by ");
         mapKeysTerminatedBy.accept(this);
      }

      SQLExpr linesTerminatedBy = x.getLinesTerminatedBy();
      if (linesTerminatedBy != null) {
         this.println();
         this.print0(this.ucase ? "LINES TERMINATED BY " : "lines terminated by ");
         linesTerminatedBy.accept(this);
      }

      SQLExpr nullDefinedAs = x.getNullDefinedAs();
      if (nullDefinedAs != null) {
         this.println();
         this.print0(this.ucase ? "NULL DEFINED AS " : "null defined as ");
         nullDefinedAs.accept(this);
      }

      SQLExpr serde = x.getSerde();
      if (serde != null) {
         this.println();
         this.print0(this.ucase ? "SERDE " : "serde ");
         serde.accept(this);
      }

      --this.indentCount;
      return false;
   }

   public boolean visit(SQLExternalRecordFormat x) {
      SQLExpr delimitedBy = x.getDelimitedBy();
      if (delimitedBy != null) {
         this.println();
         this.print0(this.ucase ? "RECORDS DELIMITED BY " : "records delimited by ");
         delimitedBy.accept(this);
      }

      Boolean logfile = x.getLogfile();
      if (logfile != null) {
         if (logfile) {
            this.print0(this.ucase ? " LOGFILE" : " logfile");
         } else {
            this.print0(this.ucase ? " NOLOGFILE" : " nologfile");
         }
      }

      Boolean badfile = x.getBadfile();
      if (badfile != null) {
         if (badfile) {
            this.print0(this.ucase ? " BADFILE" : " badfile");
         } else {
            this.print0(this.ucase ? " NOBADFILE" : " nobadfile");
         }
      }

      SQLExpr terminatedBy = x.getTerminatedBy();
      if (terminatedBy != null) {
         this.println();
         this.print0(this.ucase ? "FIELDS TERMINATED BY " : "fields terminated by ");
         terminatedBy.accept(this);
      }

      if (x.isLtrim()) {
         this.print0(this.ucase ? " LTRIM" : " ltrim");
      }

      if (x.isMissingFieldValuesAreNull()) {
         this.print0(this.ucase ? " MISSING FIELD VALUES ARE NULL" : " missing field values are null");
      }

      if (x.isRejectRowsWithAllNullFields()) {
         this.print0(this.ucase ? " REJECT ROWS WITH ALL NULL FIELDS" : " reject rows with all null fields");
      }

      return false;
   }

   public boolean visit(SQLArrayDataType x) {
      List<SQLExpr> arguments = x.getArguments();
      if (Boolean.TRUE.equals(x.getAttribute("ads.arrayDataType"))) {
         x.getComponentType().accept(this);
         this.print('[');
         this.printAndAccept(arguments, ", ");
         this.print(']');
      } else {
         SQLDataType componentType = x.getComponentType();
         if (componentType != null) {
            this.print0(this.ucase ? "ARRAY<" : "array<");
            componentType.accept(this);
            this.print('>');
         } else {
            this.print0(this.ucase ? "ARRAY" : "array");
         }

         if (arguments.size() > 0) {
            this.print('(');
            this.printAndAccept(arguments, ", ");
            this.print(')');
         }
      }

      return false;
   }

   public boolean visit(SQLMapDataType x) {
      this.print0(this.ucase ? "MAP<" : "map<");
      SQLDataType keyType = x.getKeyType();
      SQLDataType valueType = x.getValueType();
      keyType.accept(this);
      this.print0(", ");
      valueType.accept(this);
      this.print('>');
      return false;
   }

   public boolean visit(SQLStructDataType x) {
      this.print0(this.ucase ? "STRUCT<" : "struct<");
      this.printAndAccept(x.getFields(), ", ");
      this.print('>');
      return false;
   }

   public boolean visit(SQLRowDataType x) {
      this.print0(this.ucase ? "ROW(" : "row(");
      this.printAndAccept(x.getFields(), ",");
      this.print(')');
      return false;
   }

   public boolean visit(SQLUnionDataType x) {
      this.print0(this.ucase ? "UNIONTYPE<" : "uniontype<");
      this.printAndAccept(x.getItems(), ", ");
      this.print('>');
      return false;
   }

   public boolean visit(SQLStructDataType.Field x) {
      SQLName name = x.getName();
      if (name != null) {
         name.accept(this);
      }

      SQLDataType dataType = x.getDataType();
      if (dataType != null) {
         if (x.getParent() instanceof SQLRowDataType) {
            if (name != null) {
               this.print(' ');
            }
         } else {
            this.print(':');
         }

         dataType.accept(this);
      }

      return false;
   }

   public boolean visit(SQLAlterTableMergePartition x) {
      this.print0(this.ucase ? "MERGE " : "merge ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      this.println();
      this.printlnAndAccept(x.getPartitions(), ", ");
      this.println();
      this.print0(this.ucase ? "OVERWRITE" : "overwrite");
      this.println();
      x.getOverwritePartition().accept(this);
      return false;
   }

   public boolean visit(SQLPartitionSpec x) {
      this.print0(this.ucase ? "PARTITION (" : "partition (");
      this.printAndAccept(x.getItems(), ", ");
      this.print(')');
      return false;
   }

   public boolean visit(SQLPartitionSpec.Item x) {
      x.getColumn().accept(this);
      this.print0(" = ");
      x.getValue().accept(this);
      return false;
   }

   public boolean visit(SQLAlterTableSubpartitionAvailablePartitionNum x) {
      this.print0(this.ucase ? "SUBPARTITION_AVAILABLE_PARTITION_NUM = " : "subpartition_available_partition_num = ");
      x.getNumber().accept(this);
      return false;
   }

   public boolean visit(SQLShowDatabasesStatement x) {
      this.print0(this.ucase ? "SHOW " : "show ");
      if (x.isFull()) {
         this.print0(this.ucase ? "FULL " : "full ");
      }

      if (x.isPhysical()) {
         this.print0(this.ucase ? "PHYSICAL " : "physical ");
      }

      this.print0(this.ucase ? "DATABASES" : "databases");
      if (x.getLike() != null) {
         this.print0(this.ucase ? " LIKE " : " like ");
         x.getLike().accept(this);
      }

      if (x.getWhere() != null) {
         this.print0(this.ucase ? " WHERE " : " where ");
         x.getWhere().accept(this);
      }

      if (x.isExtra()) {
         this.print0(this.ucase ? " EXTRA" : " extra");
      }

      return false;
   }

   public boolean visit(SQLShowTableGroupsStatement x) {
      this.print0(this.ucase ? "SHOW TABLEGROUPS" : "show tablegroups");
      if (x.getDatabase() != null) {
         this.print0(this.ucase ? " IN " : " in ");
         x.getDatabase().accept(this);
      }

      return false;
   }

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

      if (x.isFull()) {
         this.print0(this.ucase ? "SHOW FULL COLUMNS" : "show full columns");
      } else {
         this.print0(this.ucase ? "SHOW COLUMNS" : "show columns");
      }

      if (x.getTable() != null) {
         this.print0(this.ucase ? " FROM " : " from ");
         if (x.getDatabase() != null) {
            x.getDatabase().accept(this);
            this.print('.');
         }

         x.getTable().accept(this);
      }

      if (x.getLike() != null) {
         this.print0(this.ucase ? " LIKE " : " like ");
         x.getLike().accept(this);
      }

      if (x.getWhere() != null) {
         this.print0(this.ucase ? " WHERE " : " where ");
         x.getWhere().accept(this);
      }

      return false;
   }

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

      if (x.isAll()) {
         this.print0(this.ucase ? "SHOW ALL CREATE TABLE " : "show all create table ");
      } else {
         this.print0(this.ucase ? "SHOW CREATE TABLE " : "show create table ");
      }

      x.getName().accept(this);
      if (x.getLikeMapping() != null) {
         this.print0(this.ucase ? " LIKE MAPPING (" : " like mapping ");
         x.getLikeMapping().accept(this);
         this.print0(")");
      }

      return false;
   }

   public boolean visit(SQLShowProcessListStatement x) {
      this.print0(this.ucase ? "SHOW " : "show ");
      if (x.isFull()) {
         this.print0(this.ucase ? "FULL " : "full ");
      }

      this.print0(this.ucase ? "PROCESSLIST" : "processlist");
      if (x.isMpp()) {
         this.print0(this.ucase ? " MPP" : " mpp");
      }

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

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

      SQLLimit limit = x.getLimit();
      if (limit != null) {
         this.print(' ');
         limit.accept(this);
      }

      return false;
   }

   public boolean visit(SQLAlterTableSetOption x) {
      this.print0(this.ucase ? "SET TBLPROPERTIES (" : "set tblproperties (");
      this.printAndAccept(x.getOptions(), ", ");
      this.print(')');
      SQLExpr on = x.getOn();
      if (on != null) {
         this.print0(this.ucase ? " ON " : " on ");
         on.accept(this);
      }

      return false;
   }

   public boolean visit(SQLShowCreateViewStatement x) {
      this.print0(this.ucase ? "SHOW CREATE VIEW " : "show create view ");
      x.getName().accept(this);
      return false;
   }

   public boolean visit(SQLShowViewsStatement x) {
      this.print0(this.ucase ? "SHOW VIEWS" : "show views");
      if (x.getDatabase() != null) {
         this.print0(this.ucase ? " FROM " : " from ");
         x.getDatabase().accept(this);
      }

      if (x.getLike() != null) {
         this.print0(this.ucase ? " LIKE " : " like ");
         x.getLike().accept(this);
      }

      return false;
   }

   public boolean visit(SQLAlterTableRenameIndex x) {
      this.print0(this.ucase ? "RENAME INDEX " : "rename index ");
      x.getName().accept(this);
      this.print0(this.ucase ? " TO " : " to ");
      x.getTo().accept(this);
      return false;
   }

   public boolean visit(SQLCreateRoleStatement x) {
      this.print0(this.ucase ? "CREATE ROLE " : "create role ");
      x.getName().accept(this);
      return false;
   }

   public boolean visit(SQLDropRoleStatement x) {
      this.print0(this.ucase ? "DROP ROLE " : "drop role ");
      if (x.isIfExists()) {
         this.printUcase("IF EXISTS ");
      }

      if (x.getNames() != null) {
         this.printAndAccept(x.getNames().getItems(), ", ");
      } else {
         x.getName().accept(this);
      }

      return false;
   }

   public void endVisit(SQLMatchAgainstExpr x) {
   }

   public boolean visit(SQLMatchAgainstExpr x) {
      this.print0(this.ucase ? "MATCH (" : "match (");
      this.printAndAccept(x.getColumns(), ", ");
      this.print(')');
      this.print0(this.ucase ? " AGAINST (" : " against (");
      x.getAgainst().accept(this);
      if (x.getSearchModifier() != null) {
         this.print(' ');
         this.print0(this.ucase ? x.getSearchModifier().name : x.getSearchModifier().name_lcase);
      }

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

   public boolean visit(MySqlPrimaryKey x) {
      this.visit(x.getIndexDefinition());
      if (x.getName() != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         x.getName().accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "PRIMARY KEY" : "primary key");
      if (x.getIndexType() != null) {
         this.print0(this.ucase ? " USING " : " using ");
         this.print0(x.getIndexType());
      }

      this.print0(" (");
      int i = 0;

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

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

      this.print(')');
      SQLExpr keyBlockSize = x.getKeyBlockSize();
      if (keyBlockSize != null) {
         this.print0(this.ucase ? " KEY_BLOCK_SIZE = " : " key_block_size = ");
         keyBlockSize.accept(this);
      }

      SQLExpr comment = x.getComment();
      if (comment != null) {
         this.print0(this.ucase ? " COMMENT " : " comment ");
         comment.accept(this);
      }

      return false;
   }

   public boolean visit(MySqlCreateTableStatement 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());
      }

      this.print0(this.ucase ? "CREATE " : "create ");

      for(SQLCommentHint hint : x.getHints()) {
         hint.accept(this);
         this.print(' ');
      }

      if (x.isDimension()) {
         this.print0(this.ucase ? "DIMENSION " : "dimension ");
      }

      if (SQLCreateTableStatement.Type.GLOBAL_TEMPORARY.equals(x.getType())) {
         this.print0(this.ucase ? "TEMPORARY TABLE " : "temporary table ");
      } else if (SQLCreateTableStatement.Type.SHADOW.equals(x.getType())) {
         this.print0(this.ucase ? "SHADOW TABLE " : "shadow table ");
      } else if (x.isExternal()) {
         this.print0(this.ucase ? "EXTERNAL TABLE " : "external table ");
      } else {
         this.print0(this.ucase ? "TABLE " : "table ");
      }

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

      this.printTableSourceExpr(x.getName());
      if (x.getLike() != null) {
         this.print0(this.ucase ? " LIKE " : " like ");
         x.getLike().accept(this);
      }

      this.printTableElements(x.getTableElementList());
      if (x.isBroadCast()) {
         this.print0(this.ucase ? " BROADCAST" : " broadcast");
      }

      List<SQLAssignItem> tableOptions = x.getTableOptions();
      if (Boolean.TRUE.equals(x.getAttribute("ads.options"))) {
         if (tableOptions.size() > 0) {
            this.println();
            this.print0(this.ucase ? "OPTIONS (" : "options (");
            this.printAndAccept(tableOptions, ", ");
            this.print(')');
         }
      } else {
         for(SQLAssignItem option : tableOptions) {
            String key = ((SQLIdentifierExpr)option.getTarget()).getName();
            this.print(' ');
            this.print0(this.ucase ? key : key.toLowerCase());
            if ("TABLESPACE".equals(key)) {
               this.print(' ');
               option.getValue().accept(this);
            } else {
               this.print0(" = ");
               option.getValue().accept(this);
            }
         }
      }

      SQLExpr comment = x.getComment();
      if (comment != null) {
         this.print0(this.ucase ? " COMMENT " : " comment ");
         comment.accept(this);
      }

      if (x.getDistributeByType() != null) {
         this.println();
         if (this.isEnabled(VisitorFeature.OutputDistributedLiteralInCreateTableStmt)) {
            this.print0(this.ucase ? "DISTRIBUTED BY " : "distributed by ");
         } else {
            this.print0(this.ucase ? "DISTRIBUTE BY " : "distribute by ");
         }

         SQLName distributeByType = x.getDistributeByType();
         if ("HASH".equalsIgnoreCase(distributeByType.getSimpleName())) {
            this.print0(this.ucase ? "HASH(" : "hash(");
            this.printAndAccept(x.getDistributeBy(), ",");
            this.print0(")");
         } else if ("BROADCAST".equalsIgnoreCase(distributeByType.getSimpleName())) {
            this.print0(this.ucase ? "BROADCAST " : "broadcast ");
         }
      }

      SQLPartitionBy partitionBy = x.getPartitioning();
      if (partitionBy != null) {
         this.println();
         this.print0(this.ucase ? "PARTITION BY " : "partition by ");
         partitionBy.accept(this);
      }

      List<SQLSelectOrderByItem> clusteredBy = x.getClusteredBy();
      if (clusteredBy.size() > 0) {
         this.println();
         this.print0(this.ucase ? "CLUSTERED BY (" : "clustered by (");
         this.printAndAccept(clusteredBy, ",");
         this.print0(")");
      }

      SQLExpr dbPartitionBy = x.getDbPartitionBy();
      if (dbPartitionBy != null) {
         this.println();
         this.print0(this.ucase ? "DBPARTITION BY " : "dbpartition by ");
         dbPartitionBy.accept(this);
      }

      SQLExpr dbpartitions = x.getDbpartitions();
      if (dbpartitions != null) {
         this.print0(this.ucase ? " DBPARTITIONS " : " dbpartitions ");
         dbpartitions.accept(this);
      }

      SQLExpr tbPartitionsBy = x.getTablePartitionBy();
      if (tbPartitionsBy != null) {
         this.println();
         this.print0(this.ucase ? "TBPARTITION BY " : "tbpartition by ");
         tbPartitionsBy.accept(this);
      }

      SQLExpr tablePartitions = x.getTablePartitions();
      if (tablePartitions != null) {
         this.print0(this.ucase ? " TBPARTITIONS " : " tbpartitions ");
         tablePartitions.accept(this);
      }

      MySqlExtPartition extPartition = x.getExtPartition();
      if (extPartition != null) {
         this.println();
         extPartition.accept(this);
      }

      if (x.getArchiveBy() != null) {
         this.println();
         this.print0(this.ucase ? "ARCHIVE BY = " : "archive by = ");
         x.getArchiveBy().accept(this);
      }

      if (x.getTableGroup() != null) {
         this.println();
         this.print0(this.ucase ? "TABLEGROUP " : "tablegroup ");
         x.getTableGroup().accept(this);
      }

      if (x.isReplace()) {
         this.println();
         this.print0(this.ucase ? "REPLACE " : "replace ");
      } else if (x.isIgnore()) {
         this.println();
         this.print0(this.ucase ? "IGNORE " : "ignore ");
      }

      if (x.getSelect() != null) {
         this.println();
         this.print0(this.ucase ? "AS" : "as");
         this.println();
         x.getSelect().accept(this);
      }

      if (x.getStoredBy() != null) {
         this.println();
         this.print0(this.ucase ? " STORED BY " : " stored by ");
         x.getStoredBy().accept(this);
      }

      if (x.getWith().size() > 0) {
         this.println();
         this.print0(this.ucase ? " WITH (" : " with (");
         int i = 0;

         for(Map.Entry<String, SQLName> option : x.getWith().entrySet()) {
            if (i != 0) {
               this.print0(", ");
            }

            this.print0((String)option.getKey());
            this.print0(" = ");
            ((SQLName)option.getValue()).accept(this);
            ++i;
         }

         this.print(')');
      }

      if (x.getWithData() != null) {
         this.println();
         if (x.getWithData()) {
            this.print0(this.ucase ? "WITH DATA" : "with data");
         } else {
            this.print0(this.ucase ? "WITH NO DATA" : "with no data");
         }
      }

      for(SQLCommentHint hint : x.getOptionHints()) {
         this.print(' ');
         hint.accept(this);
      }

      return false;
   }

   public boolean visit(SQLShowPartitionsStmt x) {
      this.print0(this.ucase ? "SHOW PARTITIONS " : "show partitions ");
      x.getTableSource().accept(this);
      if (x.getPartition().size() > 0) {
         this.print0(this.ucase ? " PARTITION (" : " partition (");
         this.printAndAccept(x.getPartition(), ", ");
         this.print0(")");
      }

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

      return false;
   }

   public boolean visit(SQLValuesExpr x) {
      this.print0(this.ucase ? "VALUES (" : "values (");
      this.printAndAccept(x.getValues(), ", ");
      return false;
   }

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

      this.print0(this.ucase ? "DUMP DATA " : "dump data ");
      if (x.isOverwrite()) {
         this.print0(this.ucase ? "OVERWRITE " : "overwrite ");
      }

      SQLExprTableSource into = x.getInto();
      if (into != null) {
         this.print0(this.ucase ? "INTO " : "into ");
         into.accept(this);
         this.print0(" ");
      }

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

   public boolean visit(SQLValuesTableSource x) {
      List<SQLName> columns = x.getColumns();
      boolean quote = columns.size() > 0;
      if (quote) {
         this.print('(');
      }

      this.print0(this.ucase ? "VALUES " : "values ");
      this.printAndAccept(x.getValues(), ", ");
      if (quote) {
         this.print(')');
      }

      String alias = x.getAlias();
      if (alias != null) {
         this.print0(this.ucase ? " AS " : " as ");
         this.print0(alias);
      }

      if (columns.size() > 0) {
         if (alias == null) {
            this.print0(this.ucase ? " AS" : " as");
         }

         this.print0(" (");
         this.printAndAccept(columns, ", ");
         this.print(')');
      }

      return false;
   }

   public boolean visit(SQLExtractExpr x) {
      this.print0(this.ucase ? "EXTRACT(" : "extract(");
      this.print0(x.getUnit().name());
      this.print0(this.ucase ? " FROM " : " from ");
      x.getValue().accept(this);
      this.print(')');
      return false;
   }

   public boolean visit(SQLWindow x) {
      x.getName().accept(this);
      this.print0(this.ucase ? " AS " : " as ");
      x.getOver().accept(this);
      return false;
   }

   public boolean visit(SQLJSONExpr x) {
      this.print0(this.ucase ? "JSON " : "json ");
      this.printChars(x.getLiteral());
      return false;
   }

   public boolean visit(SQLAnnIndex x) {
      this.print0(this.ucase ? "ANNINDX (type = '" : "annindx (type = '");
      int indexType = x.getIndexType();
      if ((indexType & SQLAnnIndex.IndexType.Flat.mask) != 0) {
         this.print0(this.ucase ? "FLAT" : "flat");
      }

      if ((indexType & SQLAnnIndex.IndexType.FastIndex.mask) != 0) {
         if (indexType != SQLAnnIndex.IndexType.FastIndex.mask) {
            this.print(',');
         }

         this.print0(this.ucase ? "FLAT_INDEX" : "fast_index");
      }

      this.print0(this.ucase ? "', DISTANCE = '" : "', distance = '");
      this.print0(x.getDistance().name());
      this.print0("'");
      int rtIndexType = x.getRtIndexType();
      if (rtIndexType != 0) {
         this.print0(this.ucase ? ", RTTYPE = '" : ", rttype = '");
         if ((rtIndexType & SQLAnnIndex.IndexType.Flat.mask) != 0) {
            this.print0(this.ucase ? "FLAT" : "flat");
         }

         if ((rtIndexType & SQLAnnIndex.IndexType.FastIndex.mask) != 0) {
            if (rtIndexType != SQLAnnIndex.IndexType.FastIndex.mask) {
               this.print(',');
            }

            this.print0(this.ucase ? "FLAT_INDEX " : "fast_index ");
         }

         this.print('\'');
      }

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

   public boolean visit(SQLAlterTableRecoverPartitions x) {
      this.print0(this.ucase ? "RECOVER PARTITIONS" : "recover partitions");
      return false;
   }

   public boolean visit(SQLAlterIndexStatement x) {
      this.print0(this.ucase ? "ALTER INDEX " : "alter index ");
      x.getName().accept(this);
      if (x.getRenameTo() != null) {
         this.print0(this.ucase ? " RENAME TO " : " rename to ");
         x.getRenameTo().accept(this);
      }

      SQLExprTableSource table = x.getTable();
      if (table != null) {
         this.print0(this.ucase ? " ON " : " on ");
         table.accept(this);
      }

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

      if (x.isCompile()) {
         this.print0(this.ucase ? " COMPILE" : " compile");
      }

      if (x.getEnable() == Boolean.TRUE) {
         this.print0(this.ucase ? " ENABLE" : " enable");
      }

      if (x.getEnable() == Boolean.FALSE) {
         this.print0(this.ucase ? " DISABLE" : " disable");
      }

      if (x.isUnusable()) {
         this.print0(this.ucase ? " UNUSABLE" : " unusable");
      }

      if (x.getMonitoringUsage() != null) {
         this.print0(this.ucase ? " MONITORING USAGE" : " monitoring usage");
      }

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

      if (x.getParallel() != null) {
         this.print0(this.ucase ? " PARALLEL" : " parallel");
         x.getParallel().accept(this);
      }

      return false;
   }

   public boolean visit(SQLAlterIndexStatement.Rebuild x) {
      this.print0(this.ucase ? "REBUILD" : "rebuild");
      if (x.getOption() != null) {
         this.print(' ');
         x.getOption().accept(this);
      }

      return false;
   }

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

      this.print0(this.ucase ? "SHOW " : "show ");
      if (x.isExtended()) {
         this.print0(this.ucase ? "EXTENDED " : "extended ");
      }

      this.print0(this.ucase ? x.getType().toUpperCase() : x.getType().toLowerCase());
      SQLExprTableSource table = x.getTable();
      if (table != null) {
         this.print0(this.ucase ? " FROM " : " from ");
         x.getTable().accept(this);
      }

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

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

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

      if (x.getWhere() != null) {
         this.print0(this.ucase ? " WHERE " : " where ");
         x.getWhere().accept(this);
      }

      return false;
   }

   public boolean visit(SQLAnalyzeTableStatement x) {
      this.print0(this.ucase ? "ANALYZE TABLE " : "analyze table ");
      this.printAndAccept(x.getTables(), ", ");
      SQLPartitionRef partition = x.getPartition();
      if (partition != null) {
         this.print(' ');
         partition.accept(this);
      }

      if (x.isComputeStatistics()) {
         this.print0(this.ucase ? " COMPUTE STATISTICS" : " compute statistics");
      }

      if (x.isForColums()) {
         this.print0(this.ucase ? " FOR COLUMNS" : " for columns");
      }

      if (x.isCacheMetadata()) {
         this.print0(this.ucase ? " CACHE METADATA" : " cache metadata");
      }

      if (x.isNoscan()) {
         this.print0(this.ucase ? " NOSCAN" : " noscan");
      }

      return false;
   }

   public boolean visit(SQLPartitionRef x) {
      this.print0(this.ucase ? "PARTITION (" : "partition (");

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

         SQLPartitionRef.Item item = (SQLPartitionRef.Item)x.getItems().get(i);
         this.visit(item);
      }

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

   public boolean visit(SQLPartitionRef.Item x) {
      this.visit(x.getColumnName());
      SQLExpr value = x.getValue();
      if (value != null) {
         SQLBinaryOperator operator = x.getOperator();
         if (operator == null) {
            this.print(" = ");
         } else {
            this.printOperator(operator);
         }

         this.printExpr(value);
      }

      return false;
   }

   public boolean visit(SQLExportTableStatement x) {
      this.print0(this.ucase ? "EXPORT TABLE " : "export table ");
      x.getTable().accept(this);
      if (x.getPartition().size() > 0) {
         this.print0(this.ucase ? " PARTITION (" : " partition (");
         this.printAndAccept(x.getPartition(), ", ");
         this.print(')');
      }

      SQLExpr to = x.getTo();
      if (to != null) {
         this.print0(this.ucase ? " TO " : " to ");
         to.accept(this);
      }

      return false;
   }

   public boolean visit(SQLImportTableStatement x) {
      if (x.isExtenal()) {
         this.print0(this.ucase ? "IMPORT EXTERNAL" : "import external");
      } else {
         this.print0(this.ucase ? "IMPORT" : "import");
      }

      SQLExprTableSource table = x.getTable();
      if (table != null) {
         this.print0(this.ucase ? " TABLE " : " table ");
         table.accept(this);
      }

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

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

      SQLExpr location = x.getLocation();
      if (location != null) {
         this.print0(this.ucase ? " LOCATION " : " location ");
         location.accept(this);
      }

      if (x.getVersion() != null) {
         this.print0(this.ucase ? " VERSIOIN = " : " version = ");
         x.getVersion().accept(this);
      }

      if (x.isUsingBuild()) {
         this.print0(this.ucase ? " BUILD = 'Y'" : " build = 'y'");
      }

      return false;
   }

   public boolean visit(SQLTableSampling x) {
      this.print0(this.ucase ? "TABLESAMPLE " : "tablesample ");
      if (x.isBernoulli()) {
         this.print0(this.ucase ? "BERNOULLI " : "bernoulli ");
      } else if (x.isSystem()) {
         this.print0(this.ucase ? "SYSTEM " : "system ");
      }

      this.print('(');
      SQLExpr bucket = x.getBucket();
      if (bucket != null) {
         this.print0(this.ucase ? "BUCKET " : "bucket ");
         bucket.accept(this);
      }

      SQLExpr outOf = x.getOutOf();
      if (outOf != null) {
         this.print0(this.ucase ? " OUT OF " : " out of ");
         outOf.accept(this);
      }

      SQLExpr on = x.getOn();
      if (on != null) {
         this.print0(this.ucase ? " ON " : " on ");
         on.accept(this);
      }

      SQLExpr percent = x.getPercent();
      if (percent != null) {
         percent.accept(this);
         this.print0(this.ucase ? " PERCENT" : " percent");
      }

      SQLExpr rows = x.getRows();
      if (rows != null) {
         rows.accept(this);
         if (this.dbType != DbType.mysql) {
            this.print0(this.ucase ? " ROWS" : " rows");
         }
      }

      SQLExpr size = x.getByteLength();
      if (size != null) {
         size.accept(this);
      }

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

   public boolean visit(SQLSizeExpr x) {
      x.getValue().accept(this);
      this.print0(x.getUnit().name());
      return false;
   }

   public boolean visit(SQLAlterTableArchivePartition x) {
      this.print0(this.ucase ? "ARCHIVE PARTITION (" : "archive partition (");
      this.printAndAccept(x.getPartitions(), ", ");
      this.print(')');
      return false;
   }

   public boolean visit(SQLAlterTableUnarchivePartition x) {
      this.print0(this.ucase ? "UNARCHIVE PARTITION (" : "unarchive partition (");
      this.printAndAccept(x.getPartitions(), ", ");
      this.print(')');
      return false;
   }

   public boolean visit(SQLCreateOutlineStatement x) {
      this.print0(this.ucase ? "CREATE OUTLINE " : "create outline ");
      x.getName().accept(this);
      this.print0(this.ucase ? " ON " : " on ");
      x.getOn().accept(this);
      this.print0(this.ucase ? " TO " : " to ");
      x.getTo().accept(this);
      return false;
   }

   public boolean visit(SQLDropOutlineStatement x) {
      this.print0(this.ucase ? "DROP OUTLINE " : "drop outline ");
      x.getName().accept(this);
      return false;
   }

   public boolean visit(SQLShowQueryTaskStatement x) {
      if (x.isFull()) {
         this.print0(this.ucase ? "SHOW FULL QUERY_TASK" : "show full query_task");
      } else {
         this.print0(this.ucase ? "SHOW QUERY_TASK" : "show query_task");
      }

      if (x.getUser() != null) {
         this.println();
         this.print0(this.ucase ? "FOR " : "for ");
         this.printExpr(x.getUser());
      }

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

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

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

      return false;
   }

   public boolean visit(SQLShowOutlinesStatement x) {
      this.print0(this.ucase ? "SHOW OUTLINES" : "show outlines");
      SQLExpr where = x.getWhere();
      if (where != null) {
         this.println();
         this.print0(this.ucase ? "WHERE " : "where ");
         this.printExpr(where);
      }

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

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

      return false;
   }

   public boolean visit(SQLPurgeTableStatement x) {
      this.print0(this.ucase ? "PURGE TABLE " : "purge table ");
      x.getTable().accept(this);
      return false;
   }

   public boolean visit(SQLPurgeRecyclebinStatement x) {
      this.print0(this.ucase ? "PURGE RECYCLEBIN" : "purge recyclebin");
      return false;
   }

   public boolean visit(SQLPurgeLogsStatement x) {
      this.print0(this.ucase ? "PURGE" : "purge");
      if (x.isBinary()) {
         this.print0(this.ucase ? " BINARY" : " binary");
      }

      if (x.isMaster()) {
         this.print0(this.ucase ? " MASTER" : " MASTER");
      }

      if (x.isAll()) {
         this.print0(this.ucase ? " ALL" : " all");
         return false;
      } else {
         this.print0(this.ucase ? " LOGS" : " logs");
         SQLExpr to = x.getTo();
         if (to != null) {
            this.print0(this.ucase ? " TO " : " to ");
            to.accept(this);
         }

         if (x.getBefore() != null) {
            this.print0(this.ucase ? " BEFORE " : " before ");
            x.getBefore().accept(this);
         }

         return false;
      }
   }

   public boolean visit(SQLAlterOutlineStatement x) {
      this.print0(this.ucase ? "ALTER OUTLINE " : "alter outline ");
      x.getName().accept(this);
      if (x.isResync()) {
         this.print0(this.ucase ? " RESYNC" : " resync");
      }

      if (x.isDisable()) {
         this.print0(this.ucase ? " DISABLE" : " disable");
      }

      if (x.isEnable()) {
         this.print0(this.ucase ? " ENABLE" : " enable");
      }

      return false;
   }

   public boolean visit(SQLAlterTableAddSupplemental x) {
      this.print0(this.ucase ? "ADD " : "add ");
      x.getElement().accept(this);
      return false;
   }

   public boolean visit(SQLDbLinkExpr x) {
      SQLExpr expr = x.getExpr();
      if (expr instanceof SQLMethodInvokeExpr) {
         SQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr)x.getExpr();
         SQLExpr owner = methodInvokeExpr.getOwner();
         if (owner != null) {
            this.printMethodOwner(owner);
         }

         String function = methodInvokeExpr.getMethodName();
         this.printFunctionName(function);
         this.print('@');
         this.print0(x.getDbLink());
         this.printMethodParameters(methodInvokeExpr);
      } else {
         if (expr != null) {
            expr.accept(this);
            this.print('@');
         }

         this.print0(x.getDbLink());
      }

      return false;
   }

   public boolean visit(SQLShowStatisticStmt x) {
      if (x.isFull()) {
         this.print0(this.ucase ? "SHOW FULL STATS" : "show full stats");
      } else {
         this.print0(this.ucase ? "SHOW STATS" : "show stats");
      }

      List<SQLAssignItem> partitions = x.getPartitions();
      if (!partitions.isEmpty()) {
         this.print0(this.ucase ? " PARTITION (" : " partition (");
         this.printAndAccept(partitions, ", ");
         this.print(')');
      }

      return false;
   }

   public boolean visit(SQLShowStatisticListStmt x) {
      this.print0(this.ucase ? "SHOW STATISTIC_LIST" : "show statistic_list");
      SQLExprTableSource table = x.getTableSource();
      if (table != null) {
         this.print(' ');
         table.accept(this);
      }

      return false;
   }

   public boolean visit(SQLShowPackagesStatement x) {
      this.print0(this.ucase ? "SHOW PACKAGES" : "show packages");
      return false;
   }

   public boolean visit(SQLShowGrantsStatement x) {
      this.print0(this.ucase ? "SHOW GRANTS" : "show grants");
      SQLExpr user = x.getUser();
      if (user != null) {
         this.print0(this.ucase ? " FOR " : " for ");
         user.accept(this);
      }

      SQLExpr on = x.getOn();
      if (on != null) {
         this.print0(this.ucase ? " ON " : " on ");
         on.accept(this);
      }

      return false;
   }

   public boolean visit(SQLCurrentTimeExpr x) {
      SQLCurrentTimeExpr.Type type = x.getType();
      this.print(this.ucase ? type.name : type.name_lower);
      return false;
   }

   public boolean visit(SQLCurrentUserExpr x) {
      this.print(this.ucase ? "CURRENT_USER" : "current_user");
      return false;
   }

   public boolean visit(SQLAdhocTableSource x) {
      SQLCreateTableStatement definition = x.getDefinition();
      definition.accept(this);
      return false;
   }

   protected void printSerdeProperties(Map<String, SQLObject> serdeProperties) {
      if (!serdeProperties.isEmpty()) {
         this.println();
         this.print0(this.ucase ? "WITH SERDEPROPERTIES (" : "with serdeproperties (");
         this.incrementIndent();
         this.println();
         int i = 0;

         for(Map.Entry<String, SQLObject> option : serdeProperties.entrySet()) {
            if (i != 0) {
               this.print(",");
               this.println();
            }

            String key = (String)option.getKey();
            boolean unquote = false;
            char c0;
            if (key.length() > 0 && (c0 = key.charAt(0)) != '"' && c0 != '`' && c0 != '\'') {
               unquote = true;
            }

            if (unquote) {
               this.print('\'');
            }

            this.print0(key);
            if (unquote) {
               this.print('\'');
            }

            this.print0(" = ");
            ((SQLObject)option.getValue()).accept(this);
            ++i;
         }

         this.decrementIndent();
         this.println();
         this.print(')');
      }
   }

   public boolean visit(SQLWhoamiStatement x) {
      this.print0(this.ucase ? "WHO AM I" : "who am i");
      return false;
   }

   public boolean visit(SQLForStatement x) {
      this.print0(this.ucase ? "FOR " : "for ");
      x.getIndex().accept(this);
      this.print0(this.ucase ? " IN " : " in ");
      SQLExpr range = x.getRange();
      range.accept(this);
      this.println();
      this.print0(this.ucase ? "LOOP" : "loop");
      ++this.indentCount;
      this.println();
      int i = 0;

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

      --this.indentCount;
      this.println();
      this.print0(this.ucase ? "END LOOP" : "end loop");
      return false;
   }

   public boolean visit(SQLCopyFromStatement x) {
      this.print0(this.ucase ? "COPY " : "copy ");
      SQLExprTableSource table = x.getTable();
      table.accept(this);
      List<SQLName> columns = x.getColumns();
      if (columns.size() > 0) {
         this.print('(');
         this.printAndAccept(columns, ", ");
         this.print(")");
      }

      List<SQLAssignItem> partitions = x.getPartitions();
      if (partitions.size() > 0) {
         this.print0(this.ucase ? " PARTITIONS (" : " partitions (");
         this.printAndAccept(partitions, ", ");
         this.print(")");
      }

      this.print0(this.ucase ? " FROM " : " from ");
      x.getFrom().accept(this);
      SQLExpr accessKeyId = x.getAccessKeyId();
      SQLExpr accessKeySecret = x.getAccessKeySecret();
      if (accessKeyId != null || accessKeySecret != null) {
         this.print0(this.ucase ? " CREDENTIALS" : " credentials");
         if (accessKeyId != null) {
            this.print0(this.ucase ? " access_key_id " : " access_key_id ");
            accessKeyId.accept(this);
         }

         if (accessKeySecret != null) {
            this.print0(this.ucase ? " ACCESS_KEY_SECRET " : " access_key_secret ");
            accessKeySecret.accept(this);
         }
      }

      List<SQLAssignItem> options = x.getOptions();
      if (options.size() > 0) {
         this.print0(this.ucase ? " WITH (" : " with (");
         this.printAndAccept(options, ", ");
         this.print(')');
      }

      return false;
   }

   public boolean visit(SQLShowUsersStatement x) {
      this.print0(this.ucase ? "SHOW USERS" : "show users");
      return false;
   }

   public boolean visit(SQLSyncMetaStatement x) {
      this.print0(this.ucase ? "SYNC META TABLE" : "SYNC META TABLE");
      Boolean restrict = x.getRestrict();
      if (restrict != null && restrict) {
         this.print0(this.ucase ? " RESTRICT " : " restrict ");
      }

      Boolean ignore = x.getIgnore();
      if (ignore != null && ignore) {
         this.print0(this.ucase ? " IGNORE " : " ignore ");
      }

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

      SQLExpr like = x.getLike();
      if (like != null) {
         this.print0(this.ucase ? " LIKE " : " like ");
         like.accept(this);
      }

      return false;
   }

   public boolean visit(SQLTableLike x) {
      this.print0(this.ucase ? "LIKE " : "like ");
      x.getTable().accept(this);
      if (x.isIncludeProperties()) {
         this.print0(this.ucase ? " INCLUDING PROPERTIES" : " including properties");
      } else if (x.isExcludeProperties()) {
         this.print0(this.ucase ? " EXCLUDING PROPERTIES" : " excluding properties");
      }

      return false;
   }

   public boolean visit(SQLValuesQuery x) {
      this.print0(this.ucase ? "VALUES " : "values ");
      this.printAndAccept(x.getValues(), ", ");
      return false;
   }

   public boolean visit(SQLBuildTableStatement x) {
      this.print0(this.ucase ? "BUILD TABLE " : "build table ");
      x.getTable().accept(this);
      if (x.getVersion() != null) {
         this.print0(this.ucase ? " VERSION = " : " version = ");
         x.getVersion().accept(this);
      }

      if (x.isWithSplit()) {
         this.print0(this.ucase ? " WITH SPLIT" : " with split");
      }

      if (x.isForce()) {
         this.print0(this.ucase ? " FORCE = true" : " force = true");
      } else {
         this.print0(this.ucase ? " FORCE = false" : " force = false");
      }

      return false;
   }

   public boolean visit(SQLExportDatabaseStatement x) {
      this.print0(this.ucase ? "EXPORT DATABASE " : "export database ");
      x.getDb().accept(this);
      this.print0(this.ucase ? " REALTIME = " : " realtime = ");
      if (x.isRealtime()) {
         this.print0(this.ucase ? "'Y'" : "'y'");
      } else {
         this.print0(this.ucase ? "'N'" : "'n'");
      }

      return false;
   }

   public boolean visit(SQLImportDatabaseStatement x) {
      this.print0(this.ucase ? "IMPORT DATABASE " : "import database ");
      x.getDb().accept(this);
      if (x.getStatus() != null) {
         this.print0(this.ucase ? " STATUS = " : " status = ");
         x.getStatus().accept(this);
      }

      return false;
   }

   public boolean visit(SQLRenameUserStatement x) {
      this.print0(this.ucase ? "RENAME USER " : "rename user ");
      x.getName().accept(this);
      this.print0(this.ucase ? " TO " : " to ");
      x.getTo().accept(this);
      return false;
   }

   public boolean visit(SQLSubmitJobStatement x) {
      this.print0(this.ucase ? "SUBMIT JOB " : "SUBMIT JOB ");
      if (x.isAwait()) {
         this.print0(this.ucase ? "AWAIT " : "await ");
      }

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

   public boolean visit(SQLRestoreStatement x) {
      this.print0(this.ucase ? "RESTORE " : "RESTORE ");
      x.getType().accept(this);
      this.print0(this.ucase ? " FROM " : " from ");
      this.printAndAccept(x.getProperties(), ",");
      return false;
   }

   public boolean visit(SQLArchiveTableStatement x) {
      this.print0(this.ucase ? "ARCHIVE TABLE " : "archive table ");
      x.getTable().accept(this);

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

         this.print0(" ");
         ((SQLIntegerExpr)x.getSpIdList().get(i)).accept(this);
         this.print0(":");
         ((SQLIntegerExpr)x.getpIdList().get(i)).accept(this);
      }

      return false;
   }

   public boolean visit(SQLBackupStatement x) {
      this.print0(this.ucase ? "BACKUP " : "backup ");
      String type = x.getType().getSimpleName().toUpperCase();
      String action = x.getAction().getSimpleName().toUpperCase();
      if ("BACKUP_DATA".equalsIgnoreCase(type)) {
         if ("BACKUP".equalsIgnoreCase(action)) {
            this.print0(this.ucase ? "DATA INTO " : "data into ");
         } else if ("BACKUP_CANCEL".equalsIgnoreCase(action)) {
            this.print0(this.ucase ? "CANCEL " : "cancel ");
         }
      } else if ("BACKUP_LOG".equalsIgnoreCase(type)) {
         this.print0(this.ucase ? "LOG " : "log ");
         if ("BACKUP".equalsIgnoreCase(action)) {
            this.print0(this.ucase ? "INTO " : "into ");
         } else if ("LIST_LOG".equalsIgnoreCase(action)) {
            this.print0(this.ucase ? "LIST_LOGS" : "list_logs");
         } else if ("STATUS".equalsIgnoreCase(action)) {
            this.print0(this.ucase ? "STATUS" : "status");
         }
      }

      this.printAndAccept(x.getProperties(), ",");
      return false;
   }

   public void visitStatementList(List<SQLStatement> statementList) {
      boolean printStmtSeperator;
      if (DbType.sqlserver == this.dbType) {
         printStmtSeperator = false;
      } else {
         printStmtSeperator = DbType.oracle != this.dbType;
      }

      int i = 0;

      for(int size = statementList.size(); i < size; ++i) {
         SQLStatement stmt = (SQLStatement)statementList.get(i);
         if (i > 0) {
            SQLStatement preStmt = (SQLStatement)statementList.get(i - 1);
            if (printStmtSeperator && !preStmt.isAfterSemi()) {
               this.print(";");
            }

            List<String> comments = preStmt.getAfterCommentsDirect();
            if (comments != null) {
               for(int j = 0; j < comments.size(); ++j) {
                  String comment = (String)comments.get(j);
                  if (j != 0) {
                     this.println();
                  }

                  this.printComment(comment);
               }
            }

            if (printStmtSeperator) {
               this.println();
            }

            if (!(stmt instanceof SQLSetStatement)) {
               this.println();
            }
         }

         List<String> comments = stmt.getBeforeCommentsDirect();
         if (comments != null) {
            for(String comment : comments) {
               this.printComment(comment);
               this.println();
            }
         }

         stmt.accept(this);
         if (i == size - 1) {
            comments = stmt.getAfterCommentsDirect();
            if (comments != null) {
               for(int j = 0; j < comments.size(); ++j) {
                  String comment = (String)comments.get(j);
                  if (j != 0) {
                     this.println();
                  }

                  this.printComment(comment);
               }
            }
         }
      }

   }

   public boolean visit(SQLCreateResourceGroupStatement x) {
      this.print0(this.ucase ? "CREATE RESOURCE GROUP " : "create resource group ");
      x.getName().accept(this);

      for(Map.Entry<String, SQLExpr> entry : x.getProperties().entrySet()) {
         this.print(' ');
         this.print((String)entry.getKey());
         this.print(" = ");
         SQLExpr value = (SQLExpr)entry.getValue();
         if (value instanceof SQLListExpr) {
            this.printAndAccept(((SQLListExpr)value).getItems(), ",");
         } else {
            value.accept(this);
         }
      }

      if (x.getEnable() != null) {
         if (x.getEnable()) {
            this.print0(this.ucase ? " ENABLE" : " enable");
         } else {
            this.print0(this.ucase ? " DISABLE" : " disable");
         }
      }

      return false;
   }

   public boolean visit(SQLAlterResourceGroupStatement x) {
      this.print0(this.ucase ? "ALTER RESOURCE GROUP " : "create resource group ");
      x.getName().accept(this);

      for(Map.Entry<String, SQLExpr> entry : x.getProperties().entrySet()) {
         this.print(' ');
         this.print((String)entry.getKey());
         this.print(" = ");
         SQLExpr value = (SQLExpr)entry.getValue();
         if (value instanceof SQLListExpr) {
            this.printAndAccept(((SQLListExpr)value).getItems(), ",");
         } else {
            value.accept(this);
         }
      }

      if (x.getEnable() != null) {
         if (x.getEnable()) {
            this.print0(this.ucase ? " ENABLE" : " enable");
         } else {
            this.print0(this.ucase ? " DISABLE" : " disable");
         }
      }

      return false;
   }

   public boolean visit(MySqlKillStatement x) {
      if (MySqlKillStatement.Type.CONNECTION.equals(x.getType())) {
         this.print0(this.ucase ? "KILL CONNECTION " : "kill connection ");
      } else if (MySqlKillStatement.Type.QUERY.equals(x.getType())) {
         this.print0(this.ucase ? "KILL QUERY " : "kill query ");
      } else {
         this.print0(this.ucase ? "KILL " : "kill ");
      }

      this.printAndAccept(x.getThreadIds(), ", ");
      return false;
   }

   public char getNameQuote() {
      return this.quote;
   }

   public void setNameQuote(char quote) {
      this.quote = quote;
   }

   public boolean visit(SQLLoadIndexIntoCacheStatement x) {
      this.print0(this.ucase ? "LOAD INDEX INTO CACHE " : "load index into cache ");
      if (x.getTables() != null) {
         List<MySqlTableTableSource> tables = x.getTables();
         int size = tables.size();
         int lastNum = size - 1;

         for(int i = 0; i < size; ++i) {
            this.println();
            String tableName = ((MySqlTableTableSource)tables.get(i)).getName().toString();
            this.println(tableName + " ");
            if (((MySqlTableTableSource)tables.get(i)).isPartition()) {
               this.print0(this.ucase ? "PARTITION (" : "partition (");
               if (((MySqlTableTableSource)tables.get(i)).isAll()) {
                  this.print0(this.ucase ? "ALL )" : "all )");
                  this.println();
               } else {
                  this.printAndAccept(((MySqlTableTableSource)tables.get(i)).getPartitionList(), ", ");
                  this.println(")");
               }
            }

            if (((MySqlTableTableSource)tables.get(i)).getIndexOrKey() != null) {
               ((MySqlTableTableSource)tables.get(i)).getIndexOrKey().accept(this);
               this.print(" (");
               this.printAndAccept(((MySqlTableTableSource)tables.get(i)).getIndexList(), ", ");
               this.println(")");
            }

            if (((MySqlTableTableSource)tables.get(i)).isIgnoreLeaves()) {
               this.print0(this.ucase ? "IGNORE LEAVES" : "ignore leaves");
            }

            if (i < lastNum) {
               this.print(", ");
            }
         }
      }

      return false;
   }

   public boolean visit(SQLSetSchemaStatement x) {
      this.print0(this.ucase ? "SET SCHEMA " : "set schema ");
      x.getSchemaName().accept(this);
      return false;
   }

   public boolean visit(SQLCreateTablespaceStatement.FileItem x) {
      x.getFilepath().accept(this);
      if (x.getMirrorFilepath() != null) {
         this.print0(this.ucase ? " MIRROR " : " mirror ");
         x.getMirrorFilepath().accept(this);
      }

      this.print0(this.ucase ? " SIZE " : " size ");
      if (x.getFilesize() != null) {
         x.getFilesize().accept(this);
      }

      if (x.getOn() != null) {
         this.print0(this.ucase ? " AUTOEXTEND ON" : " autoextend on");
         if (x.getNext() != null) {
            this.print0(this.ucase ? " NEXT " : " next ");
            x.getNext().accept(this);
         }

         if (x.getMaxsize() != null) {
            this.print0(this.ucase ? " MAXSIZE " : " maxsize ");
            x.getMaxsize().accept(this);
         }
      }

      if (x.getOff() != null) {
         this.print0(this.ucase ? " AUTOEXTEND OFF" : " autoextend off");
      }

      return false;
   }

   public boolean visit(SQLCreateTablespaceStatement x) {
      this.print0(this.ucase ? "CREATE TABLESPACE " : "create tablespace ");
      x.getName().accept(this);
      this.print0(this.ucase ? " DATAFILE " : " datafile ");
      this.printAndAccept(x.getFileItems(), ", ");
      return false;
   }

   public boolean visit(SQLAlterTablespaceStatement x) {
      this.print0(this.ucase ? "ALTER TABLESPACE " : "alter tablespace ");
      x.getName().accept(this);
      if (x.getStatus() != null) {
         this.print0(" ");
         this.print0(x.getStatus().toString());
      }

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

      return false;
   }

   public boolean visit(SQLAlterTablespaceRename x) {
      this.print0(this.ucase ? " RENAME TO " : " rename to ");
      x.getName().accept(this);
      return false;
   }

   public boolean visit(SQLAlterTablespaceCache x) {
      this.print0(this.ucase ? " CACHE = " : " cache = ");
      x.getCacheName().accept(this);
      return false;
   }

   public boolean visit(SQLAlterTablespaceRenameDatafile x) {
      this.print0(this.ucase ? " RENAME DATAFILE " : " rename datafile ");
      this.printAndAccept(x.getFilepaths(), ", ");
      this.print0(this.ucase ? " TO " : " to ");
      this.printAndAccept(x.getToFilepaths(), ", ");
      return false;
   }

   public boolean visit(SQLAlterTablespaceAddDatafile x) {
      this.print0(this.ucase ? " ADD DATAFILE " : " add datafile ");
      this.printAndAccept(x.getFileItems(), ", ");
      return false;
   }

   public boolean visit(SQLAlterTablespaceResizeDatafile x) {
      this.print0(this.ucase ? " RESIZE DATAFILE " : " resize datafile ");
      x.getFilepath().accept(this);
      this.print0(this.ucase ? " TO " : " to ");
      x.getFilesize().accept(this);
      return false;
   }

   public boolean visit(SQLAlterTablespaceDatafile x) {
      this.print0(this.ucase ? " DATAFILE " : " datafile ");
      this.printAndAccept(x.getFilepaths(), ", ");
      if (x.getOn() != null) {
         this.print0(this.ucase ? " AUTOEXTEND ON" : " autoextend on");
         if (x.getNext() != null) {
            this.print0(this.ucase ? " NEXT " : " next ");
            x.getNext().accept(this);
         }

         if (x.getMaxsize() != null) {
            this.print0(this.ucase ? " MAXSIZE " : " maxsize ");
            x.getMaxsize().accept(this);
         }
      }

      if (x.getOff() != null) {
         this.print0(this.ucase ? " AUTOEXTEND OFF" : " autoextend off");
      }

      return false;
   }

   public boolean visit(SQLCreateDomainStatement x) {
      this.print0(this.ucase ? "CREATE DOMAIN " : "CREATE DOMAIN ");
      x.getName().accept(this);
      this.print0(" ");
      x.getDataType().accept(this);
      if (x.getDefaultExpr() != null) {
         this.print0(this.ucase ? " DEFAULT " : " default ");
         x.getDefaultExpr().accept(this);
      }

      if (x.getConstraintName() != null) {
         this.print0(this.ucase ? " CONSTRAINT " : " constraint ");
         x.getConstraintName().accept(this);
      }

      if (x.getCheckExpr() != null) {
         this.print0(this.ucase ? " CHECK (" : " check (");
         x.getCheckExpr().accept(this);
         this.print0(" )");
      }

      return false;
   }

   public boolean visit(SQLDropDomainStatement x) {
      this.print0(this.ucase ? "DROP DOMAIN " : "drop domain ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      x.getName().accept(this);
      if (x.isCascade()) {
         this.printCascade();
      }

      if (x.isRestrict()) {
         this.print0(this.ucase ? " RESTRICT" : " restrict");
      }

      return false;
   }

   public boolean visit(SQLDropContextStatement x) {
      this.print0(this.ucase ? "DROP CONTEXT " : "drop context ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

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

   public boolean visit(SQLDropDirectoryStatement x) {
      this.print0(this.ucase ? "DROP DIRECTORY " : "drop directory ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

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

   public boolean visit(SQLCreateContextStatement x) {
      this.print0(this.ucase ? "CREATE" : "create");
      if (x.isOrReplace()) {
         this.print0(this.ucase ? " OR REPLACE" : " or replace");
      }

      this.print0(this.ucase ? " CONTEXT " : " context ");
      x.getNamespace().accept(this);
      this.print0(this.ucase ? " USING " : " using ");
      x.getPackagename().accept(this);
      return false;
   }

   public boolean visit(SQLCreateDirectoryStatement x) {
      this.print0(this.ucase ? "CREATE" : "create");
      if (x.isOrReplace()) {
         this.print0(this.ucase ? " OR REPLACE" : " or replace");
      }

      this.print0(this.ucase ? " DIRECTORY " : " directory ");
      x.getName().accept(this);
      this.print0(this.ucase ? " AS " : " as ");
      x.getDirPath().accept(this);
      return false;
   }

   public boolean visit(SQLSetTimeZoneStatement x) {
      this.print0(this.ucase ? "SET TIME ZONE " : "set time zone ");
      if (x.isLocal()) {
         this.print0(this.ucase ? "LOCAL" : "local");
      } else if (x.isInterval()) {
         this.print0(this.ucase ? "INTERVAL " : "interval ");
         x.getTimeZone().accept(this);
         if (x.getType() != null) {
            this.print0(" ");
            x.getType().accept(this);
         }
      } else {
         x.getTimeZone().accept(this);
      }

      return false;
   }

   public boolean visit(SQLAlterSetNlsDateLanguageStatement x) {
      this.print0(this.ucase ? "ALTER SESSION SET NLS_DATE_LANGUAGE=" : "alter session set nls_date_language=");
      this.print0(x.getType().name);
      return false;
   }

   public boolean visit(SQLAlterSetDateFormatStatement x) {
      this.print0(this.ucase ? "ALTER SESSION SET " : "alter session set ");
      x.getType().accept(this);
      this.print0("=");
      x.getFormat().accept(this);
      if (x.isPurge()) {
         this.print0(" PURGE");
      }

      return false;
   }

   public boolean visit(SQLAlterSystemStatement x) {
      this.print0(this.ucase ? "ALTER SYSTEM " : "alter system ");
      if (x.isArchiveLogCurrent()) {
         this.print0(this.ucase ? "ARCHIVE LOG CURRENT" : "archive log current");
         return false;
      } else if (x.isSwitchLogfile()) {
         this.print0(this.ucase ? "SWITCH LOGFILE" : "switch logfile");
         return false;
      } else {
         this.print0(this.ucase ? "SET " : "set ");
         x.getItem().accept(this);
         this.print0("=");
         x.getValue().accept(this);
         if (x.isDeferred()) {
            this.print0(this.ucase ? " DEFERRED" : " deferred");
         }

         if (x.getOption() != null) {
            this.print0(" ");
            this.print0(x.getOption().toString());
         }

         return false;
      }
   }

   protected void printTblProperties(HiveCreateTableStatement x) {
      List<SQLAssignItem> tblProperties = x.getTblProperties();
      if (tblProperties.size() > 0) {
         this.println();
         this.print0(this.ucase ? "TBLPROPERTIES (" : "tblproperties (");
         this.incrementIndent();
         this.println();
         int i = 0;

         for(SQLAssignItem property : tblProperties) {
            if (i != 0) {
               this.print(",");
               this.println();
            }

            String key = property.getTarget().toString();
            boolean unquote = false;
            char c0;
            if (key.length() > 0 && (c0 = key.charAt(0)) != '"' && c0 != '`' && c0 != '\'') {
               unquote = true;
            }

            if (unquote) {
               this.print('\'');
            }

            this.print0(key);
            if (unquote) {
               this.print('\'');
            }

            this.print0(" = ");
            property.getValue().accept(this);
            ++i;
         }

         this.decrementIndent();
         this.println();
         this.print(')');
      }

   }

   static {
      try {
         defaultPrintStatementAfterSemi = Utils.getBoolean(System.getProperties(), "fastsql.sql.output.printStatementAfterSemi");
      } catch (SecurityException var3) {
      }

      ONE = 1;
      variantValuesCache_1 = new String[64];
      variantValuesCache = new String[64];

      for(int len = 0; len < variantValuesCache_1.length; ++len) {
         StringBuffer buf = new StringBuffer();
         buf.append('(');

         for(int i = 0; i < len; ++i) {
            if (i != 0) {
               if (i % 5 == 0) {
                  buf.append("\n\t");
               }

               buf.append(", ");
            }

            buf.append('?');
         }

         buf.append(')');
         variantValuesCache_1[len] = buf.toString();
      }

      for(int len = 0; len < variantValuesCache.length; ++len) {
         StringBuffer buf = new StringBuffer();
         buf.append('(');

         for(int i = 0; i < len; ++i) {
            if (i != 0) {
               if (i % 5 == 0) {
                  buf.append("\n\t\t");
               }

               buf.append(", ");
            }

            buf.append('?');
         }

         buf.append(')');
         variantValuesCache[len] = buf.toString();
      }

   }
}
