MySQLQueryType MySQLBaseLexer::determineQueryType()

in mysqlshdk/libs/parser/MySQLBaseLexer.cpp [178:859]


MySQLQueryType MySQLBaseLexer::determineQueryType() {
  std::unique_ptr<Token> tok = nextDefaultChannelToken();
  if (tok->getType() == Token::EOF) return QtUnknown;

  switch (tok->getType()) {
    case MySQLLexer::ALTER_SYMBOL:
      tok = nextDefaultChannelToken();
      if (tok->getType() == Token::EOF) return QtAmbiguous;

      switch (tok->getType()) {
        case MySQLLexer::DATABASE_SYMBOL:
          return QtAlterDatabase;

        case MySQLLexer::LOGFILE_SYMBOL:
          return QtAlterLogFileGroup;

        case MySQLLexer::FUNCTION_SYMBOL:
          return QtAlterFunction;

        case MySQLLexer::PROCEDURE_SYMBOL:
          return QtAlterProcedure;

        case MySQLLexer::SERVER_SYMBOL:
          return QtAlterServer;

        case MySQLLexer::TABLE_SYMBOL:
        case MySQLLexer::ONLINE_SYMBOL:   // Optional part of ALTER TABLE.
        case MySQLLexer::OFFLINE_SYMBOL:  // ditto
        case MySQLLexer::IGNORE_SYMBOL:
          return QtAlterTable;

        case MySQLLexer::TABLESPACE_SYMBOL:
          return QtAlterTableSpace;

        case MySQLLexer::EVENT_SYMBOL:
          return QtAlterEvent;

        case MySQLLexer::VIEW_SYMBOL:
          return QtAlterView;

        case MySQLLexer::DEFINER_SYMBOL:  // Can be both event or view.
          if (!skipDefiner(tok)) return QtAmbiguous;

          tok = nextDefaultChannelToken();

          switch (tok->getType()) {
            case MySQLLexer::EVENT_SYMBOL:
              return QtAlterEvent;

            case MySQLLexer::SQL_SYMBOL:
            case MySQLLexer::VIEW_SYMBOL:
              return QtAlterView;
          }
          break;

        case MySQLLexer::ALGORITHM_SYMBOL:  // Optional part of CREATE VIEW.
          return QtAlterView;

        case MySQLLexer::USER_SYMBOL:
          return QtAlterUser;
      }
      break;

    case MySQLLexer::CREATE_SYMBOL: {
      tok = nextDefaultChannelToken();
      if (tok->getType() == Token::EOF) return QtAmbiguous;

      switch (tok->getType()) {
        case MySQLLexer::TEMPORARY_SYMBOL:  // Optional part of CREATE TABLE.
        case MySQLLexer::TABLE_SYMBOL:
          return QtCreateTable;

        case MySQLLexer::ONLINE_SYMBOL:
        case MySQLLexer::OFFLINE_SYMBOL:
        case MySQLLexer::INDEX_SYMBOL:
        case MySQLLexer::UNIQUE_SYMBOL:
        case MySQLLexer::FULLTEXT_SYMBOL:
        case MySQLLexer::SPATIAL_SYMBOL:
          return QtCreateIndex;

        case MySQLLexer::DATABASE_SYMBOL:
          return QtCreateDatabase;

        case MySQLLexer::TRIGGER_SYMBOL:
          return QtCreateTrigger;

        case MySQLLexer::DEFINER_SYMBOL:  // Can be event, view, procedure,
                                          // function, UDF, trigger.
        {
          if (!skipDefiner(tok)) return QtAmbiguous;

          switch (tok->getType()) {
            case MySQLLexer::EVENT_SYMBOL:
              return QtCreateEvent;

            case MySQLLexer::VIEW_SYMBOL:
            case MySQLLexer::SQL_SYMBOL:
              return QtCreateView;

            case MySQLLexer::PROCEDURE_SYMBOL:
              return QtCreateProcedure;

            case MySQLLexer::FUNCTION_SYMBOL: {
              tok = nextDefaultChannelToken();
              if (tok->getType() == Token::EOF) return QtAmbiguous;

              if (!isIdentifier(tok->getType())) return QtAmbiguous;

              tok = nextDefaultChannelToken();
              if (tok->getType() == MySQLLexer::RETURNS_SYMBOL)
                return QtCreateUdf;

              return QtCreateFunction;
            }

            case MySQLLexer::AGGREGATE_SYMBOL:
              return QtCreateUdf;

            case MySQLLexer::TRIGGER_SYMBOL:
              return QtCreateTrigger;
          }

          return QtUnknown;
        }

        case MySQLLexer::VIEW_SYMBOL:
        case MySQLLexer::OR_SYMBOL:         // CREATE OR REPLACE ... VIEW
        case MySQLLexer::ALGORITHM_SYMBOL:  // CREATE ALGORITHM ... VIEW
          return QtCreateView;

        case MySQLLexer::EVENT_SYMBOL:
          return QtCreateEvent;

        case MySQLLexer::FUNCTION_SYMBOL:
          return QtCreateFunction;

        case MySQLLexer::AGGREGATE_SYMBOL:
          return QtCreateUdf;

        case MySQLLexer::PROCEDURE_SYMBOL:
          return QtCreateProcedure;

        case MySQLLexer::LOGFILE_SYMBOL:
          return QtCreateLogFileGroup;

        case MySQLLexer::SERVER_SYMBOL:
          return QtCreateServer;

        case MySQLLexer::TABLESPACE_SYMBOL:
          return QtCreateTableSpace;

        case MySQLLexer::USER_SYMBOL:
          return QtCreateUser;
      }
      break;
    }

    case MySQLLexer::DROP_SYMBOL: {
      tok = nextDefaultChannelToken();
      if (tok->getType() == Token::EOF) return QtAmbiguous;

      switch (tok->getType()) {
        case MySQLLexer::DATABASE_SYMBOL:
          return QtDropDatabase;

        case MySQLLexer::EVENT_SYMBOL:
          return QtDropEvent;

        case MySQLLexer::PROCEDURE_SYMBOL:
          return QtDropProcedure;

        case MySQLLexer::FUNCTION_SYMBOL:
          return QtDropFunction;

        case MySQLLexer::ONLINE_SYMBOL:
        case MySQLLexer::OFFLINE_SYMBOL:
        case MySQLLexer::INDEX_SYMBOL:
          return QtDropIndex;

        case MySQLLexer::LOGFILE_SYMBOL:
          return QtDropLogfileGroup;

        case MySQLLexer::SERVER_SYMBOL:
          return QtDropServer;

        case MySQLLexer::TEMPORARY_SYMBOL:
        case MySQLLexer::TABLE_SYMBOL:
        case MySQLLexer::TABLES_SYMBOL:
          return QtDropTable;

        case MySQLLexer::TABLESPACE_SYMBOL:
          return QtDropTablespace;

        case MySQLLexer::TRIGGER_SYMBOL:
          return QtDropTrigger;

        case MySQLLexer::VIEW_SYMBOL:
          return QtDropView;

        case MySQLLexer::PREPARE_SYMBOL:
          return QtDeallocate;

        case MySQLLexer::USER_SYMBOL:
          return QtDropUser;
      }

      return QtUnknown;
    }

    case MySQLLexer::TRUNCATE_SYMBOL:
      return QtTruncateTable;

    case MySQLLexer::CALL_SYMBOL:
      return QtCall;

    case MySQLLexer::DELETE_SYMBOL:
      return QtDelete;

    case MySQLLexer::DO_SYMBOL:
      return QtDo;

    case MySQLLexer::HANDLER_SYMBOL:
      return QtHandler;

    case MySQLLexer::INSERT_SYMBOL:
      return QtInsert;

    case MySQLLexer::LOAD_SYMBOL: {
      tok = nextDefaultChannelToken();
      if (tok->getType() == Token::EOF) return QtAmbiguous;

      switch (tok->getType()) {
        case MySQLLexer::DATA_SYMBOL: {
          tok = nextDefaultChannelToken();
          if (tok->getType() == Token::EOF) return QtAmbiguous;

          if (tok->getType() == MySQLLexer::FROM_SYMBOL)
            return QtLoadDataMaster;
          return QtLoadData;
        }
        case MySQLLexer::XML_SYMBOL:
          return QtLoadXML;

        case MySQLLexer::TABLE_SYMBOL:
          return QtLoadTableMaster;

        case MySQLLexer::INDEX_SYMBOL:
          return QtLoadIndex;
      }

      return QtUnknown;
    }

    case MySQLLexer::REPLACE_SYMBOL:
      return QtReplace;

    case MySQLLexer::SELECT_SYMBOL:
      return QtSelect;

    case MySQLLexer::TABLE_SYMBOL:
      return QtTable;

    case MySQLLexer::VALUES_SYMBOL:
      return QtValues;

    case MySQLLexer::UPDATE_SYMBOL:
      return QtUpdate;

    case MySQLLexer::OPEN_PAR_SYMBOL:  // Either (((select ..))) or
                                       // (partition...)
    {
      while (tok->getType() == MySQLLexer::OPEN_PAR_SYMBOL) {
        tok = nextDefaultChannelToken();
        if (tok->getType() == Token::EOF) return QtAmbiguous;
      }
      if (tok->getType() == MySQLLexer::SELECT_SYMBOL) return QtSelect;
      return QtPartition;
    }

    case MySQLLexer::PARTITION_SYMBOL:
    case MySQLLexer::PARTITIONS_SYMBOL:
      return QtPartition;

    case MySQLLexer::START_SYMBOL: {
      tok = nextDefaultChannelToken();
      if (tok->getType() == Token::EOF) return QtAmbiguous;

      if (tok->getType() == MySQLLexer::TRANSACTION_SYMBOL)
        return QtStartTransaction;
      return QtStartSlave;
    }

    case MySQLLexer::BEGIN_SYMBOL:  // Begin directly at the start of the query
                                    // must be a transaction start.
      return QtBeginWork;

    case MySQLLexer::COMMIT_SYMBOL:
      return QtCommit;

    case MySQLLexer::ROLLBACK_SYMBOL: {
      // We assume a transaction statement here unless we exactly know it's
      // about a savepoint.
      tok = nextDefaultChannelToken();
      if (tok->getType() == Token::EOF) return QtRollbackWork;
      if (tok->getType() == MySQLLexer::WORK_SYMBOL) {
        tok = nextDefaultChannelToken();
        if (tok->getType() == Token::EOF) return QtRollbackWork;
      }

      if (tok->getType() == MySQLLexer::TO_SYMBOL) return QtRollbackSavepoint;
      return QtRollbackWork;
    }

    case MySQLLexer::SET_SYMBOL: {
      tok = nextDefaultChannelToken();
      if (tok->getType() == Token::EOF) return QtSet;

      switch (tok->getType()) {
        case MySQLLexer::PASSWORD_SYMBOL:
          return QtSetPassword;

        case MySQLLexer::GLOBAL_SYMBOL:
        case MySQLLexer::LOCAL_SYMBOL:
        case MySQLLexer::SESSION_SYMBOL:
          tok = nextDefaultChannelToken();
          if (tok->getType() == Token::EOF) return QtSet;
          break;

        case MySQLLexer::IDENTIFIER: {
          std::string text = tok->getText();
          std::transform(text.begin(), text.end(), text.begin(), ::tolower);
          if (text == "autocommit") return QtSetAutoCommit;
          break;
        }
      }

      if (tok->getType() == MySQLLexer::TRANSACTION_SYMBOL)
        return QtSetTransaction;
      return QtSet;
    }

    case MySQLLexer::SAVEPOINT_SYMBOL:
      return QtSavepoint;

    case MySQLLexer::RELEASE_SYMBOL:  // Release at the start of the query,
                                      // obviously.
      return QtReleaseSavepoint;

    case MySQLLexer::LOCK_SYMBOL:
      return QtLock;

    case MySQLLexer::UNLOCK_SYMBOL:
      return QtUnlock;

    case MySQLLexer::XA_SYMBOL:
      return QtXA;

    case MySQLLexer::PURGE_SYMBOL:
      return QtPurge;

    case MySQLLexer::CHANGE_SYMBOL:
      return QtChangeMaster;

    case MySQLLexer::RESET_SYMBOL: {
      tok = nextDefaultChannelToken();
      if (tok->getType() == Token::EOF) return QtReset;

      switch (tok->getType()) {
        case MySQLLexer::SERVER_SYMBOL:
          return QtResetMaster;
        case MySQLLexer::SLAVE_SYMBOL:
          return QtResetSlave;
        case MySQLLexer::PERSIST_SYMBOL:
          return QtResetPersist;
        default:
          return QtReset;
      }
    }

    case MySQLLexer::STOP_SYMBOL:
      return QtStopSlave;

    case MySQLLexer::PREPARE_SYMBOL:
      return QtPrepare;

    case MySQLLexer::EXECUTE_SYMBOL:
      return QtExecute;

    case MySQLLexer::DEALLOCATE_SYMBOL:
      return QtDeallocate;

    case MySQLLexer::GRANT_SYMBOL: {
      tok = nextDefaultChannelToken();
      if (tok->getType() == Token::EOF) return QtAmbiguous;

      if (tok->getType() == MySQLLexer::PROXY_SYMBOL) return QtGrantProxy;
      return QtGrant;
    }

    case MySQLLexer::RENAME_SYMBOL: {
      tok = nextDefaultChannelToken();
      if (tok->getType() == Token::EOF) return QtAmbiguous;

      if (tok->getType() == MySQLLexer::USER_SYMBOL) return QtRenameUser;
      return QtRenameTable;
    }

    case MySQLLexer::REVOKE_SYMBOL: {
      tok = nextDefaultChannelToken();
      if (tok->getType() == Token::EOF) return QtAmbiguous;

      if (tok->getType() == MySQLLexer::PROXY_SYMBOL) return QtRevokeProxy;
      return QtRevoke;
    }

    case MySQLLexer::ANALYZE_SYMBOL:
      return QtAnalyzeTable;

    case MySQLLexer::CHECK_SYMBOL:
      return QtCheckTable;

    case MySQLLexer::CHECKSUM_SYMBOL:
      return QtChecksumTable;

    case MySQLLexer::OPTIMIZE_SYMBOL:
      return QtOptimizeTable;

    case MySQLLexer::REPAIR_SYMBOL:
      return QtRepairTable;

    case MySQLLexer::BACKUP_SYMBOL:
      return QtBackUpTable;

    case MySQLLexer::RESTORE_SYMBOL:
      return QtRestoreTable;

    case MySQLLexer::INSTALL_SYMBOL:
      return QtInstallPlugin;

    case MySQLLexer::UNINSTALL_SYMBOL:
      return QtUninstallPlugin;

    case MySQLLexer::SHOW_SYMBOL: {
      tok = nextDefaultChannelToken();
      if (tok->getType() == Token::EOF) return QtShow;

      if (tok->getType() == MySQLLexer::FULL_SYMBOL) {
        // Not all SHOW cases allow an optional FULL keyword, but this is not
        // about checking for a valid query but to find the most likely type.
        tok = nextDefaultChannelToken();
        if (tok->getType() == Token::EOF) return QtShow;
      }

      switch (tok->getType()) {
        case MySQLLexer::GLOBAL_SYMBOL:
        case MySQLLexer::LOCK_SYMBOL:
        case MySQLLexer::SESSION_SYMBOL: {
          tok = nextDefaultChannelToken();
          if (tok->getType() == Token::EOF) return QtShow;

          if (tok->getType() == MySQLLexer::STATUS_SYMBOL) return QtShowStatus;
          return QtShowVariables;
        }

        case MySQLLexer::AUTHORS_SYMBOL:
          return QtShowAuthors;

        case MySQLLexer::BINARY_SYMBOL:
          return QtShowBinaryLogs;

        case MySQLLexer::BINLOG_SYMBOL:
          return QtShowBinlogEvents;

        case MySQLLexer::RELAYLOG_SYMBOL:
          return QtShowRelaylogEvents;

        case MySQLLexer::CHAR_SYMBOL:
          return QtShowCharset;

        case MySQLLexer::COLLATION_SYMBOL:
          return QtShowCollation;

        case MySQLLexer::COLUMNS_SYMBOL:
          return QtShowColumns;

        case MySQLLexer::CONTRIBUTORS_SYMBOL:
          return QtShowContributors;

        case MySQLLexer::COUNT_SYMBOL: {
          tok = nextDefaultChannelToken();
          if (tok->getType() != MySQLLexer::OPEN_PAR_SYMBOL) return QtShow;
          tok = nextDefaultChannelToken();
          if (tok->getType() != MySQLLexer::MULT_OPERATOR) return QtShow;
          tok = nextDefaultChannelToken();
          if (tok->getType() != MySQLLexer::CLOSE_PAR_SYMBOL) return QtShow;

          tok = nextDefaultChannelToken();
          if (tok->getType() == Token::EOF) return QtShow;

          switch (tok->getType()) {
            case MySQLLexer::WARNINGS_SYMBOL:
              return QtShowWarnings;

            case MySQLLexer::ERRORS_SYMBOL:
              return QtShowErrors;
          }

          return QtShow;
        }

        case MySQLLexer::CREATE_SYMBOL: {
          tok = nextDefaultChannelToken();
          if (tok->getType() == Token::EOF) return QtShow;

          switch (tok->getType()) {
            case MySQLLexer::DATABASE_SYMBOL:
              return QtShowCreateDatabase;

            case MySQLLexer::EVENT_SYMBOL:
              return QtShowCreateEvent;

            case MySQLLexer::FUNCTION_SYMBOL:
              return QtShowCreateFunction;

            case MySQLLexer::PROCEDURE_SYMBOL:
              return QtShowCreateProcedure;

            case MySQLLexer::TABLE_SYMBOL:
              return QtShowCreateTable;

            case MySQLLexer::TRIGGER_SYMBOL:
              return QtShowCreateTrigger;

            case MySQLLexer::VIEW_SYMBOL:
              return QtShowCreateView;
          }

          return QtShow;
        }

        case MySQLLexer::DATABASES_SYMBOL:
          return QtShowDatabases;

        case MySQLLexer::ENGINE_SYMBOL:
          return QtShowEngineStatus;

        case MySQLLexer::STORAGE_SYMBOL:
        case MySQLLexer::ENGINES_SYMBOL:
          return QtShowStorageEngines;

        case MySQLLexer::ERRORS_SYMBOL:
          return QtShowErrors;

        case MySQLLexer::EVENTS_SYMBOL:
          return QtShowEvents;

        case MySQLLexer::FUNCTION_SYMBOL: {
          tok = nextDefaultChannelToken();
          if (tok->getType() == Token::EOF) return QtAmbiguous;

          if (tok->getType() == MySQLLexer::CODE_SYMBOL)
            return QtShowFunctionCode;
          return QtShowFunctionStatus;
        }

        case MySQLLexer::GRANT_SYMBOL:
          return QtShowGrants;

        case MySQLLexer::INDEX_SYMBOL:
        case MySQLLexer::INDEXES_SYMBOL:
        case MySQLLexer::KEY_SYMBOL:
          return QtShowIndexes;

        case MySQLLexer::MASTER_SYMBOL:
          return QtShowMasterStatus;

        case MySQLLexer::OPEN_SYMBOL:
          return QtShowOpenTables;

        case MySQLLexer::PLUGIN_SYMBOL:
        case MySQLLexer::PLUGINS_SYMBOL:
          return QtShowPlugins;

        case MySQLLexer::PROCEDURE_SYMBOL: {
          tok = nextDefaultChannelToken();
          if (tok->getType() == Token::EOF) return QtShow;

          if (tok->getType() == MySQLLexer::STATUS_SYMBOL)
            return QtShowProcedureStatus;
          return QtShowProcedureCode;
        }

        case MySQLLexer::PRIVILEGES_SYMBOL:
          return QtShowPrivileges;

        case MySQLLexer::PROCESSLIST_SYMBOL:
          return QtShowProcessList;

        case MySQLLexer::PROFILE_SYMBOL:
          return QtShowProfile;

        case MySQLLexer::PROFILES_SYMBOL:
          return QtShowProfiles;

        case MySQLLexer::SLAVE_SYMBOL: {
          tok = nextDefaultChannelToken();
          if (tok->getType() == Token::EOF) return QtAmbiguous;

          if (tok->getType() == MySQLLexer::HOSTS_SYMBOL)
            return QtShowSlaveHosts;
          return QtShowSlaveStatus;
        }

        case MySQLLexer::STATUS_SYMBOL:
          return QtShowStatus;

        case MySQLLexer::VARIABLES_SYMBOL:
          return QtShowVariables;

        case MySQLLexer::TABLE_SYMBOL:
          return QtShowTableStatus;

        case MySQLLexer::TABLES_SYMBOL:
          return QtShowTables;

        case MySQLLexer::TRIGGERS_SYMBOL:
          return QtShowTriggers;

        case MySQLLexer::WARNINGS_SYMBOL:
          return QtShowWarnings;
      }

      return QtShow;
    }

    case MySQLLexer::CACHE_SYMBOL:
      return QtCacheIndex;

    case MySQLLexer::FLUSH_SYMBOL:
      return QtFlush;

    case MySQLLexer::KILL_SYMBOL:
      return QtKill;

    case MySQLLexer::DESCRIBE_SYMBOL:  // EXPLAIN is converted to DESCRIBE in
                                       // the lexer.
    case MySQLLexer::DESC_SYMBOL: {
      tok = nextDefaultChannelToken();
      if (tok->getType() == Token::EOF) return QtAmbiguous;

      if (isIdentifier(tok->getType()) ||
          tok->getType() == MySQLLexer::DOT_SYMBOL)
        return QtExplainTable;

      // EXTENDED is a bit special as it can be both, a table identifier or the
      // keyword.
      if (tok->getType() == MySQLLexer::EXTENDED_SYMBOL) {
        tok = nextDefaultChannelToken();
        if (tok->getType() == Token::EOF) return QtExplainTable;

        switch (tok->getType()) {
          case MySQLLexer::DELETE_SYMBOL:
          case MySQLLexer::INSERT_SYMBOL:
          case MySQLLexer::REPLACE_SYMBOL:
          case MySQLLexer::UPDATE_SYMBOL:
            return QtExplainStatement;
          default:
            return QtExplainTable;
        }
      }
      return QtExplainStatement;
    }

    case MySQLLexer::HELP_SYMBOL:
      return QtHelp;

    case MySQLLexer::USE_SYMBOL:
      return QtUse;
  }

  return QtUnknown;
}