package com.alibaba.druid.sql.dialect.mariadb.parser;

import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLCommentHint;
import com.alibaba.druid.sql.ast.SQLDataType;
import com.alibaba.druid.sql.ast.SQLDataTypeImpl;
import com.alibaba.druid.sql.ast.SQLDeclareItem;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLHint;
import com.alibaba.druid.sql.ast.SQLLimit;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.ast.SQLParameter;
import com.alibaba.druid.sql.ast.SQLPartition;
import com.alibaba.druid.sql.ast.SQLPartitionBy;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.SQLStatementImpl;
import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLHexExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntervalExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntervalUnit;
import com.alibaba.druid.sql.ast.expr.SQLLiteralExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.expr.SQLQueryExpr;
import com.alibaba.druid.sql.ast.expr.SQLTextLiteralExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.SQLAlterCharacter;
import com.alibaba.druid.sql.ast.statement.SQLAlterDatabaseStatement;
import com.alibaba.druid.sql.ast.statement.SQLAlterFunctionStatement;
import com.alibaba.druid.sql.ast.statement.SQLAlterIndexStatement;
import com.alibaba.druid.sql.ast.statement.SQLAlterOutlineStatement;
import com.alibaba.druid.sql.ast.statement.SQLAlterProcedureStatement;
import com.alibaba.druid.sql.ast.statement.SQLAlterSystemGetConfigStatement;
import com.alibaba.druid.sql.ast.statement.SQLAlterSystemSetConfigStatement;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddColumn;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddConstraint;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddIndex;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddPartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAnalyzePartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableBlockSize;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableCheckPartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableCoalescePartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableConvertCharSet;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDisableConstraint;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDisableKeys;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDiscardPartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropCheck;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropClusteringKey;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropColumnItem;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropConstraint;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropForeignKey;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropIndex;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropKey;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropPartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropPrimaryKey;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropSubpartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableEnableConstraint;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableEnableKeys;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableExchangePartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableGroupStatement;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableImportPartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableModifyClusteredBy;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableOptimizePartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTablePartitionCount;
import com.alibaba.druid.sql.ast.statement.SQLAlterTablePartitionLifecycle;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableReOrganizePartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableRebuildPartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableRename;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableRenameColumn;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableRenameIndex;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableRepairPartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableSetOption;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableSubpartitionAvailablePartitionNum;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableSubpartitionLifecycle;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableTruncatePartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterViewStatement;
import com.alibaba.druid.sql.ast.statement.SQLArchiveTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLAssignItem;
import com.alibaba.druid.sql.ast.statement.SQLBackupStatement;
import com.alibaba.druid.sql.ast.statement.SQLBlockStatement;
import com.alibaba.druid.sql.ast.statement.SQLBuildTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLCancelJobStatement;
import com.alibaba.druid.sql.ast.statement.SQLCheck;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLCommitStatement;
import com.alibaba.druid.sql.ast.statement.SQLCopyFromStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateDatabaseStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateFunctionStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateIndexStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateOutlineStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateProcedureStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLExportDatabaseStatement;
import com.alibaba.druid.sql.ast.statement.SQLExportTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLIfStatement;
import com.alibaba.druid.sql.ast.statement.SQLImportDatabaseStatement;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.ast.statement.SQLLoadIndexIntoCacheStatement;
import com.alibaba.druid.sql.ast.statement.SQLLoopStatement;
import com.alibaba.druid.sql.ast.statement.SQLObjectType;
import com.alibaba.druid.sql.ast.statement.SQLRenameUserStatement;
import com.alibaba.druid.sql.ast.statement.SQLReplaceStatement;
import com.alibaba.druid.sql.ast.statement.SQLRestoreStatement;
import com.alibaba.druid.sql.ast.statement.SQLRevokeStatement;
import com.alibaba.druid.sql.ast.statement.SQLRollbackStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.ast.statement.SQLSetStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowCatalogsStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowColumnsStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowCreateMaterializedViewStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowCreateViewStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowDatabasesStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowFunctionsStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowIndexesStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowOutlinesStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowPartitionsStmt;
import com.alibaba.druid.sql.ast.statement.SQLShowQueryTaskStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowRecylebinStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowSessionStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowStatisticStmt;
import com.alibaba.druid.sql.ast.statement.SQLShowTableGroupsStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowTablesStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowUsersStatement;
import com.alibaba.druid.sql.ast.statement.SQLStartTransactionStatement;
import com.alibaba.druid.sql.ast.statement.SQLSubmitJobStatement;
import com.alibaba.druid.sql.ast.statement.SQLSyncMetaStatement;
import com.alibaba.druid.sql.ast.statement.SQLTableConstraint;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem;
import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement;
import com.alibaba.druid.sql.ast.statement.SQLWhileStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.AnalyzerIndexType;
import com.alibaba.druid.sql.dialect.mariadb.ast.FullTextType;
import com.alibaba.druid.sql.dialect.mariadb.ast.MariadbForeignKey;
import com.alibaba.druid.sql.dialect.mariadb.ast.MariadbPrimaryKey;
import com.alibaba.druid.sql.dialect.mariadb.ast.MariadbUnique;
import com.alibaba.druid.sql.dialect.mariadb.ast.clause.ConditionValue;
import com.alibaba.druid.sql.dialect.mariadb.ast.clause.MariadbCaseStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.clause.MariadbCursorDeclareStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.clause.MariadbDeclareConditionStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.clause.MariadbDeclareHandlerStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.clause.MariadbDeclareStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.clause.MariadbHandlerType;
import com.alibaba.druid.sql.dialect.mariadb.ast.clause.MariadbIterateStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.clause.MariadbLeaveStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.clause.MariadbRepeatStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.clause.MariadbSelectIntoStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.clause.MariadbTableTableSource;
import com.alibaba.druid.sql.dialect.mariadb.ast.expr.MariadbUserName;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.CobarShowStatus;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.DrdsBaselineStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.DrdsCancelDDLJob;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.DrdsChangeDDLJob;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.DrdsClearDDLJobCache;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.DrdsInspectDDLJobCache;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.DrdsRecoverDDLJob;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.DrdsRemoveDDLJob;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.DrdsRollbackDDLJob;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.DrdsShowDDLJobs;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.DrdsShowGlobalIndex;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.DrdsShowMetadataLock;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterDatabaseKillJob;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterDatabaseSetOption;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterEventStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterFullTextStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterLogFileGroupStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterServerStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableAddExtPartition;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableAlterCheck;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableAlterColumn;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableAlterFullTextIndex;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableAlterIndex;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableChangeColumn;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableDiscardTablespace;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableDropExtPartition;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableForce;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableImportTablespace;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableLock;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableModifyColumn;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableOption;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableOrderBy;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableValidation;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTablespaceStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAlterUserStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbAnalyzeStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbBinlogStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbCacheIndexStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbCheckTableStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbChecksumTableStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbClearPlanCacheStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbCreateAddLogFileGroupStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbCreateEventStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbCreateFullTextAnalyzerStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbCreateFullTextCharFilterStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbCreateFullTextDictionaryStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbCreateFullTextTokenFilterStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbCreateFullTextTokenizerStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbCreateServerStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbCreateTableSpaceStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbCreateTableStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbCreateUserStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbDeallocatePrepareStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbDeleteStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbDisabledPlanCacheStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbEventSchedule;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbExecuteForAdsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbExecuteStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbExplainStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbExtPartition;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbFlashbackStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbFlushStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbGrantStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbHelpStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbHintStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbImportTableStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbInsertStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbKillStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbLoadDataInFileStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbLoadXmlStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbLockTableStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbManageInstanceGroupStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbMigrateStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbOptimizeStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbPrepareStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbRaftLeaderTransferStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbRaftMemberChangeStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbRenameSequenceStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbRenameTableStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbRepairTableStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbResetStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbRevokeStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbSetTransactionStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowAuthorsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowBinLogEventsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowBinaryLogsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowBroadcastsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowCharacterSetStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowClusterNameStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowCollationStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowColumnStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowConfigStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowContributorsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowCreateDatabaseStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowCreateEventStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowCreateFullTextStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowCreateFunctionStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowCreateProcedureStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowCreateTableStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowCreateTriggerStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowDatabaseStatusStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowDatasourcesStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowDbLockStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowDdlStatusStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowDsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowEngineStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowEnginesStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowErrorsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowEventsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowFullTextStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowFunctionCodeStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowFunctionStatusStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowGrantsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowHMSMetaStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowHelpStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowHtcStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowJobStatusStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowMasterLogsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowMasterStatusStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowMigrateTaskStatusStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowNodeStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowOpenTablesStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowPhysicalProcesslistStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowPlanCacheStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowPlanCacheStatusStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowPluginsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowPrivilegesStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowProcedureCodeStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowProcedureStatusStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowProcessListStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowProfileStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowProfilesStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowRelayLogEventsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowRuleStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowRuleStatusStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowSequencesStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowSlaveHostsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowSlaveStatusStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowSlowStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowStatusStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowStcStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowTableStatusStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowTopologyStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowTraceStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowTriggersStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowVariantsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbShowWarningsStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbUnlockTablesStatement;
import com.alibaba.druid.sql.dialect.mariadb.ast.statement.MariadbUpdateStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlTableTableSource;
import com.alibaba.druid.sql.parser.EOFParserException;
import com.alibaba.druid.sql.parser.InsertColumnsCache;
import com.alibaba.druid.sql.parser.Lexer;
import com.alibaba.druid.sql.parser.ParserException;
import com.alibaba.druid.sql.parser.SQLExprParser;
import com.alibaba.druid.sql.parser.SQLParserFeature;
import com.alibaba.druid.sql.parser.SQLSelectParser;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.sql.parser.Token;
import com.alibaba.druid.sql.repository.SchemaObject;
import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor;
import com.alibaba.druid.util.FnvHash;
import com.alibaba.druid.util.StringUtils;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MariadbStatementParser extends SQLStatementParser {
   private static final String AUTO_INCREMENT = "AUTO_INCREMENT";
   private static final String AVG_ROW_LENGTH = "AVG_ROW_LENGTH";
   private static final String CHECKSUM2 = "CHECKSUM";
   private static final String DELAY_KEY_WRITE = "DELAY_KEY_WRITE";
   private static final String ENCRYPTION2 = "ENCRYPTION";
   private static final String INSERT_METHOD = "INSERT_METHOD";
   private static final String KEY_BLOCK_SIZE2 = "KEY_BLOCK_SIZE";
   private static final String MAX_ROWS2 = "MAX_ROWS";
   private static final String MIN_ROWS2 = "MIN_ROWS";
   private static final String PASSWORD2 = "PASSWORD";
   private static final String STATS_AUTO_RECALC = "STATS_AUTO_RECALC";
   private static final String STATS_PERSISTENT = "STATS_PERSISTENT";
   private static final String STATS_SAMPLE_PAGES = "STATS_SAMPLE_PAGES";
   private static final String TABLESPACE2 = "TABLESPACE";
   private static final String CHAIN = "CHAIN";
   private static final String ENGINES = "ENGINES";
   private static final String ENGINE = "ENGINE";
   private static final String BINLOG = "BINLOG";
   private static final String EVENTS = "EVENTS";
   private static final String GLOBAL = "GLOBAL";
   private static final String VARIABLES = "VARIABLES";
   private static final String STATUS = "STATUS";
   private static final String DBLOCK = "DBLOCK";
   private static final String RESET = "RESET";
   private static final String DESCRIBE = "DESCRIBE";
   private static final String WRITE = "WRITE";
   private static final String READ = "READ";
   private static final String LOCAL = "LOCAL";
   private static final String TABLES = "TABLES";
   private static final String CONNECTION = "CONNECTION";
   private int maxIntoClause = -1;

   public MariadbStatementParser(String sql) {
      super((SQLExprParser)(new MariadbExprParser(sql)));
   }

   public MariadbStatementParser(String sql, SQLParserFeature... features) {
      super((SQLExprParser)(new MariadbExprParser(sql, features)));
   }

   public MariadbStatementParser(String sql, boolean keepComments) {
      super((SQLExprParser)(new MariadbExprParser(sql, keepComments)));
   }

   public MariadbStatementParser(String sql, boolean skipComment, boolean keepComments) {
      super((SQLExprParser)(new MariadbExprParser(sql, skipComment, keepComments)));
   }

   public MariadbStatementParser(Lexer lexer) {
      super((SQLExprParser)(new MariadbExprParser(lexer)));
   }

   public int getMaxIntoClause() {
      return this.maxIntoClause;
   }

   public void setMaxIntoClause(int maxIntoClause) {
      this.maxIntoClause = maxIntoClause;
   }

   public SQLCreateTableStatement parseCreateTable() {
      MariadbCreateTableParser parser = new MariadbCreateTableParser(this.exprParser);
      return parser.parseCreateTable();
   }

   public SQLStatement parseSelect() {
      MariadbSelectParser selectParser = this.createSQLSelectParser();
      SQLSelect select = selectParser.select();
      return (SQLStatement)(selectParser.returningFlag ? selectParser.updateStmt : new SQLSelectStatement(select, DbType.mysql));
   }

   public SQLUpdateStatement parseUpdateStatement() {
      return (new MariadbSelectParser(this.exprParser, this.selectListCache)).parseUpdateStatment();
   }

   protected MariadbUpdateStatement createUpdateStatement() {
      return new MariadbUpdateStatement();
   }

   public MariadbDeleteStatement parseDeleteStatement() {
      MariadbDeleteStatement deleteStatement = new MariadbDeleteStatement();
      if (this.lexer.isKeepComments() && this.lexer.hasComment()) {
         List<String> comments = this.lexer.readAndResetComments();
         if (comments != null) {
            deleteStatement.addBeforeComment(comments);
         }
      }

      if (this.lexer.token() == Token.DELETE) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.COMMENT) {
            this.lexer.nextToken();
         }

         if (this.lexer.token() == Token.HINT) {
            this.getExprParser().parseHints(deleteStatement.getHints());
         }

         if (this.lexer.identifierEquals(FnvHash.Constants.LOW_PRIORITY)) {
            deleteStatement.setLowPriority(true);
            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("QUICK")) {
            deleteStatement.setQuick(true);
            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals(FnvHash.Constants.IGNORE)) {
            deleteStatement.setIgnore(true);
            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals(FnvHash.Constants.FORCE)) {
            Lexer.SavePoint savePoint = this.lexer.mark();
            this.lexer.nextToken();
            if (this.lexer.token() == Token.ALL) {
               this.lexer.nextToken();
               this.acceptIdentifier("PARTITIONS");
               deleteStatement.setForceAllPartitions(true);
            } else if (this.lexer.identifierEquals(FnvHash.Constants.PARTITIONS)) {
               this.lexer.nextToken();
               deleteStatement.setForceAllPartitions(true);
            } else if (this.lexer.token() == Token.PARTITION) {
               this.lexer.nextToken();
               SQLName partition = this.exprParser.name();
               deleteStatement.setForcePartition(partition);
            } else {
               this.lexer.reset(savePoint);
            }
         }

         if (this.lexer.token() == Token.IDENTIFIER) {
            deleteStatement.setTableSource(this.createSQLSelectParser().parseTableSource());
            if (this.lexer.token() == Token.FROM) {
               this.lexer.nextToken();
               SQLTableSource tableSource = this.createSQLSelectParser().parseTableSource();
               deleteStatement.setFrom(tableSource);
            }
         } else {
            if (this.lexer.token() != Token.FROM) {
               throw new ParserException("syntax error. " + this.lexer.info());
            }

            this.lexer.nextToken();
            if (this.lexer.token() == Token.FULLTEXT) {
               this.lexer.nextToken();
               if (this.lexer.identifierEquals(FnvHash.Constants.DICTIONARY)) {
                  this.lexer.nextToken();
                  deleteStatement.setFulltextDictionary(true);
               }
            }

            deleteStatement.setTableSource(this.createSQLSelectParser().parseTableSource());
         }

         if (this.lexer.identifierEquals(FnvHash.Constants.USING)) {
            this.lexer.nextToken();
            SQLTableSource tableSource = this.createSQLSelectParser().parseTableSource();
            deleteStatement.setUsing(tableSource);
         }
      }

      if (this.lexer.token() == Token.WHERE) {
         this.lexer.nextToken();
         SQLExpr where = this.exprParser.expr();
         deleteStatement.setWhere(where);
      }

      if (this.lexer.token() == Token.ORDER) {
         SQLOrderBy orderBy = this.exprParser.parseOrderBy();
         deleteStatement.setOrderBy(orderBy);
      }

      if (this.lexer.token() == Token.LIMIT) {
         deleteStatement.setLimit(this.exprParser.parseLimit());
      }

      if (this.lexer.token() != Token.EOF && this.lexer.token() != Token.SEMI) {
         throw new ParserException("syntax error. " + this.lexer.info());
      } else {
         return deleteStatement;
      }
   }

   public SQLStatement parseCreate() {
      List<String> comments = null;
      if (this.lexer.isKeepComments() && this.lexer.hasComment()) {
         comments = this.lexer.readAndResetComments();
      }

      Lexer.SavePoint mark = this.lexer.mark();
      this.accept(Token.CREATE);
      boolean replace = false;
      if (this.lexer.token() == Token.OR) {
         this.lexer.nextToken();
         this.accept(Token.REPLACE);
         replace = true;
      }

      boolean physical = false;
      if (this.lexer.identifierEquals(FnvHash.Constants.PHYSICAL)) {
         this.lexer.nextToken();
         physical = true;
      }

      if (this.lexer.token() == Token.GROUP) {
         this.lexer.nextToken();
      } else if (this.lexer.identifierEquals(FnvHash.Constants.SIMPLE)) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.WITH) {
            this.lexer.nextToken();
            this.accept(Token.CACHE);
         }
      } else if (this.lexer.identifierEquals(FnvHash.Constants.TIME)) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.SEQUENCE) {
            this.lexer.reset(mark);
            return this.parseCreateSequence(true);
         }
      }

      List<SQLCommentHint> hints = this.exprParser.parseHints();
      boolean isExternal = false;
      if (this.lexer.identifierEquals(FnvHash.Constants.EXTERNAL)) {
         isExternal = true;
         this.lexer.nextToken();
         if (this.lexer.identifierEquals(FnvHash.Constants.CATALOG)) {
            this.lexer.reset(mark);
            return this.parseCreateExternalCatalog();
         }
      }

      if (this.lexer.token() != Token.TABLE && !this.lexer.identifierEquals(FnvHash.Constants.TEMPORARY) && !isExternal && !this.lexer.identifierEquals("SHADOW")) {
         switch (this.lexer.token()) {
            case DATABASE:
            case SCHEMA:
               if (replace) {
                  this.lexer.reset(mark);
               }

               SQLCreateDatabaseStatement stmt = (SQLCreateDatabaseStatement)this.parseCreateDatabase();
               if (physical) {
                  stmt.setPhysical(true);
               }

               return stmt;
            case USER:
               if (replace) {
                  this.lexer.reset(mark);
               }

               return this.parseCreateUser();
            case TRIGGER:
               this.lexer.reset(mark);
               return this.parseCreateTrigger();
            case PROCEDURE:
               if (replace) {
                  this.lexer.reset(mark);
               }

               return this.parseCreateProcedure();
            case FUNCTION:
               if (replace) {
                  this.lexer.reset(mark);
               }

               return this.parseCreateFunction();
            case SEQUENCE:
               this.lexer.reset(mark);
               return this.parseCreateSequence(true);
            case FULLTEXT:
               this.lexer.reset(mark);
               return this.parseCreateFullTextStatement();
            default:
               if (this.lexer.token() != Token.UNIQUE && this.lexer.token() != Token.INDEX && this.lexer.token() != Token.FULLTEXT && !this.lexer.identifierEquals(FnvHash.Constants.SPATIAL) && !this.lexer.identifierEquals(FnvHash.Constants.ANN) && !this.lexer.identifierEquals(FnvHash.Constants.GLOBAL) && !this.lexer.identifierEquals(FnvHash.Constants.LOCAL)) {
                  if (this.lexer.token() != Token.VIEW && !this.lexer.identifierEquals(FnvHash.Constants.ALGORITHM)) {
                     if (this.lexer.identifierEquals(FnvHash.Constants.EVENT)) {
                        this.lexer.reset(mark);
                        return this.parseCreateEvent();
                     } else if (this.lexer.identifierEquals(FnvHash.Constants.DEFINER)) {
                        this.lexer.nextToken();
                        this.accept(Token.EQ);
                        this.getExprParser().userName();
                        if (this.lexer.identifierEquals(FnvHash.Constants.SQL)) {
                           this.lexer.nextToken();
                           this.acceptIdentifier("SECURITY");
                           if (this.lexer.token() == Token.EQ) {
                              this.lexer.nextToken();
                           }

                           this.lexer.nextToken();
                        }

                        if (this.lexer.identifierEquals(FnvHash.Constants.EVENT)) {
                           this.lexer.reset(mark);
                           return this.parseCreateEvent();
                        } else if (this.lexer.token() == Token.TRIGGER) {
                           this.lexer.reset(mark);
                           return this.parseCreateTrigger();
                        } else if (this.lexer.token() == Token.VIEW) {
                           this.lexer.reset(mark);
                           return this.parseCreateView();
                        } else if (this.lexer.token() == Token.FUNCTION) {
                           this.lexer.reset(mark);
                           return this.parseCreateFunction();
                        } else {
                           this.lexer.reset(mark);
                           return this.parseCreateProcedure();
                        }
                     } else if (this.lexer.identifierEquals(FnvHash.Constants.LOGFILE)) {
                        return this.parseCreateLogFileGroup();
                     } else if (this.lexer.identifierEquals(FnvHash.Constants.SERVER)) {
                        return this.parseCreateServer();
                     } else if (this.lexer.token() == Token.TABLESPACE) {
                        return this.parseCreateTableSpace();
                     } else if (this.lexer.identifierEquals(FnvHash.Constants.DIMENSION)) {
                        this.lexer.reset(mark);
                        return this.parseCreateTable();
                     } else if (this.lexer.identifierEquals(FnvHash.Constants.TABLEGROUP)) {
                        this.lexer.reset(mark);
                        return this.parseCreateTableGroup();
                     } else if (this.lexer.identifierEquals(FnvHash.Constants.OUTLINE)) {
                        this.lexer.reset(mark);
                        return this.parseCreateOutline();
                     } else if (this.lexer.identifierEquals(FnvHash.Constants.CLUSTERED)) {
                        this.lexer.reset(mark);
                        return this.parseCreateIndex(true);
                     } else if (this.lexer.identifierEquals(FnvHash.Constants.RESOURCE)) {
                        this.lexer.reset(mark);
                        return this.parseCreateResourceGroup();
                     } else if (this.lexer.identifierEquals(FnvHash.Constants.MATERIALIZED)) {
                        this.lexer.reset(mark);
                        return this.parseCreateMaterializedView();
                     } else {
                        throw new ParserException("TODO " + this.lexer.info());
                     }
                  } else {
                     if (replace) {
                        this.lexer.reset(mark);
                     }

                     return this.parseCreateView();
                  }
               } else {
                  if (replace) {
                     this.lexer.reset(mark);
                  }

                  return this.parseCreateIndex(false);
               }
         }
      } else {
         this.lexer.reset(mark);
         MariadbCreateTableParser parser = new MariadbCreateTableParser(this.exprParser);
         MariadbCreateTableStatement stmt = parser.parseCreateTable(true);
         stmt.setHints(hints);
         if (comments != null) {
            stmt.addBeforeComment(comments);
         }

         return stmt;
      }
   }

   public SQLStatement parseCreateFullTextStatement() {
      Lexer.SavePoint mark = this.lexer.mark();
      this.accept(Token.CREATE);
      this.accept(Token.FULLTEXT);
      if (this.lexer.identifierEquals(FnvHash.Constants.CHARFILTER)) {
         this.lexer.nextToken();
         return this.parseFullTextCharFilter();
      } else if (this.lexer.identifierEquals(FnvHash.Constants.TOKENIZER)) {
         this.lexer.nextToken();
         return this.parseFullTextTokenizer();
      } else if (this.lexer.identifierEquals(FnvHash.Constants.TOKENFILTER)) {
         this.lexer.nextToken();
         return this.parseFullTextTokenFilter();
      } else if (this.lexer.identifierEquals(FnvHash.Constants.ANALYZER)) {
         this.lexer.nextToken();
         return this.parseFullTextAnalyzer();
      } else if (this.lexer.token() == Token.INDEX) {
         this.lexer.reset(mark);
         return this.parseCreateIndex(true);
      } else if (this.lexer.identifierEquals(FnvHash.Constants.DICTIONARY)) {
         this.lexer.nextToken();
         MariadbCreateFullTextDictionaryStatement stmt = new MariadbCreateFullTextDictionaryStatement();
         SQLName name = this.exprParser.name();
         stmt.setName(name);
         this.accept(Token.LPAREN);
         SQLColumnDefinition col = new SQLColumnDefinition();
         col.setName(this.exprParser.name());
         this.acceptIdentifier("varchar");
         col.setDataType(new SQLDataTypeImpl("varchar"));
         if (this.lexer.token() == Token.COMMENT) {
            this.accept(Token.COMMENT);
            col.setComment((SQLExpr)this.exprParser.name());
         }

         stmt.setColumn(col);
         this.accept(Token.RPAREN);
         if (this.lexer.token() == Token.COMMENT) {
            this.accept(Token.COMMENT);
            stmt.setComment(this.exprParser.name().getSimpleName());
         }

         return stmt;
      } else {
         throw new ParserException("TODO " + this.lexer.info());
      }
   }

   private SQLStatement parseFullTextAnalyzer() {
      MariadbCreateFullTextAnalyzerStatement stmt = new MariadbCreateFullTextAnalyzerStatement();
      SQLName name = this.exprParser.name();
      stmt.setName(name);
      this.accept(Token.LPAREN);

      while(true) {
         String key = "";
         if (this.lexer.token() == Token.LITERAL_ALIAS || this.lexer.token() == Token.LITERAL_CHARS) {
            key = StringUtils.removeNameQuotes(this.lexer.stringVal());
            if (key.equalsIgnoreCase("charfilter")) {
               this.lexer.nextToken();
               this.accept(Token.EQ);
               this.accept(Token.LBRACKET);

               while(true) {
                  String c = SQLUtils.normalize(this.exprParser.name().getSimpleName());
                  stmt.getCharfilters().add(c);
                  if (this.lexer.token() != Token.COMMA) {
                     this.accept(Token.RBRACKET);
                     break;
                  }

                  this.lexer.nextToken();
               }
            } else if (!key.equalsIgnoreCase("tokenfilter")) {
               if (key.equalsIgnoreCase("tokenizer")) {
                  this.lexer.nextToken();
                  this.accept(Token.EQ);
                  stmt.setTokenizer(SQLUtils.normalize(this.exprParser.name().getSimpleName()));
               }
            } else {
               this.lexer.nextToken();
               this.accept(Token.EQ);
               this.accept(Token.LBRACKET);

               while(true) {
                  String c = SQLUtils.normalize(this.exprParser.name().getSimpleName());
                  stmt.getTokenizers().add(c);
                  if (this.lexer.token() != Token.COMMA) {
                     this.accept(Token.RBRACKET);
                     break;
                  }

                  this.lexer.nextToken();
               }
            }
         }

         if (this.lexer.token() != Token.COMMA) {
            this.accept(Token.RPAREN);
            key = stmt.getTokenizer();
            if (key != null && !StringUtils.isEmpty(key)) {
               return stmt;
            }

            throw new ParserException("tokenizer is require.");
         }

         this.lexer.nextToken();
      }
   }

   private SQLStatement parseFullTextTokenizer() {
      MariadbCreateFullTextTokenizerStatement stmt = new MariadbCreateFullTextTokenizerStatement();
      SQLName name = this.exprParser.name();
      stmt.setName(name);
      this.accept(Token.LPAREN);

      while(true) {
         SQLAssignItem assignItem = this.exprParser.parseAssignItem();
         assignItem.setParent(stmt);
         SQLExpr target = assignItem.getTarget();
         if ("type".equalsIgnoreCase(((SQLTextLiteralExpr)target).getText())) {
            stmt.setTypeName((SQLTextLiteralExpr)assignItem.getValue());
         } else if ("user_defined_dict".equalsIgnoreCase(((SQLTextLiteralExpr)target).getText())) {
            stmt.setUserDefinedDict((SQLTextLiteralExpr)assignItem.getValue());
         } else {
            stmt.getOptions().add(assignItem);
         }

         if (this.lexer.token() != Token.COMMA) {
            this.accept(Token.RPAREN);
            SQLTextLiteralExpr typeName = stmt.getTypeName();
            if (typeName != null && !StringUtils.isEmpty(typeName.getText())) {
               return stmt;
            }

            throw new ParserException("type is require.");
         }

         this.lexer.nextToken();
      }
   }

   private SQLStatement parseFullTextCharFilter() {
      MariadbCreateFullTextCharFilterStatement stmt = new MariadbCreateFullTextCharFilterStatement();
      SQLName name = this.exprParser.name();
      stmt.setName(name);
      this.accept(Token.LPAREN);

      while(true) {
         SQLAssignItem assignItem = this.exprParser.parseAssignItem();
         assignItem.setParent(stmt);
         if ("type".equalsIgnoreCase(((SQLTextLiteralExpr)assignItem.getTarget()).getText())) {
            stmt.setTypeName((SQLTextLiteralExpr)assignItem.getValue());
         } else {
            stmt.getOptions().add(assignItem);
         }

         if (this.lexer.token() != Token.COMMA) {
            this.accept(Token.RPAREN);
            SQLTextLiteralExpr typeName = stmt.getTypeName();
            if (typeName != null && !StringUtils.isEmpty(typeName.getText())) {
               return stmt;
            }

            throw new ParserException("type is require.");
         }

         this.lexer.nextToken();
      }
   }

   private SQLStatement parseFullTextTokenFilter() {
      MariadbCreateFullTextTokenFilterStatement stmt = new MariadbCreateFullTextTokenFilterStatement();
      SQLName name = this.exprParser.name();
      stmt.setName(name);
      this.accept(Token.LPAREN);

      while(true) {
         SQLAssignItem assignItem = this.exprParser.parseAssignItem();
         assignItem.setParent(stmt);
         if ("type".equalsIgnoreCase(((SQLTextLiteralExpr)assignItem.getTarget()).getText())) {
            stmt.setTypeName((SQLTextLiteralExpr)assignItem.getValue());
         } else {
            stmt.getOptions().add(assignItem);
         }

         if (this.lexer.token() != Token.COMMA) {
            this.accept(Token.RPAREN);
            SQLTextLiteralExpr typeName = stmt.getTypeName();
            if (typeName != null && !StringUtils.isEmpty(typeName.getText())) {
               return stmt;
            }

            throw new ParserException("type is require.");
         }

         this.lexer.nextToken();
      }
   }

   public SQLStatement parseCreateOutline() {
      this.accept(Token.CREATE);
      this.acceptIdentifier("OUTLINE");
      SQLCreateOutlineStatement stmt = new SQLCreateOutlineStatement();
      stmt.setDbType(this.dbType);
      SQLName name = this.exprParser.name();
      stmt.setName(name);
      if (this.lexer.token() == Token.WHERE) {
         this.lexer.nextToken();
         stmt.setWhere(this.exprParser.expr());
      }

      this.accept(Token.ON);
      SQLStatement on = this.parseStatement();
      stmt.setOn(on);
      this.accept(Token.TO);
      SQLStatement to = this.parseStatement();
      stmt.setTo(to);
      return stmt;
   }

   public SQLStatement parseCreateTableSpace() {
      if (this.lexer.token() == Token.CREATE) {
         this.accept(Token.CREATE);
      }

      MariadbCreateTableSpaceStatement stmt = new MariadbCreateTableSpaceStatement();
      this.accept(Token.TABLESPACE);
      stmt.setName(this.exprParser.name());
      if (this.lexer.identifierEquals(FnvHash.Constants.ADD)) {
         this.lexer.nextToken();
         this.acceptIdentifier("DATAFILE");
         SQLExpr file = this.exprParser.primary();
         stmt.setAddDataFile(file);
      }

      while(true) {
         while(!this.lexer.identifierEquals(FnvHash.Constants.INITIAL_SIZE)) {
            if (this.lexer.identifierEquals(FnvHash.Constants.FILE_BLOCK_SIZE)) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.EQ) {
                  this.lexer.nextToken();
               }

               SQLExpr fileBlockSize = this.exprParser.expr();
               stmt.setFileBlockSize(fileBlockSize);
            } else if (this.lexer.identifierEquals(FnvHash.Constants.EXTENT_SIZE)) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.EQ) {
                  this.lexer.nextToken();
               }

               SQLExpr extentSize = this.exprParser.expr();
               stmt.setExtentSize(extentSize);
            } else if (this.lexer.identifierEquals(FnvHash.Constants.AUTOEXTEND_SIZE)) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.EQ) {
                  this.lexer.nextToken();
               }

               SQLExpr extentSize = this.exprParser.expr();
               stmt.setAutoExtentSize(extentSize);
            } else if (this.lexer.identifierEquals(FnvHash.Constants.MAX_SIZE)) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.EQ) {
                  this.lexer.nextToken();
               }

               SQLExpr size = this.exprParser.expr();
               stmt.setMaxSize(size);
            } else if (this.lexer.identifierEquals(FnvHash.Constants.NODEGROUP)) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.EQ) {
                  this.lexer.nextToken();
               }

               SQLExpr size = this.exprParser.expr();
               stmt.setNodeGroup(size);
            } else if (this.lexer.identifierEquals(FnvHash.Constants.WAIT)) {
               this.lexer.nextToken();
               stmt.setWait(true);
            } else if (this.lexer.identifierEquals(FnvHash.Constants.ENGINE)) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.EQ) {
                  this.lexer.nextToken();
               }

               SQLExpr engine = this.exprParser.expr();
               stmt.setEngine(engine);
            } else if (this.lexer.token() == Token.COMMENT) {
               this.lexer.nextToken();
               SQLExpr comment = this.exprParser.expr();
               stmt.setComment(comment);
            } else {
               if (this.lexer.token() != Token.USE) {
                  return stmt;
               }

               this.lexer.nextToken();
               this.acceptIdentifier("LOGFILE");
               this.accept(Token.GROUP);
               SQLExpr logFileGroup = this.exprParser.expr();
               stmt.setFileBlockSize(logFileGroup);
            }
         }

         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         SQLExpr initialSize = this.exprParser.expr();
         stmt.setInitialSize(initialSize);
      }
   }

   public SQLStatement parseCreateServer() {
      if (this.lexer.token() == Token.CREATE) {
         this.accept(Token.CREATE);
      }

      MariadbCreateServerStatement stmt = new MariadbCreateServerStatement();
      this.acceptIdentifier("SERVER");
      stmt.setName(this.exprParser.name());
      this.accept(Token.FOREIGN);
      this.acceptIdentifier("DATA");
      this.acceptIdentifier("WRAPPER");
      stmt.setForeignDataWrapper(this.exprParser.name());
      this.acceptIdentifier("OPTIONS");
      this.accept(Token.LPAREN);

      while(true) {
         if (this.lexer.identifierEquals(FnvHash.Constants.HOST)) {
            this.lexer.nextToken();
            SQLExpr host = this.exprParser.expr();
            stmt.setHost(host);
         } else if (this.lexer.token() == Token.USER) {
            this.lexer.nextToken();
            SQLExpr user = this.exprParser.expr();
            stmt.setUser(user);
         } else if (this.lexer.token() == Token.DATABASE) {
            this.lexer.nextToken();
            SQLExpr db = this.exprParser.expr();
            stmt.setDatabase(db);
         } else if (this.lexer.identifierEquals(FnvHash.Constants.PASSWORD)) {
            this.lexer.nextToken();
            SQLExpr pwd = this.exprParser.expr();
            stmt.setPassword(pwd);
         } else if (this.lexer.identifierEquals(FnvHash.Constants.SOCKET)) {
            this.lexer.nextToken();
            SQLExpr sock = this.exprParser.expr();
            stmt.setSocket(sock);
         } else if (this.lexer.identifierEquals(FnvHash.Constants.OWNER)) {
            this.lexer.nextToken();
            SQLExpr owner = this.exprParser.expr();
            stmt.setOwner(owner);
         } else if (this.lexer.identifierEquals(FnvHash.Constants.PORT)) {
            this.lexer.nextToken();
            SQLExpr port = this.exprParser.expr();
            stmt.setPort(port);
         }

         if (this.lexer.token() != Token.COMMA) {
            this.accept(Token.RPAREN);
            return stmt;
         }

         this.lexer.nextToken();
      }
   }

   public SQLCreateIndexStatement parseCreateIndex(boolean acceptCreate) {
      if (acceptCreate) {
         this.accept(Token.CREATE);
      }

      SQLCreateIndexStatement stmt = new SQLCreateIndexStatement();
      this.exprParser.parseIndex(stmt.getIndexDefinition());
      return stmt;
   }

   private void parseCreateIndexUsing(SQLCreateIndexStatement stmt) {
      if (this.lexer.identifierEquals(FnvHash.Constants.USING)) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals(FnvHash.Constants.BTREE)) {
            stmt.setUsing("BTREE");
            this.lexer.nextToken();
         } else {
            if (!this.lexer.identifierEquals(FnvHash.Constants.HASH)) {
               throw new ParserException("TODO " + this.lexer.info());
            }

            stmt.setUsing("HASH");
            this.lexer.nextToken();
         }
      }

   }

   public SQLStatement parseCreateUser() {
      if (this.lexer.token() == Token.CREATE) {
         this.lexer.nextToken();
      }

      this.accept(Token.USER);
      MariadbCreateUserStatement stmt = new MariadbCreateUserStatement();
      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.accept(Token.NOT);
         this.accept(Token.EXISTS);
         stmt.setIfNotExists(true);
      }

      while(true) {
         MariadbCreateUserStatement.UserSpecification userSpec = new MariadbCreateUserStatement.UserSpecification();
         if (this.lexer.token() == Token.IF) {
            this.lexer.nextToken();
            this.accept(Token.NOT);
            this.accept(Token.EXISTS);
            stmt.setIfNotExists(true);
         }

         SQLExpr expr = this.exprParser.primary();
         if (expr instanceof SQLCharExpr) {
            expr = new SQLIdentifierExpr(((SQLCharExpr)expr).getText());
         }

         if (expr instanceof SQLIdentifierExpr && this.lexer.token() == Token.VARIANT && this.lexer.stringVal().charAt(0) == '@') {
            String str = this.lexer.stringVal();
            MariadbUserName mySqlUserName = new MariadbUserName();
            mySqlUserName.setUserName(((SQLIdentifierExpr)expr).getName());
            mySqlUserName.setHost(str.substring(1));
            expr = mySqlUserName;
            this.lexer.nextToken();
         }

         userSpec.setUser(expr);
         if (this.lexer.identifierEquals(FnvHash.Constants.IDENTIFIED)) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.BY) {
               this.lexer.nextToken();
               if (this.lexer.identifierEquals("PASSWORD")) {
                  this.lexer.nextToken();
                  userSpec.setPasswordHash(true);
               }

               SQLExpr password = this.exprParser.expr();
               if (!(password instanceof SQLIdentifierExpr) && !(password instanceof SQLCharExpr)) {
                  throw new ParserException("syntax error. invalid " + password + " expression.");
               }

               userSpec.setPassword(password);
            } else if (this.lexer.token() == Token.WITH) {
               this.lexer.nextToken();
               userSpec.setAuthPlugin(this.exprParser.expr());
               if (this.lexer.token() == Token.BY || this.lexer.token() == Token.AS) {
                  userSpec.setPluginAs(this.lexer.token() == Token.AS);
                  this.lexer.nextToken();
                  if (userSpec.isPluginAs()) {
                     String psw = this.lexer.stringVal();
                     if (psw.length() >= 2 && '\'' == psw.charAt(0) && '\'' == psw.charAt(psw.length() - 1)) {
                        userSpec.setPassword(new SQLCharExpr(psw.substring(1, psw.length() - 1)));
                     } else {
                        userSpec.setPassword(new SQLCharExpr(psw));
                     }

                     this.lexer.nextToken();
                  } else {
                     userSpec.setPassword(this.exprParser.charExpr());
                  }
               }
            }
         }

         stmt.addUser(userSpec);
         if (this.lexer.token() != Token.COMMA) {
            return stmt;
         }

         this.lexer.nextToken();
      }
   }

   public SQLStatement parseKill() {
      this.accept(Token.KILL);
      MariadbKillStatement stmt = new MariadbKillStatement();
      if (this.lexer.identifierEquals("CONNECTION")) {
         stmt.setType(MariadbKillStatement.Type.CONNECTION);
         this.lexer.nextToken();
      } else if (!this.lexer.identifierEquals(FnvHash.Constants.QUERY) && !this.lexer.identifierEquals(FnvHash.Constants.PROCESS)) {
         if (this.lexer.token() != Token.LITERAL_INT && this.lexer.token() != Token.LITERAL_CHARS) {
            if (this.lexer.token() != Token.ALL) {
               throw new ParserException("not support kill type " + this.lexer.token() + ". " + this.lexer.info());
            }

            SQLIdentifierExpr all = new SQLIdentifierExpr(this.lexer.stringVal());
            all.setParent(stmt);
            stmt.getThreadIds().add(all);
            this.lexer.nextToken();
         }
      } else {
         stmt.setType(MariadbKillStatement.Type.QUERY);
         this.lexer.nextToken();
      }

      this.exprParser.exprList(stmt.getThreadIds(), stmt);
      if (this.lexer.token() == Token.SEMI) {
         this.lexer.nextToken();
         stmt.setAfterSemi(true);
      }

      return stmt;
   }

   public SQLStatement parseBinlog() {
      this.acceptIdentifier("binlog");
      MariadbBinlogStatement stmt = new MariadbBinlogStatement();
      SQLExpr expr = this.exprParser.expr();
      stmt.setExpr(expr);
      return stmt;
   }

   public MariadbAnalyzeStatement parseAnalyze() {
      this.accept(Token.ANALYZE);
      MariadbAnalyzeStatement stmt = new MariadbAnalyzeStatement();
      if (this.lexer.identifierEquals("NO_WRITE_TO_BINLOG")) {
         this.lexer.nextToken();
         stmt.setNoWriteToBinlog(true);
      }

      if (this.lexer.identifierEquals("LOCAL")) {
         this.lexer.nextToken();
         stmt.setLocal(true);
      }

      if (this.lexer.token() == Token.TABLE) {
         this.accept(Token.TABLE);
         List<SQLName> names = new ArrayList();
         this.exprParser.names(names, stmt);

         for(SQLName name : names) {
            stmt.addTableSource(new SQLExprTableSource(name));
         }

         if (this.lexer.token() == Token.UPDATE) {
            this.accept(Token.UPDATE);
            stmt.setUpdate(true);
            if (this.lexer.identifierEquals("HISTOGRAM")) {
               this.lexer.nextToken();
            }

            if (this.lexer.token() == Token.ON) {
               this.lexer.nextToken();

               while(true) {
                  SQLExpr column = this.exprParser.expr();
                  stmt.getIdentifiedByColumns().add(column);
                  if (this.lexer.token() != Token.COMMA) {
                     break;
                  }

                  this.lexer.nextToken();
               }
            }

            if (this.lexer.token() == Token.WITH) {
               this.accept(Token.WITH);
               stmt.setWith(true);
               SQLExpr n = this.exprParser.expr();
               stmt.setN(n);
               if (this.lexer.identifierEquals("BUCKETS")) {
                  this.lexer.nextToken();
                  stmt.setBuckets(true);
               }
            }

            if (this.lexer.identifierEquals("USING")) {
               this.lexer.nextToken();
               stmt.setUsing(true);
               if (this.lexer.identifierEquals("DATA")) {
                  this.lexer.nextToken();
                  stmt.setJsonData(this.lexer.stringVal());
                  this.lexer.nextToken();
               }
            }
         } else if (this.lexer.token() == Token.DROP) {
            this.accept(Token.DROP);
            stmt.setDrop(true);
            if (this.lexer.identifierEquals("HISTOGRAM")) {
               this.lexer.nextToken();
            }

            if (this.lexer.token() == Token.ON) {
               this.lexer.nextToken();

               while(true) {
                  SQLExpr column = this.exprParser.expr();
                  stmt.getIdentifiedByColumns().add(column);
                  if (this.lexer.token() != Token.COMMA) {
                     break;
                  }

                  this.lexer.nextToken();
               }
            }
         }

         if (this.lexer.token() == Token.WHERE) {
            this.accept(Token.WHERE);
            SQLExpr where = this.exprParser.expr();
            stmt.setAdbWhere(where);
         }
      } else if (this.lexer.token() == Token.DATABASE) {
         this.accept(Token.DATABASE);
         SQLName name = this.exprParser.name();
         stmt.setAdbSchema((SQLIdentifierExpr)name);
      } else if (this.lexer.token() == Token.COLUMN) {
         this.accept(Token.COLUMN);
         SQLName table = this.exprParser.name();
         stmt.setTable(table);
         this.accept(Token.LPAREN);

         while(true) {
             SQLExpr name = this.exprParser.name();
            stmt.getAdbColumns().add((SQLIdentifierExpr)name);
            if (this.lexer.token() != Token.COMMA) {
               this.accept(Token.RPAREN);
               if (this.lexer.token() == Token.WHERE) {
                  this.accept(Token.WHERE);
                  name = this.exprParser.expr();
                  stmt.setAdbWhere(name);
               }
               break;
            }

            this.accept(Token.COMMA);
         }
      } else if (this.lexer.identifierEquals("columns")) {
         this.lexer.nextToken();
         this.accept(Token.GROUP);
         SQLName table = this.exprParser.name();
         stmt.setTable(table);
         this.accept(Token.LPAREN);

         while(true) {
             SQLExpr name = this.exprParser.name();
            stmt.getAdbColumnsGroup().add((SQLIdentifierExpr)name);
            if (this.lexer.token() != Token.COMMA) {
               this.accept(Token.RPAREN);
               if (this.lexer.token() == Token.WHERE) {
                  this.accept(Token.WHERE);
                  name = this.exprParser.expr();
                  stmt.setAdbWhere(name);
               }
               break;
            }

            this.accept(Token.COMMA);
         }
      }

      if (this.lexer.token() == Token.PARTITION) {
         stmt.setPartition(this.parsePartitionRef());
      }

      if (this.lexer.token() == Token.COMPUTE) {
         this.lexer.nextToken();
         this.acceptIdentifier("STATISTICS");
         stmt.setComputeStatistics(true);
      }

      if (this.lexer.token() == Token.FOR) {
         this.lexer.nextToken();
         this.acceptIdentifier("COLUMNS");
         stmt.setForColums(true);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.CACHE)) {
         this.lexer.nextToken();
         this.acceptIdentifier("METADATA");
         stmt.setCacheMetadata(true);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.NOSCAN)) {
         this.lexer.nextToken();
         stmt.setNoscan(true);
      }

      return stmt;
   }

   public MariadbOptimizeStatement parseOptimize() {
      MariadbOptimizeStatement stmt = new MariadbOptimizeStatement();
      this.accept(Token.OPTIMIZE);
      if (this.lexer.identifierEquals("NO_WRITE_TO_BINLOG")) {
         this.lexer.nextToken();
         stmt.setNoWriteToBinlog(true);
      }

      if (this.lexer.identifierEquals("LOCAL")) {
         this.lexer.nextToken();
         stmt.setLocal(true);
      }

      this.accept(Token.TABLE);
      List<SQLName> names = new ArrayList();
      this.exprParser.names(names, stmt);

      for(SQLName name : names) {
         stmt.addTableSource(new SQLExprTableSource(name));
      }

      return stmt;
   }

   public SQLStatement parseReset() {
      this.acceptIdentifier("RESET");
      MariadbResetStatement stmt = new MariadbResetStatement();

      while(this.lexer.token() == Token.IDENTIFIER) {
         if (this.lexer.identifierEquals("QUERY")) {
            this.lexer.nextToken();
            this.accept(Token.CACHE);
            stmt.getOptions().add("QUERY CACHE");
         } else {
            stmt.getOptions().add(this.lexer.stringVal());
            this.lexer.nextToken();
         }

         if (this.lexer.token() != Token.COMMA) {
            break;
         }

         this.lexer.nextToken();
      }

      return stmt;
   }

   public boolean parseStatementListDialect(List<SQLStatement> statementList) {
      if (this.lexer.identifierEquals("PREPARE")) {
         MariadbPrepareStatement stmt = this.parsePrepare();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals("EXECUTE")) {
         this.acceptIdentifier("EXECUTE");
         if (!this.lexer.identifierEquals("RESTART") && !this.lexer.identifierEquals("UPDATE")) {
            MariadbExecuteStatement stmt = this.parseExecute();
            statementList.add(stmt);
         } else {
            MariadbExecuteForAdsStatement stmt = this.parseExecuteForAds();
            statementList.add(stmt);
         }

         return true;
      } else if (this.lexer.identifierEquals("DEALLOCATE")) {
         MariadbDeallocatePrepareStatement stmt = this.parseDeallocatePrepare();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals("LOAD")) {
         SQLStatement stmt = this.parseLoad();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.token() == Token.REPLACE) {
         SQLReplaceStatement stmt = this.parseReplace();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals("START")) {
         SQLStartTransactionStatement stmt = this.parseStart();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.token() == Token.SHOW) {
         SQLStatement stmt = this.parseShow();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals("CLEAR")) {
         this.lexer.nextToken();
         if (this.isEnabled(SQLParserFeature.DRDSAsyncDDL) && this.lexer.identifierEquals("DDL")) {
            this.lexer.nextToken();
            this.accept(Token.CACHE);
            DrdsClearDDLJobCache stmt = new DrdsClearDDLJobCache();
            if (Token.ALL == this.lexer.token()) {
               this.lexer.nextToken();
               stmt.setAllJobs(true);
               statementList.add(stmt);
               return true;
            } else {
               while(true) {
                  stmt.addJobId(this.lexer.integerValue().longValue());
                  this.accept(Token.LITERAL_INT);
                  if (Token.COMMA != this.lexer.token()) {
                     if (this.lexer.token() != Token.EOF && this.lexer.token() != Token.SEMI) {
                        throw new ParserException("syntax error, expect job id, actual " + this.lexer.token() + ", " + this.lexer.info());
                     } else {
                        statementList.add(stmt);
                        return true;
                     }
                  }

                  this.lexer.nextToken();
               }
            }
         } else {
            this.acceptIdentifier("PLANCACHE");
            statementList.add(new MariadbClearPlanCacheStatement());
            return true;
         }
      } else if (this.lexer.identifierEquals("DISABLED")) {
         this.lexer.nextToken();
         this.acceptIdentifier("PLANCACHE");
         statementList.add(new MariadbDisabledPlanCacheStatement());
         return true;
      } else if (this.lexer.token() == Token.EXPLAIN) {
         SQLStatement stmt = this.parseExplain();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals("BINLOG")) {
         SQLStatement stmt = this.parseBinlog();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals("RESET")) {
         SQLStatement stmt = this.parseReset();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.token() == Token.ANALYZE) {
         SQLStatement stmt = this.parseAnalyze();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals(FnvHash.Constants.ARCHIVE)) {
         SQLStatement stmt = this.parseArchive();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals(FnvHash.Constants.BACKUP)) {
         SQLStatement stmt = this.parseBackup();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals(FnvHash.Constants.RESTORE)) {
         SQLStatement stmt = this.parseRestore();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals("BUILD")) {
         SQLStatement stmt = this.parseBuildTable();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals("CANCEL")) {
         SQLStatement stmt = this.parseCancelJob();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals(FnvHash.Constants.EXPORT)) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.TABLE) {
            SQLStatement stmt = this.parseExportTable();
            statementList.add(stmt);
         } else if (this.lexer.token() == Token.DATABASE) {
            SQLStatement stmt = this.parseExportDB();
            statementList.add(stmt);
         }

         return true;
      } else if (this.lexer.identifierEquals(FnvHash.Constants.IMPORT)) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.TABLE) {
            SQLStatement stmt = this.parseImportTable();
            statementList.add(stmt);
         } else if (this.lexer.token() == Token.DATABASE) {
            SQLStatement stmt = this.parseImportDB();
            statementList.add(stmt);
         }

         return true;
      } else if (this.lexer.identifierEquals("SUBMIT")) {
         this.lexer.nextToken();
         this.acceptIdentifier("JOB");
         SQLStatement stmt = this.parseSubmitJob();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals(FnvHash.Constants.MIGRATE)) {
         SQLStatement stmt = this.parseMigrate();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.token() == Token.OPTIMIZE) {
         SQLStatement stmt = this.parseOptimize();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals("HELP")) {
         this.lexer.nextToken();
         MariadbHelpStatement stmt = new MariadbHelpStatement();
         stmt.setContent(this.exprParser.primary());
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals("FLUSH")) {
         SQLStatement stmt = this.parseFlush();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals(FnvHash.Constants.SYNC)) {
         SQLStatement stmt = this.parseSync();
         statementList.add(stmt);
         return true;
      } else if (this.lexer.identifierEquals(FnvHash.Constants.INIT)) {
         statementList.add(new SQLExprStatement(this.exprParser.expr()));
         return true;
      } else if (this.isEnabled(SQLParserFeature.DRDSAsyncDDL) && this.lexer.identifierEquals(FnvHash.Constants.RECOVER)) {
         this.lexer.nextToken();
         this.acceptIdentifier("DDL");
         DrdsRecoverDDLJob stmt = new DrdsRecoverDDLJob();
         if (Token.ALL == this.lexer.token()) {
            this.lexer.nextToken();
            stmt.setAllJobs(true);
            statementList.add(stmt);
            return true;
         } else {
            while(true) {
               stmt.addJobId(this.lexer.integerValue().longValue());
               this.accept(Token.LITERAL_INT);
               if (Token.COMMA != this.lexer.token()) {
                  if (this.lexer.token() != Token.EOF && this.lexer.token() != Token.SEMI) {
                     throw new ParserException("syntax error, expect job id, actual " + this.lexer.token() + ", " + this.lexer.info());
                  } else {
                     statementList.add(stmt);
                     return true;
                  }
               }

               this.lexer.nextToken();
            }
         }
      } else if (this.isEnabled(SQLParserFeature.DRDSAsyncDDL) && this.lexer.identifierEquals(FnvHash.Constants.REMOVE)) {
         this.lexer.nextToken();
         this.acceptIdentifier("DDL");
         DrdsRemoveDDLJob stmt = new DrdsRemoveDDLJob();
         if (Token.ALL == this.lexer.token()) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("COMPLETED")) {
               this.lexer.nextToken();
               stmt.setAllCompleted(true);
            } else {
               if (!this.lexer.identifierEquals("PENDING")) {
                  throw new ParserException("syntax error, expect COMPLETED or PENDING, actual " + this.lexer.token() + ", " + this.lexer.info());
               }

               this.lexer.nextToken();
               stmt.setAllPending(true);
            }
         } else {
            while(true) {
               stmt.addJobId(this.lexer.integerValue().longValue());
               this.accept(Token.LITERAL_INT);
               if (Token.COMMA != this.lexer.token()) {
                  if (this.lexer.token() != Token.EOF && this.lexer.token() != Token.SEMI) {
                     throw new ParserException("syntax error, expect job id, actual " + this.lexer.token() + ", " + this.lexer.info());
                  }
                  break;
               }

               this.lexer.nextToken();
            }
         }

         statementList.add(stmt);
         return true;
      } else if (this.isEnabled(SQLParserFeature.DRDSAsyncDDL) && this.lexer.identifierEquals("INSPECT")) {
         this.lexer.nextToken();
         this.acceptIdentifier("DDL");
         this.accept(Token.CACHE);
         statementList.add(new DrdsInspectDDLJobCache());
         return true;
      } else {
         if (this.isEnabled(SQLParserFeature.DRDSAsyncDDL) && this.lexer.identifierEquals(FnvHash.Constants.CHANGE)) {
            Lexer.SavePoint mark = this.lexer.mark();
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("DDL")) {
               this.lexer.nextToken();
               DrdsChangeDDLJob stmt = new DrdsChangeDDLJob();
               stmt.setJobId(this.lexer.integerValue().longValue());
               this.accept(Token.LITERAL_INT);
               if (this.lexer.identifierEquals("SKIP")) {
                  this.lexer.nextToken();
                  stmt.setSkip(true);
               } else {
                  if (!this.lexer.identifierEquals("ADD")) {
                     throw new ParserException("syntax error, expect SKIP or ADD, actual " + this.lexer.token() + ", " + this.lexer.info());
                  }

                  this.lexer.nextToken();
                  stmt.setAdd(true);
               }

               StringBuilder builder = new StringBuilder();

               while(true) {
                  while(Token.COMMA == this.lexer.token()) {
                     this.lexer.nextToken();
                     stmt.addGroupAndTableNameList(builder.toString());
                     builder = new StringBuilder();
                  }

                  if (this.lexer.token() == Token.EOF || this.lexer.token() == Token.SEMI) {
                     stmt.addGroupAndTableNameList(builder.toString());
                     statementList.add(stmt);
                     return true;
                  }

                  if (this.lexer.token() == Token.COLON) {
                     builder.append(':');
                     this.lexer.nextToken();
                  } else if (this.lexer.token() == Token.DOT) {
                     builder.append('.');
                     this.lexer.nextToken();
                  } else {
                     builder.append(this.lexer.stringVal());
                     this.lexer.nextToken();
                  }
               }
            }

            this.lexer.reset(mark);
         }

         if (this.isEnabled(SQLParserFeature.DRDSBaseline) && this.lexer.identifierEquals("BASELINE")) {
            this.lexer.nextToken();
            DrdsBaselineStatement stmt = new DrdsBaselineStatement();
            if (Token.EOF != this.lexer.token() && Token.SEMI != this.lexer.token() && !this.lexer.stringVal().isEmpty() && !this.lexer.stringVal().equalsIgnoreCase("BASELINE")) {
               stmt.setOperation(this.lexer.stringVal());
               this.lexer.setToken(Token.COMMA);
               this.lexer.nextToken();
               if (this.lexer.identifierEquals(FnvHash.Constants.SQL)) {
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.HINT) {
                     stmt.setHeadHints(this.exprParser.parseHints());
                  }

                  MariadbSelectParser selectParser = this.createSQLSelectParser();
                  stmt.setSelect(selectParser.select());
               } else {
                  while(this.lexer.token() != Token.EOF && this.lexer.token() != Token.SEMI) {
                     stmt.addBaselineId(this.lexer.integerValue().longValue());
                     this.accept(Token.LITERAL_INT);
                     if (Token.COMMA == this.lexer.token()) {
                        this.lexer.nextToken();
                     }
                  }
               }

               statementList.add(stmt);
               return true;
            } else {
               throw new ParserException("syntax error, expect baseline operation, actual " + this.lexer.token() + ", " + this.lexer.info());
            }
         } else if (this.lexer.token() != Token.DESC && !this.lexer.identifierEquals("DESCRIBE")) {
            if (this.lexer.token() == Token.LOCK) {
               this.lexer.nextToken();
               String val = this.lexer.stringVal();
               boolean isLockTables = "TABLES".equalsIgnoreCase(val) && this.lexer.token() == Token.IDENTIFIER;
               boolean isLockTable = "TABLE".equalsIgnoreCase(val) && this.lexer.token() == Token.TABLE;
               if (!isLockTables && !isLockTable) {
                  this.setErrorEndPos(this.lexer.pos());
                  throw new ParserException("syntax error, expect TABLES or TABLE, actual " + this.lexer.token() + ", " + this.lexer.info());
               } else {
                  this.lexer.nextToken();
                  MariadbLockTableStatement var61 = new MariadbLockTableStatement();

                  while(true) {
                     MariadbLockTableStatement.Item item = new MariadbLockTableStatement.Item();
                     SQLExprTableSource tableSource = null;
                     SQLName tableName = this.exprParser.name();
                     if (this.lexer.token() == Token.AS) {
                        this.lexer.nextToken();
                        String as = this.lexer.stringVal();
                        tableSource = new SQLExprTableSource(tableName, as);
                        this.lexer.nextToken();
                     } else {
                        tableSource = new SQLExprTableSource(tableName);
                     }

                     item.setTableSource(tableSource);
                     var61.getItems().add(item);
                     if (this.lexer.token() == Token.COMMA) {
                        this.lexer.nextToken();
                     } else {
                        if (this.lexer.identifierEquals("READ")) {
                           this.lexer.nextToken();
                           if (this.lexer.identifierEquals("LOCAL")) {
                              this.lexer.nextToken();
                              item.setLockType(MariadbLockTableStatement.LockType.READ_LOCAL);
                           } else {
                              item.setLockType(MariadbLockTableStatement.LockType.READ);
                           }
                        } else if (this.lexer.identifierEquals("WRITE")) {
                           this.lexer.nextToken();
                           item.setLockType(MariadbLockTableStatement.LockType.WRITE);
                        } else {
                           if (!this.lexer.identifierEquals(FnvHash.Constants.LOW_PRIORITY)) {
                              throw new ParserException("syntax error, expect READ or WRITE OR AS, actual " + this.lexer.token() + ", " + this.lexer.info());
                           }

                           this.lexer.nextToken();
                           this.acceptIdentifier("WRITE");
                           this.lexer.nextToken();
                           item.setLockType(MariadbLockTableStatement.LockType.LOW_PRIORITY_WRITE);
                        }

                        if (this.lexer.token() == Token.HINT) {
                           item.setHints(this.exprParser.parseHints());
                        }

                        if (this.lexer.token() != Token.COMMA) {
                           statementList.add(var61);
                           return true;
                        }

                        this.lexer.nextToken();
                     }
                  }
               }
            } else if (this.lexer.identifierEquals("UNLOCK")) {
               this.lexer.nextToken();
               String val = this.lexer.stringVal();
               boolean isUnLockTables = "TABLES".equalsIgnoreCase(val) && this.lexer.token() == Token.IDENTIFIER;
               boolean isUnLockTable = "TABLE".equalsIgnoreCase(val) && this.lexer.token() == Token.TABLE;
               statementList.add(new MariadbUnlockTablesStatement());
               if (!isUnLockTables && !isUnLockTable) {
                  this.setErrorEndPos(this.lexer.pos());
                  throw new ParserException("syntax error, expect TABLES or TABLE, actual " + this.lexer.token() + ", " + this.lexer.info());
               } else {
                  this.lexer.nextToken();
                  return true;
               }
            } else if (this.lexer.identifierEquals(FnvHash.Constants.CHECKSUM)) {
               statementList.add(this.parseChecksum());
               return true;
            } else if (this.lexer.token() == Token.HINT) {
               List<SQLCommentHint> hints = this.exprParser.parseHints();
               boolean tddlHints = false;
               boolean accept = false;
               boolean acceptHint = false;
               switch (this.lexer.token()) {
                  case SELECT:
                  case WITH:
                  case DELETE:
                  case UPDATE:
                  case INSERT:
                  case SHOW:
                  case REPLACE:
                  case TRUNCATE:
                  case DROP:
                  case ALTER:
                  case CREATE:
                  case CHECK:
                  case SET:
                  case DESC:
                  case OPTIMIZE:
                  case ANALYZE:
                  case KILL:
                  case EXPLAIN:
                  case LPAREN:
                     acceptHint = true;
                     break;
                  case IDENTIFIER:
                     acceptHint = this.lexer.hash_lower() == FnvHash.Constants.DUMP || this.lexer.hash_lower() == FnvHash.Constants.RENAME || this.lexer.hash_lower() == FnvHash.Constants.DESCRIBE;
               }

               if (hints.size() >= 1 && statementList.size() == 0 && acceptHint) {
                  SQLCommentHint hint = (SQLCommentHint)hints.get(0);
                  String hintText = hint.getText().toUpperCase();
                  if (!hintText.startsWith("+TDDL") && !hintText.startsWith("+ TDDL") && !hintText.startsWith("TDDL") && !hintText.startsWith("!TDDL")) {
                     if (hintText.startsWith("+")) {
                        accept = true;
                     }
                  } else {
                     tddlHints = true;
                  }
               }

               if (tddlHints) {
                  SQLStatementImpl stmt = (SQLStatementImpl)this.parseStatement();
                  stmt.setHeadHints(hints);
                  statementList.add(stmt);
                  return true;
               } else if (accept) {
                  SQLStatementImpl stmt = (SQLStatementImpl)this.parseStatement();
                  stmt.setHeadHints(hints);
                  statementList.add(stmt);
                  return true;
               } else {
                  MariadbHintStatement stmt = new MariadbHintStatement();
                  stmt.setHints(hints);
                  statementList.add(stmt);
                  return true;
               }
            } else if (this.lexer.token() == Token.BEGIN) {
               statementList.add(this.parseBlock());
               return true;
            } else if (this.lexer.identifierEquals(FnvHash.Constants.ADD)) {
               statementList.add(this.parseAddManageInstanceGroup());
               return true;
            } else {
               if (this.lexer.token() == Token.IDENTIFIER) {
                  String label = this.lexer.stringVal();
                  char ch = this.lexer.current();
                  int bp = this.lexer.bp();
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.VARIANT && this.lexer.stringVal().equals(":")) {
                     this.lexer.nextToken();
                     if (this.lexer.token() == Token.LOOP) {
                        statementList.add(this.parseLoop(label));
                     } else if (this.lexer.token() == Token.WHILE) {
                        statementList.add(this.parseWhile(label));
                     } else if (this.lexer.token() == Token.BEGIN) {
                        SQLBlockStatement block = this.parseBlock(label);
                        statementList.add(block);
                     } else if (this.lexer.token() == Token.REPEAT) {
                        statementList.add(this.parseRepeat(label));
                     }

                     return true;
                  }

                  this.lexer.reset(bp, ch, Token.IDENTIFIER);
               }

               if (this.lexer.token() != Token.CHECK) {
                  if (this.lexer.token() == Token.ITERATE) {
                     statementList.add(this.parseIterate());
                  }

                  if (this.lexer.token() == Token.LEAVE) {
                     statementList.add(this.parseLeave());
                  }

                  return false;
               } else {
                  Lexer.SavePoint mark = this.lexer.mark();
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.TABLE) {
                     this.lexer.nextToken();
                     MariadbCheckTableStatement stmt = new MariadbCheckTableStatement();

                     while(true) {
                        SQLName table = this.exprParser.name();
                        stmt.addTable(new SQLExprTableSource(table));
                        if (this.lexer.token() != Token.COMMA) {
                           while(this.lexer.token() != Token.EOF) {
                              List<String> identifiedList = Arrays.asList("QUICK", "FAST", "MEDIUM", "EXTENDED", "CHANGED");
                              if (this.lexer.token() == Token.FOR) {
                                 this.lexer.nextToken();
                                 this.acceptIdentifier("UPGRADE");
                                 stmt.getIdentifiedList().add(new SQLIdentifierExpr("FOR UPGRADE"));
                              } else {
                                 if (!identifiedList.contains(this.lexer.stringVal())) {
                                    break;
                                 }

                                 SQLExpr identified = this.exprParser.expr();
                                 stmt.getIdentifiedList().add(identified);
                              }
                           }

                           statementList.add(stmt);
                           break;
                        }

                        this.lexer.nextToken();
                     }
                  }

                  return true;
               }
            }
         } else {
            SQLStatement stmt = this.parseDescribe();
            statementList.add(stmt);
            return true;
         }
      }
   }

   private SQLStatement parseArchive() {
      this.lexer.nextToken();
      this.accept(Token.TABLE);
      SQLArchiveTableStatement stmt = new SQLArchiveTableStatement();
      SQLName tableName = this.exprParser.name();
      stmt.setTable(tableName);
      stmt.setType(new SQLIdentifierExpr("UPLOAD"));
      if (this.lexer.token() == Token.LITERAL_INT) {
         while(true) {
            stmt.getSpIdList().add(this.exprParser.integerExpr());
            String pidStr = this.lexer.stringVal();
            this.accept(Token.VARIANT);
            String s = pidStr.replaceAll(":", "");
            if (StringUtils.isEmpty(s)) {
               stmt.getpIdList().add(this.exprParser.integerExpr());
            } else {
               stmt.getpIdList().add(new SQLIntegerExpr(Integer.valueOf(s)));
            }

            if (this.lexer.token() != Token.COMMA) {
               break;
            }

            this.lexer.nextToken();
         }
      }

      return stmt;
   }

   private SQLStatement parseBackup() {
      this.lexer.nextToken();
      SQLBackupStatement stmt = new SQLBackupStatement();
      String type = "BACKUP_DATA";
      String action = "BACKUP";
      if (this.lexer.identifierEquals(FnvHash.Constants.DATA)) {
         this.lexer.nextToken();
         this.accept(Token.INTO);
         type = "BACKUP_DATA";

         while(true) {
            stmt.getProperties().add(new SQLCharExpr(this.lexer.stringVal()));
            this.accept(Token.LITERAL_CHARS);
            if (this.lexer.token() != Token.COMMA) {
               break;
            }

            this.lexer.nextToken();
         }
      } else if (this.lexer.identifierEquals(FnvHash.Constants.LOG)) {
         type = "BACKUP_LOG";
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("LIST_LOGS")) {
            this.lexer.nextToken();
            action = "LIST_LOG";
         } else if (this.lexer.identifierEquals(FnvHash.Constants.STATUS)) {
            this.lexer.nextToken();
            action = "STATUS";
         } else if (this.lexer.token() == Token.INTO) {
            this.lexer.nextToken();

            while(true) {
               stmt.getProperties().add(new SQLCharExpr(this.lexer.stringVal()));
               this.accept(Token.LITERAL_CHARS);
               if (this.lexer.token() != Token.COMMA) {
                  break;
               }

               this.lexer.nextToken();
            }
         }
      } else if (this.lexer.identifierEquals("CANCEL")) {
         this.lexer.nextToken();
         type = "BACKUP_DATA";
         action = "BACKUP_CANCEL";
         stmt.getProperties().add(new SQLCharExpr(this.lexer.stringVal()));
         this.accept(Token.LITERAL_CHARS);
      }

      stmt.setType(new SQLIdentifierExpr(type));
      stmt.setAction(new SQLIdentifierExpr(action));
      return stmt;
   }

   private SQLStatement parseRestore() {
      this.lexer.nextToken();
      String type = "DATA";
      SQLRestoreStatement stmt = new SQLRestoreStatement();
      if (this.lexer.identifierEquals(FnvHash.Constants.DATA)) {
         this.lexer.nextToken();
         type = "DATA";
      } else if (this.lexer.identifierEquals(FnvHash.Constants.LOG)) {
         this.lexer.nextToken();
         type = "LOG";
      }

      stmt.setType(new SQLIdentifierExpr(type));
      this.accept(Token.FROM);

      while(true) {
         stmt.getProperties().add(new SQLCharExpr(this.lexer.stringVal()));
         this.accept(Token.LITERAL_CHARS);
         if (this.lexer.token() != Token.COMMA) {
            return stmt;
         }

         this.lexer.nextToken();
      }
   }

   private SQLStatement parseBuildTable() {
      this.lexer.nextToken();
      SQLBuildTableStatement stmt = new SQLBuildTableStatement();
      this.accept(Token.TABLE);
      stmt.setTable(this.exprParser.name());
      if (this.lexer.identifierEquals(FnvHash.Constants.VERSION)) {
         this.lexer.nextToken();
         this.accept(Token.EQ);
         stmt.setVersion(this.exprParser.integerExpr());
      }

      if (this.lexer.token() == Token.WITH) {
         this.lexer.nextToken();
         this.acceptIdentifier("SPLIT");
         stmt.setWithSplit(true);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.FORCE)) {
         this.lexer.nextToken();
         this.accept(Token.EQ);
         if (this.lexer.token() == Token.TRUE) {
            this.lexer.nextToken();
            stmt.setForce(true);
         } else if (this.lexer.token() == Token.FALSE) {
            this.lexer.nextToken();
            stmt.setForce(false);
         }
      }

      return stmt;
   }

   private SQLStatement parseCancelJob() {
      this.lexer.nextToken();
      if (this.isEnabled(SQLParserFeature.DRDSAsyncDDL) && this.lexer.identifierEquals("DDL")) {
         this.lexer.nextToken();
         DrdsCancelDDLJob cancelDDLJob = new DrdsCancelDDLJob();

         while(true) {
            cancelDDLJob.addJobId(this.lexer.integerValue().longValue());
            this.accept(Token.LITERAL_INT);
            if (Token.COMMA != this.lexer.token()) {
               if (this.lexer.token() != Token.EOF && this.lexer.token() != Token.SEMI) {
                  throw new ParserException("syntax error, expect job id, actual " + this.lexer.token() + ", " + this.lexer.info());
               } else {
                  return cancelDDLJob;
               }
            }

            this.lexer.nextToken();
         }
      } else {
         SQLCancelJobStatement stmt = new SQLCancelJobStatement();
         if (this.lexer.identifierEquals("JOB")) {
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("LOAD_JOB")) {
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("SYNC_JOB")) {
            this.lexer.nextToken();
            stmt.setImport(true);
         }

         stmt.setJobName(this.exprParser.name());
         return stmt;
      }
   }

   protected SQLStatement parseExportTable() {
      this.accept(Token.TABLE);
      SQLExportTableStatement stmt = new SQLExportTableStatement();
      stmt.setTable(new SQLExprTableSource(this.exprParser.name()));
      return stmt;
   }

   protected SQLStatement parseExportDB() {
      this.accept(Token.DATABASE);
      SQLExportDatabaseStatement stmt = new SQLExportDatabaseStatement();
      stmt.setDb(this.exprParser.name());
      if (this.lexer.identifierEquals("REALTIME")) {
         this.lexer.nextToken();
         this.accept(Token.EQ);
         if ("y".equalsIgnoreCase(this.lexer.stringVal())) {
            this.lexer.nextToken();
            stmt.setRealtime(true);
         } else {
            if (!"n".equalsIgnoreCase(this.lexer.stringVal())) {
               throw new ParserException("Invalid 'realtime' option, should be 'Y' or 'N'. ");
            }

            this.lexer.nextToken();
            stmt.setRealtime(false);
         }
      }

      return stmt;
   }

   protected SQLStatement parseRaftLeaderTransfer() {
      this.acceptIdentifier("RAFT_LEADER_TRANSFER");
      MariadbRaftLeaderTransferStatement stmt = new MariadbRaftLeaderTransferStatement();
      this.acceptIdentifier("SHARD");
      this.accept(Token.EQ);
      stmt.setShard(this.exprParser.charExpr());
      this.accept(Token.FROM);
      this.accept(Token.EQ);
      stmt.setFrom(this.exprParser.charExpr());
      this.accept(Token.TO);
      this.accept(Token.EQ);
      stmt.setTo(this.exprParser.charExpr());
      this.acceptIdentifier("TIMEOUT");
      this.accept(Token.EQ);
      stmt.setTimeout(this.exprParser.integerExpr());
      return stmt;
   }

   protected SQLStatement parseRaftMemeberChange() {
      this.acceptIdentifier("RAFT_MEMBER_CHANGE");
      MariadbRaftMemberChangeStatement stmt = new MariadbRaftMemberChangeStatement();
      if (this.lexer.identifierEquals("NOLEADER")) {
         this.lexer.nextToken();
         stmt.setNoLeader(true);
      }

      this.acceptIdentifier("SHARD");
      this.accept(Token.EQ);
      stmt.setShard(this.exprParser.charExpr());
      this.acceptIdentifier("HOST");
      this.accept(Token.EQ);
      stmt.setHost(this.exprParser.charExpr());
      this.acceptIdentifier("STATUS");
      this.accept(Token.EQ);
      stmt.setStatus(this.exprParser.charExpr());
      if (this.lexer.identifierEquals(FnvHash.Constants.FORCE)) {
         this.lexer.nextToken();
         stmt.setForce(true);
      }

      return stmt;
   }

   protected SQLStatement parseMigrate() {
      MariadbMigrateStatement stmt = new MariadbMigrateStatement();
      this.acceptIdentifier("MIGRATE");
      this.accept(Token.DATABASE);
      stmt.setSchema(this.exprParser.name());
      this.acceptIdentifier("SHARDS");
      this.accept(Token.EQ);
      stmt.setShardNames(this.exprParser.charExpr());
      if (this.lexer.token() == Token.GROUP) {
         this.lexer.nextToken();
         stmt.setMigrateType(new SQLIntegerExpr(0));
      } else if (this.lexer.identifierEquals(FnvHash.Constants.HOST)) {
         this.lexer.nextToken();
         stmt.setMigrateType(new SQLIntegerExpr(1));
      }

      this.accept(Token.FROM);
      stmt.setFromInsId(this.exprParser.charExpr());
      if (this.lexer.token() == Token.VARIANT) {
         this.lexer.nextToken();
         stmt.setFromInsIp(this.exprParser.charExpr());
         String variant = this.lexer.stringVal();
         Integer number = Integer.valueOf(variant.substring(1, variant.length()));
         stmt.setFromInsPort(new SQLIntegerExpr(number));
         this.accept(Token.VARIANT);
         this.accept(Token.VARIANT);
         stmt.setFromInsStatus(this.exprParser.charExpr());
      }

      this.accept(Token.TO);
      stmt.setToInsId(this.exprParser.charExpr());
      if (this.lexer.token() == Token.VARIANT) {
         this.lexer.nextToken();
         stmt.setToInsIp(this.exprParser.charExpr());
         String variant = this.lexer.stringVal();
         Integer number = Integer.valueOf(variant.substring(1, variant.length()));
         stmt.setToInsPort(new SQLIntegerExpr(number));
         this.accept(Token.VARIANT);
         this.accept(Token.VARIANT);
         stmt.setToInsStatus(this.exprParser.charExpr());
      }

      return stmt;
   }

   protected SQLStatement parseImportDB() {
      this.accept(Token.DATABASE);
      SQLImportDatabaseStatement stmt = new SQLImportDatabaseStatement();
      stmt.setDb(this.exprParser.name());
      if (this.lexer.identifierEquals(FnvHash.Constants.STATUS)) {
         this.lexer.nextToken();
         this.accept(Token.EQ);
         stmt.setStatus(this.exprParser.name());
      }

      return stmt;
   }

   protected SQLStatement parseImportTable() {
      MariadbImportTableStatement stmt = new MariadbImportTableStatement();
      this.accept(Token.TABLE);
      this.accept(Token.FROM);

      while(true) {
         SQLName sdiFile = this.exprParser.name();
         stmt.getSdiFiles().add(sdiFile);
         if (this.lexer.token() != Token.COMMA) {
            return stmt;
         }

         this.lexer.nextToken();
      }
   }

   protected SQLStatement parseSubmitJob() {
      SQLSubmitJobStatement stmt = new SQLSubmitJobStatement();
      if (this.lexer.identifierEquals("AWAIT")) {
         this.lexer.nextToken();
         stmt.setAwait(true);
      }

      stmt.setStatment(this.parseStatement());
      return stmt;
   }

   public SQLStatement parseSync() {
      this.lexer.nextToken();
      if (this.lexer.identifierEquals("RAFT_LEADER_TRANSFER")) {
         return this.parseRaftLeaderTransfer();
      } else if (this.lexer.identifierEquals("RAFT_MEMBER_CHANGE")) {
         return this.parseRaftMemeberChange();
      } else {
         this.acceptIdentifier("META");
         this.acceptIdentifier("TABLES");
         SQLSyncMetaStatement stmt = new SQLSyncMetaStatement();
         if (this.lexer.token() == Token.FROM) {
            this.lexer.nextToken();
            stmt.setFrom(this.exprParser.name());
         }

         if (this.lexer.token() == Token.LIKE) {
            this.lexer.nextToken();
            stmt.setLike(this.exprParser.expr());
         }

         return stmt;
      }
   }

   public SQLStatement parseFlush() {
      this.acceptIdentifier("FLUSH");
      MariadbFlushStatement stmt = new MariadbFlushStatement();
      if (this.lexer.identifierEquals("NO_WRITE_TO_BINLOG")) {
         this.lexer.nextToken();
         stmt.setNoWriteToBinlog(true);
      }

      if (this.lexer.identifierEquals("LOCAL")) {
         this.lexer.nextToken();
         stmt.setLocal(true);
      }

      while(true) {
         while(this.lexer.token() == Token.BINARY || this.lexer.identifierEquals("BINARY")) {
            this.lexer.nextToken();
            this.acceptIdentifier("LOGS");
            stmt.setBinaryLogs(true);
         }

         if (this.lexer.identifierEquals("DES_KEY_FILE")) {
            this.lexer.nextToken();
            stmt.setDesKeyFile(true);
         } else if (this.lexer.identifierEquals("ENGINE")) {
            this.lexer.nextToken();
            this.acceptIdentifier("LOGS");
            stmt.setEngineLogs(true);
         } else if (this.lexer.identifierEquals("ERROR")) {
            this.lexer.nextToken();
            this.acceptIdentifier("LOGS");
            stmt.setErrorLogs(true);
         } else if (this.lexer.identifierEquals("GENERAL")) {
            this.lexer.nextToken();
            this.acceptIdentifier("LOGS");
            stmt.setGeneralLogs(true);
         } else if (this.lexer.identifierEquals("HOSTS")) {
            this.lexer.nextToken();
            stmt.setHots(true);
         } else if (this.lexer.identifierEquals("LOGS")) {
            this.lexer.nextToken();
            stmt.setLogs(true);
         } else if (this.lexer.identifierEquals("PRIVILEGES")) {
            this.lexer.nextToken();
            stmt.setPrivileges(true);
         } else if (this.lexer.identifierEquals("OPTIMIZER_COSTS")) {
            this.lexer.nextToken();
            stmt.setOptimizerCosts(true);
         } else if (this.lexer.identifierEquals("QUERY")) {
            this.lexer.nextToken();
            this.accept(Token.CACHE);
            stmt.setQueryCache(true);
         } else if (this.lexer.identifierEquals("RELAY")) {
            this.lexer.nextToken();
            this.acceptIdentifier("LOGS");
            stmt.setRelayLogs(true);
            if (this.lexer.token() == Token.FOR) {
               this.lexer.nextToken();
               this.acceptIdentifier("CHANNEL");
               stmt.setRelayLogsForChannel(this.exprParser.primary());
            }
         } else if (this.lexer.identifierEquals("SLOW")) {
            this.lexer.nextToken();
            this.acceptIdentifier("LOGS");
            stmt.setSlowLogs(true);
         } else if (this.lexer.identifierEquals("STATUS")) {
            this.lexer.nextToken();
            stmt.setStatus(true);
         } else if (this.lexer.identifierEquals("USER_RESOURCES")) {
            this.lexer.nextToken();
            stmt.setUserResources(true);
         } else {
            if (this.lexer.token() != Token.COMMA) {
               if (this.lexer.identifierEquals("TABLES") || this.lexer.token() == Token.TABLE) {
                  this.lexer.nextToken();
                  stmt.setTableOption(true);
                  if (this.lexer.token() == Token.WITH) {
                     this.lexer.nextToken();
                     this.acceptIdentifier("READ");
                     this.accept(Token.LOCK);
                     stmt.setWithReadLock(true);
                  }

                  if (this.lexer.token() == Token.IDENTIFIER) {
                     while(true) {
                        SQLName name = this.exprParser.name();
                        stmt.addTable(name);
                        if (this.lexer.token() != Token.COMMA) {
                           break;
                        }

                        this.lexer.nextToken();
                     }
                  }

                  if (stmt.getTables().size() != 0) {
                     if (this.lexer.token() == Token.FOR) {
                        this.lexer.nextToken();
                        this.acceptIdentifier("EXPORT");
                        stmt.setForExport(true);
                     } else if (this.lexer.token() == Token.WITH) {
                        this.lexer.nextToken();
                        this.acceptIdentifier("READ");
                        this.accept(Token.LOCK);
                        stmt.setWithReadLock(true);
                     } else if (this.lexer.identifierEquals(FnvHash.Constants.VERSION)) {
                        this.lexer.nextToken();
                        this.accept(Token.EQ);
                        stmt.setVersion(this.exprParser.integerExpr());
                     }
                  }
               }

               return stmt;
            }

            this.lexer.nextToken();
         }
      }
   }

   public SQLBlockStatement parseBlock() {
      SQLBlockStatement block = new SQLBlockStatement();
      block.setDbType(this.dbType);
      this.accept(Token.BEGIN);
      List<SQLStatement> statementList = block.getStatementList();
      this.lexer.throwIfStateEnd = false;
      this.parseStatementList(statementList, -1, block);
      if (this.lexer.token() == Token.END || statementList.size() <= 0 || !(statementList.get(statementList.size() - 1) instanceof SQLCommitStatement) && !(statementList.get(statementList.size() - 1) instanceof SQLRollbackStatement)) {
         this.accept(Token.END);
         return block;
      } else {
         block.setEndOfCommit(true);
         return block;
      }
   }

   public MariadbExplainStatement parseDescribe() {
      MariadbExplainStatement describe = new MariadbExplainStatement();
      if (this.lexer.token() != Token.DESC && !this.lexer.identifierEquals("DESCRIBE")) {
         throw new ParserException("expect one of {DESCRIBE | DESC} , actual " + this.lexer.token() + ", " + this.lexer.info());
      } else {
         this.lexer.nextToken();
         describe.setDescribe(true);
         return this.parseExplain(describe);
      }
   }

   public MariadbExplainStatement parseExplain() {
      MariadbExplainStatement explain = new MariadbExplainStatement();
      explain.setSourceLine(this.lexer.getPosLine());
      explain.setSourceLine(this.lexer.getPosColumn());
      if (this.lexer.token() == Token.EXPLAIN) {
         this.lexer.nextToken();
         return this.parseExplain(explain);
      } else {
         throw new ParserException("expect EXPLAIN , actual " + this.lexer.token() + ", " + this.lexer.info());
      }
   }

   private MariadbExplainStatement parseExplain(MariadbExplainStatement explain) {
      if (this.lexer.identifierEquals(FnvHash.Constants.PLAN)) {
         Lexer.SavePoint mark = this.lexer.mark();
         this.lexer.nextToken();
         if (this.lexer.token() == Token.FOR) {
            this.lexer.nextToken();
         } else {
            this.lexer.reset(mark);
         }
      }

      if (this.lexer.token() == Token.ANALYZE) {
         this.lexer.nextToken();
         explain.setType("ANALYZE");
      }

      if (this.lexer.token() == Token.HINT) {
         List<SQLCommentHint> hints = this.exprParser.parseHints();
         explain.setHints(hints);
      }

      switch (this.dbType) {
         case mysql:
         case ads:
         case presto:
            Lexer.SavePoint mark = this.lexer.mark();
            if (this.lexer.token() == Token.LPAREN) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.SELECT) {
                  this.lexer.reset(mark);
               } else {
                  while(true) {
                     if (this.lexer.identifierEquals("FORMAT")) {
                        this.lexer.nextToken();
                        String format = this.lexer.stringVal();
                        explain.setFormat(format);
                        this.lexer.nextToken();
                     } else {
                        if (!this.lexer.identifierEquals("TYPE")) {
                           break;
                        }

                        this.lexer.nextToken();
                        String type = this.lexer.stringVal();
                        explain.setType(type);
                        this.lexer.nextToken();
                     }

                     if (this.lexer.token() != Token.COMMA) {
                        break;
                     }

                     this.lexer.nextToken();
                  }

                  this.accept(Token.RPAREN);
                  explain.setParenthesis(true);
               }
            }
         default:
            boolean table = false;
            if (this.lexer.token() == Token.IDENTIFIER) {
               long hash = this.lexer.hash_lower();
               String stringVal = this.lexer.stringVal();
               if (hash == FnvHash.Constants.EXTENDED) {
                  explain.setExtended(true);
                  this.lexer.nextToken();
               } else if (hash == FnvHash.Constants.PARTITIONS) {
                  explain.setType(stringVal);
                  this.lexer.nextToken();
               } else if (hash == FnvHash.Constants.OPTIMIZER) {
                  explain.setOptimizer(true);
                  this.lexer.nextToken();
               } else if (hash == FnvHash.Constants.FORMAT) {
                  this.lexer.nextToken();
                  this.accept(Token.EQ);
                  String format = this.lexer.stringVal();
                  explain.setFormat(format);
                  this.accept(Token.IDENTIFIER);
               } else {
                  explain.setTableName(this.exprParser.name());
                  if (this.lexer.token() == Token.IDENTIFIER) {
                     explain.setColumnName(this.exprParser.name());
                  } else if (this.lexer.token() == Token.LITERAL_CHARS) {
                     explain.setWild(this.exprParser.expr());
                  }

                  table = true;
               }
            }

            if (this.lexer.token() == Token.DISTRIBUTE) {
               this.lexer.nextToken();
               this.acceptIdentifier("INFO");
               explain.setDistributeInfo(true);
            }

            if (this.lexer.token() == Token.FOR) {
               this.lexer.nextToken();
               this.acceptIdentifier("CONNECTION");
               explain.setConnectionId(this.exprParser.expr());
            } else if (!table) {
               explain.setStatement(this.parseStatement());
            }

            return explain;
      }
   }

   public SQLStatement parseShow() {
      this.accept(Token.SHOW);
      boolean extended = false;
      MariadbShowColumnStatement scs = new MariadbShowColumnStatement();

      for(int i = 0; i < 2; ++i) {
         if (this.lexer.identifierEquals("EXTENDED")) {
            SQLExpr expr = this.exprParser.expr();
            scs.setExtended(expr);
            extended = true;
         } else {
            if (this.lexer.token() != Token.FULL) {
               break;
            }

            SQLExpr expr = this.exprParser.expr();
            scs.setFull(expr);
         }
      }

      if (!this.lexer.identifierEquals("COLUMNS") && !this.lexer.identifierEquals("FIELDS")) {
         if (this.lexer.token() == Token.COMMENT) {
            this.lexer.nextToken();
         }

         boolean isPhysical = false;
         if (this.lexer.identifierEquals(FnvHash.Constants.PHYSICAL)) {
            this.lexer.nextToken();
            isPhysical = true;
         }

         boolean full = false;
         if (this.lexer.token() == Token.FULL) {
            this.lexer.nextToken();
            full = true;
         } else if (this.lexer.token() == Token.HINT) {
            String hints = this.lexer.stringVal().toLowerCase();
            if (hints.endsWith(" full") && hints.length() <= 11 && hints.charAt(0) == '!' && hints.charAt(1) == '5') {
               this.lexer.nextToken();
               full = true;
            }
         }

         if (this.lexer.identifierEquals(FnvHash.Constants.STATS)) {
            this.lexer.nextToken();
            SQLShowStatisticStmt showStats = new SQLShowStatisticStmt();
            showStats.setDbType(DbType.mysql);
            if (full) {
               showStats.setFull(true);
            }

            return showStats;
         } else if (this.lexer.identifierEquals(FnvHash.Constants.PROCESSLIST)) {
            this.lexer.nextToken();
            MariadbShowProcessListStatement stmt = new MariadbShowProcessListStatement();
            stmt.setFull(full);
            if (!full && this.lexer.identifierEquals(FnvHash.Constants.MPP)) {
               this.lexer.nextToken();
               stmt.setMpp(true);
            }

            if (this.lexer.token() == Token.WHERE) {
               this.lexer.nextToken();
               stmt.setWhere(this.exprParser.expr());
            }

            if (this.lexer.token() == Token.ORDER) {
               stmt.setOrderBy(this.exprParser.parseOrderBy());
            }

            if (this.lexer.token() == Token.LIMIT) {
               stmt.setLimit(this.exprParser.parseLimit());
            }

            return stmt;
         } else if (!this.lexer.identifierEquals("COLUMNS") && !this.lexer.identifierEquals("FIELDS")) {
            if (this.lexer.identifierEquals("COLUMNS")) {
               this.lexer.nextToken();
               SQLShowColumnsStatement stmt = this.parseShowColumns();
               return stmt;
            } else if (this.lexer.identifierEquals("TABLES")) {
               this.lexer.nextToken();
               SQLShowTablesStatement stmt = this.parseShowTables();
               stmt.setFull(full);
               return stmt;
            } else if (this.lexer.identifierEquals("DATABASES")) {
               this.lexer.nextToken();
               SQLShowDatabasesStatement stmt = this.parseShowDatabases(isPhysical);
               if (full) {
                  stmt.setFull(true);
               }

               return stmt;
            } else if (this.lexer.identifierEquals("WARNINGS")) {
               this.lexer.nextToken();
               MariadbShowWarningsStatement stmt = this.parseShowWarnings();
               return stmt;
            } else if (this.lexer.identifierEquals("COUNT")) {
               this.lexer.nextToken();
               this.accept(Token.LPAREN);
               this.accept(Token.STAR);
               this.accept(Token.RPAREN);
               if (this.lexer.identifierEquals(FnvHash.Constants.ERRORS)) {
                  this.lexer.nextToken();
                  MariadbShowErrorsStatement stmt = new MariadbShowErrorsStatement();
                  stmt.setCount(true);
                  return stmt;
               } else {
                  this.acceptIdentifier("WARNINGS");
                  MariadbShowWarningsStatement stmt = new MariadbShowWarningsStatement();
                  stmt.setCount(true);
                  return stmt;
               }
            } else if (this.lexer.identifierEquals(FnvHash.Constants.ERRORS)) {
               this.lexer.nextToken();
               MariadbShowErrorsStatement stmt = new MariadbShowErrorsStatement();
               stmt.setLimit(this.exprParser.parseLimit());
               return stmt;
            } else if (this.lexer.identifierEquals("STATUS")) {
               this.lexer.nextToken();
               MariadbShowStatusStatement stmt = this.parseShowStatus();
               return stmt;
            } else if (this.lexer.identifierEquals("DBLOCK")) {
               this.lexer.nextToken();
               return new MariadbShowDbLockStatement();
            } else if (this.lexer.identifierEquals("VARIABLES")) {
               this.lexer.nextToken();
               MariadbShowVariantsStatement stmt = this.parseShowVariants();
               return stmt;
            } else {
               if (this.lexer.identifierEquals("GLOBAL")) {
                  this.lexer.nextToken();
                  if (this.lexer.identifierEquals("STATUS")) {
                     this.lexer.nextToken();
                     MariadbShowStatusStatement stmt = this.parseShowStatus();
                     stmt.setGlobal(true);
                     return stmt;
                  }

                  if (this.lexer.identifierEquals("VARIABLES")) {
                     this.lexer.nextToken();
                     MariadbShowVariantsStatement stmt = this.parseShowVariants();
                     stmt.setGlobal(true);
                     return stmt;
                  }

                  if (this.isEnabled(SQLParserFeature.DRDSAsyncDDL) && (Token.INDEX == this.lexer.token() || this.lexer.identifierEquals("INDEXES"))) {
                     this.lexer.nextToken();
                     DrdsShowGlobalIndex stmt = new DrdsShowGlobalIndex();
                     if (Token.FROM == this.lexer.token()) {
                        this.lexer.nextToken();
                        stmt.setTableName(this.exprParser.name());
                     }

                     return stmt;
                  }
               }

               if (this.lexer.identifierEquals(FnvHash.Constants.SESSION)) {
                  this.lexer.nextToken();
                  if (this.lexer.identifierEquals("STATUS")) {
                     this.lexer.nextToken();
                     MariadbShowStatusStatement stmt = this.parseShowStatus();
                     stmt.setSession(true);
                     return stmt;
                  } else if (this.lexer.identifierEquals("VARIABLES")) {
                     this.lexer.nextToken();
                     MariadbShowVariantsStatement stmt = this.parseShowVariants();
                     stmt.setSession(true);
                     return stmt;
                  } else {
                     SQLShowSessionStatement stmt = new SQLShowSessionStatement();
                     if (this.lexer.token() == Token.LIKE) {
                        this.lexer.nextToken();
                        SQLExpr like = this.exprParser.expr();
                        stmt.setLike(like);
                     }

                     return stmt;
                  }
               } else if (this.lexer.identifierEquals("COBAR_STATUS")) {
                  this.lexer.nextToken();
                  return new CobarShowStatus();
               } else if (this.lexer.identifierEquals("AUTHORS")) {
                  this.lexer.nextToken();
                  return new MariadbShowAuthorsStatement();
               } else if (this.lexer.token() == Token.BINARY) {
                  this.lexer.nextToken();
                  this.acceptIdentifier("LOGS");
                  return new MariadbShowBinaryLogsStatement();
               } else if (this.lexer.identifierEquals("MASTER")) {
                  this.lexer.nextToken();
                  if (this.lexer.identifierEquals("LOGS")) {
                     this.lexer.nextToken();
                     return new MariadbShowMasterLogsStatement();
                  } else {
                     this.acceptIdentifier("STATUS");
                     return new MariadbShowMasterStatusStatement();
                  }
               } else if (this.lexer.identifierEquals("CLUSTER")) {
                  this.lexer.nextToken();
                  this.acceptIdentifier("NAME");
                  return new MariadbShowClusterNameStatement();
               } else if (this.lexer.identifierEquals("SYNC_JOB")) {
                  this.lexer.nextToken();
                  this.acceptIdentifier("STATUS");
                  MariadbShowJobStatusStatement stmt = new MariadbShowJobStatusStatement();
                  stmt.setSync(true);
                  if (this.lexer.token() == Token.WHERE) {
                     this.lexer.nextToken();
                     stmt.setWhere(this.exprParser.expr());
                  }

                  return stmt;
               } else if (this.lexer.identifierEquals("JOB")) {
                  this.lexer.nextToken();
                  this.acceptIdentifier("STATUS");
                  MariadbShowJobStatusStatement stmt = new MariadbShowJobStatusStatement();
                  if (this.lexer.token() == Token.WHERE) {
                     this.lexer.nextToken();
                     stmt.setWhere(this.exprParser.expr());
                  }

                  return stmt;
               } else if (this.lexer.identifierEquals("MIGRATE")) {
                  this.lexer.nextToken();
                  this.acceptIdentifier("TASK");
                  this.acceptIdentifier("STATUS");
                  MariadbShowMigrateTaskStatusStatement stmt = new MariadbShowMigrateTaskStatusStatement();
                  if (this.lexer.token() == Token.WHERE) {
                     this.lexer.nextToken();
                     stmt.setWhere(this.exprParser.expr());
                  }

                  return stmt;
               } else if (this.lexer.identifierEquals(FnvHash.Constants.CHARSET)) {
                  this.lexer.nextToken();
                  MariadbShowCharacterSetStatement stmt = new MariadbShowCharacterSetStatement();
                  if (this.lexer.token() == Token.LIKE) {
                     this.lexer.nextTokenValue();
                     stmt.setPattern(this.exprParser.expr());
                  }

                  if (this.lexer.token() == Token.WHERE) {
                     this.lexer.nextToken();
                     stmt.setWhere(this.exprParser.expr());
                  }

                  return stmt;
               } else if (this.lexer.identifierEquals(FnvHash.Constants.CHARACTER)) {
                  this.lexer.nextToken();
                  this.accept(Token.SET);
                  MariadbShowCharacterSetStatement stmt = new MariadbShowCharacterSetStatement();
                  if (this.lexer.token() == Token.LIKE) {
                     this.lexer.nextTokenValue();
                     stmt.setPattern(this.exprParser.expr());
                  }

                  if (this.lexer.token() == Token.WHERE) {
                     this.lexer.nextToken();
                     stmt.setWhere(this.exprParser.expr());
                  }

                  return stmt;
               } else if (this.lexer.identifierEquals("COLLATION")) {
                  this.lexer.nextToken();
                  MariadbShowCollationStatement stmt = new MariadbShowCollationStatement();
                  if (this.lexer.token() == Token.LIKE) {
                     this.lexer.nextTokenValue();
                     stmt.setPattern(this.exprParser.expr());
                  }

                  if (this.lexer.token() == Token.WHERE) {
                     this.lexer.nextToken();
                     stmt.setWhere(this.exprParser.expr());
                  }

                  return stmt;
               } else if (this.lexer.identifierEquals("BINLOG")) {
                  this.lexer.nextToken();
                  this.acceptIdentifier("EVENTS");
                  MariadbShowBinLogEventsStatement stmt = new MariadbShowBinLogEventsStatement();
                  if (this.lexer.token() == Token.IN) {
                     this.lexer.nextToken();
                     stmt.setIn(this.exprParser.expr());
                  }

                  if (this.lexer.token() == Token.FROM) {
                     this.lexer.nextToken();
                     stmt.setFrom(this.exprParser.expr());
                  }

                  stmt.setLimit(this.exprParser.parseLimit());
                  return stmt;
               } else if (this.lexer.identifierEquals("CONTRIBUTORS")) {
                  this.lexer.nextToken();
                  return new MariadbShowContributorsStatement();
               } else if (this.lexer.token() == Token.ALL) {
                  this.lexer.nextToken();
                  this.accept(Token.CREATE);
                  this.accept(Token.TABLE);
                  SQLShowCreateTableStatement stmt = new SQLShowCreateTableStatement();
                  stmt.setAll(true);
                  stmt.setName(this.exprParser.name());
                  return stmt;
               } else if (this.lexer.token() == Token.CREATE) {
                  this.lexer.nextToken();
                  if (this.lexer.token() != Token.DATABASE && this.lexer.token() != Token.SCHEMA) {
                     if (this.lexer.identifierEquals("EVENT")) {
                        this.lexer.nextToken();
                        MariadbShowCreateEventStatement stmt = new MariadbShowCreateEventStatement();
                        stmt.setEventName(this.exprParser.name());
                        return stmt;
                     } else if (this.lexer.token() == Token.FUNCTION) {
                        this.lexer.nextToken();
                        MariadbShowCreateFunctionStatement stmt = new MariadbShowCreateFunctionStatement();
                        stmt.setName(this.exprParser.name());
                        return stmt;
                     } else if (this.lexer.token() == Token.PROCEDURE) {
                        this.lexer.nextToken();
                        MariadbShowCreateProcedureStatement stmt = new MariadbShowCreateProcedureStatement();
                        stmt.setName(this.exprParser.name());
                        return stmt;
                     } else if (this.lexer.token() == Token.TABLE) {
                        this.lexer.nextToken();
                        MariadbShowCreateTableStatement stmt = new MariadbShowCreateTableStatement();
                        stmt.setTable(new SQLExprTableSource(this.lexer.stringVal()));
                        this.lexer.nextToken();
                        if (this.lexer.token() == Token.ERROR) {
                           stmt.setStr(this.exprParser.expr());
                           return stmt;
                        } else {
                           if (this.lexer.token() != Token.LIKE && this.lexer.token() != Token.EOF) {
                              stmt.setName(this.exprParser.name());
                           }

                           if (this.lexer.token() == Token.LIKE) {
                              this.lexer.nextToken();
                              if (this.lexer.identifierEquals(FnvHash.Constants.MAPPING)) {
                                 this.lexer.nextToken();
                                 this.accept(Token.LPAREN);
                                 SQLName name = this.exprParser.name();
                                 stmt.setLikeMapping(name);
                                 this.accept(Token.RPAREN);
                              }
                           }

                           return stmt;
                        }
                     } else if (this.lexer.token() == Token.VIEW) {
                        this.lexer.nextToken();
                        SQLShowCreateViewStatement stmt = new SQLShowCreateViewStatement();
                        stmt.setName(this.exprParser.name());
                        return stmt;
                     } else if (this.lexer.token() == Token.TRIGGER) {
                        this.lexer.nextToken();
                        MariadbShowCreateTriggerStatement stmt = new MariadbShowCreateTriggerStatement();
                        stmt.setName(this.exprParser.name());
                        return stmt;
                     } else if (this.lexer.token() == Token.FULLTEXT) {
                        this.lexer.nextToken();
                        MariadbShowCreateFullTextStatement stmt = new MariadbShowCreateFullTextStatement();
                        stmt.setType(this.parseMariadbFullTextType());
                        stmt.setName(this.exprParser.name());
                        return stmt;
                     } else if (this.lexer.identifierEquals("MATERIALIZED")) {
                        this.lexer.nextToken();
                        SQLShowCreateMaterializedViewStatement stmt = new SQLShowCreateMaterializedViewStatement();
                        this.accept(Token.VIEW);
                        stmt.setName(this.exprParser.name());
                        return stmt;
                     } else {
                        throw new ParserException("TODO " + this.lexer.info());
                     }
                  } else {
                     this.lexer.nextToken();
                     MariadbShowCreateDatabaseStatement stmt = new MariadbShowCreateDatabaseStatement();
                     if (this.lexer.token() == Token.IF) {
                        this.lexer.nextToken();
                        this.accept(Token.NOT);
                        this.accept(Token.EXISTS);
                        stmt.setIfNotExists(true);
                     }

                     stmt.setDatabase(this.exprParser.name());
                     return stmt;
                  }
               } else if (this.lexer.identifierEquals("ENGINE")) {
                  this.lexer.nextToken();
                  MariadbShowEngineStatement stmt = new MariadbShowEngineStatement();
                  stmt.setName(this.exprParser.name());
                  stmt.setOption(MariadbShowEngineStatement.Option.valueOf(this.lexer.stringVal().toUpperCase()));
                  this.lexer.nextToken();
                  return stmt;
               } else if (this.lexer.token() != Token.DATABASE && !this.lexer.identifierEquals(FnvHash.Constants.DB)) {
                  if (this.lexer.identifierEquals("STORAGE")) {
                     this.lexer.nextToken();
                     this.acceptIdentifier("ENGINES");
                     MariadbShowEnginesStatement stmt = new MariadbShowEnginesStatement();
                     stmt.setStorage(true);
                     return stmt;
                  } else if (this.lexer.identifierEquals("ENGINES")) {
                     this.lexer.nextToken();
                     MariadbShowEnginesStatement stmt = new MariadbShowEnginesStatement();
                     return stmt;
                  } else if (this.lexer.identifierEquals("EVENTS")) {
                     this.lexer.nextToken();
                     MariadbShowEventsStatement stmt = new MariadbShowEventsStatement();
                     if (this.lexer.token() == Token.FROM || this.lexer.token() == Token.IN) {
                        this.lexer.nextToken();
                        stmt.setSchema(this.exprParser.name());
                     }

                     if (this.lexer.token() == Token.LIKE) {
                        this.lexer.nextTokenValue();
                        stmt.setLike(this.exprParser.expr());
                     }

                     if (this.lexer.token() == Token.WHERE) {
                        this.lexer.nextToken();
                        stmt.setWhere(this.exprParser.expr());
                     }

                     return stmt;
                  } else if (this.lexer.token() == Token.FUNCTION) {
                     this.lexer.nextToken();
                     if (this.lexer.identifierEquals("CODE")) {
                        this.lexer.nextToken();
                        MariadbShowFunctionCodeStatement stmt = new MariadbShowFunctionCodeStatement();
                        stmt.setName(this.exprParser.name());
                        return stmt;
                     } else {
                        this.acceptIdentifier("STATUS");
                        MariadbShowFunctionStatusStatement stmt = new MariadbShowFunctionStatusStatement();
                        if (this.lexer.token() == Token.LIKE) {
                           this.lexer.nextTokenValue();
                           stmt.setLike(this.exprParser.expr());
                        }

                        if (this.lexer.token() == Token.WHERE) {
                           this.lexer.nextToken();
                           stmt.setWhere(this.exprParser.expr());
                        }

                        return stmt;
                     }
                  } else if (this.lexer.identifierEquals("ENGINE")) {
                     this.lexer.nextToken();
                     MariadbShowEngineStatement stmt = new MariadbShowEngineStatement();
                     stmt.setName(this.exprParser.name());
                     stmt.setOption(MariadbShowEngineStatement.Option.valueOf(this.lexer.stringVal().toUpperCase()));
                     this.lexer.nextToken();
                     return stmt;
                  } else if (this.lexer.identifierEquals("STORAGE")) {
                     this.lexer.nextToken();
                     this.accept(Token.EQ);
                     this.accept(Token.DEFAULT);
                     MariadbShowEnginesStatement stmt = new MariadbShowEnginesStatement();
                     stmt.setStorage(true);
                     return stmt;
                  } else if (this.lexer.identifierEquals("GRANTS")) {
                     this.lexer.nextToken();
                     MariadbShowGrantsStatement stmt = new MariadbShowGrantsStatement();
                     if (this.lexer.token() == Token.FOR) {
                        this.lexer.nextToken();
                        stmt.setUser(this.exprParser.expr());
                     }

                     if (this.lexer.token() == Token.ON) {
                        this.lexer.nextToken();
                        SQLExpr on = this.exprParser.expr();
                        stmt.setOn(on);
                     }

                     return stmt;
                  } else if (this.lexer.token() != Token.INDEX && !this.lexer.identifierEquals("INDEXES") && !this.lexer.identifierEquals("KEYS")) {
                     if (this.lexer.token() != Token.OPEN && !this.lexer.identifierEquals("OPEN")) {
                        if (this.lexer.identifierEquals("PLUGINS")) {
                           this.lexer.nextToken();
                           MariadbShowPluginsStatement stmt = new MariadbShowPluginsStatement();
                           return stmt;
                        } else if (this.lexer.identifierEquals("HTC")) {
                           this.lexer.nextToken();
                           MariadbShowHtcStatement stmt = new MariadbShowHtcStatement();
                           stmt.setFull(false);
                           return stmt;
                        } else if (this.lexer.identifierEquals("HMSMETA")) {
                           this.lexer.nextToken();
                           SQLName name = this.exprParser.name();
                           MariadbShowHMSMetaStatement stmt = new MariadbShowHMSMetaStatement();
                           stmt.setName(name);
                           return stmt;
                        } else if (this.lexer.identifierEquals("STC")) {
                           this.lexer.nextToken();
                           MariadbShowStcStatement stmt = new MariadbShowStcStatement();
                           if (this.lexer.identifierEquals("HIS")) {
                              this.lexer.nextToken();
                              stmt.setHis(true);
                           } else {
                              stmt.setHis(false);
                           }

                           return stmt;
                        } else if (this.lexer.identifierEquals("PRIVILEGES")) {
                           this.lexer.nextToken();
                           MariadbShowPrivilegesStatement stmt = new MariadbShowPrivilegesStatement();
                           return stmt;
                        } else if (this.lexer.token() == Token.PROCEDURE) {
                           this.lexer.nextToken();
                           if (this.lexer.identifierEquals("CODE")) {
                              this.lexer.nextToken();
                              MariadbShowProcedureCodeStatement stmt = new MariadbShowProcedureCodeStatement();
                              stmt.setName(this.exprParser.name());
                              return stmt;
                           } else {
                              this.acceptIdentifier("STATUS");
                              MariadbShowProcedureStatusStatement stmt = new MariadbShowProcedureStatusStatement();
                              if (this.lexer.token() == Token.LIKE) {
                                 this.lexer.nextTokenValue();
                                 stmt.setLike(this.exprParser.expr());
                              }

                              if (this.lexer.token() == Token.WHERE) {
                                 this.lexer.nextToken();
                                 stmt.setWhere(this.exprParser.expr());
                              }

                              return stmt;
                           }
                        } else if (this.lexer.identifierEquals("PROFILES")) {
                           this.lexer.nextToken();
                           MariadbShowProfilesStatement stmt = new MariadbShowProfilesStatement();
                           return stmt;
                        } else if (this.lexer.identifierEquals("PROFILE")) {
                           this.lexer.nextToken();
                           MariadbShowProfileStatement stmt = new MariadbShowProfileStatement();

                           while(true) {
                              if (this.lexer.token() == Token.ALL) {
                                 stmt.getTypes().add(MariadbShowProfileStatement.Type.ALL);
                                 this.lexer.nextToken();
                              } else if (this.lexer.identifierEquals("BLOCK")) {
                                 this.lexer.nextToken();
                                 this.acceptIdentifier("IO");
                                 stmt.getTypes().add(MariadbShowProfileStatement.Type.BLOCK_IO);
                              } else if (this.lexer.identifierEquals("CONTEXT")) {
                                 this.lexer.nextToken();
                                 this.acceptIdentifier("SWITCHES");
                                 stmt.getTypes().add(MariadbShowProfileStatement.Type.CONTEXT_SWITCHES);
                              } else if (this.lexer.identifierEquals("CPU")) {
                                 this.lexer.nextToken();
                                 stmt.getTypes().add(MariadbShowProfileStatement.Type.CPU);
                              } else if (this.lexer.identifierEquals("IPC")) {
                                 this.lexer.nextToken();
                                 stmt.getTypes().add(MariadbShowProfileStatement.Type.IPC);
                              } else if (this.lexer.identifierEquals("MEMORY")) {
                                 this.lexer.nextToken();
                                 stmt.getTypes().add(MariadbShowProfileStatement.Type.MEMORY);
                              } else if (this.lexer.identifierEquals("PAGE")) {
                                 this.lexer.nextToken();
                                 this.acceptIdentifier("FAULTS");
                                 stmt.getTypes().add(MariadbShowProfileStatement.Type.PAGE_FAULTS);
                              } else if (this.lexer.identifierEquals("SOURCE")) {
                                 this.lexer.nextToken();
                                 stmt.getTypes().add(MariadbShowProfileStatement.Type.SOURCE);
                              } else {
                                 if (!this.lexer.identifierEquals("SWAPS")) {
                                    break;
                                 }

                                 this.lexer.nextToken();
                                 stmt.getTypes().add(MariadbShowProfileStatement.Type.SWAPS);
                              }

                              if (this.lexer.token() != Token.COMMA) {
                                 break;
                              }

                              this.lexer.nextToken();
                           }

                           if (this.lexer.token() == Token.FOR) {
                              this.lexer.nextToken();
                              this.acceptIdentifier("QUERY");
                              stmt.setForQuery(this.exprParser.primary());
                           }

                           stmt.setLimit(this.exprParser.parseLimit());
                           return stmt;
                        } else if (this.lexer.identifierEquals("RELAYLOG")) {
                           this.lexer.nextToken();
                           this.acceptIdentifier("EVENTS");
                           MariadbShowRelayLogEventsStatement stmt = new MariadbShowRelayLogEventsStatement();
                           if (this.lexer.token() == Token.IN) {
                              this.lexer.nextToken();
                              stmt.setLogName(this.exprParser.primary());
                           }

                           if (this.lexer.token() == Token.FROM) {
                              this.lexer.nextToken();
                              stmt.setFrom(this.exprParser.primary());
                           }

                           stmt.setLimit(this.exprParser.parseLimit());
                           return stmt;
                        } else if (this.lexer.identifierEquals("RELAYLOG")) {
                           this.lexer.nextToken();
                           this.acceptIdentifier("EVENTS");
                           MariadbShowRelayLogEventsStatement stmt = new MariadbShowRelayLogEventsStatement();
                           if (this.lexer.token() == Token.IN) {
                              this.lexer.nextToken();
                              stmt.setLogName(this.exprParser.primary());
                           }

                           if (this.lexer.token() == Token.FROM) {
                              this.lexer.nextToken();
                              stmt.setFrom(this.exprParser.primary());
                           }

                           stmt.setLimit(this.exprParser.parseLimit());
                           return stmt;
                        } else if (this.lexer.identifierEquals("SLAVE")) {
                           this.lexer.nextToken();
                           if (this.lexer.identifierEquals("STATUS")) {
                              this.lexer.nextToken();
                              return new MariadbShowSlaveStatusStatement();
                           } else {
                              this.acceptIdentifier("HOSTS");
                              MariadbShowSlaveHostsStatement stmt = new MariadbShowSlaveHostsStatement();
                              return stmt;
                           }
                        } else if (this.lexer.token() == Token.TABLE) {
                           this.lexer.nextToken();
                           this.acceptIdentifier("STATUS");
                           MariadbShowTableStatusStatement stmt = new MariadbShowTableStatusStatement();
                           if (this.lexer.token() == Token.FROM || this.lexer.token() == Token.IN) {
                              this.lexer.nextToken();
                              SQLName name = this.exprParser.name();
                              if (name instanceof SQLPropertyExpr) {
                                 stmt.setDatabase((SQLIdentifierExpr)((SQLPropertyExpr)name).getOwner());
                                 stmt.setTableGroup(new SQLIdentifierExpr(((SQLPropertyExpr)name).getName()));
                              } else {
                                 stmt.setDatabase(name);
                              }
                           }

                           if (this.lexer.token() == Token.LIKE) {
                              this.lexer.nextTokenValue();
                              stmt.setLike(this.exprParser.expr());
                           }

                           if (this.lexer.token() == Token.WHERE) {
                              this.lexer.nextToken();
                              stmt.setWhere(this.exprParser.expr());
                           }

                           return stmt;
                        } else if (this.lexer.identifierEquals("TRIGGERS")) {
                           this.lexer.nextToken();
                           MariadbShowTriggersStatement stmt = new MariadbShowTriggersStatement();
                           if (this.lexer.token() == Token.FROM || this.lexer.token() == Token.IN) {
                              this.lexer.nextToken();
                              SQLName database = this.exprParser.name();
                              stmt.setDatabase(database);
                           }

                           if (this.lexer.token() == Token.LIKE) {
                              this.lexer.nextTokenValue();
                              SQLExpr like = this.exprParser.expr();
                              stmt.setLike(like);
                           }

                           if (this.lexer.token() == Token.WHERE) {
                              this.lexer.nextToken();
                              SQLExpr where = this.exprParser.expr();
                              stmt.setWhere(where);
                           }

                           return stmt;
                        } else if (this.lexer.identifierEquals(FnvHash.Constants.BROADCASTS)) {
                           this.lexer.nextToken();
                           MariadbShowBroadcastsStatement stmt = new MariadbShowBroadcastsStatement();
                           if (this.lexer.token() == Token.WHERE) {
                              this.lexer.nextToken();
                              SQLExpr where = this.exprParser.expr();
                              stmt.setWhere(where);
                           }

                           if (this.lexer.token() == Token.ORDER) {
                              SQLOrderBy orderBy = this.exprParser.parseOrderBy();
                              stmt.setOrderBy(orderBy);
                           }

                           if (this.lexer.token() == Token.LIMIT) {
                              SQLLimit limit = this.exprParser.parseLimit();
                              stmt.setLimit(limit);
                           }

                           return stmt;
                        } else if (this.lexer.identifierEquals(FnvHash.Constants.DATASOURCES)) {
                           this.lexer.nextToken();
                           MariadbShowDatasourcesStatement stmt = new MariadbShowDatasourcesStatement();
                           if (this.lexer.token() == Token.WHERE) {
                              this.lexer.nextToken();
                              SQLExpr where = this.exprParser.expr();
                              stmt.setWhere(where);
                           }

                           if (this.lexer.token() == Token.ORDER) {
                              SQLOrderBy orderBy = this.exprParser.parseOrderBy();
                              stmt.setOrderBy(orderBy);
                           }

                           if (this.lexer.token() == Token.LIMIT) {
                              SQLLimit limit = this.exprParser.parseLimit();
                              stmt.setLimit(limit);
                           }

                           return stmt;
                        } else if (this.lexer.identifierEquals(FnvHash.Constants.NODE)) {
                           this.lexer.nextToken();
                           MariadbShowNodeStatement stmt = new MariadbShowNodeStatement();
                           if (this.lexer.token() == Token.WHERE) {
                              this.lexer.nextToken();
                              SQLExpr where = this.exprParser.expr();
                              stmt.setWhere(where);
                           }

                           if (this.lexer.token() == Token.ORDER) {
                              SQLOrderBy orderBy = this.exprParser.parseOrderBy();
                              stmt.setOrderBy(orderBy);
                           }

                           if (this.lexer.token() == Token.LIMIT) {
                              SQLLimit limit = this.exprParser.parseLimit();
                              stmt.setLimit(limit);
                           }

                           return stmt;
                        } else if (this.lexer.identifierEquals(FnvHash.Constants.HELP)) {
                           this.lexer.nextToken();
                           MariadbShowHelpStatement stmt = new MariadbShowHelpStatement();
                           if (this.lexer.token() == Token.WHERE) {
                              this.lexer.nextToken();
                              SQLExpr where = this.exprParser.expr();
                              stmt.setWhere(where);
                           }

                           if (this.lexer.token() == Token.ORDER) {
                              SQLOrderBy orderBy = this.exprParser.parseOrderBy();
                              stmt.setOrderBy(orderBy);
                           }

                           if (this.lexer.token() == Token.LIMIT) {
                              SQLLimit limit = this.exprParser.parseLimit();
                              stmt.setLimit(limit);
                           }

                           return stmt;
                        } else if (this.lexer.token() != Token.SEQUENCE && !this.lexer.identifierEquals(FnvHash.Constants.SEQUENCES)) {
                           if (this.lexer.identifierEquals("PARTITIONS")) {
                              this.lexer.nextToken();
                              SQLShowPartitionsStmt stmt = new SQLShowPartitionsStmt();
                              if (this.lexer.token() == Token.FROM) {
                                 this.lexer.nextToken();
                              }

                              SQLName name = this.exprParser.name();
                              stmt.setTableSource((SQLExpr)name);
                              if (this.lexer.token() == Token.PARTITION) {
                                 this.lexer.nextToken();
                                 this.accept(Token.LPAREN);
                                 this.parseAssignItems(stmt.getPartition(), stmt, false);
                                 this.accept(Token.RPAREN);
                              }

                              if (this.lexer.token() == Token.WHERE) {
                                 this.lexer.nextToken();
                                 stmt.setWhere(this.exprParser.expr());
                              }

                              return stmt;
                           } else if (this.lexer.identifierEquals("RULE")) {
                              this.lexer.nextToken();
                              boolean version = false;
                              if (this.lexer.identifierEquals(FnvHash.Constants.VERSION)) {
                                 version = true;
                                 this.lexer.nextToken();
                              } else if (this.lexer.identifierEquals(FnvHash.Constants.FULL) || this.lexer.token() == Token.FULL) {
                                 full = true;
                                 this.lexer.nextToken();
                              }

                              if (this.lexer.identifierEquals(FnvHash.Constants.STATUS)) {
                                 this.lexer.nextToken();
                                 MariadbShowRuleStatusStatement stmt = new MariadbShowRuleStatusStatement();
                                 if (full) {
                                    stmt.setFull(full);
                                 }

                                 if (version) {
                                    stmt.setVersion(true);
                                 }

                                 if (this.lexer.token() == Token.FROM) {
                                    this.lexer.nextToken();
                                 }

                                 if (full) {
                                    stmt.setLite(false);
                                 }

                                 if (this.lexer.token() == Token.WHERE) {
                                    this.lexer.nextToken();
                                    SQLExpr where = this.exprParser.expr();
                                    stmt.setWhere(where);
                                 }

                                 if (this.lexer.token() == Token.ORDER) {
                                    SQLOrderBy orderBy = this.exprParser.parseOrderBy();
                                    stmt.setOrderBy(orderBy);
                                 }

                                 if (this.lexer.token() == Token.LIMIT) {
                                    SQLLimit limit = this.exprParser.parseLimit();
                                    stmt.setLimit(limit);
                                 }

                                 return stmt;
                              } else {
                                 MariadbShowRuleStatement stmt = new MariadbShowRuleStatement();
                                 if (full) {
                                    stmt.setFull(full);
                                 }

                                 if (version) {
                                    stmt.setVersion(true);
                                 }

                                 if (this.lexer.identifierEquals(FnvHash.Constants.VERSION)) {
                                    this.lexer.nextToken();
                                    stmt.setVersion(true);
                                 }

                                 if (this.lexer.token() != Token.EOF && this.lexer.token() != Token.SEMI) {
                                    if (this.lexer.token() == Token.FROM) {
                                       this.lexer.nextToken();
                                       stmt.setName(this.exprParser.name());
                                    }

                                    if (this.lexer.token() == Token.WHERE) {
                                       this.lexer.nextToken();
                                       SQLExpr where = this.exprParser.expr();
                                       stmt.setWhere(where);
                                    }

                                    if (this.lexer.token() == Token.ORDER) {
                                       SQLOrderBy orderBy = this.exprParser.parseOrderBy();
                                       stmt.setOrderBy(orderBy);
                                    }

                                    if (this.lexer.token() == Token.LIMIT) {
                                       SQLLimit limit = this.exprParser.parseLimit();
                                       stmt.setLimit(limit);
                                    }

                                    return stmt;
                                 } else {
                                    return stmt;
                                 }
                              }
                           } else if (this.lexer.identifierEquals("DS")) {
                              this.lexer.nextToken();
                              MariadbShowDsStatement stmt = new MariadbShowDsStatement();
                              if (this.lexer.token() == Token.WHERE) {
                                 this.lexer.nextToken();
                                 SQLExpr where = this.exprParser.expr();
                                 stmt.setWhere(where);
                              }

                              if (this.lexer.token() == Token.ORDER) {
                                 SQLOrderBy orderBy = this.exprParser.parseOrderBy();
                                 stmt.setOrderBy(orderBy);
                              }

                              if (this.lexer.token() == Token.LIMIT) {
                                 SQLLimit limit = this.exprParser.parseLimit();
                                 stmt.setLimit(limit);
                              }

                              return stmt;
                           } else if (this.lexer.identifierEquals("DDL")) {
                              this.lexer.nextToken();
                              if (this.isEnabled(SQLParserFeature.DRDSAsyncDDL) && !this.lexer.identifierEquals("STATUS")) {
                                 DrdsShowDDLJobs showDDLJobs = new DrdsShowDDLJobs();
                                 showDDLJobs.setFull(full);

                                 while(this.lexer.token() != Token.EOF && this.lexer.token() != Token.SEMI) {
                                    showDDLJobs.addJobId(this.lexer.integerValue().longValue());
                                    this.accept(Token.LITERAL_INT);
                                    if (Token.COMMA != this.lexer.token()) {
                                       if (this.lexer.token() != Token.EOF && this.lexer.token() != Token.SEMI) {
                                          throw new ParserException("syntax error, expect job id, actual " + this.lexer.token() + ", " + this.lexer.info());
                                       }
                                       break;
                                    }

                                    this.lexer.nextToken();
                                 }

                                 return showDDLJobs;
                              } else {
                                 this.acceptIdentifier("STATUS");
                                 MariadbShowDdlStatusStatement stmt = new MariadbShowDdlStatusStatement();
                                 if (this.lexer.token() == Token.WHERE) {
                                    this.lexer.nextToken();
                                    SQLExpr where = this.exprParser.expr();
                                    stmt.setWhere(where);
                                 }

                                 if (this.lexer.token() == Token.ORDER) {
                                    SQLOrderBy orderBy = this.exprParser.parseOrderBy();
                                    stmt.setOrderBy(orderBy);
                                 }

                                 if (this.lexer.token() == Token.LIMIT) {
                                    SQLLimit limit = this.exprParser.parseLimit();
                                    stmt.setLimit(limit);
                                 }

                                 return stmt;
                              }
                           } else if (this.lexer.identifierEquals("TRACE")) {
                              this.lexer.nextToken();
                              MariadbShowTraceStatement stmt = new MariadbShowTraceStatement();
                              if (this.lexer.token() == Token.WHERE) {
                                 this.lexer.nextToken();
                                 SQLExpr where = this.exprParser.expr();
                                 stmt.setWhere(where);
                              }

                              if (this.lexer.token() == Token.ORDER) {
                                 SQLOrderBy orderBy = this.exprParser.parseOrderBy();
                                 stmt.setOrderBy(orderBy);
                              }

                              if (this.lexer.token() == Token.LIMIT) {
                                 SQLLimit limit = this.exprParser.parseLimit();
                                 stmt.setLimit(limit);
                              }

                              return stmt;
                           } else if (this.lexer.identifierEquals("TOPOLOGY")) {
                              this.lexer.nextToken();
                              MariadbShowTopologyStatement stmt = new MariadbShowTopologyStatement();
                              if (this.lexer.token() == Token.FROM) {
                                 this.lexer.nextToken();
                              }

                              stmt.setName(this.exprParser.name());
                              if (this.lexer.token() == Token.WHERE) {
                                 this.lexer.nextToken();
                                 SQLExpr where = this.exprParser.expr();
                                 stmt.setWhere(where);
                              }

                              if (this.lexer.token() == Token.ORDER) {
                                 SQLOrderBy orderBy = this.exprParser.parseOrderBy();
                                 stmt.setOrderBy(orderBy);
                              }

                              if (this.lexer.token() == Token.LIMIT) {
                                 SQLLimit limit = this.exprParser.parseLimit();
                                 stmt.setLimit(limit);
                              }

                              stmt.setFull(full);
                              return stmt;
                           } else if (this.lexer.identifierEquals(FnvHash.Constants.PLANCACHE)) {
                              this.lexer.nextToken();
                              if (this.lexer.identifierEquals(FnvHash.Constants.STATUS)) {
                                 this.lexer.nextToken();
                                 return new MariadbShowPlanCacheStatusStatement();
                              } else if (this.lexer.identifierEquals(FnvHash.Constants.PLAN)) {
                                 this.lexer.nextToken();
                                 SQLSelect select = this.createSQLSelectParser().select();
                                 return new MariadbShowPlanCacheStatement(select);
                              } else {
                                 throw new ParserException("TODO " + this.lexer.info());
                              }
                           } else if (this.lexer.identifierEquals(FnvHash.Constants.SLOW)) {
                              MariadbShowSlowStatement stmt = this.parserShowSlow();
                              stmt.setPhysical(false);
                              stmt.setFull(full);
                              return stmt;
                           } else if (this.lexer.identifierEquals("PHYSICAL_SLOW")) {
                              MariadbShowSlowStatement stmt = this.parserShowSlow();
                              stmt.setPhysical(true);
                              stmt.setFull(full);
                              return stmt;
                           } else if (this.lexer.identifierEquals(FnvHash.Constants.QUERY_TASK)) {
                              this.lexer.nextToken();
                              SQLShowQueryTaskStatement stmt = new SQLShowQueryTaskStatement();
                              stmt.setDbType(this.dbType);
                              if (this.lexer.token() == Token.FOR) {
                                 this.lexer.nextToken();
                                 stmt.setUser(this.exprParser.expr());
                              }

                              if (this.lexer.token() == Token.WHERE) {
                                 this.lexer.nextToken();
                                 SQLExpr where = this.exprParser.expr();
                                 stmt.setWhere(where);
                              }

                              if (this.lexer.token() == Token.ORDER) {
                                 SQLOrderBy orderBy = this.exprParser.parseOrderBy();
                                 stmt.setOrderBy(orderBy);
                              }

                              if (this.lexer.token() == Token.LIMIT) {
                                 SQLLimit limit = this.exprParser.parseLimit();
                                 stmt.setLimit(limit);
                              }

                              if (full) {
                                 stmt.setFull(true);
                              }

                              return stmt;
                           } else if (this.lexer.identifierEquals(FnvHash.Constants.OUTLINES)) {
                              this.lexer.nextToken();
                              SQLShowOutlinesStatement stmt = new SQLShowOutlinesStatement();
                              stmt.setDbType(this.dbType);
                              if (this.lexer.token() == Token.WHERE) {
                                 this.lexer.nextToken();
                                 SQLExpr where = this.exprParser.expr();
                                 stmt.setWhere(where);
                              }

                              if (this.lexer.token() == Token.ORDER) {
                                 SQLOrderBy orderBy = this.exprParser.parseOrderBy();
                                 stmt.setOrderBy(orderBy);
                              }

                              if (this.lexer.token() == Token.LIMIT) {
                                 SQLLimit limit = this.exprParser.parseLimit();
                                 stmt.setLimit(limit);
                              }

                              return stmt;
                           } else if (this.lexer.identifierEquals(FnvHash.Constants.RECYCLEBIN)) {
                              this.lexer.nextToken();
                              SQLShowRecylebinStatement stmt = new SQLShowRecylebinStatement();
                              stmt.setDbType(this.dbType);
                              return stmt;
                           } else if (this.lexer.identifierEquals(FnvHash.Constants.TABLEGROUPS)) {
                              this.lexer.nextToken();
                              SQLShowTableGroupsStatement stmt = this.parseShowTableGroups();
                              return stmt;
                           } else if (this.lexer.identifierEquals(FnvHash.Constants.CATALOGS)) {
                              this.lexer.nextToken();
                              SQLShowCatalogsStatement stmt = new SQLShowCatalogsStatement();
                              if (this.lexer.token() == Token.LIKE) {
                                 this.lexer.nextToken();
                                 SQLExpr like = this.exprParser.expr();
                                 stmt.setLike(like);
                              }

                              return stmt;
                           } else if (this.lexer.identifierEquals(FnvHash.Constants.FUNCTIONS)) {
                              this.lexer.nextToken();
                              SQLShowFunctionsStatement stmt = new SQLShowFunctionsStatement();
                              if (this.lexer.token() == Token.LIKE) {
                                 this.lexer.nextToken();
                                 SQLExpr like = this.exprParser.expr();
                                 stmt.setLike(like);
                              }

                              return stmt;
                           } else if (!this.lexer.identifierEquals(FnvHash.Constants.SCHEMAS)) {
                              if (this.lexer.identifierEquals(FnvHash.Constants.CONFIG)) {
                                 this.lexer.nextToken();
                                 SQLName name = this.exprParser.name();
                                 MariadbShowConfigStatement stmt = new MariadbShowConfigStatement();
                                 stmt.setName(name);
                                 return stmt;
                              } else if (this.lexer.identifierEquals(FnvHash.Constants.USERS)) {
                                 this.lexer.nextToken();
                                 SQLShowUsersStatement stmt = new SQLShowUsersStatement();
                                 stmt.setDbType(this.dbType);
                                 return stmt;
                              } else if (this.lexer.identifierEquals(FnvHash.Constants.PHYSICAL_PROCESSLIST)) {
                                 this.lexer.nextToken();
                                 MariadbShowPhysicalProcesslistStatement stmt = new MariadbShowPhysicalProcesslistStatement();
                                 if (full) {
                                    stmt.setFull(full);
                                 }

                                 return stmt;
                              } else if (this.lexer.identifierEquals("MATERIALIZED")) {
                                 return this.parseShowMaterializedView();
                              } else if (this.lexer.token() == Token.FULLTEXT) {
                                 this.lexer.nextToken();
                                 MariadbShowFullTextStatement stmt = new MariadbShowFullTextStatement();
                                 if (this.lexer.identifierEquals(FnvHash.Constants.CHARFILTERS)) {
                                    stmt.setType(FullTextType.CHARFILTER);
                                 } else if (this.lexer.identifierEquals(FnvHash.Constants.TOKENIZERS)) {
                                    stmt.setType(FullTextType.TOKENIZER);
                                 } else if (this.lexer.identifierEquals(FnvHash.Constants.TOKENFILTERS)) {
                                    stmt.setType(FullTextType.TOKENFILTER);
                                 } else if (this.lexer.identifierEquals(FnvHash.Constants.ANALYZERS)) {
                                    stmt.setType(FullTextType.ANALYZER);
                                 } else {
                                    if (!this.lexer.identifierEquals(FnvHash.Constants.DICTIONARIES)) {
                                       throw new ParserException("type of full text must be [CHARFILTERS/TOKENIZERS/TOKENFILTERS/ANALYZERS/DICTIONARYS] .");
                                    }

                                    stmt.setType(FullTextType.DICTIONARY);
                                 }

                                 this.lexer.nextToken();
                                 return stmt;
                              } else if (this.isEnabled(SQLParserFeature.DRDSAsyncDDL) && this.lexer.identifierEquals("METADATA")) {
                                 this.lexer.nextToken();
                                 if (Token.LOCK != this.lexer.token() && !this.lexer.identifierEquals("LOCKS")) {
                                    throw new ParserException("syntax error, expect LOCK/LOCKS, actual " + this.lexer.token() + ", " + this.lexer.info());
                                 } else {
                                    this.lexer.nextToken();
                                    DrdsShowMetadataLock stmt = new DrdsShowMetadataLock();
                                    if (Token.SEMI != this.lexer.token() && Token.EOF != this.lexer.token()) {
                                       stmt.setSchemaName(this.exprParser.name());
                                       return stmt;
                                    } else {
                                       return stmt;
                                    }
                                 }
                              } else {
                                 throw new ParserException("TODO " + this.lexer.info());
                              }
                           } else {
                              this.lexer.nextToken();
                              SQLShowDatabasesStatement stmt = new SQLShowDatabasesStatement();
                              stmt.setPhysical(isPhysical);
                              if (this.lexer.token() == Token.IN || this.lexer.token() == Token.FROM) {
                                 this.lexer.nextToken();
                                 SQLName db = this.exprParser.name();
                                 stmt.setDatabase(db);
                              }

                              if (full) {
                                 stmt.setFull(true);
                              }

                              if (this.lexer.token() == Token.LIKE) {
                                 this.lexer.nextToken();
                                 SQLExpr like = this.exprParser.expr();
                                 stmt.setLike(like);
                              }

                              return stmt;
                           }
                        } else {
                           this.lexer.nextToken();
                           MariadbShowSequencesStatement stmt = new MariadbShowSequencesStatement();
                           if (this.lexer.token() == Token.WHERE) {
                              this.lexer.nextToken();
                              SQLExpr where = this.exprParser.expr();
                              stmt.setWhere(where);
                           }

                           if (this.lexer.token() == Token.ORDER) {
                              SQLOrderBy orderBy = this.exprParser.parseOrderBy();
                              stmt.setOrderBy(orderBy);
                           }

                           if (this.lexer.token() == Token.LIMIT) {
                              SQLLimit limit = this.exprParser.parseLimit();
                              stmt.setLimit(limit);
                           }

                           return stmt;
                        }
                     } else {
                        this.lexer.nextToken();
                        this.acceptIdentifier("TABLES");
                        MariadbShowOpenTablesStatement stmt = new MariadbShowOpenTablesStatement();
                        if (this.lexer.token() == Token.FROM || this.lexer.token() == Token.IN) {
                           stmt.setFromOrInDatabase(new SQLIdentifierExpr(this.lexer.token().name));
                           this.lexer.nextToken();
                           stmt.setDatabase(this.exprParser.name());
                        }

                        if (this.lexer.token() == Token.LIKE) {
                           this.lexer.nextTokenValue();
                           stmt.setLike(this.exprParser.expr());
                        }

                        if (this.lexer.token() == Token.WHERE) {
                           this.lexer.nextToken();
                           stmt.setWhere(this.exprParser.expr());
                        }

                        return stmt;
                     }
                  } else {
                     SQLShowIndexesStatement stmt = new SQLShowIndexesStatement();
                     if (extended) {
                        stmt.setExtended(true);
                     }

                     stmt.setType(this.lexer.stringVal());
                     this.lexer.nextToken();
                     if (this.lexer.token() == Token.FROM || this.lexer.token() == Token.IN) {
                        this.lexer.nextToken();
                        SQLName table = this.exprParser.name();
                        stmt.setTable(table);
                        if (this.lexer.token() == Token.FROM || this.lexer.token() == Token.IN) {
                           stmt.setFromOrInDatabase(new SQLIdentifierExpr(this.lexer.token().name));
                           this.lexer.nextToken();
                           stmt.setDb(new SQLIdentifierExpr(this.lexer.stringVal()));
                           this.lexer.nextToken();
                        }

                        if (this.lexer.token() == Token.WHERE) {
                           this.lexer.nextToken();
                           SQLExpr where = this.exprParser.expr();
                           stmt.setWhere(where);
                        }
                     }

                     if (this.lexer.token() == Token.HINT) {
                        stmt.setHints(this.exprParser.parseHints());
                     }

                     return stmt;
                  }
               } else {
                  this.lexer.nextToken();
                  MariadbShowDatabaseStatusStatement stmt = new MariadbShowDatabaseStatusStatement();
                  if (full) {
                     stmt.setFull(true);
                  }

                  if (this.lexer.identifierEquals("STATUS")) {
                     this.lexer.nextToken();
                     if (this.lexer.token() == Token.LIKE) {
                        this.lexer.nextTokenValue();
                        stmt.setName(this.exprParser.name());
                     } else {
                        if (this.lexer.token() == Token.WHERE) {
                           this.lexer.nextToken();
                           SQLExpr where = this.exprParser.expr();
                           stmt.setWhere(where);
                        }

                        if (this.lexer.token() == Token.ORDER) {
                           SQLOrderBy orderBy = this.exprParser.parseOrderBy();
                           stmt.setOrderBy(orderBy);
                        }

                        if (this.lexer.token() == Token.LIMIT) {
                           SQLLimit limit = this.exprParser.parseLimit();
                           stmt.setLimit(limit);
                        }
                     }
                  }

                  return stmt;
               }
            }
         } else {
            this.lexer.nextToken();
            SQLShowColumnsStatement stmt = this.parseShowColumns();
            stmt.setFull(full);
            return stmt;
         }
      } else {
         SQLExpr expr = new SQLIdentifierExpr(this.lexer.stringVal());
         scs.setColumnsOrFields(expr);
         this.lexer.nextToken();
         if (this.lexer.token() == Token.FROM || this.lexer.token() == Token.IN) {
            String str = this.lexer.stringVal();
            scs.setFromOrInTable(new SQLIdentifierExpr(str));
            this.lexer.nextToken();
            scs.setTableName(new SQLExprTableSource(this.exprParser.name()));
            if (this.lexer.token() == Token.EOF) {
               return scs;
            }

            if (this.lexer.token() == Token.FROM || this.lexer.token() == Token.IN) {
               String fromOrIn = this.lexer.stringVal();
               scs.setFromOrInUser(new SQLIdentifierExpr(fromOrIn));
               this.lexer.nextToken();
               SQLExpr var9 = this.exprParser.expr();
               scs.setUser(var9);
            }

            if (this.lexer.token() == Token.LIKE) {
               this.lexer.nextToken();
               scs.setLike(true);
               SQLExpr var10 = this.exprParser.expr();
               scs.setLikeNote(var10);
            }

            if (this.lexer.token() == Token.WHERE) {
               this.lexer.nextToken();
               scs.setWhere(true);
               SQLExpr var11 = this.exprParser.expr();
               scs.setWhereNote(var11);
            }
         }

         return scs;
      }
   }

   private MariadbShowStatusStatement parseShowStatus() {
      MariadbShowStatusStatement stmt = new MariadbShowStatusStatement();
      if (this.lexer.token() == Token.LIKE) {
         this.lexer.nextToken();
         SQLExpr like = this.exprParser.expr();
         stmt.setLike(like);
      }

      if (this.lexer.token() == Token.WHERE) {
         this.lexer.nextToken();
         SQLExpr where = this.exprParser.expr();
         stmt.setWhere(where);
      }

      return stmt;
   }

   public MariadbShowSlowStatement parserShowSlow() {
      this.lexer.nextToken();
      MariadbShowSlowStatement stmt = new MariadbShowSlowStatement();
      if (this.lexer.token() == Token.WHERE) {
         this.lexer.nextToken();
         SQLExpr where = this.exprParser.expr();
         stmt.setWhere(where);
      }

      if (this.lexer.token() == Token.ORDER) {
         SQLOrderBy orderBy = this.exprParser.parseOrderBy();
         stmt.setOrderBy(orderBy);
      }

      if (this.lexer.token() == Token.LIMIT) {
         SQLLimit limit = this.exprParser.parseLimit();
         stmt.setLimit(limit);
      }

      return stmt;
   }

   private MariadbShowVariantsStatement parseShowVariants() {
      MariadbShowVariantsStatement stmt = new MariadbShowVariantsStatement();
      if (this.lexer.token() == Token.LIKE) {
         this.lexer.nextToken();
         SQLExpr like = this.exprParser.expr();
         stmt.setLike(like);
      }

      if (this.lexer.token() == Token.WHERE) {
         this.lexer.nextToken();
         SQLExpr where = this.exprParser.expr();
         stmt.setWhere(where);
      }

      return stmt;
   }

   private MariadbShowWarningsStatement parseShowWarnings() {
      MariadbShowWarningsStatement stmt = new MariadbShowWarningsStatement();
      stmt.setLimit(this.exprParser.parseLimit());
      return stmt;
   }

   public SQLStartTransactionStatement parseStart() {
      this.acceptIdentifier("START");
      this.acceptIdentifier("TRANSACTION");
      SQLStartTransactionStatement stmt = new SQLStartTransactionStatement(this.dbType);
      if (this.lexer.token() == Token.WITH) {
         this.lexer.nextToken();
         this.acceptIdentifier("CONSISTENT");
         this.acceptIdentifier("SNAPSHOT");
         stmt.setConsistentSnapshot(true);
      }

      if (this.lexer.token() == Token.BEGIN) {
         this.lexer.nextToken();
         stmt.setBegin(true);
         if (this.lexer.identifierEquals("WORK")) {
            this.lexer.nextToken();
            stmt.setWork(true);
         }
      }

      if (this.lexer.token() == Token.HINT) {
         stmt.setHints(this.exprParser.parseHints());
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.ISOLATION)) {
         this.lexer.nextToken();
         this.acceptIdentifier("LEVEL");
         if (this.lexer.identifierEquals(FnvHash.Constants.READ)) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals(FnvHash.Constants.UNCOMMITTED)) {
               this.lexer.nextToken();
               stmt.setIsolationLevel(SQLStartTransactionStatement.IsolationLevel.READ_UNCOMMITTED);
            } else {
               if (!this.lexer.identifierEquals(FnvHash.Constants.COMMITTED)) {
                  throw new ParserException(this.lexer.info());
               }

               this.lexer.nextToken();
               stmt.setIsolationLevel(SQLStartTransactionStatement.IsolationLevel.READ_COMMITTED);
            }
         } else if (this.lexer.identifierEquals(FnvHash.Constants.REPEATABLE)) {
            this.lexer.nextToken();
            this.acceptIdentifier("READ");
            stmt.setIsolationLevel(SQLStartTransactionStatement.IsolationLevel.REPEATABLE_READ);
         } else {
            if (!this.lexer.identifierEquals(FnvHash.Constants.SERIALIZABLE)) {
               throw new ParserException(this.lexer.info());
            }

            this.lexer.nextToken();
            stmt.setIsolationLevel(SQLStartTransactionStatement.IsolationLevel.SERIALIZABLE);
         }
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.READ)) {
         this.lexer.nextToken();
         this.acceptIdentifier("ONLY");
         stmt.setReadOnly(true);
      }

      return stmt;
   }

   public SQLStatement parseRollback() {
      this.acceptIdentifier("ROLLBACK");
      if (this.isEnabled(SQLParserFeature.DRDSAsyncDDL) && this.lexer.identifierEquals("DDL")) {
         this.lexer.nextToken();
         DrdsRollbackDDLJob stmt = new DrdsRollbackDDLJob();

         while(true) {
            stmt.addJobId(this.lexer.integerValue().longValue());
            this.accept(Token.LITERAL_INT);
            if (Token.COMMA != this.lexer.token()) {
               if (this.lexer.token() != Token.EOF && this.lexer.token() != Token.SEMI) {
                  throw new ParserException("syntax error, expect job id, actual " + this.lexer.token() + ", " + this.lexer.info());
               } else {
                  return stmt;
               }
            }

            this.lexer.nextToken();
         }
      } else {
         SQLRollbackStatement stmt = new SQLRollbackStatement();
         if (this.lexer.identifierEquals("WORK")) {
            this.lexer.nextToken();
         }

         if (this.lexer.token() == Token.AND) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.NOT) {
               this.lexer.nextToken();
               this.acceptIdentifier("CHAIN");
               stmt.setChain(Boolean.FALSE);
            } else {
               this.acceptIdentifier("CHAIN");
               stmt.setChain(Boolean.TRUE);
            }
         }

         if (this.lexer.token() == Token.TO) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("SAVEPOINT")) {
               this.lexer.nextToken();
            }

            stmt.setTo(this.exprParser.name());
         }

         return stmt;
      }
   }

   public SQLStatement parseCommit() {
      this.acceptIdentifier("COMMIT");
      SQLCommitStatement stmt = new SQLCommitStatement();
      if (this.lexer.identifierEquals("WORK")) {
         this.lexer.nextToken();
         stmt.setWork(true);
      }

      if (this.lexer.token() == Token.AND) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.NOT) {
            this.lexer.nextToken();
            this.acceptIdentifier("CHAIN");
            stmt.setChain(Boolean.FALSE);
         } else {
            this.acceptIdentifier("CHAIN");
            stmt.setChain(Boolean.TRUE);
         }
      }

      return stmt;
   }

   public SQLReplaceStatement parseReplace() {
      SQLReplaceStatement stmt = new SQLReplaceStatement();
      stmt.setDbType(DbType.mysql);
      List<SQLCommentHint> list = new ArrayList();

      while(this.lexer.token() == Token.HINT) {
         this.exprParser.parseHints(list);
      }

      stmt.setHeadHints(list);
      this.accept(Token.REPLACE);

      while(this.lexer.token() == Token.HINT) {
         this.exprParser.parseHints(stmt.getHints());
      }

      if (this.lexer.token() == Token.COMMENT) {
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.LOW_PRIORITY)) {
         stmt.setLowPriority(true);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.DELAYED)) {
         stmt.setDelayed(true);
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.INTO) {
         this.lexer.nextToken();
      }

      SQLName tableName = this.exprParser.name();
      stmt.setTableName(tableName);
      if (this.lexer.token() == Token.PARTITION) {
         this.lexer.nextToken();
         this.accept(Token.LPAREN);

         while(true) {
            SQLAssignItem ptExpr = new SQLAssignItem();
            ptExpr.setTarget(this.exprParser.name());
            if (this.lexer.token() == Token.EQ) {
               this.lexer.nextToken();
               SQLExpr ptValue = this.exprParser.expr();
               ptExpr.setValue(ptValue);
            }

            stmt.addPartition(ptExpr);
            if (this.lexer.token() != Token.COMMA) {
               this.accept(Token.RPAREN);
               break;
            }

            this.lexer.nextToken();
         }
      }

      if (this.lexer.token() == Token.LPAREN) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.SELECT) {
            SQLQueryExpr queryExpr = (SQLQueryExpr)this.exprParser.expr();
            stmt.setQuery(queryExpr);
         } else {
            this.exprParser.exprList(stmt.getColumns(), stmt);
         }

         this.accept(Token.RPAREN);
      }

      if (this.lexer.token() != Token.VALUES && !this.lexer.identifierEquals("VALUE")) {
         if (this.lexer.token() == Token.SELECT) {
            SQLQueryExpr queryExpr = (SQLQueryExpr)this.exprParser.expr();
            stmt.setQuery(queryExpr);
         } else if (this.lexer.token() == Token.SET) {
            this.lexer.nextToken();
            SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause();
            values.setParent(stmt);
            stmt.getValuesList().add(values);

            while(true) {
               stmt.addColumn(this.exprParser.name());
               if (this.lexer.token() == Token.COLONEQ) {
                  this.lexer.nextToken();
               } else {
                  this.accept(Token.EQ);
               }

               values.addValue(this.exprParser.expr());
               if (this.lexer.token() != Token.COMMA) {
                  break;
               }

               this.lexer.nextToken();
            }
         } else if (this.lexer.token() == Token.LPAREN) {
            SQLSelect select = this.createSQLSelectParser().select();
            SQLQueryExpr queryExpr = new SQLQueryExpr(select);
            stmt.setQuery(queryExpr);
         }
      } else {
         this.lexer.nextToken();
         this.parseValueClause(stmt.getValuesList(), (List)null, 0, stmt);
      }

      return stmt;
   }

   protected SQLStatement parseLoad() {
      this.acceptIdentifier("LOAD");
      if (this.lexer.identifierEquals("DATA")) {
         SQLStatement stmt = this.parseLoadDataInFile();
         return stmt;
      } else if (this.lexer.token() == Token.INDEX) {
         this.lexer.nextToken();
         SQLStatement stmt = this.parseLoadIndexIntoCheck();
         return stmt;
      } else if (this.lexer.identifierEquals("XML")) {
         SQLStatement stmt = this.parseLoadXml();
         return stmt;
      } else {
         throw new ParserException("TODO. " + this.lexer.info());
      }
   }

   private SQLLoadIndexIntoCacheStatement parseLoadIndexIntoCheck() {
      this.accept(Token.INTO);
      this.accept(Token.CACHE);
      SQLLoadIndexIntoCacheStatement stmt = new SQLLoadIndexIntoCacheStatement();

      while(true) {
         SQLName table = this.exprParser.name();
         MySqlTableTableSource mySqlTableTableSource = new MySqlTableTableSource(table);
         stmt.getTables().add(mySqlTableTableSource);
         if (this.lexer.token() == Token.PARTITION) {
            mySqlTableTableSource.setPartition(true);
            this.lexer.nextToken();
            if (this.lexer.token() == Token.LPAREN) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.ALL) {
                  mySqlTableTableSource.setAll(true);
                  this.lexer.nextToken();
               } else {
                  while(true) {
                     mySqlTableTableSource.getPartitionList().add(new SQLIdentifierExpr(this.lexer.stringVal()));
                     this.lexer.nextToken();
                     if (this.lexer.token() != Token.COMMA) {
                        break;
                     }

                     this.lexer.nextToken();
                  }
               }

               if (this.lexer.token() != Token.RPAREN) {
                  break;
               }

               this.lexer.nextToken();
            }
         }

         if (this.lexer.token() == Token.INDEX || this.lexer.token() == Token.KEY) {
            mySqlTableTableSource.setIndexOrKey(new SQLIdentifierExpr(this.lexer.stringVal()));
            this.lexer.nextToken();
            if (this.lexer.token() == Token.LPAREN) {
               this.lexer.nextToken();
            }

            while(true) {
               mySqlTableTableSource.getIndexList().add(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
               if (this.lexer.token() != Token.COMMA) {
                  if (this.lexer.token() == Token.RPAREN) {
                     this.lexer.nextToken();
                  }
                  break;
               }

               this.lexer.nextToken();
            }
         }

         if (this.lexer.identifierEquals("IGNORE")) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("LEAVES")) {
               this.lexer.nextToken();
            }

            mySqlTableTableSource.setIgnoreLeaves(true);
         }

         if (this.lexer.token() != Token.COMMA) {
            break;
         }

         this.lexer.nextToken();
      }

      this.lexer.nextToken();
      return stmt;
   }

   protected MariadbLoadXmlStatement parseLoadXml() {
      this.acceptIdentifier("XML");
      MariadbLoadXmlStatement stmt = new MariadbLoadXmlStatement();
      if (this.lexer.identifierEquals(FnvHash.Constants.LOW_PRIORITY)) {
         stmt.setLowPriority(true);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals("CONCURRENT")) {
         stmt.setConcurrent(true);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals("LOCAL")) {
         stmt.setLocal(true);
         this.lexer.nextToken();
      }

      this.acceptIdentifier("INFILE");
      SQLLiteralExpr fileName = (SQLLiteralExpr)this.exprParser.expr();
      stmt.setFileName(fileName);
      if (this.lexer.token() == Token.REPLACE) {
         stmt.setReplicate(true);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.IGNORE)) {
         stmt.setIgnore(true);
         this.lexer.nextToken();
      }

      this.accept(Token.INTO);
      this.accept(Token.TABLE);
      SQLName tableName = this.exprParser.name();
      stmt.setTableName(tableName);
      if (this.lexer.identifierEquals(FnvHash.Constants.CHARACTER)) {
         this.lexer.nextToken();
         this.accept(Token.SET);
         String charset = this.lexer.stringVal();
         this.lexer.nextToken();
         stmt.setCharset(charset);
      }

      if (this.lexer.identifierEquals("ROWS")) {
         this.lexer.nextToken();
         this.acceptIdentifier("IDENTIFIED");
         this.accept(Token.BY);
         SQLExpr rowsIdentifiedBy = this.exprParser.expr();
         stmt.setRowsIdentifiedBy(rowsIdentifiedBy);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.IGNORE)) {
         this.lexer.nextToken();
         stmt.setIgnoreLinesNumber(this.exprParser.expr());
         if (this.lexer.identifierEquals("LINES") || this.lexer.identifierEquals("ROWS")) {
            this.lexer.nextToken();
         }
      }

      if (this.lexer.token() == Token.LPAREN) {
         this.lexer.nextToken();
         this.exprParser.exprList(stmt.getColumns(), stmt);
         this.accept(Token.RPAREN);
      }

      if (this.lexer.token() == Token.SET) {
         this.lexer.nextToken();
         this.exprParser.exprList(stmt.getSetList(), stmt);
      }

      return stmt;
   }

   protected MariadbLoadDataInFileStatement parseLoadDataInFile() {
      this.acceptIdentifier("DATA");
      MariadbLoadDataInFileStatement stmt = new MariadbLoadDataInFileStatement();
      if (this.lexer.identifierEquals(FnvHash.Constants.LOW_PRIORITY)) {
         stmt.setLowPriority(true);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals("CONCURRENT")) {
         stmt.setConcurrent(true);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals("LOCAL")) {
         stmt.setLocal(true);
         this.lexer.nextToken();
      }

      this.acceptIdentifier("INFILE");
      SQLLiteralExpr fileName = (SQLLiteralExpr)this.exprParser.expr();
      stmt.setFileName(fileName);
      if (this.lexer.token() == Token.REPLACE) {
         stmt.setReplicate(true);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.IGNORE)) {
         stmt.setIgnore(true);
         this.lexer.nextToken();
      }

      this.accept(Token.INTO);
      this.accept(Token.TABLE);
      SQLName tableName = this.exprParser.name();
      stmt.setTableName(tableName);
      if (this.lexer.token() == Token.PARTITION) {
         this.lexer.nextToken();
         this.accept(Token.LPAREN);

         while(true) {
            SQLName partitionName = this.exprParser.name();
            stmt.getPartitionNames().add(partitionName);
            if (this.lexer.token() != Token.COMMA) {
               this.accept(Token.RPAREN);
               break;
            }

            this.lexer.nextToken();
         }
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.CHARACTER)) {
         this.lexer.nextToken();
         this.accept(Token.SET);
         String charset = this.lexer.stringVal();
         this.lexer.nextToken();
         stmt.setCharset(charset);
      }

      if (this.lexer.identifierEquals("FIELDS") || this.lexer.identifierEquals("COLUMNS")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("TERMINATED")) {
            this.lexer.nextToken();
            this.accept(Token.BY);
            if (this.lexer.token() == Token.LITERAL_CHARS) {
               stmt.setColumnsTerminatedBy(new SQLCharExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
            } else {
               SQLExpr primary = this.exprParser.primary();
               if (!(primary instanceof SQLHexExpr)) {
                  throw new ParserException("invalid expr for columns terminated : " + primary);
               }

               stmt.setColumnsTerminatedBy((SQLHexExpr)primary);
            }
         }

         if (this.lexer.identifierEquals("OPTIONALLY")) {
            stmt.setColumnsEnclosedOptionally(true);
            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("ENCLOSED")) {
            this.lexer.nextToken();
            this.accept(Token.BY);
            stmt.setColumnsEnclosedBy(new SQLCharExpr(this.lexer.stringVal()));
            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("ESCAPED")) {
            this.lexer.nextToken();
            this.accept(Token.BY);
            stmt.setColumnsEscaped(new SQLCharExpr(this.lexer.stringVal()));
            this.lexer.nextToken();
         }
      }

      if (this.lexer.identifierEquals("LINES")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("STARTING")) {
            this.lexer.nextToken();
            this.accept(Token.BY);
            if (this.lexer.token() == Token.LITERAL_CHARS) {
               stmt.setLinesStartingBy(new SQLCharExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
            } else {
               SQLExpr primary = this.exprParser.primary();
               if (!(primary instanceof SQLHexExpr)) {
                  throw new ParserException("invalid expr for lines starting : " + primary);
               }

               stmt.setLinesStartingBy((SQLHexExpr)primary);
            }
         }

         if (this.lexer.identifierEquals("TERMINATED")) {
            this.lexer.nextToken();
            this.accept(Token.BY);
            if (this.lexer.token() == Token.LITERAL_CHARS) {
               stmt.setLinesTerminatedBy(new SQLCharExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
            } else {
               SQLExpr primary = this.exprParser.primary();
               if (!(primary instanceof SQLHexExpr)) {
                  throw new ParserException("invalid expr for lines terminated : " + primary);
               }

               stmt.setLinesTerminatedBy((SQLHexExpr)primary);
            }
         }
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.IGNORE)) {
         this.lexer.nextToken();
         stmt.setIgnoreLinesNumber(this.exprParser.expr());
         if (this.lexer.identifierEquals("LINES") || this.lexer.identifierEquals("ROWS")) {
            this.lexer.nextToken();
         }
      }

      if (this.lexer.token() == Token.LPAREN) {
         this.lexer.nextToken();
         this.exprParser.exprList(stmt.getColumns(), stmt);
         this.accept(Token.RPAREN);
      }

      if (this.lexer.token() == Token.SET) {
         this.lexer.nextToken();
         this.exprParser.exprList(stmt.getSetList(), stmt);
      }

      return stmt;
   }

   public MariadbPrepareStatement parsePrepare() {
      this.acceptIdentifier("PREPARE");
      SQLName name = this.exprParser.name();
      this.accept(Token.FROM);
      SQLExpr from = this.exprParser.expr();
      return new MariadbPrepareStatement(name, from);
   }

   public MariadbExecuteStatement parseExecute() {
      MariadbExecuteStatement stmt = new MariadbExecuteStatement();
      SQLName statementName = this.exprParser.name();
      stmt.setStatementName(statementName);
      if (this.lexer.identifierEquals("USING")) {
         this.lexer.nextToken();
         this.exprParser.exprList(stmt.getParameters(), stmt);
      } else if (this.lexer.token() == Token.IDENTIFIER) {
         this.exprParser.exprList(stmt.getParameters(), stmt);
      }

      return stmt;
   }

   public MariadbExecuteForAdsStatement parseExecuteForAds() {
      MariadbExecuteForAdsStatement stmt = new MariadbExecuteForAdsStatement();
      stmt.setAction(this.exprParser.name());
      stmt.setRole(this.exprParser.name());
      stmt.setTargetId(this.exprParser.charExpr());
      if (this.lexer.token() == Token.IDENTIFIER) {
         stmt.setStatus(this.exprParser.name());
      }

      return stmt;
   }

   public MariadbDeallocatePrepareStatement parseDeallocatePrepare() {
      this.acceptIdentifier("DEALLOCATE");
      this.acceptIdentifier("PREPARE");
      MariadbDeallocatePrepareStatement stmt = new MariadbDeallocatePrepareStatement();
      SQLName statementName = this.exprParser.name();
      stmt.setStatementName(statementName);
      return stmt;
   }

   public SQLInsertStatement parseInsert() {
      MariadbInsertStatement stmt = new MariadbInsertStatement();
      SQLName tableName = null;
      if (this.lexer.token() == Token.INSERT) {
         this.lexer.nextToken();

         while(this.lexer.token() == Token.IDENTIFIER) {
            long hash = this.lexer.hash_lower();
            if (hash == FnvHash.Constants.LOW_PRIORITY) {
               stmt.setLowPriority(true);
               this.lexer.nextToken();
            } else if (hash == FnvHash.Constants.DELAYED) {
               stmt.setDelayed(true);
               this.lexer.nextToken();
            } else if (hash == FnvHash.Constants.HIGH_PRIORITY) {
               stmt.setHighPriority(true);
               this.lexer.nextToken();
            } else if (hash == FnvHash.Constants.IGNORE) {
               stmt.setIgnore(true);
               this.lexer.nextToken();
            } else {
               if (hash != FnvHash.Constants.ROLLBACK_ON_FAIL) {
                  break;
               }

               stmt.setRollbackOnFail(true);
               this.lexer.nextToken();
            }
         }

         if (this.lexer.token() == Token.HINT) {
            List<SQLCommentHint> hints = this.exprParser.parseHints();
            stmt.setHints(hints);
         }

         if (this.lexer.token() == Token.INTO) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.TABLE) {
               this.lexer.nextToken();
            }
         } else if (this.lexer.identifierEquals(FnvHash.Constants.OVERWRITE)) {
            this.lexer.nextToken();
            stmt.setOverwrite(true);
            if (this.lexer.token() == Token.TABLE) {
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.INTO) {
               this.lexer.nextToken();
            }
         }

         if (this.lexer.token() == Token.LINE_COMMENT) {
            this.lexer.nextToken();
         }

         if (this.lexer.token() == Token.FULLTEXT) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals(FnvHash.Constants.DICTIONARY)) {
               this.lexer.nextToken();
               stmt.setFulltextDictionary(true);
            }
         }

         tableName = this.exprParser.name();
         stmt.setTableName(tableName);
         if (this.lexer.token() == Token.HINT) {
            String comment = "/*" + this.lexer.stringVal() + "*/";
            this.lexer.nextToken();
            stmt.getTableSource().addAfterComment(comment);
         }

         if (this.lexer.token() == Token.IDENTIFIER && !this.lexer.identifierEquals(FnvHash.Constants.VALUE)) {
            stmt.setAlias(this.lexer.stringVal());
            this.lexer.nextToken();
         }

         if (this.lexer.token() == Token.WITH) {
            SQLSelectStatement withStmt = (SQLSelectStatement)this.parseWith();
            stmt.setQuery(withStmt.getSelect());
         }

         if (this.lexer.token() == Token.PARTITION) {
            this.lexer.nextToken();
            this.accept(Token.LPAREN);

            while(true) {
               SQLAssignItem ptExpr = new SQLAssignItem();
               ptExpr.setTarget(this.exprParser.name());
               if (this.lexer.token() == Token.EQ) {
                  this.lexer.nextToken();
                  SQLExpr ptValue = this.exprParser.expr();
                  ptExpr.setValue(ptValue);
               }

               stmt.addPartition(ptExpr);
               if (this.lexer.token() != Token.COMMA) {
                  this.accept(Token.RPAREN);
                  if (this.lexer.token() == Token.IF) {
                     this.lexer.nextToken();
                     this.accept(Token.NOT);
                     this.accept(Token.EXISTS);
                     stmt.setIfNotExists(true);
                  }
                  break;
               }

               this.lexer.nextToken();
            }
         }
      }

      int columnSize = 0;
      List<SQLColumnDefinition> columnDefinitionList = null;
      if (this.lexer.token() == Token.LPAREN) {
         boolean useInsertColumnsCache = this.lexer.isEnabled(SQLParserFeature.UseInsertColumnsCache);
         InsertColumnsCache insertColumnsCache = null;
         long tableNameHash = 0L;
         InsertColumnsCache.Entry cachedColumns = null;
         if (useInsertColumnsCache) {
            insertColumnsCache = this.insertColumnsCache;
            if (insertColumnsCache == null) {
               insertColumnsCache = InsertColumnsCache.global;
            }

            if (tableName != null) {
               tableNameHash = tableName.nameHashCode64();
               cachedColumns = insertColumnsCache.get(tableNameHash);
            }
         }

         SchemaObject tableObject = null;
         int pos = this.lexer.pos();
         if (cachedColumns != null && this.lexer.text.startsWith(cachedColumns.columnsString, pos)) {
            if (!this.lexer.isEnabled(SQLParserFeature.OptimizedForParameterized)) {
               List<SQLExpr> columns = stmt.getColumns();
               List<SQLExpr> cachedColumns2 = cachedColumns.columns;
               int i = 0;

               for(int size = cachedColumns2.size(); i < size; ++i) {
                  columns.add(((SQLExpr)cachedColumns2.get(i)).clone());
               }
            }

            stmt.setColumnsString(cachedColumns.columnsFormattedString, cachedColumns.columnsFormattedStringHash);
            int p2 = pos + cachedColumns.columnsString.length();
            this.lexer.reset(p2);
            this.lexer.nextToken();
         } else {
            Lexer.SavePoint mark = this.lexer.mark();
            this.lexer.nextToken();
            if (this.lexer.token() == Token.SELECT) {
               this.lexer.reset(mark);
               SQLSelect select = this.exprParser.createSelectParser().select();
               select.setParent(stmt);
               stmt.setQuery(select);
            } else {
               if (this.repository != null && this.lexer.isEnabled(SQLParserFeature.InsertValueCheckType)) {
                  tableObject = this.repository.findTable(tableName.nameHashCode64());
               }

               if (tableObject != null) {
                  columnDefinitionList = new ArrayList();
               }

               List<SQLExpr> columns = stmt.getColumns();
               if (this.lexer.token() != Token.RPAREN) {
                  while(true) {
                     Token token = this.lexer.token();
                     String identName;
                     long hash;
                     if (token == Token.IDENTIFIER) {
                        identName = this.lexer.stringVal();
                        hash = this.lexer.hash_lower();
                     } else if (token == Token.LITERAL_CHARS) {
                        if (this.lexer.isEnabled(SQLParserFeature.IgnoreNameQuotes)) {
                           identName = this.lexer.stringVal();
                        } else {
                           identName = '\'' + this.lexer.stringVal() + '\'';
                        }

                        hash = 0L;
                     } else if (token == Token.LITERAL_ALIAS) {
                        identName = this.lexer.stringVal();
                        if (this.lexer.isEnabled(SQLParserFeature.IgnoreNameQuotes)) {
                           identName = SQLUtils.normalize(identName, this.dbType);
                        }

                        hash = 0L;
                     } else {
                        identName = this.lexer.stringVal();
                        hash = 0L;
                     }

                     this.lexer.nextTokenComma();

                     SQLExpr expr;
                     String propertyName;
                     for(expr = new SQLIdentifierExpr(identName, hash); this.lexer.token() == Token.DOT; expr = new SQLPropertyExpr(expr, propertyName)) {
                        this.lexer.nextToken();
                        propertyName = this.lexer.stringVal();
                        this.lexer.nextToken();
                     }

                     expr.setParent(stmt);
                     columns.add(expr);
                     ++columnSize;
                     if (tableObject != null) {
                        SQLColumnDefinition columnDefinition = tableObject.findColumn(hash);
                        columnDefinitionList.add(columnDefinition);
                     }

                     if (this.lexer.token() != Token.COMMA) {
                        columnSize = stmt.getColumns().size();
                        if (insertColumnsCache == null || tableName == null) {
                           break;
                        }

                        identName = this.lexer.subString(pos, this.lexer.pos() - pos);
                        List<SQLExpr> clonedColumns = new ArrayList(columnSize);

                        for(int i = 0; i < columns.size(); ++i) {
                           clonedColumns.add(((SQLExpr)columns.get(i)).clone());
                        }

                        StringBuilder buf = new StringBuilder();
                        SQLASTOutputVisitor outputVisitor = SQLUtils.createOutputVisitor(buf, this.dbType);
                        outputVisitor.printInsertColumns(columns);
                        String formattedColumnsString = buf.toString();
                        long columnsFormattedStringHash = FnvHash.fnv1a_64_lower(formattedColumnsString);
                        insertColumnsCache.put(tableName.hashCode64(), identName, formattedColumnsString, clonedColumns);
                        stmt.setColumnsString(formattedColumnsString, columnsFormattedStringHash);
                        break;
                     }

                     this.lexer.nextTokenIdent();
                  }
               }

               this.accept(Token.RPAREN);
            }
         }
      }

      List<SQLCommentHint> commentHints = null;
      if (this.lexer.token() == Token.HINT) {
         commentHints = this.exprParser.parseHints();
      } else if (this.lexer.token() == Token.LINE_COMMENT) {
         this.lexer.nextToken();
      }

      if (this.lexer.token() != Token.VALUES && !this.lexer.identifierEquals(FnvHash.Constants.VALUE)) {
         if (this.lexer.token() == Token.SET) {
            this.lexer.nextToken();
            SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause();
            stmt.addValueCause(values);

            while(true) {
               SQLName name = this.exprParser.name();
               stmt.addColumn(name);
               if (this.lexer.token() == Token.EQ) {
                  this.lexer.nextToken();
               } else {
                  this.accept(Token.COLONEQ);
               }

               values.addValue(this.exprParser.expr());
               if (this.lexer.token() != Token.COMMA) {
                  break;
               }

               this.lexer.nextToken();
            }
         } else if (this.lexer.token() == Token.SELECT) {
            SQLSelect select = this.exprParser.createSelectParser().select();
            if (commentHints != null && !commentHints.isEmpty()) {
               select.setHeadHint((SQLHint)commentHints.get(0));
            }

            select.setParent(stmt);
            stmt.setQuery(select);
         } else if (this.lexer.token() == Token.LPAREN) {
            this.lexer.nextToken();
            SQLSelect select = this.exprParser.createSelectParser().select();
            select.setParent(stmt);
            stmt.setQuery(select);
            this.accept(Token.RPAREN);
         } else if (this.lexer.token() == Token.WITH) {
            SQLSelect query = this.exprParser.createSelectParser().select();
            stmt.setQuery(query);
         }
      } else {
         this.lexer.nextTokenLParen();
         if (this.lexer.isEnabled(SQLParserFeature.InsertReader)) {
            return stmt;
         }

         if (this.lexer.isEnabled(SQLParserFeature.InsertValueNative)) {
            this.parseValueClauseNative(stmt.getValuesList(), columnDefinitionList, columnSize, stmt);
         } else {
            this.parseValueClause(stmt.getValuesList(), columnDefinitionList, columnSize, stmt);
         }
      }

      if (this.lexer.token() == Token.ON) {
         this.lexer.nextToken();
         this.acceptIdentifier("DUPLICATE");
         this.accept(Token.KEY);
         this.accept(Token.UPDATE);
         List<SQLExpr> duplicateKeyUpdate = stmt.getDuplicateKeyUpdate();

         while(true) {
            SQLName name = this.exprParser.name();
            this.accept(Token.EQ);

            SQLExpr value;
            try {
               value = this.exprParser.expr();
            } catch (EOFParserException e) {
               throw new ParserException("EOF, " + name + "=", e);
            }

            SQLBinaryOpExpr assignment = new SQLBinaryOpExpr(name, SQLBinaryOperator.Equality, value);
            assignment.setParent(stmt);
            duplicateKeyUpdate.add(assignment);
            if (this.lexer.token() != Token.COMMA) {
               break;
            }

            this.lexer.nextTokenIdent();
         }
      }

      return stmt;
   }

   public MariadbSelectParser createSQLSelectParser() {
      return new MariadbSelectParser(this.exprParser, this.selectListCache);
   }

   public SQLStatement parseSet() {
      this.accept(Token.SET);
      if (this.lexer.identifierEquals(FnvHash.Constants.PASSWORD)) {
         this.lexer.nextToken();
         SQLSetStatement stmt = new SQLSetStatement();
         stmt.setDbType(this.dbType);
         stmt.setOption(SQLSetStatement.Option.PASSWORD);
         SQLExpr user = null;
         if (this.lexer.token() == Token.FOR) {
            this.lexer.nextToken();
            user = this.exprParser.name();
         }

         this.accept(Token.EQ);
         SQLExpr password = this.exprParser.expr();
         stmt.set(user, password);
         return stmt;
      } else {
         Boolean global = null;
         Boolean session = null;
         boolean local = false;
         if (this.lexer.identifierEquals("GLOBAL")) {
            global = Boolean.TRUE;
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals(FnvHash.Constants.SESSION)) {
            session = Boolean.TRUE;
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals(FnvHash.Constants.LOCAL)) {
            this.lexer.nextToken();
            local = true;
         }

         if (this.lexer.identifierEquals(FnvHash.Constants.TRANSACTION)) {
            MariadbSetTransactionStatement stmt = new MariadbSetTransactionStatement();
            stmt.setGlobal(global);
            stmt.setSession(session);
            if (local) {
               stmt.setLocal(true);
            }

            this.lexer.nextToken();
            if (this.lexer.identifierEquals("ISOLATION")) {
               this.lexer.nextToken();
               this.acceptIdentifier("LEVEL");
               if (this.lexer.identifierEquals("READ")) {
                  this.lexer.nextToken();
                  if (this.lexer.identifierEquals("UNCOMMITTED")) {
                     stmt.setIsolationLevel("READ UNCOMMITTED");
                     this.lexer.nextToken();
                  } else if (this.lexer.identifierEquals("WRITE")) {
                     stmt.setIsolationLevel("READ WRITE");
                     this.lexer.nextToken();
                  } else if (this.lexer.identifierEquals("ONLY")) {
                     stmt.setIsolationLevel("READ ONLY");
                     this.lexer.nextToken();
                  } else {
                     if (!this.lexer.identifierEquals("COMMITTED")) {
                        throw new ParserException("UNKOWN TRANSACTION LEVEL : " + this.lexer.stringVal() + ", " + this.lexer.info());
                     }

                     stmt.setIsolationLevel("READ COMMITTED");
                     this.lexer.nextToken();
                  }
               } else if (this.lexer.identifierEquals("SERIALIZABLE")) {
                  stmt.setIsolationLevel("SERIALIZABLE");
                  this.lexer.nextToken();
               } else {
                  if (!this.lexer.identifierEquals("REPEATABLE")) {
                     throw new ParserException("UNKOWN TRANSACTION LEVEL : " + this.lexer.stringVal() + ", " + this.lexer.info());
                  }

                  this.lexer.nextToken();
                  if (!this.lexer.identifierEquals("READ")) {
                     throw new ParserException("UNKOWN TRANSACTION LEVEL : " + this.lexer.stringVal() + ", " + this.lexer.info());
                  }

                  stmt.setIsolationLevel("REPEATABLE READ");
                  this.lexer.nextToken();
               }
            } else if (this.lexer.identifierEquals(FnvHash.Constants.POLICY)) {
               this.lexer.nextToken();
               SQLExpr policy = this.exprParser.primary();
               stmt.setPolicy(policy);
            } else if (this.lexer.identifierEquals("READ")) {
               this.lexer.nextToken();
               if (this.lexer.identifierEquals("ONLY")) {
                  stmt.setAccessModel("ONLY");
                  this.lexer.nextToken();
               } else {
                  if (!this.lexer.identifierEquals("WRITE")) {
                     throw new ParserException("UNKOWN ACCESS MODEL : " + this.lexer.stringVal() + ", " + this.lexer.info());
                  }

                  stmt.setAccessModel("WRITE");
                  this.lexer.nextToken();
               }
            }

            return stmt;
         } else {
            SQLSetStatement stmt = new SQLSetStatement(this.getDbType());
            this.parseAssignItems(stmt.getItems(), stmt, true);
            if (global != null) {
               SQLVariantRefExpr varRef = (SQLVariantRefExpr)((SQLAssignItem)stmt.getItems().get(0)).getTarget();
               varRef.setGlobal(true);
            }

            if (session != null) {
               SQLVariantRefExpr varRef = (SQLVariantRefExpr)((SQLAssignItem)stmt.getItems().get(0)).getTarget();
               varRef.setSession(true);
            }

            if (this.lexer.token() == Token.HINT) {
               stmt.setHints(this.exprParser.parseHints());
            }

            return stmt;
         }
      }
   }

   public SQLStatement parseAlter() {
      List<String> comments = null;
      if (this.lexer.isKeepComments() && this.lexer.hasComment()) {
         comments = this.lexer.readAndResetComments();
      }

      Lexer.SavePoint mark = this.lexer.mark();
      this.accept(Token.ALTER);
      if (this.lexer.token() == Token.USER) {
         return this.parseAlterUser();
      } else {
         boolean online = false;
         boolean offline = false;
         if (this.lexer.identifierEquals("ONLINE")) {
            online = true;
            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("OFFLINE")) {
            offline = true;
            this.lexer.nextToken();
         }

         boolean ignore = false;
         if (this.lexer.identifierEquals(FnvHash.Constants.IGNORE)) {
            ignore = true;
            this.lexer.nextToken();
         }

         if (this.lexer.token() == Token.TABLE) {
            SQLStatement alterTable = this.parseAlterTable(ignore, online, offline);
            if (comments != null) {
               alterTable.addBeforeComment(comments);
            }

            return alterTable;
         } else if (this.lexer.token() != Token.DATABASE && this.lexer.token() != Token.SCHEMA) {
            if (this.lexer.identifierEquals(FnvHash.Constants.EVENT)) {
               return this.parseAlterEvent();
            } else if (this.lexer.token() == Token.FUNCTION) {
               return this.parseAlterFunction();
            } else if (this.lexer.token() == Token.PROCEDURE) {
               return this.parseAlterProcedure();
            } else if (this.lexer.token() == Token.TABLESPACE) {
               return this.parseAlterTableSpace();
            } else if (this.lexer.token() == Token.VIEW) {
               return this.parseAlterView();
            } else if (this.lexer.token() == Token.SEQUENCE) {
               this.lexer.reset(mark);
               return this.parseAlterSequence();
            } else if (this.lexer.identifierEquals(FnvHash.Constants.LOGFILE)) {
               return this.parseAlterLogFileGroup();
            } else if (this.lexer.identifierEquals(FnvHash.Constants.SERVER)) {
               return this.parseAlterServer();
            } else if (this.lexer.identifierEquals(FnvHash.Constants.ALGORITHM)) {
               return this.parseAlterView();
            } else if (this.lexer.identifierEquals(FnvHash.Constants.OUTLINE)) {
               this.lexer.reset(mark);
               return this.parseAlterOutline();
            } else if (this.lexer.token() == Token.FULLTEXT) {
               this.lexer.reset(mark);
               return this.parseAlterFullTextCharFilter();
            } else {
               if (this.lexer.token() == Token.INDEX) {
                  this.lexer.reset(mark);
                  this.accept(Token.ALTER);
                  this.accept(Token.INDEX);
                  SQLAlterIndexStatement stmt = new SQLAlterIndexStatement();
                  stmt.setName(this.exprParser.name());
                  this.accept(Token.SET);
                  this.accept(Token.FULLTEXT);
               }

               if (this.lexer.identifierEquals(FnvHash.Constants.DEFINER)) {
                  Lexer.SavePoint savePoint = this.lexer.mark();
                  this.lexer.nextToken();
                  this.accept(Token.EQ);
                  this.getExprParser().userName();
                  if (this.lexer.identifierEquals(FnvHash.Constants.EVENT)) {
                     this.lexer.reset(savePoint);
                     return this.parseAlterEvent();
                  } else {
                     this.lexer.reset(savePoint);
                     return this.parseAlterView();
                  }
               } else if (this.lexer.identifierEquals("TABLEGROUP")) {
                  this.lexer.reset(mark);
                  return this.parseAlterTableGroup();
               } else if (this.lexer.identifierEquals("SYSTEM")) {
                  this.lexer.reset(mark);
                  return this.parseAlterSystem();
               } else if (this.lexer.identifierEquals(FnvHash.Constants.RESOURCE)) {
                  this.lexer.reset(mark);
                  return this.parseAlterResourceGroup();
               } else if (this.lexer.identifierEquals(FnvHash.Constants.MATERIALIZED)) {
                  this.lexer.reset(mark);
                  return this.parseAlterMaterialized();
               } else {
                  throw new ParserException("TODO " + this.lexer.info());
               }
            }
         } else {
            return this.parseAlterDatabase();
         }
      }
   }

   private SQLStatement parseAddManageInstanceGroup() {
      this.lexer.nextToken();
      MariadbManageInstanceGroupStatement stmt = new MariadbManageInstanceGroupStatement();
      stmt.setOperation(new SQLIdentifierExpr("ADD"));
      this.acceptIdentifier("INSTANCE_GROUP");

      while(true) {
         stmt.getGroupNames().add(this.exprParser.expr());
         if (this.lexer.token() != Token.COMMA) {
            this.acceptIdentifier("REPLICATION");
            this.accept(Token.EQ);
            stmt.setReplication(this.exprParser.integerExpr());
            return stmt;
         }

         this.lexer.nextToken();
      }
   }

   private SQLStatement parseAlterFullTextCharFilter() {
      this.accept(Token.ALTER);
      this.accept(Token.FULLTEXT);
      MariadbAlterFullTextStatement stmt = new MariadbAlterFullTextStatement();
      stmt.setType(this.parseMariadbFullTextType());
      SQLName name = this.exprParser.name();
      stmt.setName(name);
      this.accept(Token.SET);
      SQLAssignItem item = this.exprParser.parseAssignItem();
      stmt.setItem(item);
      return stmt;
   }

   protected FullTextType parseMariadbFullTextType() {
      FullTextType textType;
      if (this.lexer.identifierEquals(FnvHash.Constants.CHARFILTER)) {
         textType = FullTextType.CHARFILTER;
      } else if (this.lexer.identifierEquals(FnvHash.Constants.TOKENIZER)) {
         textType = FullTextType.TOKENIZER;
      } else if (this.lexer.identifierEquals(FnvHash.Constants.TOKENFILTER)) {
         textType = FullTextType.TOKENFILTER;
      } else if (this.lexer.identifierEquals(FnvHash.Constants.ANALYZER)) {
         textType = FullTextType.ANALYZER;
      } else {
         if (!this.lexer.identifierEquals(FnvHash.Constants.DICTIONARY)) {
            throw new ParserException("type of full text must be [CHARFILTER/TOKENIZER/TOKENFILTER/ANALYZER/DICTIONARY] .");
         }

         textType = FullTextType.DICTIONARY;
      }

      this.lexer.nextToken();
      return textType;
   }

   protected SQLStatement parseAlterTableGroup() {
      this.accept(Token.ALTER);
      this.acceptIdentifier("TABLEGROUP");
      SQLName name = this.exprParser.name();
      SQLAlterTableGroupStatement stmt = new SQLAlterTableGroupStatement();
      stmt.setName(name);

      do {
         SQLName key = this.exprParser.name();
         this.accept(Token.EQ);
         SQLExpr value = this.exprParser.expr();
         stmt.getOptions().add(new SQLAssignItem(key, value));
      } while(this.lexer.token() != Token.EOF);

      return stmt;
   }

   public SQLStatement parseAlterSystem() {
      this.accept(Token.ALTER);
      this.acceptIdentifier("SYSTEM");
      if (this.lexer.token() != Token.SET) {
         if (this.lexer.identifierEquals("GET")) {
            this.acceptIdentifier("GET");
            this.acceptIdentifier("CONFIG");
            SQLName name = this.exprParser.name();
            SQLAlterSystemGetConfigStatement stmt = new SQLAlterSystemGetConfigStatement();
            stmt.setName(name);
            return stmt;
         } else {
            throw new ParserException("TODO " + this.lexer.info());
         }
      } else {
         this.accept(Token.SET);
         this.acceptIdentifier("CONFIG");
         SQLAlterSystemSetConfigStatement stmt = new SQLAlterSystemSetConfigStatement();

         do {
            SQLName key = this.exprParser.name();
            this.accept(Token.EQ);
            SQLExpr value = this.exprParser.expr();
            stmt.getOptions().add(new SQLAssignItem(key, value));
         } while(this.lexer.token() != Token.EOF);

         return stmt;
      }
   }

   protected SQLStatement parseAlterOutline() {
      this.accept(Token.ALTER);
      if (this.lexer.identifierEquals(FnvHash.Constants.OUTLINE)) {
         this.lexer.nextToken();
         SQLAlterOutlineStatement stmt = new SQLAlterOutlineStatement();
         stmt.setDbType(this.dbType);
         stmt.setName(this.exprParser.name());
         if (this.lexer.identifierEquals("RESYNC")) {
            this.lexer.nextToken();
            stmt.setResync(true);
         }

         return stmt;
      } else {
         throw new ParserException("TODO " + this.lexer.info());
      }
   }

   protected SQLStatement parseAlterView() {
      if (this.lexer.token() == Token.ALTER) {
         this.lexer.nextToken();
      }

      SQLAlterViewStatement createView = new SQLAlterViewStatement(this.getDbType());
      if (this.lexer.identifierEquals("ALGORITHM")) {
         this.lexer.nextToken();
         this.accept(Token.EQ);
         String algorithm = this.lexer.stringVal();
         createView.setAlgorithm(algorithm);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals("DEFINER")) {
         this.lexer.nextToken();
         this.accept(Token.EQ);
         SQLName definer = (SQLName)this.exprParser.expr();
         createView.setDefiner(definer);
      }

      if (this.lexer.identifierEquals("SQL")) {
         this.lexer.nextToken();
         this.acceptIdentifier("SECURITY");
         String sqlSecurity = this.lexer.stringVal();
         createView.setSqlSecurity(sqlSecurity);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.FORCE)) {
         this.lexer.nextToken();
         createView.setForce(true);
      }

      this.accept(Token.VIEW);
      if (this.lexer.token() == Token.IF || this.lexer.identifierEquals("IF")) {
         this.lexer.nextToken();
         this.accept(Token.NOT);
         this.accept(Token.EXISTS);
         createView.setIfNotExists(true);
      }

      createView.setName(this.exprParser.name());
      if (this.lexer.token() == Token.LPAREN) {
         this.lexer.nextToken();

         while(true) {
            if (this.lexer.token() == Token.CONSTRAINT) {
               SQLTableConstraint constraint = (SQLTableConstraint)this.exprParser.parseConstaint();
               createView.addColumn(constraint);
            } else {
               SQLColumnDefinition column = new SQLColumnDefinition();
               column.setDbType(this.dbType);
               SQLName expr = this.exprParser.name();
               column.setName(expr);
               this.exprParser.parseColumnRest(column);
               if (this.lexer.token() == Token.COMMENT) {
                  this.lexer.nextToken();
                  SQLExpr comment;
                  if (this.lexer.token() == Token.LITERAL_ALIAS) {
                     String alias = this.lexer.stringVal();
                     if (alias.length() > 2 && alias.charAt(0) == '"' && alias.charAt(alias.length() - 1) == '"') {
                        alias = alias.substring(1, alias.length() - 1);
                     }

                     comment = new SQLCharExpr(alias);
                     this.lexer.nextToken();
                  } else {
                     comment = this.exprParser.primary();
                  }

                  column.setComment(comment);
               }

               column.setParent(createView);
               createView.addColumn(column);
            }

            if (this.lexer.token() != Token.COMMA) {
               this.accept(Token.RPAREN);
               break;
            }

            this.lexer.nextToken();
         }
      }

      if (this.lexer.token() == Token.COMMENT) {
         this.lexer.nextToken();
         SQLCharExpr comment = (SQLCharExpr)this.exprParser.primary();
         createView.setComment(comment);
      }

      this.accept(Token.AS);
      SQLSelectParser selectParser = this.createSQLSelectParser();
      createView.setSubQuery(selectParser.select());
      if (this.lexer.token() == Token.WITH) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("CASCADED")) {
            createView.setWithCascaded(true);
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("LOCAL")) {
            createView.setWithLocal(true);
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("READ")) {
            this.lexer.nextToken();
            this.accept(Token.ONLY);
            createView.setWithReadOnly(true);
         }

         if (this.lexer.token() == Token.CHECK) {
            this.lexer.nextToken();
            this.acceptIdentifier("OPTION");
            createView.setWithCheckOption(true);
         }
      }

      return createView;
   }

   protected SQLStatement parseAlterTableSpace() {
      if (this.lexer.token() == Token.ALTER) {
         this.lexer.nextToken();
      }

      this.accept(Token.TABLESPACE);
      SQLName name = this.exprParser.name();
      MariadbAlterTablespaceStatement stmt = new MariadbAlterTablespaceStatement();
      stmt.setName(name);
      if (this.lexer.identifierEquals(FnvHash.Constants.ADD)) {
         this.lexer.nextToken();
         this.acceptIdentifier("DATAFILE");
         SQLExpr file = this.exprParser.primary();
         stmt.setAddDataFile(file);
      } else if (this.lexer.token() == Token.DROP) {
         this.lexer.nextToken();
         this.acceptIdentifier("DATAFILE");
         SQLExpr file = this.exprParser.primary();
         stmt.setDropDataFile(file);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.INITIAL_SIZE)) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         SQLExpr initialSize = this.exprParser.expr();
         stmt.setInitialSize(initialSize);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.WAIT)) {
         this.lexer.nextToken();
         stmt.setWait(true);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.ENGINE)) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         SQLExpr engine = this.exprParser.expr();
         stmt.setEngine(engine);
      }

      return stmt;
   }

   protected SQLStatement parseAlterServer() {
      if (this.lexer.token() == Token.ALTER) {
         this.lexer.nextToken();
      }

      this.acceptIdentifier("SERVER");
      SQLName name = this.exprParser.name();
      MariadbAlterServerStatement stmt = new MariadbAlterServerStatement();
      stmt.setName(name);
      this.acceptIdentifier("OPTIONS");
      this.accept(Token.LPAREN);
      if (this.lexer.token() == Token.USER) {
         this.lexer.nextToken();
         SQLExpr user = this.exprParser.name();
         stmt.setUser(user);
      }

      this.accept(Token.RPAREN);
      return stmt;
   }

   protected SQLStatement parseCreateLogFileGroup() {
      if (this.lexer.token() == Token.ALTER) {
         this.lexer.nextToken();
      }

      this.acceptIdentifier("LOGFILE");
      this.accept(Token.GROUP);
      SQLName name = this.exprParser.name();
      MariadbCreateAddLogFileGroupStatement stmt = new MariadbCreateAddLogFileGroupStatement();
      stmt.setName(name);
      this.acceptIdentifier("ADD");
      this.acceptIdentifier("UNDOFILE");
      SQLExpr fileName = this.exprParser.primary();
      stmt.setAddUndoFile(fileName);
      if (this.lexer.identifierEquals(FnvHash.Constants.INITIAL_SIZE)) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         SQLExpr initialSize = this.exprParser.expr();
         stmt.setInitialSize(initialSize);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.WAIT)) {
         this.lexer.nextToken();
         stmt.setWait(true);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.ENGINE)) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         SQLExpr engine = this.exprParser.expr();
         stmt.setEngine(engine);
      }

      return stmt;
   }

   protected SQLStatement parseAlterLogFileGroup() {
      if (this.lexer.token() == Token.ALTER) {
         this.lexer.nextToken();
      }

      this.acceptIdentifier("LOGFILE");
      this.accept(Token.GROUP);
      SQLName name = this.exprParser.name();
      MariadbAlterLogFileGroupStatement stmt = new MariadbAlterLogFileGroupStatement();
      stmt.setName(name);
      this.acceptIdentifier("ADD");
      this.acceptIdentifier("UNDOFILE");
      SQLExpr fileName = this.exprParser.primary();
      stmt.setAddUndoFile(fileName);
      if (this.lexer.identifierEquals(FnvHash.Constants.INITIAL_SIZE)) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         SQLExpr initialSize = this.exprParser.expr();
         stmt.setInitialSize(initialSize);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.WAIT)) {
         this.lexer.nextToken();
         stmt.setWait(true);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.ENGINE)) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         SQLExpr engine = this.exprParser.expr();
         stmt.setEngine(engine);
      }

      return stmt;
   }

   protected SQLStatement parseAlterProcedure() {
      if (this.lexer.token() == Token.ALTER) {
         this.lexer.nextToken();
      }

      this.accept(Token.PROCEDURE);
      SQLAlterProcedureStatement stmt = new SQLAlterProcedureStatement();
      stmt.setDbType(this.dbType);
      SQLName name = this.exprParser.name();
      stmt.setName(name);

      while(true) {
         while(this.lexer.token() != Token.COMMENT) {
            if (this.lexer.identifierEquals(FnvHash.Constants.LANGUAGE)) {
               this.lexer.nextToken();
               this.acceptIdentifier("SQL");
               stmt.setLanguageSql(true);
            } else if (this.lexer.identifierEquals(FnvHash.Constants.SQL)) {
               this.lexer.nextToken();
               this.acceptIdentifier("SECURITY");
               SQLExpr sqlSecurity = this.exprParser.name();
               stmt.setSqlSecurity(sqlSecurity);
            } else if (!this.lexer.identifierEquals(FnvHash.Constants.CONTAINS) && this.lexer.token() != Token.CONTAINS) {
               if (this.lexer.identifierEquals(FnvHash.Constants.NO)) {
                  this.lexer.nextToken();
                  this.acceptIdentifier("SQL");
                  stmt.setNoSql(true);
               } else if (this.lexer.identifierEquals(FnvHash.Constants.READS)) {
                  this.lexer.nextToken();
                  this.acceptIdentifier("SQL");
                  this.acceptIdentifier("DATA");
                  stmt.setReadSqlData(true);
               } else {
                  if (!this.lexer.identifierEquals(FnvHash.Constants.MODIFIES)) {
                     return stmt;
                  }

                  this.lexer.nextToken();
                  this.acceptIdentifier("SQL");
                  this.acceptIdentifier("DATA");
                  stmt.setModifiesSqlData(true);
               }
            } else {
               this.lexer.nextToken();
               this.acceptIdentifier("SQL");
               stmt.setContainsSql(true);
            }
         }

         this.lexer.nextToken();
         SQLExpr comment = this.exprParser.primary();
         stmt.setComment(comment);
      }
   }

   protected SQLStatement parseAlterFunction() {
      if (this.lexer.token() == Token.ALTER) {
         this.lexer.nextToken();
      }

      this.accept(Token.FUNCTION);
      SQLAlterFunctionStatement stmt = new SQLAlterFunctionStatement();
      stmt.setDbType(this.dbType);
      SQLName name = this.exprParser.name();
      stmt.setName(name);

      while(true) {
         while(this.lexer.token() != Token.COMMENT) {
            if (this.lexer.identifierEquals(FnvHash.Constants.LANGUAGE)) {
               this.lexer.nextToken();
               this.acceptIdentifier("SQL");
               stmt.setLanguageSql(true);
            } else if (this.lexer.identifierEquals(FnvHash.Constants.SQL)) {
               this.lexer.nextToken();
               this.acceptIdentifier("SECURITY");
               SQLExpr sqlSecurity = this.exprParser.name();
               stmt.setSqlSecurity(sqlSecurity);
            } else if (!this.lexer.identifierEquals(FnvHash.Constants.CONTAINS) && this.lexer.token() != Token.CONTAINS) {
               if (this.lexer.identifierEquals(FnvHash.Constants.NO)) {
                  this.lexer.nextToken();
                  this.acceptIdentifier("SQL");
                  stmt.setNoSql(true);
               } else if (this.lexer.identifierEquals(FnvHash.Constants.READS)) {
                  this.lexer.nextToken();
                  this.acceptIdentifier("SQL");
                  this.acceptIdentifier("DATA");
                  stmt.setReadSqlData(true);
               } else {
                  if (!this.lexer.identifierEquals(FnvHash.Constants.MODIFIES)) {
                     return stmt;
                  }

                  this.lexer.nextToken();
                  this.acceptIdentifier("SQL");
                  this.acceptIdentifier("DATA");
                  stmt.setModifiesSqlData(true);
               }
            } else {
               this.lexer.nextToken();
               this.acceptIdentifier("SQL");
               stmt.setContainsSql(true);
            }
         }

         this.lexer.nextToken();
         SQLExpr comment = this.exprParser.primary();
         stmt.setComment(comment);
      }
   }

   protected SQLStatement parseCreateEvent() {
      if (this.lexer.token() == Token.CREATE) {
         this.lexer.nextToken();
      }

      MariadbCreateEventStatement stmt = new MariadbCreateEventStatement();
      if (this.lexer.identifierEquals(FnvHash.Constants.DEFINER)) {
         this.lexer.nextToken();
         this.accept(Token.EQ);
         SQLName definer = this.getExprParser().userName();
         stmt.setDefiner(definer);
         if (this.lexer.token() == Token.LPAREN) {
            this.lexer.nextToken();
            this.accept(Token.RPAREN);
         }
      }

      this.acceptIdentifier("EVENT");
      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.accept(Token.NOT);
         this.accept(Token.EXISTS);
         stmt.setIfNotExists(true);
      }

      SQLName eventName = this.exprParser.name();
      stmt.setName(eventName);

      while(this.lexer.token() == Token.ON) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals(FnvHash.Constants.SCHEDULE)) {
            this.lexer.nextToken();
            MariadbEventSchedule schedule = this.parseSchedule();
            stmt.setSchedule(schedule);
         } else {
            if (!this.lexer.identifierEquals(FnvHash.Constants.COMPLETION)) {
               throw new ParserException("TODO " + this.lexer.info());
            }

            this.lexer.nextToken();
            boolean value;
            if (this.lexer.token() == Token.NOT) {
               this.lexer.nextToken();
               value = false;
            } else {
               value = true;
            }

            this.acceptIdentifier("PRESERVE");
            stmt.setOnCompletionPreserve(value);
         }
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.RENAME)) {
         this.lexer.nextToken();
         this.accept(Token.TO);
         SQLName renameTo = this.exprParser.name();
         stmt.setRenameTo(renameTo);
      }

      if (this.lexer.token() == Token.ENABLE) {
         stmt.setEnable(true);
         this.lexer.nextToken();
      } else if (this.lexer.token() == Token.DISABLE) {
         this.lexer.nextToken();
         stmt.setEnable(false);
         if (this.lexer.token() == Token.ON) {
            this.lexer.nextToken();
            this.acceptIdentifier("SLAVE");
            stmt.setDisableOnSlave(true);
         }
      }

      if (this.lexer.token() == Token.COMMENT) {
         this.lexer.nextToken();
         SQLExpr comment = this.exprParser.primary();
         stmt.setComment(comment);
      }

      if (this.lexer.token() == Token.DO) {
         this.lexer.nextToken();
         SQLStatement eventBody = this.parseStatement();
         stmt.setEventBody(eventBody);
      } else if (this.lexer.token() == Token.IDENTIFIER) {
         SQLExpr expr = this.exprParser.expr();
         SQLExprStatement eventBody = new SQLExprStatement(expr);
         eventBody.setDbType(this.dbType);
         stmt.setEventBody(eventBody);
      }

      return stmt;
   }

   protected SQLStatement parseAlterEvent() {
      if (this.lexer.token() == Token.ALTER) {
         this.lexer.nextToken();
      }

      MariadbAlterEventStatement stmt = new MariadbAlterEventStatement();
      if (this.lexer.identifierEquals(FnvHash.Constants.DEFINER)) {
         this.lexer.nextToken();
         this.accept(Token.EQ);
         SQLName definer = this.getExprParser().userName();
         stmt.setDefiner(definer);
      }

      this.acceptIdentifier("EVENT");
      SQLName eventName = this.exprParser.name();
      stmt.setName(eventName);

      while(this.lexer.token() == Token.ON) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals(FnvHash.Constants.SCHEDULE)) {
            this.lexer.nextToken();
            MariadbEventSchedule schedule = this.parseSchedule();
            stmt.setSchedule(schedule);
         } else {
            if (!this.lexer.identifierEquals(FnvHash.Constants.COMPLETION)) {
               throw new ParserException("TODO " + this.lexer.info());
            }

            this.lexer.nextToken();
            boolean value;
            if (this.lexer.token() == Token.NOT) {
               this.lexer.nextToken();
               value = false;
            } else {
               value = true;
            }

            this.acceptIdentifier("PRESERVE");
            stmt.setOnCompletionPreserve(value);
         }
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.RENAME)) {
         this.lexer.nextToken();
         this.accept(Token.TO);
         SQLName renameTo = this.exprParser.name();
         stmt.setRenameTo(renameTo);
      }

      if (this.lexer.token() == Token.ENABLE) {
         stmt.setEnable(true);
         this.lexer.nextToken();
      } else if (this.lexer.token() == Token.DISABLE) {
         this.lexer.nextToken();
         stmt.setEnable(false);
         if (this.lexer.token() == Token.ON) {
            this.lexer.nextToken();
            this.acceptIdentifier("SLAVE");
            stmt.setDisableOnSlave(true);
         }
      }

      if (this.lexer.token() == Token.COMMENT) {
         this.lexer.nextToken();
         SQLExpr comment = this.exprParser.primary();
         stmt.setComment(comment);
      }

      if (this.lexer.token() == Token.DO) {
         this.lexer.nextToken();
         SQLStatement eventBody = this.parseStatement();
         stmt.setEventBody(eventBody);
      } else if (this.lexer.token() == Token.IDENTIFIER) {
         SQLExpr expr = this.exprParser.expr();
         SQLExprStatement eventBody = new SQLExprStatement(expr);
         eventBody.setDbType(this.dbType);
         stmt.setEventBody(eventBody);
      }

      return stmt;
   }

   private MariadbEventSchedule parseSchedule() {
      MariadbEventSchedule schedule = new MariadbEventSchedule();
      if (this.lexer.identifierEquals(FnvHash.Constants.AT)) {
         this.lexer.nextToken();
         schedule.setAt(this.exprParser.expr());
      } else if (this.lexer.identifierEquals(FnvHash.Constants.EVERY)) {
         this.lexer.nextToken();
         SQLExpr value = this.exprParser.expr();
         String unit = this.lexer.stringVal();
         this.lexer.nextToken();
         SQLIntervalExpr intervalExpr = new SQLIntervalExpr();
         intervalExpr.setValue(value);
         intervalExpr.setUnit(SQLIntervalUnit.valueOf(unit.toUpperCase()));
         schedule.setEvery(intervalExpr);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.STARTS)) {
         this.lexer.nextToken();
         schedule.setStarts(this.exprParser.expr());
         if (this.lexer.identifierEquals(FnvHash.Constants.ENDS)) {
            this.lexer.nextToken();
            schedule.setEnds(this.exprParser.expr());
         }
      } else if (this.lexer.identifierEquals(FnvHash.Constants.ENDS)) {
         this.lexer.nextToken();
         schedule.setEnds(this.exprParser.expr());
      }

      return schedule;
   }

   private boolean parseAlterSpecification(SQLAlterTableStatement stmt) {
      switch (this.lexer.token()) {
         case WITH: {
            this.lexer.nextToken();
            this.acceptIdentifier("VALIDATION");
            MariadbAlterTableValidation item = new MariadbAlterTableValidation();
            item.setWithValidation(true);
            stmt.addItem(item);
            return true;}
         case DELETE:
         case UPDATE:
         case INSERT:
         case SHOW:
         case REPLACE:
         case CREATE:
         case DESC:
         case KILL:
         case EXPLAIN:
         case LPAREN:
         case COLUMN:
         case INDEX:
         case KEY:
         case CONSTRAINT:
         case PRIMARY:
         case UNIQUE:
         case FOREIGN:
         case TO:
         case AS:
         default:
            break;
         case TRUNCATE:{
            this.lexer.nextToken();
            this.accept(Token.PARTITION);
            SQLAlterTableTruncatePartition item = new SQLAlterTableTruncatePartition();
            if (this.lexer.token() == Token.ALL) {
               item.getPartitions().add(new SQLIdentifierExpr("ALL"));
               this.lexer.nextToken();
            } else {
               this.exprParser.names(item.getPartitions(), item);
            }

            stmt.addItem(item);
            return true;}
         case DROP:{
            this.parseAlterDrop(stmt);
            return true;}
         case ALTER:{
            this.lexer.nextToken();
            if (this.lexer.token() != Token.INDEX) {
               if (this.lexer.token() != Token.CHECK && this.lexer.token() != Token.CONSTRAINT) {
                  if (this.lexer.token() == Token.COLUMN) {
                     this.lexer.nextToken();
                  }

                  MariadbAlterTableAlterColumn alterColumn = new MariadbAlterTableAlterColumn();
                  alterColumn.setColumn(this.exprParser.name());
                  if (this.lexer.token() == Token.SET) {
                     this.lexer.nextToken();
                     if (this.lexer.identifierEquals(FnvHash.Constants.VISIBLE)) {
                        this.lexer.nextToken();
                        alterColumn.setVisible(true);
                     } else if (this.lexer.identifierEquals(FnvHash.Constants.INVISIBLE)) {
                        this.lexer.nextToken();
                        alterColumn.setInvisible(true);
                     } else {
                        this.accept(Token.DEFAULT);
                        alterColumn.setDefaultExpr(this.exprParser.expr());
                     }
                  } else {
                     this.accept(Token.DROP);
                     this.accept(Token.DEFAULT);
                     alterColumn.setDropDefault(true);
                  }

                  stmt.addItem(alterColumn);
               } else {
                  this.lexer.nextToken();
                  MariadbAlterTableAlterCheck check = new MariadbAlterTableAlterCheck();
                  check.setName(this.exprParser.name());
                  boolean enforce = true;
                  if (this.lexer.token() == Token.NOT) {
                     enforce = false;
                     this.lexer.nextToken();
                  }

                  if (this.lexer.stringVal().equalsIgnoreCase("ENFORCED")) {
                     check.setEnforced(enforce);
                     this.lexer.nextToken();
                  }

                  stmt.addItem(check);
               }

               return true;
            }

            this.lexer.nextToken();
            SQLName indexName = this.exprParser.name();
            if (this.lexer.identifierEquals(FnvHash.Constants.VISIBLE)) {
               MariadbAlterTableAlterIndex index = new MariadbAlterTableAlterIndex();
               index.setIndexName(indexName);
               this.lexer.nextToken();
               index.setVisible(true);
               stmt.addItem(index);
            } else {
               if (!this.lexer.identifierEquals(FnvHash.Constants.INVISIBLE)) {
                  MariadbAlterTableAlterFullTextIndex alterIndex = new MariadbAlterTableAlterFullTextIndex();
                  alterIndex.setIndexName(indexName);
                  this.accept(Token.SET);
                  this.accept(Token.FULLTEXT);
                  if (this.lexer.token() == Token.INDEX) {
                     this.lexer.nextToken();
                     alterIndex.setAnalyzerType(AnalyzerIndexType.INDEX);
                  } else if (this.lexer.identifierEquals(FnvHash.Constants.QUERY)) {
                     this.lexer.nextToken();
                     alterIndex.setAnalyzerType(AnalyzerIndexType.QUERY);
                  }

                  this.acceptIdentifier("ANALYZER");
                  this.accept(Token.EQ);
                  alterIndex.setAnalyzerName(this.exprParser.name());
                  stmt.addItem(alterIndex);
                  return true;
               }

               MariadbAlterTableAlterIndex index = new MariadbAlterTableAlterIndex();
               index.setIndexName(indexName);
               this.lexer.nextToken();
               index.setInvisible(true);
               stmt.addItem(index);
            }
            break;}
         case CHECK:{
            this.lexer.nextToken();
            this.accept(Token.PARTITION);
            SQLAlterTableCheckPartition item = new SQLAlterTableCheckPartition();
            if (this.lexer.token() == Token.ALL) {
               this.lexer.nextToken();
               item.getPartitions().add(new SQLIdentifierExpr("ALL"));
            } else {
               this.exprParser.names(item.getPartitions(), item);
            }

            stmt.addItem(item);
            return true;}
         case SET:{
            this.lexer.nextToken();
            if (this.lexer.identifierEquals(FnvHash.Constants.RULE)) {
               SQLAlterTableSetOption setOption = new SQLAlterTableSetOption();
               SQLAssignItem item = this.exprParser.parseAssignItem();
               setOption.addOption(item);
               stmt.addItem(setOption);
            } else {
               this.acceptIdentifier("TBLPROPERTIES");
               SQLAlterTableSetOption setOption = new SQLAlterTableSetOption();
               this.accept(Token.LPAREN);

               while(true) {
                  SQLAssignItem item = this.exprParser.parseAssignItem();
                  setOption.addOption(item);
                  if (this.lexer.token() != Token.COMMA) {
                     this.accept(Token.RPAREN);
                     stmt.addItem(setOption);
                     if (this.lexer.token() == Token.ON) {
                        this.lexer.nextToken();
                        SQLName on = this.exprParser.name();
                        setOption.setOn(on);
                     }
                     break;
                  }

                  this.lexer.nextToken();
               }
            }

            return true;}
         case OPTIMIZE:{
            this.lexer.nextToken();
            this.accept(Token.PARTITION);
            SQLAlterTableOptimizePartition item = new SQLAlterTableOptimizePartition();
            if (this.lexer.token() == Token.ALL) {
               this.lexer.nextToken();
               item.getPartitions().add(new SQLIdentifierExpr("ALL"));
            } else {
               this.exprParser.names(item.getPartitions(), item);
            }

            stmt.addItem(item);
            return true;}
         case ANALYZE:{
            this.lexer.nextToken();
            this.accept(Token.PARTITION);
            SQLAlterTableAnalyzePartition item = new SQLAlterTableAnalyzePartition();
            if (this.lexer.token() == Token.ALL) {
               this.lexer.nextToken();
               item.getPartitions().add(new SQLIdentifierExpr("ALL"));
            } else {
               this.exprParser.names(item.getPartitions(), item);
            }

            stmt.addItem(item);
            return true;}
         case IDENTIFIER:
            if (this.lexer.identifierEquals(FnvHash.Constants.ADD)) {
               this.lexer.nextToken();
               boolean hasConstraint = false;
               SQLName constraintSymbol = null;
               switch (this.lexer.token()) {
                  case FULLTEXT:
                  case IDENTIFIER:{
                     if (this.lexer.token() != Token.FULLTEXT && !this.lexer.identifierEquals(FnvHash.Constants.SPATIAL) && !this.lexer.identifierEquals(FnvHash.Constants.CLUSTERED) && !this.lexer.identifierEquals(FnvHash.Constants.CLUSTERING) && !this.lexer.identifierEquals(FnvHash.Constants.ANN) && !this.lexer.identifierEquals(FnvHash.Constants.GLOBAL) && !this.lexer.identifierEquals(FnvHash.Constants.LOCAL)) {
                        if (this.lexer.identifierEquals(FnvHash.Constants.EXTPARTITION)) {
                           this.lexer.nextToken();
                           this.accept(Token.LPAREN);
                           MariadbAlterTableAddExtPartition extPartitionItem = new MariadbAlterTableAddExtPartition();
                           MariadbExtPartition partitionDef = this.parseExtPartition();
                           extPartitionItem.setExPartition(partitionDef);
                           stmt.addItem(extPartitionItem);
                           this.accept(Token.RPAREN);
                        } else {
                           this.parseAlterTableAddColumn(stmt);
                        }
                     } else {
                        SQLAlterTableAddIndex item = new SQLAlterTableAddIndex();
                        this.exprParser.parseIndex(item.getIndexDefinition());
                        stmt.addItem(item);
                     }

                     return true;}
                  case SELECT:
                  case WITH:
                  case DELETE:
                  case UPDATE:
                  case INSERT:
                  case SHOW:
                  case REPLACE:
                  case TRUNCATE:
                  case DROP:
                  case ALTER:
                  case CREATE:
                  case SET:
                  case DESC:
                  case OPTIMIZE:
                  case ANALYZE:
                  case KILL:
                  case EXPLAIN:
                  default:
                     this.parseAlterTableAddColumn(stmt);
                     return true;
                  case COLUMN:
                     this.lexer.nextToken();
                  case LPAREN:
                     this.parseAlterTableAddColumn(stmt);
                     return true;
                  case INDEX:
                  case KEY:{
                     SQLAlterTableAddIndex item = new SQLAlterTableAddIndex();
                     this.exprParser.parseIndex(item.getIndexDefinition());
                     stmt.addItem(item);
                     return true;}
                  case CONSTRAINT:{
                     hasConstraint = true;
                     this.lexer.nextToken();
                     if (this.lexer.token() == Token.IDENTIFIER) {
                        constraintSymbol = this.exprParser.name();
                        if (this.lexer.token() != Token.PRIMARY && this.lexer.token() != Token.UNIQUE && this.lexer.token() != Token.FOREIGN && this.lexer.token() != Token.CHECK) {
                           throw new ParserException("syntax error, expect PRIMARY, UNIQUE or FOREIGN, actual " + this.lexer.token() + ", " + this.lexer.info());
                        }
                     }}
                  case CHECK:
                  case PRIMARY:
                  case UNIQUE:
                  case FOREIGN:{
                     if (this.lexer.token() == Token.FOREIGN) {
                        MariadbForeignKey fk = this.getExprParser().parseForeignKey();
                        if (constraintSymbol != null) {
                           fk.setName(constraintSymbol);
                        }

                        fk.setHasConstraint(hasConstraint);
                        SQLAlterTableAddConstraint constraint = new SQLAlterTableAddConstraint(fk);
                        stmt.addItem(constraint);
                     } else if (this.lexer.token() == Token.PRIMARY) {
                        MariadbPrimaryKey pk = new MariadbPrimaryKey();
                        if (constraintSymbol != null) {
                           pk.setName(constraintSymbol);
                        }

                        pk.getIndexDefinition().setHasConstraint(hasConstraint);
                        pk.getIndexDefinition().setSymbol(constraintSymbol);
                        this.exprParser.parseIndex(pk.getIndexDefinition());
                        SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(pk);
                        stmt.addItem(item);
                     } else if (this.lexer.token() == Token.UNIQUE) {
                        MariadbUnique uk = new MariadbUnique();
                        uk.getIndexDefinition().setHasConstraint(hasConstraint);
                        uk.getIndexDefinition().setSymbol(constraintSymbol);
                        this.exprParser.parseIndex(uk.getIndexDefinition());
                        SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(uk);
                        stmt.addItem(item);
                     } else if (this.lexer.token() == Token.CHECK) {
                        this.lexer.nextToken();
                        this.accept(Token.LPAREN);
                        SQLCheck check = new SQLCheck();
                        if (null != constraintSymbol) {
                           check.setName(constraintSymbol);
                        }

                        check.setExpr(this.exprParser.expr());
                        this.accept(Token.RPAREN);
                        boolean enforce = true;
                        if (this.lexer.token() == Token.NOT) {
                           enforce = false;
                           this.lexer.nextToken();
                        }

                        if (this.lexer.stringVal().equalsIgnoreCase("ENFORCED")) {
                           check.setEnforced(enforce);
                           this.lexer.nextToken();
                        }

                        SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(check);
                        stmt.addItem(item);
                     }

                     return true;}
                  case PARTITION:{
                     this.lexer.nextToken();
                     SQLAlterTableAddPartition item = new SQLAlterTableAddPartition();
                     if (this.lexer.identifierEquals("PARTITIONS")) {
                        this.lexer.nextToken();
                        item.setPartitionCount(this.exprParser.integerExpr());
                     }

                     if (this.lexer.token() == Token.LPAREN) {
                        this.lexer.nextToken();
                        SQLPartition partition = this.getExprParser().parsePartition();
                        this.accept(Token.RPAREN);
                        item.addPartition(partition);
                     }

                     stmt.addItem(item);
                     return true;}
               }
            }

            if (this.lexer.identifierEquals(FnvHash.Constants.ALGORITHM)) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.EQ) {
                  this.lexer.nextToken();
               }

               stmt.addItem(new MariadbAlterTableOption("ALGORITHM", this.lexer.stringVal()));
               this.lexer.nextToken();
               return true;
            }

            if (this.lexer.identifierEquals(FnvHash.Constants.CHANGE)) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.COLUMN) {
                  this.lexer.nextToken();
               }

               MariadbAlterTableChangeColumn item = new MariadbAlterTableChangeColumn();
               item.setColumnName(this.exprParser.name());
               item.setNewColumnDefinition(this.exprParser.parseColumn());
               if (this.lexer.identifierEquals("AFTER")) {
                  this.lexer.nextToken();
                  item.setAfterColumn(this.exprParser.name());
               } else if (this.lexer.identifierEquals("FIRST")) {
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.IDENTIFIER) {
                     item.setFirstColumn(this.exprParser.name());
                  } else {
                     item.setFirst(true);
                  }
               }

               stmt.addItem(item);
               return true;
            }

            if (this.lexer.identifierEquals(FnvHash.Constants.CONVERT)) {
               this.lexer.nextToken();
               this.accept(Token.TO);
               this.acceptIdentifier("CHARACTER");
               this.accept(Token.SET);
               SQLAlterTableConvertCharSet item = new SQLAlterTableConvertCharSet();
               SQLExpr charset = this.exprParser.name();
               item.setCharset(charset);
               if (this.lexer.identifierEquals("COLLATE")) {
                  this.lexer.nextToken();
                  SQLExpr collate = this.exprParser.primary();
                  item.setCollate(collate);
               }

               stmt.addItem(item);
               return true;
            }

            if (this.lexer.identifierEquals(FnvHash.Constants.DISCARD)) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.PARTITION) {
                  this.lexer.nextToken();
                  SQLAlterTableDiscardPartition item = new SQLAlterTableDiscardPartition();
                  if (this.lexer.token() == Token.ALL) {
                     this.lexer.nextToken();
                     item.getPartitions().add(new SQLIdentifierExpr("ALL"));
                  } else {
                     this.exprParser.names(item.getPartitions(), item);
                  }

                  if (this.lexer.token() == Token.TABLESPACE) {
                     this.lexer.nextToken();
                     item.setTablespace(true);
                  }

                  stmt.addItem(item);
               } else {
                  this.accept(Token.TABLESPACE);
                  MariadbAlterTableDiscardTablespace item = new MariadbAlterTableDiscardTablespace();
                  stmt.addItem(item);
               }

               return true;
            }

            if (this.lexer.identifierEquals(FnvHash.Constants.IMPORT)) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.PARTITION) {
                  this.lexer.nextToken();
                  SQLAlterTableImportPartition item = new SQLAlterTableImportPartition();
                  if (this.lexer.token() == Token.ALL) {
                     this.lexer.nextToken();
                     item.getPartitions().add(new SQLIdentifierExpr("ALL"));
                  } else {
                     this.exprParser.names(item.getPartitions(), item);
                  }

                  if (this.lexer.token() == Token.TABLESPACE) {
                     this.lexer.nextToken();
                     item.setTablespace(true);
                  }

                  stmt.addItem(item);
               } else {
                  this.accept(Token.TABLESPACE);
                  MariadbAlterTableImportTablespace item = new MariadbAlterTableImportTablespace();
                  stmt.addItem(item);
               }

               return true;
            }

            if (this.lexer.identifierEquals(FnvHash.Constants.FORCE)) {
               this.lexer.nextToken();
               MariadbAlterTableForce item = new MariadbAlterTableForce();
               stmt.addItem(item);
               return true;
            }

            if (this.lexer.identifierEquals(FnvHash.Constants.MODIFY)) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.COLUMN) {
                  this.lexer.nextToken();
               }

               boolean paren = false;
               if (this.lexer.token() == Token.LPAREN) {
                  paren = true;
                  this.lexer.nextToken();
               }

               while(true) {
                  MariadbAlterTableModifyColumn item = new MariadbAlterTableModifyColumn();
                  item.setNewColumnDefinition(this.exprParser.parseColumn());
                  if (this.lexer.identifierEquals("AFTER")) {
                     this.lexer.nextToken();
                     item.setAfterColumn(this.exprParser.name());
                  } else if (this.lexer.identifierEquals("FIRST")) {
                     this.lexer.nextToken();
                     if (this.lexer.token() == Token.IDENTIFIER) {
                        item.setFirstColumn(this.exprParser.name());
                     } else {
                        item.setFirst(true);
                     }
                  }

                  stmt.addItem(item);
                  if (!paren || this.lexer.token() != Token.COMMA) {
                     if (paren) {
                        this.accept(Token.RPAREN);
                     }

                     return true;
                  }

                  this.lexer.nextToken();
               }
            }

            if (this.lexer.identifierEquals(FnvHash.Constants.RENAME)) {
               this.lexer.nextToken();
               switch (this.lexer.token()) {
                  case COLUMN:
                     this.lexer.nextToken();
                     SQLName columnName = this.exprParser.name();
                     this.accept(Token.TO);
                     SQLName toName = this.exprParser.name();
                     SQLAlterTableRenameColumn renameColumn = new SQLAlterTableRenameColumn();
                     renameColumn.setColumn(columnName);
                     renameColumn.setTo(toName);
                     stmt.addItem(renameColumn);
                     return true;
                  case INDEX:
                  case KEY:
                     this.lexer.nextToken();
                     SQLName name = this.exprParser.name();
                     this.accept(Token.TO);
                     SQLName to = this.exprParser.name();
                     SQLAlterTableRenameIndex item = new SQLAlterTableRenameIndex(name, to);
                     stmt.addItem(item);
                     return true;
                  case CONSTRAINT:
                  case PRIMARY:
                  case UNIQUE:
                  case FOREIGN:
                  case PARTITION:
                  default:
                     return false;
                  case TO:
                  case AS:
                     this.lexer.nextToken();
                  case IDENTIFIER:
                     SQLAlterTableRename item2 = new SQLAlterTableRename();
                     SQLName to2 = this.exprParser.name();
                     item2.setTo(to2);
                     stmt.addItem(item2);
                     return true;
               }
            } else {
               if (this.lexer.identifierEquals(FnvHash.Constants.WITHOUT)) {
                  this.lexer.nextToken();
                  this.acceptIdentifier("VALIDATION");
                  MariadbAlterTableValidation item = new MariadbAlterTableValidation();
                  item.setWithValidation(false);
                  stmt.addItem(item);
                  return true;
               }

               if (this.lexer.identifierEquals("COALESCE")) {
                  this.lexer.nextToken();
                  this.accept(Token.PARTITION);
                  SQLAlterTableCoalescePartition item = new SQLAlterTableCoalescePartition();
                  SQLIntegerExpr countExpr = this.exprParser.integerExpr();
                  item.setCount(countExpr);
                  stmt.addItem(item);
                  return true;
               }

               if (this.lexer.identifierEquals("REORGANIZE")) {
                  this.lexer.nextToken();
                  this.accept(Token.PARTITION);
                  SQLAlterTableReOrganizePartition item = new SQLAlterTableReOrganizePartition();
                  this.exprParser.names(item.getNames(), item);
                  this.accept(Token.INTO);
                  this.accept(Token.LPAREN);

                  while(true) {
                     SQLPartition partition = this.getExprParser().parsePartition();
                     item.addPartition(partition);
                     if (this.lexer.token() != Token.COMMA) {
                        this.accept(Token.RPAREN);
                        stmt.addItem(item);
                        return true;
                     }

                     this.lexer.nextToken();
                  }
               }

               if (this.lexer.identifierEquals(FnvHash.Constants.EXCHANGE)) {
                  this.lexer.nextToken();
                  this.accept(Token.PARTITION);
                  SQLAlterTableExchangePartition item = new SQLAlterTableExchangePartition();
                  SQLName partition = this.exprParser.name();
                  item.addPartition(partition);
                  this.accept(Token.WITH);
                  this.accept(Token.TABLE);
                  SQLName table = this.exprParser.name();
                  item.setTable(table);
                  if (this.lexer.token() == Token.WITH) {
                     this.lexer.nextToken();
                     this.acceptIdentifier("VALIDATION");
                     item.setValidation(true);
                  } else if (this.lexer.identifierEquals(FnvHash.Constants.WITHOUT)) {
                     this.lexer.nextToken();
                     this.acceptIdentifier("VALIDATION");
                     item.setValidation(false);
                  }

                  stmt.addItem(item);
                  return true;
               }

               if (this.lexer.identifierEquals("REBUILD")) {
                  this.lexer.nextToken();
                  this.accept(Token.PARTITION);
                  SQLAlterTableRebuildPartition item = new SQLAlterTableRebuildPartition();
                  if (this.lexer.token() == Token.ALL) {
                     this.lexer.nextToken();
                     item.getPartitions().add(new SQLIdentifierExpr("ALL"));
                  } else {
                     this.exprParser.names(item.getPartitions(), item);
                  }

                  stmt.addItem(item);
                  return true;
               }

               if (this.lexer.identifierEquals("REPAIR")) {
                  this.lexer.nextToken();
                  this.accept(Token.PARTITION);
                  SQLAlterTableRepairPartition item = new SQLAlterTableRepairPartition();
                  if (this.lexer.token() == Token.ALL) {
                     this.lexer.nextToken();
                     item.getPartitions().add(new SQLIdentifierExpr("ALL"));
                  } else {
                     this.exprParser.names(item.getPartitions(), item);
                  }

                  stmt.addItem(item);
                  return true;
               }

               if (this.lexer.identifierEquals(FnvHash.Constants.REMOVE)) {
                  this.lexer.nextToken();
                  this.acceptIdentifier("PARTITIONING");
                  stmt.setRemovePatiting(true);
               } else if (this.lexer.identifierEquals("UPGRADE")) {
                  this.lexer.nextToken();
                  this.acceptIdentifier("PARTITIONING");
                  stmt.setUpgradePatiting(true);
               } else if (this.lexer.identifierEquals("HOT_PARTITION_COUNT")) {
                  this.lexer.nextToken();
                  this.accept(Token.EQ);

                  try {
                     stmt.getTableOptions().add(new SQLAssignItem(new SQLIdentifierExpr("HOT_PARTITION_COUNT"), this.exprParser.integerExpr()));
                  } catch (Exception var7) {
                     throw new ParserException("only integer number is supported for hot_partition_count");
                  }
               } else {
                  if (this.lexer.identifierEquals(FnvHash.Constants.PARTITIONS)) {
                     SQLAlterTablePartitionCount item = new SQLAlterTablePartitionCount();
                     this.lexer.nextToken();
                     if (this.lexer.token() == Token.EQ) {
                        this.lexer.nextToken();
                     }

                     item.setCount(this.exprParser.integerExpr());
                     stmt.addItem(item);
                     return true;
                  }

                  if (this.lexer.identifierEquals(FnvHash.Constants.SUBPARTITION)) {
                     this.lexer.nextToken();
                     if (this.lexer.identifierEquals(FnvHash.Constants.LIFECYCLE)) {
                        this.lexer.nextToken();
                        SQLAlterTableSubpartitionLifecycle item = new SQLAlterTableSubpartitionLifecycle();
                        if (this.lexer.token() == Token.LITERAL_INT) {
                           while(true) {
                              item.getPartitionIds().add(this.exprParser.integerExpr());
                              String pidStr = this.lexer.stringVal();
                              this.accept(Token.VARIANT);
                              String s = pidStr.replaceAll(":", "");
                              if (StringUtils.isEmpty(s)) {
                                 item.getSubpartitionLifeCycle().add(this.exprParser.integerExpr());
                              } else {
                                 item.getSubpartitionLifeCycle().add(new SQLIntegerExpr(Integer.valueOf(s)));
                              }

                              if (this.lexer.token() != Token.COMMA) {
                                 break;
                              }

                              this.lexer.nextToken();
                           }
                        }

                        stmt.addItem(item);
                     }

                     return true;
                  }

                  if (this.lexer.identifierEquals("BLOCK_SIZE")) {
                     SQLAlterTableBlockSize item = new SQLAlterTableBlockSize();
                     this.lexer.nextToken();
                     if (this.lexer.token() == Token.EQ) {
                        this.accept(Token.EQ);
                     }

                     item.setSize((SQLIntegerExpr)this.exprParser.expr());
                     stmt.addItem(item);
                     return true;
                  }

                  if (this.lexer.identifierEquals("INSERT_METHOD")) {
                     this.lexer.nextToken();
                     if (this.lexer.token() == Token.EQ) {
                        this.lexer.nextToken();
                     }

                     stmt.getTableOptions().add(new SQLAssignItem(new SQLIdentifierExpr("INSERT_METHOD"), this.exprParser.primary()));
                     return true;
                  }

                  if (this.lexer.identifierEquals(FnvHash.Constants.CLUSTERED)) {
                     SQLAlterTableModifyClusteredBy clusteredBy = new SQLAlterTableModifyClusteredBy();
                     this.acceptIdentifier("CLUSTERED");
                     this.accept(Token.BY);
                     this.accept(Token.LPAREN);
                     if (this.lexer.token() != Token.RPAREN) {
                        while(true) {
                           clusteredBy.addClusterColumn(this.exprParser.name());
                           if (this.lexer.token() != Token.COMMA) {
                              break;
                           }

                           this.accept(Token.COMMA);
                        }
                     }

                     this.accept(Token.RPAREN);
                     stmt.addItem(clusteredBy);
                     return true;
                  }

                  if (this.lexer.identifierEquals(FnvHash.Constants.SUBPARTITION_AVAILABLE_PARTITION_NUM)) {
                     this.lexer.nextToken();
                     if (this.lexer.token() == Token.EQ) {
                        this.lexer.nextToken();
                     }

                     SQLIntegerExpr num = this.exprParser.integerExpr();
                     SQLAlterTableSubpartitionAvailablePartitionNum item = new SQLAlterTableSubpartitionAvailablePartitionNum();
                     item.setNumber(num);
                     stmt.addItem(item);
                     return true;
                  }
               }
            }
            break;
         case PARTITION:
            Lexer.SavePoint mark = this.lexer.mark();
            this.lexer.nextToken();
            if (this.lexer.identifierEquals(FnvHash.Constants.LIFECYCLE)) {
               this.lexer.nextToken();
               SQLAlterTablePartitionLifecycle item = new SQLAlterTablePartitionLifecycle();
               if (this.lexer.token() == Token.EQ) {
                  this.lexer.nextToken();
               }

               item.setLifecycle(this.exprParser.integerExpr());
               stmt.addItem(item);
               return true;
            }

            this.lexer.reset(mark);
            break;
         case DISABLE:
            this.lexer.nextToken();
            if (this.lexer.token() == Token.CONSTRAINT) {
               this.lexer.nextToken();
               SQLAlterTableDisableConstraint item = new SQLAlterTableDisableConstraint();
               item.setConstraintName(this.exprParser.name());
               stmt.addItem(item);
            } else {
               this.acceptIdentifier("KEYS");
               SQLAlterTableDisableKeys item = new SQLAlterTableDisableKeys();
               stmt.addItem(item);
            }

            return true;
         case ENABLE:
            this.lexer.nextToken();
            if (this.lexer.token() == Token.CONSTRAINT) {
               this.lexer.nextToken();
               SQLAlterTableEnableConstraint item = new SQLAlterTableEnableConstraint();
               item.setConstraintName(this.exprParser.name());
               stmt.addItem(item);
            } else {
               this.acceptIdentifier("KEYS");
               SQLAlterTableEnableKeys item = new SQLAlterTableEnableKeys();
               stmt.addItem(item);
            }

            return true;
         case LOCK:
            this.lexer.nextToken();
            if (this.lexer.token() == Token.EQ) {
               this.lexer.nextToken();
            }

            MariadbAlterTableLock item = new MariadbAlterTableLock();
            item.setLockType(new SQLIdentifierExpr(this.lexer.stringVal()));
            this.lexer.nextToken();
            stmt.addItem(item);
            return true;
         case ORDER:
            this.lexer.nextToken();
            this.accept(Token.BY);
            MariadbAlterTableOrderBy item3 = new MariadbAlterTableOrderBy();

            while(this.lexer.token() == Token.IDENTIFIER) {
               SQLSelectOrderByItem column = this.exprParser.parseSelectOrderByItem();
               column.setParent(item3);
               item3.addColumn(column);
               if (this.lexer.token() != Token.COMMA) {
                  break;
               }

               this.lexer.nextToken();
            }

            stmt.addItem(item3);
            return true;
      }

      return false;
   }

   public MariadbCacheIndexStatement parseCacheIndex() {
      this.accept(Token.CACHE);
      this.accept(Token.INDEX);
      MariadbCacheIndexStatement stmt = new MariadbCacheIndexStatement();

      while(true) {
         SQLName table = this.exprParser.name();
         MariadbTableTableSource mySqlTableTableSource = new MariadbTableTableSource(table);
         stmt.getTables().add(mySqlTableTableSource);
         if (this.lexer.token() == Token.IDENTIFIER) {
            this.lexer.nextToken();
         }

         if (this.lexer.token() == Token.PARTITION) {
            mySqlTableTableSource.setPartition(true);
            this.lexer.nextToken();
            if (this.lexer.token() == Token.LPAREN) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.ALL) {
                  mySqlTableTableSource.setAll(true);
                  this.lexer.nextToken();
               } else {
                  while(true) {
                     mySqlTableTableSource.getPartitionList().add(new SQLIdentifierExpr(this.lexer.stringVal()));
                     this.lexer.nextToken();
                     if (this.lexer.token() != Token.COMMA) {
                        break;
                     }

                     this.lexer.nextToken();
                  }
               }

               if (this.lexer.token() == Token.RPAREN) {
                  this.lexer.nextToken();
               }
            }
            break;
         }

         if (this.lexer.token() == Token.INDEX || this.lexer.token() == Token.KEY) {
            mySqlTableTableSource.setIndexOrKey(new SQLIdentifierExpr(this.lexer.stringVal()));
            this.lexer.nextToken();
            if (this.lexer.token() == Token.LPAREN) {
               this.lexer.nextToken();
            }

            while(true) {
               mySqlTableTableSource.getIndexList().add(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
               if (this.lexer.token() != Token.COMMA) {
                  if (this.lexer.token() == Token.RPAREN) {
                     this.lexer.nextToken();
                  }
                  break;
               }

               this.lexer.nextToken();
            }
         }

         if (this.lexer.token() != Token.COMMA) {
            break;
         }

         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.IN) {
         this.lexer.nextToken();
         SQLExpr expr = this.exprParser.expr();
         stmt.setKeyCacheName(expr);
         this.lexer.nextToken();
      }

      return stmt;
   }

   protected SQLStatement parseAlterTable(boolean ignore, boolean online, boolean offline) {
      this.lexer.nextToken();
      SQLAlterTableStatement stmt = new SQLAlterTableStatement(this.getDbType());
      stmt.setIgnore(ignore);
      stmt.setOnline(online);
      stmt.setOffline(offline);
      stmt.setName(this.exprParser.name());

      while(true) {
         boolean parsed = ((MariadbExprParser)this.exprParser).parseTableOptions(stmt.getTableOptions(), stmt);
         if (!parsed) {
            parsed = this.parseAlterSpecification(stmt);
         }

         if (!parsed) {
            if (Token.PARTITION == this.lexer.token()) {
               SQLPartitionBy partitionBy = this.getSQLCreateTableParser().parsePartitionBy();
               stmt.setPartition(partitionBy);
            } else if (1 == stmt.getItems().size() && stmt.getItems().get(0) instanceof SQLAlterTableRename) {
               MariadbRenameTableStatement renameStmt = new MariadbRenameTableStatement();
               MariadbRenameTableStatement.Item item = new MariadbRenameTableStatement.Item();
               item.setName((SQLName)stmt.getTableSource().getExpr());
               item.setTo(((SQLAlterTableRename)stmt.getItems().get(0)).getToName());
               renameStmt.addItem(item);
               return renameStmt;
            }

            return stmt;
         }

         if (this.lexer.token() == Token.COMMA) {
            this.lexer.nextToken();
         }
      }
   }

   private MariadbExtPartition parseExtPartition() {
      MariadbExtPartition partitionDef = new MariadbExtPartition();

      while(true) {
         MariadbExtPartition.Item item = new MariadbExtPartition.Item();
         if (this.lexer.identifierEquals(FnvHash.Constants.DBPARTITION)) {
            this.lexer.nextToken();
            SQLName name = this.exprParser.name();
            item.setDbPartition(name);
            this.accept(Token.BY);
            SQLExpr value = this.exprParser.primary();
            item.setDbPartitionBy(value);
         }

         if (this.lexer.identifierEquals(FnvHash.Constants.TBPARTITION)) {
            this.lexer.nextToken();
            SQLName name = this.exprParser.name();
            item.setTbPartition(name);
            this.accept(Token.BY);
            SQLExpr value = this.exprParser.primary();
            item.setTbPartitionBy(value);
         }

         item.setParent(partitionDef);
         partitionDef.getItems().add(item);
         if (this.lexer.token() != Token.COMMA) {
            return partitionDef;
         }

         this.lexer.nextToken();
      }
   }

   private SQLAlterCharacter alterTableCharacter() {
      this.lexer.nextToken();
      this.accept(Token.SET);
      if (this.lexer.token() == Token.EQ) {
         this.lexer.nextToken();
      }

      SQLAlterCharacter item = new SQLAlterCharacter();
      item.setCharacterSet(this.exprParser.primary());
      if (this.lexer.token() == Token.COMMA) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals(FnvHash.Constants.COLLATE)) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.EQ) {
               this.lexer.nextToken();
            }

            item.setCollate(this.exprParser.primary());
         }
      }

      return item;
   }

   protected void parseAlterTableAddColumn(SQLAlterTableStatement stmt) {
      boolean parenFlag = false;
      if (this.lexer.token() == Token.LPAREN) {
         this.lexer.nextToken();
         parenFlag = true;
      }

      SQLAlterTableAddColumn item = new SQLAlterTableAddColumn();

      while(true) {
         SQLColumnDefinition columnDef = this.exprParser.parseColumn();
         item.addColumn(columnDef);
         if (this.lexer.identifierEquals("AFTER")) {
            this.lexer.nextToken();
            item.setAfterColumn(this.exprParser.name());
         } else if (this.lexer.identifierEquals("FIRST")) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.IDENTIFIER) {
               item.setFirstColumn(this.exprParser.name());
            } else {
               item.setFirst(true);
            }
         }

         if (!parenFlag || this.lexer.token() != Token.COMMA) {
            if (parenFlag) {
               this.accept(Token.RPAREN);
            }

            if (this.lexer.identifierEquals(FnvHash.Constants.RESTRICT)) {
               this.lexer.nextToken();
               item.setRestrict(true);
            } else if (this.lexer.token() != Token.CASCADE && !this.lexer.identifierEquals(FnvHash.Constants.CASCADE)) {
               item.setCascade(false);
            } else {
               this.lexer.nextToken();
               item.setCascade(true);
            }

            stmt.addItem(item);
            return;
         }

         this.lexer.nextToken();
      }
   }

   public void parseAlterDrop(SQLAlterTableStatement stmt) {
      this.lexer.nextToken();
      if (this.lexer.token() == Token.INDEX) {
         this.lexer.nextToken();
         SQLName indexName = this.exprParser.name();
         SQLAlterTableDropIndex item = new SQLAlterTableDropIndex();
         item.setIndexName(indexName);
         stmt.addItem(item);
      } else if (this.lexer.token() == Token.FOREIGN) {
         this.lexer.nextToken();
         this.accept(Token.KEY);
         SQLName indexName = this.exprParser.name();
         SQLAlterTableDropForeignKey item = new SQLAlterTableDropForeignKey();
         item.setIndexName(indexName);
         stmt.addItem(item);
      } else if (this.lexer.token() == Token.KEY) {
         this.lexer.nextToken();
         SQLName keyName = this.exprParser.name();
         SQLAlterTableDropKey item = new SQLAlterTableDropKey();
         item.setKeyName(keyName);
         stmt.addItem(item);
      } else if (this.lexer.token() == Token.PRIMARY) {
         this.lexer.nextToken();
         this.accept(Token.KEY);
         SQLAlterTableDropPrimaryKey item = new SQLAlterTableDropPrimaryKey();
         stmt.addItem(item);
      } else if (this.lexer.token() == Token.CONSTRAINT) {
         this.lexer.nextToken();
         SQLAlterTableDropConstraint item = new SQLAlterTableDropConstraint();
         item.setConstraintName(this.exprParser.name());
         stmt.addItem(item);
      } else if (this.lexer.token() == Token.CHECK) {
         this.lexer.nextToken();
         SQLAlterTableDropCheck item = new SQLAlterTableDropCheck();
         item.setConstraintName(this.exprParser.name());
         stmt.addItem(item);
      } else if (this.lexer.token() == Token.COLUMN) {
         this.lexer.nextToken();
         SQLAlterTableDropColumnItem item = new SQLAlterTableDropColumnItem();
         SQLName name = this.exprParser.name();
         name.setParent(item);
         item.addColumn(name);
         if (this.dbType != DbType.mysql) {
            while(this.lexer.token() == Token.COMMA) {
               char markChar = this.lexer.current();
               int markBp = this.lexer.bp();
               this.lexer.nextToken();
               if (this.lexer.identifierEquals(FnvHash.Constants.CHANGE) || this.lexer.identifierEquals(FnvHash.Constants.MODIFY)) {
                  this.lexer.reset(markBp, markChar, Token.COMMA);
                  break;
               }

               if (this.lexer.token() != Token.IDENTIFIER) {
                  this.lexer.reset(markBp, markChar, Token.COMMA);
                  break;
               }

               if ("ADD".equalsIgnoreCase(this.lexer.stringVal())) {
                  this.lexer.reset(markBp, markChar, Token.COMMA);
                  break;
               }

               name = this.exprParser.name();
               name.setParent(item);
               item.addColumn(name);
            }
         }

         stmt.addItem(item);
      } else if (this.lexer.token() == Token.PARTITION) {
         SQLAlterTableDropPartition dropPartition = this.parseAlterTableDropPartition(false);
         stmt.addItem(dropPartition);
      } else if (this.lexer.identifierEquals(FnvHash.Constants.SUBPARTITION)) {
         SQLAlterTableDropSubpartition dropPartition = this.parseAlterTableDropSubpartition();
         stmt.addItem(dropPartition);
      } else if (!this.lexer.identifierEquals(FnvHash.Constants.CLUSTERING) && !this.lexer.identifierEquals(FnvHash.Constants.CLUSTERED)) {
         if (this.lexer.token() == Token.IDENTIFIER) {
            if (this.lexer.identifierEquals(FnvHash.Constants.EXTPARTITION)) {
               this.lexer.nextToken();
               this.accept(Token.LPAREN);
               MariadbAlterTableDropExtPartition extPartitionItem = new MariadbAlterTableDropExtPartition();
               MariadbExtPartition partitionDef = this.parseExtPartition();
               extPartitionItem.setExPartition(partitionDef);
               stmt.addItem(extPartitionItem);
               this.accept(Token.RPAREN);
            } else {
               SQLAlterTableDropColumnItem item = new SQLAlterTableDropColumnItem();
               SQLName name = this.exprParser.name();
               item.addColumn(name);
               stmt.addItem(item);
               if (this.lexer.token() == Token.COMMA) {
                  this.lexer.nextToken();
               }

               if (this.lexer.token() == Token.DROP) {
                  this.parseAlterDrop(stmt);
               }
            }
         } else {
            super.parseAlterDrop(stmt);
         }
      } else {
         this.lexer.nextToken();
         SQLAlterTableDropClusteringKey dropPartition = new SQLAlterTableDropClusteringKey();
         this.accept(Token.KEY);
         dropPartition.setKeyName(this.exprParser.name());
         stmt.addItem(dropPartition);
      }

   }

   public SQLStatement parseRename() {
      this.acceptIdentifier("RENAME");
      if (this.lexer.token() == Token.SEQUENCE) {
         this.lexer.nextToken();
         MariadbRenameSequenceStatement stmt = new MariadbRenameSequenceStatement();
         SQLName name = this.exprParser.name();
         stmt.setName(name);
         this.accept(Token.TO);
         SQLName to = this.exprParser.name();
         stmt.setTo(to);
         return stmt;
      } else if (this.lexer.token() == Token.USER) {
         this.lexer.nextToken();
         SQLRenameUserStatement stmt = new SQLRenameUserStatement();
         SQLName name = this.exprParser.name();
         stmt.setName(name);
         this.accept(Token.TO);
         SQLName to = this.exprParser.name();
         stmt.setTo(to);
         return stmt;
      } else {
         this.accept(Token.TABLE);
         MariadbRenameTableStatement stmt = new MariadbRenameTableStatement();

         while(true) {
            MariadbRenameTableStatement.Item item = new MariadbRenameTableStatement.Item();
            item.setName(this.exprParser.name());
            this.accept(Token.TO);
            item.setTo(this.exprParser.name());
            stmt.addItem(item);
            if (this.lexer.token() != Token.COMMA) {
               return stmt;
            }

            this.lexer.nextToken();
         }
      }
   }

   public SQLStatement parseCreateDatabase() {
      if (this.lexer.token() == Token.CREATE) {
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.SCHEMA) {
         this.lexer.nextToken();
      } else {
         this.accept(Token.DATABASE);
      }

      SQLCreateDatabaseStatement stmt = new SQLCreateDatabaseStatement(this.dbType);
      if (this.lexer.token() == Token.HINT) {
         List<SQLCommentHint> hints = this.exprParser.parseHints();
         if (hints.size() == 1) {
            String text = ((SQLCommentHint)hints.get(0)).getText();
            if (text.endsWith(" IF NOT EXISTS") && text.charAt(0) == '!') {
               stmt.setIfNotExists(true);
            }
         }
      }

      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.accept(Token.NOT);
         this.accept(Token.EXISTS);
         stmt.setIfNotExists(true);
      }

      stmt.setName(this.exprParser.name());
      if (this.lexer.token() == Token.DEFAULT) {
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.HINT) {
         stmt.setHints(this.exprParser.parseHints());
      }

      if (this.lexer.token() == Token.DEFAULT) {
         this.lexer.nextToken();
      }

      while(true) {
         while(!this.lexer.identifierEquals(FnvHash.Constants.CHARACTER)) {
            if (this.lexer.identifierEquals(FnvHash.Constants.CHARSET)) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.EQ) {
                  this.lexer.nextToken();
               }

               String charset = this.lexer.stringVal();
               this.accept(Token.IDENTIFIER);
               stmt.setCharacterSet(charset);
            } else if (this.lexer.token() == Token.DEFAULT) {
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals(FnvHash.Constants.COLLATE)) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.EQ) {
                  this.lexer.nextToken();
               }

               String collate = this.lexer.stringVal();
               this.accept(Token.IDENTIFIER);
               stmt.setCollate(collate);
            } else if (this.lexer.identifierEquals(FnvHash.Constants.PASSWORD)) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.EQ) {
                  this.lexer.nextToken();
               }

               SQLExpr password = this.exprParser.primary();
               stmt.setPassword(password);
            } else {
               if (!this.lexer.identifierEquals("SHARDS") && !this.lexer.identifierEquals("SHARD_ID") && !this.lexer.identifierEquals("REPLICATION") && !this.lexer.identifierEquals("STORAGE_DEPENDENCY") && !this.lexer.identifierEquals("REPLICA_TYPE") && !this.lexer.identifierEquals("DATA_REPLICATION")) {
                  if (this.lexer.token() == Token.FOR) {
                     this.lexer.nextToken();
                     String user = this.lexer.stringVal();
                     this.lexer.nextToken();
                     stmt.setUser(user);
                  }

                  if (this.lexer.identifierEquals(FnvHash.Constants.OPTIONS)) {
                     this.lexer.nextToken();
                     this.accept(Token.LPAREN);

                     while(this.lexer.token() != Token.RPAREN) {
                        String key = this.lexer.stringVal();
                        this.lexer.nextToken();
                        this.accept(Token.EQ);
                        SQLExpr value = this.exprParser.expr();
                        stmt.getOptions().put(key, value);
                     }

                     this.accept(Token.RPAREN);
                  }

                  if (this.lexer.token() == Token.WITH) {
                     this.lexer.nextToken();
                     this.accept(Token.LPAREN);

                     while(true) {
                        SQLAssignItem assignItem = this.exprParser.parseAssignItem();
                        assignItem.setParent(stmt);
                        stmt.getDbProperties().add(assignItem);
                        if (this.lexer.token() != Token.COMMA) {
                           this.accept(Token.RPAREN);
                           break;
                        }

                        this.lexer.nextToken();
                     }
                  }

                  if (this.lexer.identifierEquals(FnvHash.Constants.STORED)) {
                     this.lexer.nextToken();
                     if (this.lexer.token() == Token.BY) {
                        this.accept(Token.BY);

                        while(true) {
                           List<SQLAssignItem> storedByItem = new ArrayList();
                           this.accept(Token.LPAREN);

                           while(true) {
                              SQLAssignItem assignItem = this.exprParser.parseAssignItem();
                              assignItem.setParent(stmt);
                              storedByItem.add(assignItem);
                              if (this.lexer.token() != Token.COMMA) {
                                 this.accept(Token.RPAREN);
                                 stmt.getStoredBy().add(storedByItem);
                                 if (this.lexer.token() != Token.COMMA) {
                                    return stmt;
                                 }

                                 this.lexer.nextToken();
                                 break;
                              }

                              this.lexer.nextToken();
                           }
                        }
                     } else if (this.lexer.token() == Token.IN) {
                        this.lexer.nextToken();
                        stmt.setStoredIn(this.exprParser.name());
                        this.accept(Token.ON);
                        this.accept(Token.LPAREN);

                        while(true) {
                           SQLAssignItem assignItem = this.exprParser.parseAssignItem();
                           assignItem.setParent(stmt);
                           stmt.getStoredOn().add(assignItem);
                           if (this.lexer.token() != Token.COMMA) {
                              this.accept(Token.RPAREN);
                              break;
                           }

                           this.lexer.nextToken();
                        }
                     } else {
                        if (this.lexer.token() != Token.AS) {
                           throw new ParserException("TODO " + this.lexer.info());
                        }

                        this.lexer.nextToken();
                        SQLExpr like = this.exprParser.expr();
                        stmt.setStoredAs(like);
                     }
                  }

                  return stmt;
               }

               String key = this.lexer.stringVal();
               this.lexer.nextToken();
               this.accept(Token.EQ);
               SQLExpr value = this.exprParser.expr();
               stmt.getOptions().put(key, value);
            }
         }

         this.lexer.nextToken();
         this.accept(Token.SET);
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         String charset = this.lexer.stringVal();
         this.accept(Token.IDENTIFIER);
         stmt.setCharacterSet(charset);
      }
   }

   protected void parseUpdateSet(SQLUpdateStatement update) {
      this.accept(Token.SET);

      while(true) {
         SQLUpdateSetItem item = this.exprParser.parseUpdateSetItem();
         update.addItem(item);
         if (this.lexer.token() != Token.COMMA) {
            return;
         }

         this.lexer.nextToken();
      }
   }

   public SQLStatement parseAlterDatabase() {
      if (this.lexer.token() == Token.SCHEMA) {
         this.lexer.nextToken();
      } else {
         this.accept(Token.DATABASE);
      }

      SQLAlterDatabaseStatement stmt = new SQLAlterDatabaseStatement(this.dbType);
      SQLName name = this.exprParser.name();
      stmt.setName(name);
      if (this.lexer.token() != Token.SET) {
         if (this.lexer.token() == Token.KILL) {
            MariadbAlterDatabaseKillJob item = new MariadbAlterDatabaseKillJob();
            this.lexer.nextToken();
            SQLName jobType = this.exprParser.name();
            SQLName jobId = this.exprParser.name();
            item.setJobType(jobType);
            item.setJobId(jobId);
            stmt.setItem(item);
         }

         if (this.lexer.identifierEquals("UPGRADE")) {
            this.lexer.nextToken();
            this.acceptIdentifier("DATA");
            this.acceptIdentifier("DIRECTORY");
            this.acceptIdentifier("NAME");
            stmt.setUpgradeDataDirectoryName(true);
         }

         if (this.lexer.token() == Token.DEFAULT) {
            this.lexer.nextToken();
            if (!this.lexer.identifierEquals(FnvHash.Constants.CHARACTER)) {
               throw new ParserException("TODO " + this.lexer.info());
            }

            SQLAlterCharacter item = this.alterTableCharacter();
            stmt.setCharacter(item);
         } else if (this.lexer.identifierEquals(FnvHash.Constants.CHARACTER)) {
            SQLAlterCharacter item = this.alterTableCharacter();
            stmt.setCharacter(item);
         }

         return stmt;
      } else {
         this.lexer.nextToken();
         MariadbAlterDatabaseSetOption option = new MariadbAlterDatabaseSetOption();

         while(true) {
            SQLName key = this.exprParser.name();
            this.accept(Token.EQ);
            SQLExpr value = this.exprParser.expr();
            option.getOptions().add(new SQLAssignItem(key, value));
            if (this.lexer.token() == Token.EOF || this.lexer.token() == Token.ON) {
               stmt.setItem(option);
               if (this.lexer.token() == Token.ON) {
                  this.lexer.nextToken();
                  key = this.exprParser.name();
                  option.setOn(key);
               }

               return stmt;
            }

            if (this.lexer.token() == Token.COMMA) {
               this.lexer.nextToken();
            }
         }
      }
   }

   public MariadbAlterUserStatement parseAlterUser() {
      this.accept(Token.USER);
      MariadbAlterUserStatement stmt = new MariadbAlterUserStatement();
      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.accept(Token.EXISTS);
         stmt.setIfExists(true);
      }

      while(true) {
         MariadbAlterUserStatement.AlterUser alterUser = new MariadbAlterUserStatement.AlterUser();
         SQLExpr user = this.exprParser.expr();
         alterUser.setUser(user);
         if (this.lexer.identifierEquals("IDENTIFIED")) {
            this.lexer.nextToken();
            this.accept(Token.BY);
            MariadbAlterUserStatement.AuthOption authOption = new MariadbAlterUserStatement.AuthOption();
            SQLCharExpr authString = this.exprParser.charExpr();
            authOption.setAuthString(authString);
            alterUser.setAuthOption(authOption);
         }

         if (this.lexer.identifierEquals("PASSWORD")) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("EXPIRE")) {
               this.lexer.nextToken();
               MariadbAlterUserStatement.PasswordOption passwordOption = new MariadbAlterUserStatement.PasswordOption();
               if (this.lexer.token() == Token.DEFAULT) {
                  this.lexer.nextToken();
                  passwordOption.setExpire(MariadbAlterUserStatement.PasswordExpire.PASSWORD_EXPIRE_DEFAULT);
               } else if (this.lexer.identifierEquals("NEVER")) {
                  this.lexer.nextToken();
                  passwordOption.setExpire(MariadbAlterUserStatement.PasswordExpire.PASSWORD_EXPIRE_NEVER);
               } else if (this.lexer.token() == Token.INTERVAL) {
                  this.lexer.nextToken();
                  passwordOption.setExpire(MariadbAlterUserStatement.PasswordExpire.PASSWORD_EXPIRE_INTERVAL);
                  SQLIntegerExpr days = this.exprParser.integerExpr();
                  passwordOption.setIntervalDays(days);
                  this.acceptIdentifier("DAY");
               } else {
                  passwordOption.setExpire(MariadbAlterUserStatement.PasswordExpire.PASSWORD_EXPIRE);
               }

               stmt.setPasswordOption(passwordOption);
            }
         }

         stmt.getAlterUsers().add(alterUser);
         if (this.lexer.token() != Token.COMMA) {
            return stmt;
         }

         this.lexer.nextToken();
      }
   }

   public MariadbExprParser getExprParser() {
      return (MariadbExprParser)this.exprParser;
   }

   public SQLCreateFunctionStatement parseCreateFunction() {
      SQLCreateFunctionStatement stmt = new SQLCreateFunctionStatement();
      stmt.setDbType(this.dbType);
      if (this.lexer.token() == Token.CREATE) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.OR) {
            this.lexer.nextToken();
            this.accept(Token.REPLACE);
            stmt.setOrReplace(true);
         }
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.DEFINER)) {
         this.lexer.nextToken();
         this.accept(Token.EQ);
         SQLName definer = this.getExprParser().userName();
         stmt.setDefiner(definer);
      }

      this.accept(Token.FUNCTION);
      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.accept(Token.NOT);
         this.accept(Token.EXISTS);
         stmt.setIfNotExists(true);
      }

      stmt.setName(this.exprParser.name());
      if (this.lexer.token() == Token.LPAREN) {
         this.lexer.nextToken();
         this.parserParameters(stmt.getParameters(), stmt);
         this.accept(Token.RPAREN);
      }

      this.acceptIdentifier("RETURNS");
      SQLDataType dataType = this.exprParser.parseDataType();
      stmt.setReturnDataType(dataType);

      while(true) {
         boolean deterministic = true;
         if (this.lexer.token() == Token.NOT) {
            this.lexer.nextToken();
            deterministic = false;
         }

         if (this.lexer.identifierEquals("DETERMINISTIC")) {
            this.lexer.nextToken();
            stmt.setDeterministic(deterministic);
         } else if (this.lexer.token() == Token.COMMENT) {
            this.lexer.nextToken();
            stmt.setComment(this.lexer.stringVal());
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("LANGUAGE")) {
            this.lexer.nextToken();
            stmt.setLanguage(this.lexer.stringVal());
            this.lexer.nextToken();
         } else if (!this.lexer.identifierEquals(FnvHash.Constants.CONTAINS) && this.lexer.token() != Token.CONTAINS) {
            if (this.lexer.identifierEquals(FnvHash.Constants.NO)) {
               this.lexer.nextToken();
               this.acceptIdentifier("SQL");
               stmt.setNoSql(true);
            } else if (this.lexer.identifierEquals(FnvHash.Constants.READS)) {
               this.lexer.nextToken();
               this.acceptIdentifier("SQL");
               this.acceptIdentifier("DATA");
               stmt.setReadSqlData(true);
            } else {
               if (!this.lexer.identifierEquals(FnvHash.Constants.MODIFIES)) {
                  if (this.lexer.identifierEquals(FnvHash.Constants.SQL)) {
                     this.lexer.nextToken();
                     this.acceptIdentifier("SECURITY");
                     SQLName authid = this.exprParser.name();
                     stmt.setAuthid(authid);
                  }

                  SQLStatement block;
                  if (this.lexer.token() == Token.BEGIN) {
                     block = this.parseBlock();
                  } else {
                     block = this.parseStatement();
                  }

                  stmt.setBlock(block);
                  return stmt;
               }

               this.lexer.nextToken();
               this.acceptIdentifier("SQL");
               this.acceptIdentifier("DATA");
               stmt.setModifiesSqlData(true);
            }
         } else {
            this.lexer.nextToken();
            this.acceptIdentifier("SQL");
            stmt.setContainsSql(true);
         }
      }
   }

   public SQLCreateProcedureStatement parseCreateProcedure() {
      SQLCreateProcedureStatement stmt = new SQLCreateProcedureStatement();
      stmt.setDbType(this.dbType);
      if (this.lexer.token() == Token.CREATE) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.OR) {
            this.lexer.nextToken();
            this.accept(Token.REPLACE);
            stmt.setOrReplace(true);
         }
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.DEFINER)) {
         this.lexer.nextToken();
         this.accept(Token.EQ);
         SQLName definer = this.getExprParser().userName();
         stmt.setDefiner(definer);
      }

      this.accept(Token.PROCEDURE);
      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.accept(Token.NOT);
         this.accept(Token.EXISTS);
         stmt.setIfNotExists(true);
      }

      stmt.setName(this.exprParser.name());
      if (this.lexer.token() == Token.LPAREN) {
         this.lexer.nextToken();
         this.parserParameters(stmt.getParameters(), stmt);
         this.accept(Token.RPAREN);
      }

      while(true) {
         if (this.lexer.token() == Token.COMMENT) {
            this.lexer.nextToken();
            stmt.setComment(this.exprParser.charExpr());
         }

         if (this.lexer.identifierEquals(FnvHash.Constants.LANGUAGE)) {
            this.lexer.nextToken();
            this.acceptIdentifier("SQL");
            stmt.setLanguageSql(true);
         }

         boolean deterministic = true;
         if (this.lexer.token() == Token.NOT) {
            this.lexer.nextToken();
            deterministic = false;
         }

         if (this.lexer.identifierEquals(FnvHash.Constants.DETERMINISTIC)) {
            this.lexer.nextToken();
            stmt.setDeterministic(deterministic);
         } else if (!this.lexer.identifierEquals(FnvHash.Constants.CONTAINS) && this.lexer.token() != Token.CONTAINS) {
            if (this.lexer.identifierEquals(FnvHash.Constants.NO)) {
               this.lexer.nextToken();
               this.acceptIdentifier("SQL");
               stmt.setNoSql(true);
            } else if (this.lexer.identifierEquals(FnvHash.Constants.READS)) {
               this.lexer.nextToken();
               this.acceptIdentifier("SQL");
               this.acceptIdentifier("DATA");
               stmt.setReadSqlData(true);
            } else {
               if (!this.lexer.identifierEquals(FnvHash.Constants.MODIFIES)) {
                  if (this.lexer.identifierEquals(FnvHash.Constants.SQL)) {
                     this.lexer.nextToken();
                     this.acceptIdentifier("SECURITY");
                     SQLName authid = this.exprParser.name();
                     stmt.setAuthid(authid);
                  }

                  SQLStatement block;
                  if (this.lexer.token() == Token.BEGIN) {
                     block = this.parseBlock();
                  } else {
                     block = this.parseStatement();
                  }

                  stmt.setBlock(block);
                  return stmt;
               }

               this.lexer.nextToken();
               this.acceptIdentifier("SQL");
               this.acceptIdentifier("DATA");
               stmt.setModifiesSqlData(true);
            }
         } else {
            this.lexer.nextToken();
            this.acceptIdentifier("SQL");
            stmt.setContainsSql(true);
         }
      }
   }

   private void parserParameters(List<SQLParameter> parameters, SQLObject parent) {
      if (this.lexer.token() != Token.RPAREN) {
         do {
            SQLParameter parameter = new SQLParameter();
            if (this.lexer.token() == Token.CURSOR) {
               this.lexer.nextToken();
               parameter.setName(this.exprParser.name());
               this.accept(Token.IS);
               SQLSelect select = this.createSQLSelectParser().select();
               SQLDataTypeImpl dataType = new SQLDataTypeImpl();
               dataType.setName("CURSOR");
               parameter.setDataType(dataType);
               parameter.setDefaultValue(new SQLQueryExpr(select));
            } else if (this.lexer.token() != Token.IN && this.lexer.token() != Token.OUT && this.lexer.token() != Token.INOUT) {
               parameter.setParamType(SQLParameter.ParameterType.DEFAULT);
               parameter.setName(this.exprParser.name());
               parameter.setDataType(this.exprParser.parseDataType());
               if (this.lexer.token() == Token.COLONEQ) {
                  this.lexer.nextToken();
                  parameter.setDefaultValue(this.exprParser.expr());
               }
            } else {
               if (this.lexer.token() == Token.IN) {
                  parameter.setParamType(SQLParameter.ParameterType.IN);
               } else if (this.lexer.token() == Token.OUT) {
                  parameter.setParamType(SQLParameter.ParameterType.OUT);
               } else if (this.lexer.token() == Token.INOUT) {
                  parameter.setParamType(SQLParameter.ParameterType.INOUT);
               }

               this.lexer.nextToken();
               parameter.setName(this.exprParser.name());
               parameter.setDataType(this.exprParser.parseDataType());
            }

            parameters.add(parameter);
            if (this.lexer.token() == Token.COMMA || this.lexer.token() == Token.SEMI) {
               this.lexer.nextToken();
            }
         } while(this.lexer.token() != Token.BEGIN && this.lexer.token() != Token.RPAREN);

      }
   }

   private void parseProcedureStatementList(List<SQLStatement> statementList) {
      this.parseProcedureStatementList(statementList, -1);
   }

   private void parseProcedureStatementList(List<SQLStatement> statementList, int max) {
      while(max == -1 || statementList.size() < max) {
         if (this.lexer.token() == Token.EOF) {
            return;
         }

         if (this.lexer.token() == Token.END) {
            return;
         }

         if (this.lexer.token() == Token.ELSE) {
            return;
         }

         if (this.lexer.token() == Token.SEMI) {
            this.lexer.nextToken();
         } else {
            if (this.lexer.token() == Token.WHEN) {
               return;
            }

            if (this.lexer.token() == Token.UNTIL) {
               return;
            }

            if (this.lexer.token() == Token.SELECT) {
               statementList.add(this.parseSelectInto());
            } else if (this.lexer.token() == Token.UPDATE) {
               statementList.add(this.parseUpdateStatement());
            } else if (this.lexer.token() == Token.CREATE) {
               statementList.add(this.parseCreate());
            } else if (this.lexer.token() == Token.INSERT) {
               SQLStatement stmt = this.parseInsert();
               statementList.add(stmt);
            } else if (this.lexer.token() == Token.DELETE) {
               statementList.add(this.parseDeleteStatement());
            } else if (this.lexer.token() != Token.LBRACE && !this.lexer.identifierEquals("CALL")) {
               if (this.lexer.token() == Token.BEGIN) {
                  statementList.add(this.parseBlock());
               } else if (this.lexer.token() == Token.VARIANT) {
                  SQLExpr variant = this.exprParser.primary();
                  if (variant instanceof SQLBinaryOpExpr) {
                     SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr)variant;
                     if (binaryOpExpr.getOperator() == SQLBinaryOperator.Assignment) {
                        SQLSetStatement stmt = new SQLSetStatement(binaryOpExpr.getLeft(), binaryOpExpr.getRight(), this.getDbType());
                        statementList.add(stmt);
                        continue;
                     }
                  }

                  this.accept(Token.COLONEQ);
                  SQLExpr value = this.exprParser.expr();
                  SQLSetStatement stmt = new SQLSetStatement(variant, value, this.getDbType());
                  statementList.add(stmt);
               } else if (this.lexer.token() == Token.LPAREN) {
                  char ch = this.lexer.current();
                  int bp = this.lexer.bp();
                  this.lexer.nextToken();
                  if (this.lexer.token() != Token.SELECT) {
                     throw new ParserException("TODO. " + this.lexer.info());
                  }

                  this.lexer.reset(bp, ch, Token.LPAREN);
                  statementList.add(this.parseSelect());
               } else if (this.lexer.token() == Token.SET) {
                  statementList.add(this.parseAssign());
               } else if (this.lexer.token() == Token.WHILE) {
                  SQLStatement stmt = this.parseWhile();
                  statementList.add(stmt);
               } else if (this.lexer.token() == Token.LOOP) {
                  statementList.add(this.parseLoop());
               } else if (this.lexer.token() == Token.IF) {
                  statementList.add(this.parseIf());
               } else if (this.lexer.token() == Token.CASE) {
                  statementList.add(this.parseCase());
               } else if (this.lexer.token() == Token.DECLARE) {
                  SQLStatement stmt = this.parseDeclare();
                  statementList.add(stmt);
               } else if (this.lexer.token() == Token.LEAVE) {
                  statementList.add(this.parseLeave());
               } else if (this.lexer.token() == Token.ITERATE) {
                  statementList.add(this.parseIterate());
               } else if (this.lexer.token() == Token.REPEAT) {
                  statementList.add(this.parseRepeat());
               } else if (this.lexer.token() == Token.OPEN) {
                  statementList.add(this.parseOpen());
               } else if (this.lexer.token() == Token.CLOSE) {
                  statementList.add(this.parseClose());
               } else if (this.lexer.token() == Token.FETCH) {
                  statementList.add(this.parseFetch());
               } else if (this.lexer.identifierEquals(FnvHash.Constants.CHECKSUM)) {
                  statementList.add(this.parseChecksum());
               } else {
                  if (this.lexer.token() == Token.IDENTIFIER) {
                     String label = this.lexer.stringVal();
                     char ch = this.lexer.current();
                     int bp = this.lexer.bp();
                     this.lexer.nextToken();
                     if (this.lexer.token() == Token.VARIANT && this.lexer.stringVal().equals(":")) {
                        this.lexer.nextToken();
                        if (this.lexer.token() == Token.LOOP) {
                           statementList.add(this.parseLoop(label));
                           continue;
                        }

                        if (this.lexer.token() == Token.WHILE) {
                           statementList.add(this.parseWhile(label));
                           continue;
                        }

                        if (this.lexer.token() == Token.BEGIN) {
                           statementList.add(this.parseBlock(label));
                           continue;
                        }

                        if (this.lexer.token() == Token.REPEAT) {
                           statementList.add(this.parseRepeat(label));
                        }
                        continue;
                     }

                     this.lexer.reset(bp, ch, Token.IDENTIFIER);
                  }

                  throw new ParserException("TODO, " + this.lexer.info());
               }
            } else {
               statementList.add(this.parseCall());
            }
         }
      }

   }

   public MariadbChecksumTableStatement parseChecksum() {
      MariadbChecksumTableStatement stmt = new MariadbChecksumTableStatement();
      if (!this.lexer.identifierEquals(FnvHash.Constants.CHECKSUM)) {
         throw new ParserException("TODO " + this.lexer.info());
      } else {
         this.lexer.nextToken();
         this.accept(Token.TABLE);

         while(true) {
             SQLExpr table = this.exprParser.name();
            stmt.addTable(new SQLExprTableSource(table));
            if (this.lexer.token() != Token.COMMA) {
               if (this.lexer.identifierEquals("QUICK") || this.lexer.identifierEquals("EXTENDED")) {
                  table = this.exprParser.expr();
                  stmt.setIdentified(table);
               }

               return stmt;
            }

            this.lexer.nextToken();
         }
      }
   }

   public SQLIfStatement parseIf() {
      this.accept(Token.IF);
      SQLIfStatement stmt = new SQLIfStatement();
      stmt.setCondition(this.exprParser.expr());
      this.accept(Token.THEN);
      this.lexer.throwIfStateEnd = false;
      this.parseStatementList(stmt.getStatements(), -1, stmt);

      while(this.lexer.token() == Token.ELSEIF || this.lexer.token() == Token.ELSE) {
         if (this.lexer.token() != Token.ELSEIF) {
            this.lexer.nextToken();
            SQLIfStatement.Else elseItem = new SQLIfStatement.Else();
            this.parseStatementList(elseItem.getStatements(), -1, elseItem);
            stmt.setElseItem(elseItem);
            break;
         }

         this.lexer.nextToken();
         SQLIfStatement.ElseIf elseIf = new SQLIfStatement.ElseIf();
         elseIf.setCondition(this.exprParser.expr());
         elseIf.setParent(stmt);
         this.accept(Token.THEN);
         this.parseStatementList(elseIf.getStatements(), -1, elseIf);
         stmt.getElseIfList().add(elseIf);
      }

      this.accept(Token.END);
      this.accept(Token.IF);
      this.accept(Token.SEMI);
      stmt.setAfterSemi(true);
      return stmt;
   }

   public SQLWhileStatement parseWhile() {
      this.accept(Token.WHILE);
      SQLWhileStatement stmt = new SQLWhileStatement();
      stmt.setCondition(this.exprParser.expr());
      this.accept(Token.DO);
      this.parseStatementList(stmt.getStatements(), -1, stmt);
      this.accept(Token.END);
      this.accept(Token.WHILE);
      this.accept(Token.SEMI);
      stmt.setAfterSemi(true);
      return stmt;
   }

   public SQLWhileStatement parseWhile(String label) {
      this.accept(Token.WHILE);
      SQLWhileStatement stmt = new SQLWhileStatement();
      stmt.setLabelName(label);
      stmt.setCondition(this.exprParser.expr());
      this.accept(Token.DO);
      this.parseStatementList(stmt.getStatements(), -1, stmt);
      this.accept(Token.END);
      this.accept(Token.WHILE);
      this.acceptIdentifier(label);
      this.accept(Token.SEMI);
      stmt.setAfterSemi(true);
      return stmt;
   }

   public MariadbCaseStatement parseCase() {
      MariadbCaseStatement stmt = new MariadbCaseStatement();
      this.accept(Token.CASE);
      if (this.lexer.token() != Token.WHEN) {
         stmt.setCondition(this.exprParser.expr());

         while(this.lexer.token() == Token.WHEN) {
            this.accept(Token.WHEN);
            MariadbCaseStatement.MariadbWhenStatement when = new MariadbCaseStatement.MariadbWhenStatement();
            when.setCondition(this.exprParser.expr());
            this.accept(Token.THEN);
            this.parseStatementList(when.getStatements(), -1, when);
            stmt.addWhenStatement(when);
         }

         if (this.lexer.token() == Token.ELSE) {
            this.accept(Token.ELSE);
            SQLIfStatement.Else elseStmt = new SQLIfStatement.Else();
            this.parseStatementList(elseStmt.getStatements(), -1, elseStmt);
            stmt.setElseItem(elseStmt);
         }
      } else {
         while(this.lexer.token() == Token.WHEN) {
            MariadbCaseStatement.MariadbWhenStatement when = new MariadbCaseStatement.MariadbWhenStatement();
            when.setCondition(this.exprParser.expr());
            this.accept(Token.THEN);
            this.parseStatementList(when.getStatements(), -1, when);
            stmt.addWhenStatement(when);
         }

         if (this.lexer.token() == Token.ELSE) {
            SQLIfStatement.Else elseStmt = new SQLIfStatement.Else();
            this.parseStatementList(elseStmt.getStatements(), -1, elseStmt);
            stmt.setElseItem(elseStmt);
         }
      }

      this.accept(Token.END);
      this.accept(Token.CASE);
      this.accept(Token.SEMI);
      return stmt;
   }

   public SQLStatement parseDeclare() {
      char markChar = this.lexer.current();
      int markBp = this.lexer.bp();
      this.lexer.nextToken();
      if (this.lexer.token() == Token.CONTINUE) {
         this.lexer.reset(markBp, markChar, Token.DECLARE);
         return this.parseDeclareHandler();
      } else {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.CURSOR) {
            this.lexer.reset(markBp, markChar, Token.DECLARE);
            return this.parseCursorDeclare();
         } else if (this.lexer.identifierEquals("HANDLER")) {
            this.lexer.reset(markBp, markChar, Token.DECLARE);
            return this.parseDeclareHandler();
         } else if (this.lexer.token() == Token.CONDITION) {
            this.lexer.reset(markBp, markChar, Token.DECLARE);
            return this.parseDeclareCondition();
         } else {
            this.lexer.reset(markBp, markChar, Token.DECLARE);
            MariadbDeclareStatement stmt = new MariadbDeclareStatement();
            this.accept(Token.DECLARE);

            while(true) {
               SQLDeclareItem item = new SQLDeclareItem();
               item.setName(this.exprParser.name());
               stmt.addVar(item);
               if (this.lexer.token() != Token.COMMA) {
                  if (this.lexer.token() != Token.EOF) {
                     item.setDataType(this.exprParser.parseDataType());
                     if (this.lexer.token() == Token.DEFAULT) {
                        this.lexer.nextToken();
                        SQLExpr defaultValue = this.exprParser.primary();
                        item.setValue(defaultValue);
                     }

                     return stmt;
                  } else {
                     throw new ParserException("TODO. " + this.lexer.info());
                  }
               }

               this.lexer.nextToken();
               stmt.setAfterSemi(true);
            }
         }
      }
   }

   public SQLSetStatement parseAssign() {
      this.accept(Token.SET);
      SQLSetStatement stmt = new SQLSetStatement(this.getDbType());
      this.parseAssignItems(stmt.getItems(), stmt);
      return stmt;
   }

   public MariadbSelectIntoStatement parseSelectInto() {
      MariadbSelectIntoParser parse = new MariadbSelectIntoParser(this.exprParser);
      return parse.parseSelectInto();
   }

   public SQLLoopStatement parseLoop() {
      SQLLoopStatement loopStmt = new SQLLoopStatement();
      this.accept(Token.LOOP);
      this.lexer.throwIfStateEnd = false;
      this.parseStatementList(loopStmt.getStatements(), -1, loopStmt);
      this.accept(Token.END);
      this.accept(Token.LOOP);
      this.accept(Token.SEMI);
      loopStmt.setAfterSemi(true);
      return loopStmt;
   }

   public SQLLoopStatement parseLoop(String label) {
      SQLLoopStatement loopStmt = new SQLLoopStatement();
      loopStmt.setLabelName(label);
      this.accept(Token.LOOP);
      this.lexer.throwIfStateEnd = false;
      this.parseStatementList(loopStmt.getStatements(), -1, loopStmt);
      this.accept(Token.END);
      this.accept(Token.LOOP);
      if (this.lexer.token() != Token.SEMI) {
         this.acceptIdentifier(label);
      }

      this.accept(Token.SEMI);
      loopStmt.setAfterSemi(true);
      return loopStmt;
   }

   public SQLBlockStatement parseBlock(String label) {
      SQLBlockStatement block = new SQLBlockStatement();
      block.setLabelName(label);
      this.accept(Token.BEGIN);
      this.parseStatementList(block.getStatementList(), -1, block);
      this.accept(Token.END);
      this.acceptIdentifier(label);
      return block;
   }

   public MariadbLeaveStatement parseLeave() {
      this.accept(Token.LEAVE);
      MariadbLeaveStatement leaveStmt = new MariadbLeaveStatement();
      leaveStmt.setLabelName(this.exprParser.name().getSimpleName());
      this.accept(Token.SEMI);
      return leaveStmt;
   }

   public MariadbIterateStatement parseIterate() {
      this.accept(Token.ITERATE);
      MariadbIterateStatement iterateStmt = new MariadbIterateStatement();
      iterateStmt.setLabelName(this.exprParser.name().getSimpleName());
      this.accept(Token.SEMI);
      return iterateStmt;
   }

   public MariadbRepeatStatement parseRepeat() {
      MariadbRepeatStatement stmt = new MariadbRepeatStatement();
      this.accept(Token.REPEAT);
      this.parseStatementList(stmt.getStatements(), -1, stmt);
      this.accept(Token.UNTIL);
      stmt.setCondition(this.exprParser.expr());
      this.accept(Token.END);
      this.accept(Token.REPEAT);
      this.accept(Token.SEMI);
      stmt.setAfterSemi(true);
      return stmt;
   }

   public MariadbRepeatStatement parseRepeat(String label) {
      MariadbRepeatStatement repeatStmt = new MariadbRepeatStatement();
      repeatStmt.setLabelName(label);
      this.accept(Token.REPEAT);
      this.parseStatementList(repeatStmt.getStatements(), -1, repeatStmt);
      this.accept(Token.UNTIL);
      repeatStmt.setCondition(this.exprParser.expr());
      this.accept(Token.END);
      this.accept(Token.REPEAT);
      if (this.lexer.token() != Token.SEMI) {
         this.acceptIdentifier(label);
      }

      this.accept(Token.SEMI);
      return repeatStmt;
   }

   public MariadbCursorDeclareStatement parseCursorDeclare() {
      MariadbCursorDeclareStatement stmt = new MariadbCursorDeclareStatement();
      this.accept(Token.DECLARE);
      stmt.setCursorName(this.exprParser.name());
      this.accept(Token.CURSOR);
      this.accept(Token.FOR);
      SQLSelect select = this.createSQLSelectParser().select();
      stmt.setSelect(select);
      this.accept(Token.SEMI);
      return stmt;
   }

   public SQLStatement parseSpStatement() {
      if (this.lexer.token() == Token.UPDATE) {
         return this.parseUpdateStatement();
      } else if (this.lexer.token() == Token.CREATE) {
         return this.parseCreate();
      } else if (this.lexer.token() == Token.INSERT) {
         return this.parseInsert();
      } else if (this.lexer.token() == Token.DELETE) {
         return this.parseDeleteStatement();
      } else if (this.lexer.token() == Token.BEGIN) {
         return this.parseBlock();
      } else if (this.lexer.token() == Token.LPAREN) {
         char ch = this.lexer.current();
         int bp = this.lexer.bp();
         this.lexer.nextToken();
         if (this.lexer.token() == Token.SELECT) {
            this.lexer.reset(bp, ch, Token.LPAREN);
            return this.parseSelect();
         } else {
            throw new ParserException("TODO. " + this.lexer.info());
         }
      } else if (this.lexer.token() == Token.SET) {
         return this.parseAssign();
      } else {
         throw new ParserException("error sp_statement. " + this.lexer.info());
      }
   }

   public MariadbDeclareHandlerStatement parseDeclareHandler() {
      MariadbDeclareHandlerStatement stmt = new MariadbDeclareHandlerStatement();
      this.accept(Token.DECLARE);
      if (this.lexer.token() == Token.CONTINUE) {
         stmt.setHandleType(MariadbHandlerType.CONTINUE);
      } else if (this.lexer.token() == Token.EXIT) {
         stmt.setHandleType(MariadbHandlerType.CONTINUE);
      } else {
         if (this.lexer.token() != Token.UNDO) {
            throw new ParserException("unkown handle type. " + this.lexer.info());
         }

         stmt.setHandleType(MariadbHandlerType.CONTINUE);
      }

      this.lexer.nextToken();
      this.acceptIdentifier("HANDLER");
      this.accept(Token.FOR);

      while(true) {
         String tokenName = this.lexer.stringVal();
         ConditionValue condition = new ConditionValue();
         if (tokenName.equalsIgnoreCase("NOT")) {
            this.lexer.nextToken();
            this.acceptIdentifier("FOUND");
            condition.setType(ConditionValue.ConditionType.SYSTEM);
            condition.setValue("NOT FOUND");
         } else if (tokenName.equalsIgnoreCase("SQLSTATE")) {
            condition.setType(ConditionValue.ConditionType.SQLSTATE);
            this.lexer.nextToken();
            condition.setValue(this.exprParser.name().toString());
         } else if (this.lexer.identifierEquals("SQLEXCEPTION")) {
            condition.setType(ConditionValue.ConditionType.SYSTEM);
            condition.setValue(this.lexer.stringVal());
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("SQLWARNING")) {
            condition.setType(ConditionValue.ConditionType.SYSTEM);
            condition.setValue(this.lexer.stringVal());
            this.lexer.nextToken();
         } else {
            if (this.lexer.token() == Token.LITERAL_INT) {
               condition.setType(ConditionValue.ConditionType.MARIADB_ERROR_CODE);
               condition.setValue(this.lexer.integerValue().toString());
            } else {
               condition.setType(ConditionValue.ConditionType.SELF);
               condition.setValue(tokenName);
            }

            this.lexer.nextToken();
         }

         stmt.getConditionValues().add(condition);
         if (this.lexer.token() != Token.COMMA) {
            if (this.lexer.token() != Token.EOF) {
               stmt.setSpStatement(this.parseSpStatement());
               if (!(stmt.getSpStatement() instanceof SQLBlockStatement)) {
                  this.accept(Token.SEMI);
               }

               return stmt;
            }

            throw new ParserException("declare handle not eof");
         }

         this.accept(Token.COMMA);
      }
   }

   public MariadbDeclareConditionStatement parseDeclareCondition() {
      MariadbDeclareConditionStatement stmt = new MariadbDeclareConditionStatement();
      this.accept(Token.DECLARE);
      stmt.setConditionName(this.exprParser.name().toString());
      this.accept(Token.CONDITION);
      this.accept(Token.FOR);
      String tokenName = this.lexer.stringVal();
      ConditionValue condition = new ConditionValue();
      if (tokenName.equalsIgnoreCase("SQLSTATE")) {
         condition.setType(ConditionValue.ConditionType.SQLSTATE);
         this.lexer.nextToken();
         condition.setValue(this.exprParser.name().toString());
      } else {
         if (this.lexer.token() != Token.LITERAL_INT) {
            throw new ParserException("declare condition grammer error. " + this.lexer.info());
         }

         condition.setType(ConditionValue.ConditionType.MARIADB_ERROR_CODE);
         condition.setValue(this.lexer.integerValue().toString());
         this.lexer.nextToken();
      }

      stmt.setConditionValue(condition);
      this.accept(Token.SEMI);
      return stmt;
   }

   public SQLStatement parseFlashback() {
      MariadbFlashbackStatement stmt = new MariadbFlashbackStatement();
      this.acceptIdentifier("FLASHBACK");
      this.accept(Token.TABLE);
      SQLName name = this.exprParser.name();
      stmt.setName(name);
      this.accept(Token.TO);
      this.acceptIdentifier("BEFORE");
      this.accept(Token.DROP);
      if (this.lexer.identifierEquals(FnvHash.Constants.RENAME)) {
         this.lexer.nextToken();
         this.accept(Token.TO);
         SQLName to = this.exprParser.name();
         stmt.setRenameTo(to);
      }

      return stmt;
   }

   public Timestamp getCurrentTimestamp() {
      return this.now;
   }

   public Date getCurrentDate() {
      return this.currentDate;
   }

   public MariadbCreateTableParser getSQLCreateTableParser() {
      return new MariadbCreateTableParser(this.exprParser);
   }

   public SQLStatement parseCopy() {
      this.acceptIdentifier("COPY");
      SQLCopyFromStatement stmt = new SQLCopyFromStatement();
      SQLExpr table = this.exprParser.name();
      stmt.setTable(new SQLExprTableSource(table));
      if (this.lexer.token() == Token.LPAREN) {
         this.lexer.nextToken();
         this.exprParser.names(stmt.getColumns(), stmt);
         this.accept(Token.RPAREN);
      }

      if (this.lexer.token() == Token.PARTITION) {
         this.lexer.nextToken();
         this.exprParser.parseAssignItem(stmt.getPartitions(), stmt);
      }

      this.accept(Token.FROM);
      SQLExpr from = this.exprParser.expr();
      stmt.setFrom(from);
      if (this.lexer.identifierEquals(FnvHash.Constants.CREDENTIALS)) {
         this.lexer.nextToken();

         label41:
         while(true) {
            while(!this.lexer.identifierEquals(FnvHash.Constants.ACCESS_KEY_ID)) {
               if (!this.lexer.identifierEquals(FnvHash.Constants.ACCESS_KEY_SECRET)) {
                  break label41;
               }

               this.lexer.nextToken();
               SQLExpr accessKeySecret = this.exprParser.primary();
               stmt.setAccessKeySecret(accessKeySecret);
            }

            this.lexer.nextToken();
            SQLExpr accessKeyId = this.exprParser.primary();
            stmt.setAccessKeyId(accessKeyId);
         }
      }

      if (this.lexer.token() == Token.WITH) {
         this.lexer.nextToken();
         this.accept(Token.LPAREN);

         while(true) {
            SQLName name = this.exprParser.name();
            if (this.lexer.token() == Token.EQ) {
               this.lexer.nextToken();
            }

            SQLExpr value = this.exprParser.expr();
            SQLAssignItem item = new SQLAssignItem(name, value);
            item.setParent(stmt);
            stmt.getOptions().add(item);
            if (this.lexer.token() != Token.COMMA) {
               this.accept(Token.RPAREN);
               break;
            }

            this.lexer.nextToken();
         }
      }

      return stmt;
   }

   public MariadbGrantStatement parseGrant() {
      this.accept(Token.GRANT);
      MariadbGrantStatement stmt = new MariadbGrantStatement(DbType.mysql);
      this.parsePrivileages(stmt.getPrivileges(), stmt);
      if (this.lexer.token() == Token.ON) {
         this.lexer.nextToken();
         switch (this.lexer.token()) {
            case PROCEDURE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.PROCEDURE);
               break;
            case FUNCTION:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.FUNCTION);
               break;
            case TABLE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.TABLE);
         }

         SQLExpr expr;
         if (this.lexer.token() == Token.DOT) {
            expr = new SQLAllColumnExpr();
            this.lexer.nextToken();
         } else {
            expr = this.exprParser.expr();
         }

         if (stmt.getResourceType() != SQLObjectType.TABLE && stmt.getResourceType() != null) {
            stmt.setResource(expr);
         } else {
            stmt.setResource(new SQLExprTableSource(expr));
         }
      }

      if (this.lexer.token() == Token.TO) {
         this.lexer.nextToken();

         while(true) {
            SQLExpr user = this.parseUser();
            stmt.getUsers().add(user);
            if (this.lexer.token() != Token.COMMA) {
               break;
            }

            this.lexer.nextToken();
         }
      }

      if (this.lexer.identifierEquals("REQUIRE")) {
         this.lexer.nextToken();
         stmt.setRequire(true);
         if (this.lexer.identifierEquals("NONE")) {
            this.lexer.nextToken();
            stmt.setNone(true);
         } else {
            while(true) {
               SQLExpr tlsOption = this.exprParser.expr();
               if (this.lexer.identifierEquals("SSL")) {
                  stmt.getTlsOptions().add(tlsOption);
               } else if (this.lexer.identifierEquals("X509")) {
                  stmt.getTlsOptions().add(tlsOption);
               } else if (this.lexer.identifierEquals("CIPHER")) {
                  SQLIdentifierExpr identifierExpr = new SQLIdentifierExpr("CIPHER 'cipher'");
                  stmt.getTlsOptions().add(identifierExpr);
                  this.lexer.nextToken();
               } else if (this.lexer.identifierEquals("ISSUER")) {
                  SQLIdentifierExpr identifierExpr = new SQLIdentifierExpr("ISSUER 'issuer'");
                  stmt.getTlsOptions().add(identifierExpr);
                  this.lexer.nextToken();
               } else {
                  if (!this.lexer.identifierEquals("SUBJECT")) {
                     break;
                  }

                  SQLIdentifierExpr identifierExpr = new SQLIdentifierExpr("SUBJECT 'subject'");
                  stmt.getTlsOptions().add(identifierExpr);
                  this.lexer.nextToken();
               }

               this.lexer.nextToken();
               if (this.lexer.token() != Token.AND) {
                  break;
               }

               this.lexer.nextToken();
            }
         }
      }

      if (this.lexer.token() == Token.WITH) {
         this.lexer.nextToken();
         stmt.setWith(true);
         if (this.lexer.token() == Token.GRANT) {
            this.lexer.nextToken();
            this.acceptIdentifier("OPTION");
            stmt.setWithGrantOption(true);
         } else {
            label116:
            while(true) {
               while(!this.lexer.identifierEquals("MAX_QUERIES_PER_HOUR")) {
                  if (this.lexer.identifierEquals("MAX_UPDATES_PER_HOUR")) {
                     this.lexer.nextToken();
                     stmt.getResourceOptions().add(new SQLIdentifierExpr("MAX_UPDATES_PER_HOUR " + this.parseIntValue() + ""));
                  } else if (this.lexer.identifierEquals("MAX_CONNECTIONS_PER_HOUR")) {
                     this.lexer.nextToken();
                     stmt.getResourceOptions().add(new SQLIdentifierExpr("MAX_CONNECTIONS_PER_HOUR " + this.parseIntValue() + ""));
                  } else {
                     if (!this.lexer.identifierEquals("MAX_USER_CONNECTIONS")) {
                        break label116;
                     }

                     this.lexer.nextToken();
                     stmt.getResourceOptions().add(new SQLIdentifierExpr("MAX_USER_CONNECTIONS " + this.parseIntValue() + ""));
                  }
               }

               this.lexer.nextToken();
               stmt.getResourceOptions().add(new SQLIdentifierExpr("MAX_QUERIES_PER_HOUR " + this.parseIntValue() + ""));
            }
         }
      }

      if (this.lexer.identifierEquals("ADMIN")) {
         this.lexer.nextToken();
         this.acceptIdentifier("OPTION");
         stmt.setAdminOption(true);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.IDENTIFIED)) {
         this.lexer.nextToken();
         this.accept(Token.BY);
         if (this.lexer.identifierEquals("PASSWORD")) {
            this.lexer.nextToken();
            String password = this.lexer.stringVal();
            this.accept(Token.LITERAL_CHARS);
            stmt.setIdentifiedByPassword(password);
         } else {
            stmt.setIdentifiedBy(this.exprParser.expr());
         }
      }

      if (this.lexer.token() == Token.AS) {
         this.lexer.nextToken();
         stmt.setAs(true);
         if (this.lexer.token() == Token.IDENTIFIER) {
            SQLExpr user = this.parseUser();
            stmt.setIdentifiedByUser(user);
         }

         if (this.lexer.token() == Token.WITH) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("ROLE")) {
               this.lexer.nextToken();
               if (this.lexer.identifierEquals("NONE")) {
                  stmt.setType("NONE");
                  this.lexer.nextToken();
               } else if (this.lexer.token() == Token.DEFAULT) {
                  stmt.setType("DEFAULT");
                  this.lexer.nextToken();
               } else if (this.lexer.token() == Token.ALL) {
                  stmt.setType("ALL");
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.EXCEPT) {
                     stmt.setExcept(true);
                     this.lexer.nextToken();

                     while(true) {
                        SQLExpr role = this.exprParser.expr();
                        stmt.getIdentifiedByRoles().add(role);
                        if (this.lexer.token() != Token.COMMA) {
                           break;
                        }

                        this.lexer.nextToken();
                     }
                  }
               } else {
                  this.lexer.nextToken();

                  while(true) {
                     SQLExpr role = this.exprParser.expr();
                     stmt.getIdentifiedByRoles().add(role);
                     if (this.lexer.token() != Token.COMMA) {
                        break;
                     }

                     this.lexer.nextToken();
                  }
               }

               stmt.setWithRole(true);
            }
         }
      }

      return stmt;
   }

   public SQLRevokeStatement parseRevoke() {
      this.accept(Token.REVOKE);
      MariadbRevokeStatement stmt = new MariadbRevokeStatement(this.dbType);
      if (this.lexer.token() == Token.IF && this.dbType == DbType.mysql) {
         this.lexer.nextToken();
         this.accept(Token.EXISTS);
         stmt.setIfExists(true);
      }

      if (this.lexer.token() == Token.GRANT) {
         this.lexer.nextToken();
         this.acceptIdentifier("OPTION");
         stmt.setGrantOption(true);
         if (this.lexer.token() == Token.FOR) {
            this.lexer.nextToken();
         }
      }

      this.parsePrivileages(stmt.getPrivileges(), stmt);
      if (this.lexer.token() == Token.ON) {
         this.lexer.nextToken();
         switch (this.lexer.token()) {
            case USER:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.USER);
               break;
            case PROCEDURE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.PROCEDURE);
               break;
            case FUNCTION:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.FUNCTION);
               break;
            case IDENTIFIER:
               if (this.lexer.identifierEquals("SYSTEM")) {
                  this.lexer.nextToken();
                  stmt.setResourceType(SQLObjectType.SYSTEM);
               } else if (this.lexer.identifierEquals("PROJECT")) {
                  this.lexer.nextToken();
                  stmt.setResourceType(SQLObjectType.PROJECT);
               }
               break;
            case TABLE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.TABLE);
         }

         SQLExpr expr = this.exprParser.expr();
         if (stmt.getResourceType() != SQLObjectType.TABLE && stmt.getResourceType() != null) {
            stmt.setResource(expr);
         } else {
            stmt.setResource(new SQLExprTableSource(expr));
         }
      }

      if (this.lexer.token() == Token.FROM) {
         this.lexer.nextToken();

         while(true) {
            if (this.lexer.token() == Token.USER && this.dbType == DbType.odps) {
               this.lexer.nextToken();
            }

            SQLExpr user = this.parseUser();
            stmt.getUsers().add(user);
            if (this.lexer.token() != Token.COMMA) {
               break;
            }

            this.lexer.nextToken();
         }
      }

      if (this.lexer.token() == Token.IDENTIFIER && this.dbType == DbType.mysql && this.lexer.identifierEquals("IGNORE")) {
         this.lexer.nextToken();
         this.acceptIdentifier("UNKNOWN");
         this.accept(Token.USER);
         stmt.setIgnoreUnknownUser(true);
      }

      return stmt;
   }

   public MariadbRepairTableStatement parseRepair() {
      MariadbRepairTableStatement stmt = new MariadbRepairTableStatement();
      this.accept(Token.REPAIR);
      if (this.lexer.identifierEquals("NO_WRITE_TO_BINLOG")) {
         this.lexer.nextToken();
         stmt.setNoWriteToBinlog(true);
      }

      if (this.lexer.identifierEquals("LOCAL")) {
         this.lexer.nextToken();
         stmt.setLocal(true);
      }

      this.accept(Token.TABLE);
      List<SQLName> names = new ArrayList();
      this.exprParser.names(names, stmt);

      for(SQLName name : names) {
         stmt.addTableSource(new SQLExprTableSource(name));
      }

      while(this.lexer.token() != Token.EOF) {
         List<String> identifiedList = Arrays.asList("QUICK", "EXTENDED", "USE_FRM");
         if (!identifiedList.contains(this.lexer.stringVal())) {
            break;
         }

         SQLExpr identified = this.exprParser.expr();
         stmt.getIdentifiedList().add(identified);
      }

      return stmt;
   }

   public int parseIntValue() {
      if (this.lexer.token() == Token.LITERAL_INT) {
         Number number = this.lexer.integerValue();
         int intVal = (Integer)number;
         this.lexer.nextToken();
         return intVal;
      } else {
         throw new ParserException("not int. " + this.lexer.info());
      }
   }
}
