MySQL 源码 - 24|句法解析:SplittingAllowedParser 解析器

MySQL 源码 - 24|SplittingAllowedParser 的解析方法

源码位置:(版本 = MySQL 8.0.37)

前置文档:MySQL 源码|SQLParser 类及其子类

SplittingAllowedParser 中,定义了一个枚举类,枚举类中有 5 个枚举值,疑似是这些任务的执行权限,我们可以通过梳理这 5 个枚举值的使用场景来具体确定它们的含义。

  enum class Allowed {
    Always,
    InTransaction,
    OnlyReadWrite,
    OnlyReadOnly,
    Never,
  };

解析函数 parse() 的原型如下:

stdx::expected<SplittingAllowedParser::Allowed, std::string>
SplittingAllowedParser::parse()

其中通过使用分支结构逐个 token 调用 accept 枚举关键字,枚举了 SQL 语句开头的各种关键字组合,并根据关键字组合返回枚举值。例如 accept(SHOW) 函数可以判断下一个 token 是否为 SHOW 关键字,如果是则返回 True 并将迭代器向后一个移动 token,否则返回 False 且不移动迭代器中的位置。

如果某个语法不存在,则会返回 Allowed::Never,这些不存在的语法在具体梳理时不再列出。

涉及的 MySQL 官方文档如下:

SHOW 开头的表达式
  if (accept(SHOW)) {
    // https://dev.mysql.com/doc/refman/en/show.html
    //
    if (                          // BINARY: below
                                  // BINLOG: below
        accept(CHAR_SYM) ||       // CHARACTER
        accept(CHARSET) ||        //
        accept(COLLATION_SYM) ||  //
        accept(COLUMNS) ||        //
        accept(CREATE) ||         //
        accept(DATABASES) ||      //
                                  // ENGINE: below
        accept(ENGINES_SYM) ||    //
        accept(ERRORS) ||         //
        accept(EVENTS_SYM) ||     //
        accept(FUNCTION_SYM) ||   //
        accept(GRANTS) ||         //
        accept(INDEX_SYM) ||      //
                                  // MASTER STATUS: below
                                  // OPEN TABLES: below
        accept(PLUGINS_SYM) ||    //
        accept(PRIVILEGES) ||     //
        accept(PROCEDURE_SYM) ||  //
                                  // PROCESSLIST: below
                                  // PROFILE: below
                                  // PROFILES: below
                                  // RELAYLOG: below
                                  // REPLICA: below
                                  // REPLICAS: below
                                  // SLAVE: below
        accept(STATUS_SYM) ||     //
        accept(TABLE_SYM) ||      //
        accept(TABLES) ||         //
        accept(TRIGGERS_SYM) ||   //
        accept(VARIABLES) ||      //
        accept(WARNINGS)) {
      return Allowed::Always;
    }

    // per instance commands
    if (accept(ENGINE_SYM) ||       //
        accept(OPEN_SYM) ||         // OPEN TABLES
        accept(PLUGINS_SYM) ||      //
        accept(PROCESSLIST_SYM) ||  //
        accept(PROFILES_SYM) ||     //
        accept(PROFILE_SYM)) {
      return Allowed::InTransaction;
    }

    if (accept(GLOBAL_SYM)) {
      if (accept(VARIABLES)) {
        return Allowed::Always;
      }
      if (accept(STATUS_SYM)) {
        return Allowed::InTransaction;
      }

      return Allowed::Never;
    }

    // Write-only
    if (accept(BINARY_SYM) ||  //
        accept(MASTER_SYM) ||  //
        accept(REPLICAS_SYM)) {
      return Allowed::OnlyReadWrite;
    }

    // Read-only
    if (accept(BINLOG_SYM) ||    //
        accept(RELAYLOG_SYM) ||  //
        accept(REPLICA_SYM)      //
    ) {
      return Allowed::OnlyReadOnly;
    }

    if (accept(SLAVE)) {
      if (accept(STATUS_SYM)) {
        return Allowed::OnlyReadOnly;
      }

      if (accept(HOSTS_SYM)) {
        return Allowed::OnlyReadWrite;
      }

      return Allowed::Never;
    }

    // SHOW [EXTENDED] [FULL] COLUMNS|FIELDS

    if (accept(EXTENDED_SYM)) {
      accept(FULL);

      if (accept(COLUMNS)) {  // FIELDS and COLUMNS both resolve to COLUMNS
        return Allowed::Always;
      }

      return Allowed::Never;
    } else if (accept(FULL)) {
      if (accept(COLUMNS) || accept(TABLES)) {
        return Allowed::Always;
      } else if (accept(PROCESSLIST_SYM)) {
        return Allowed::InTransaction;
      }

      return Allowed::Never;
    }

    // SHOW [STORAGE] ENGINES
    if (accept(STORAGE_SYM)) {
      if (accept(ENGINES_SYM)) {
        return Allowed::Always;
      }

      return Allowed::Never;
    }

    if (accept(SESSION_SYM)) {
      if (accept(STATUS_SYM) || accept(VARIABLES)) {
        return Allowed::Always;
      }
    }

    return Allowed::Never;
  }
表达式返回值
SHOW BINARY LOG STATUSAllowed::OnlyReadWrite【Write-only】
SHOW BINARY LOGSAllowed::OnlyReadWrite【Write-only】
SHOW BINLOG EVENTSAllowed::OnlyReadOnly【Read-only】
SHOW CHARACTER SETAllowed::Always
SHOW COLLATIONAllowed::Always
SHOW [FULL] COLUMNSAllowed::Always
SHOW CREATE DATABASE/EVENT/FUNCTION/PROCEDURE/TABLE/USER/VIEWAllowed::Always
SHOW DATABASESAllowed::Always
SHOW ENGINEAllowed::InTransaction
SHOW [STORAGE] ENGINESAllowed::Always
SHOW ERRORSAllowed::Always
SHOW EVENTSAllowed::Always
SHOW EXTENDED FULL COLUMNS(不在 8.4 版本 MySQL 手册中)Allowed::Always
SHOW FUNCTION CODE/STATUSAllowed::Always
SHOW GRANTSAllowed::Always
SHOW INDEXAllowed::Always
SHOW MASTER(不在 8.4 版本 MySQL 手册中)Allowed::OnlyReadWrite【Write-only】
SHOW OPEN TABLESAllowed::InTransaction
SHOW PLUGINSAllowed::Always
SHOW PRIVILEGESAllowed::Always
SHOW PROCEDURE CODE/STATUSAllowed::Always
SHOW [FULL] PROCESSLISTAllowed::InTransaction
SHOW PROFILEAllowed::InTransaction
SHOW PROFILESAllowed::InTransaction
SHOW RELAYLOG EVENTSAllowed::OnlyReadOnly【Read-only】
SHOW REPLICA STATUSAllowed::OnlyReadOnly【Read-only】
SHOW REPLICASAllowed::OnlyReadWrite【Write-only】
SHOW SLAVE HOSTS(不在 8.4 版本 MySQL 手册中)Allowed::OnlyReadWrite
`SHOW [GLOBALSESSION
SHOW TABLE STATUSAllowed::Always
SHOW [FULL] TABLESAllowed::Always
SHOW TRIGGERSAllowed::Always
`SHOW [GLOBALSESSION] VARIABLES`
SHOW WARNINGSAllowed::Always
CREATE / ALTER 开头的表达式
  else if (accept(CREATE) || accept(ALTER)) {
    if (accept(DATABASE) ||        //
        accept(EVENT_SYM) ||       //
        accept(FUNCTION_SYM) ||    //
        accept(INDEX_SYM) ||       //
                                   // INSTANCE
        accept(PROCEDURE_SYM) ||   //
                                   // SERVER
        accept(SPATIAL_SYM) ||     //
        accept(TABLE_SYM) ||       //
        accept(TABLESPACE_SYM) ||  //
        accept(TRIGGER_SYM) ||     //
        accept(VIEW_SYM) ||        //
        accept(USER) ||            //
        accept(ROLE_SYM)           //
    ) {
      return Allowed::Always;
    }

    if (accept(AGGREGATE_SYM)) {
      // CREATE AGGREGATE FUNCTION
      if (accept(FUNCTION_SYM)) {
        return Allowed::Always;
      }

      return Allowed::Never;
    }

    if (accept(ALGORITHM_SYM)) {
      // CREATE ALGORITHM = ... VIEW
      return Allowed::Always;
    }

    if (accept(DEFINER_SYM)) {
      // CREATE DEFINER = ... PROCEDURE|FUNCTION|EVENT|VIEW
      return Allowed::Always;
    }

    if (accept(OR_SYM)) {
      // CREATE OR REPLACE ... VIEW|SPATIAL REFERENCE SYSTEM
      if (accept(REPLACE_SYM)) {
        return Allowed::Always;
      }

      return Allowed::Never;
    }

    if (accept(SQL_SYM)) {
      // CREATE SQL SECURITY ... VIEW
      return Allowed::Always;
    }

    if (accept(TEMPORARY)) {
      // CREATE TEMPORARY TABLE
      if (accept(TABLE_SYM)) {
        return Allowed::Always;
      }

      return Allowed::Never;
    }

    if (accept(UNDO_SYM)) {
      // CREATE UNDO TABLESPACE
      if (accept(TABLESPACE_SYM)) {
        return Allowed::Always;
      }

      return Allowed::Never;
    }

    if (accept(UNIQUE_SYM) || accept(FULLTEXT_SYM) || accept(SPATIAL_SYM)) {
      // CREATE UNIQUE|FULLTEXT|SPATIAL INDEX
      if (accept(INDEX_SYM)) {
        return Allowed::Always;
      }
      return Allowed::Never;
    }

    // SERVER
    // INSTANCE
    // LOGFILE GROUP

    return Allowed::Never;
  }
表达式返回值
ALTER DATABASEAllowed::Always
ALTER EVENTAllowed::Always
ALTER [AGGREGATE] FUNCTIONAllowed::Always
ALTER INSTANCEAllowed::Never
ALTER LOGFILE GROUPAllowed::Never
ALTER PROCEDUREAllowed::Always
ALTER SERVERAllowed::Never
ALTER TABLEAllowed::Always
ALTER TABLESPACEAllowed::Always
`ALTER [ALGORITHM={UNDEFINEDMERGE
ALTER USERAllowed::Always
CREATE DATABASEAllowed::Always
CREATE EVENTAllowed::Always
CREATE [AGGREGATE] FUNCTIONAllowed::Always
`CREATE [UNIQUEFULLTEXT
CREATE LOGFILE GROUPAllowed::Never
CREATE PROCEDUREAllowed::Always
CREATE SERVERAllowed::Never
CREATE SPATIAL REFERENCE SYSTEMAllowed::Always
CREATE [TEMPORARY] TABLEAllowed::Always
CREATE [UNDO] TABLESPACEAllowed::Always
CREATE TRIGGERAllowed::Always
`CREATE [ALGORITHM={UNDEFINEDMERGE
CREATE OR REPLACE ...Allowed::Always
CREATE ROLEAllowed::Always
CREATE USERAllowed::Always
DROP 开头的表达式
  else if (accept(DROP)) {
    if (accept(DATABASE) ||        //
        accept(EVENT_SYM) ||       //
        accept(FUNCTION_SYM) ||    //
        accept(INDEX_SYM) ||       //
                                   // INSTANCE
        accept(PROCEDURE_SYM) ||   //
                                   // SERVER
        accept(SPATIAL_SYM) ||     //
                                   // TEMPORARY: below
        accept(TABLE_SYM) ||       //
        accept(TABLESPACE_SYM) ||  //
        accept(TRIGGER_SYM) ||     //
        accept(VIEW_SYM) ||        //
        accept(USER) ||            //
        accept(ROLE_SYM)           //
    ) {
      return Allowed::Always;
    }

    if (accept(TEMPORARY)) {
      // CREATE TEMPORARY TABLE
      if (accept(TABLE_SYM)) {
        return Allowed::Always;
      }

      return Allowed::Never;
    }

    // - SERVER
    // - INSTANCE

    return Allowed::Never;
  }
表达式返回值
DROP DATABASEAllowed::Always
DROP EVENTAllowed::Always
DROP FUNCTIONAllowed::Always
DROP INDEXAllowed::Always
DROP LOGFILE GROUPAllowed::Never
DROP PRODUCEDUREAllowed::Always
DROP SERVERAllowed::Never
DROP SPATIAL REFERENCE SYSTEMAllowed::Always
DROP [TEMPORARY] TABLEAllowed::Always
DROP TABLESPACEAllowed::Always
DROP TRIGGERAllowed::Always
DROP VIEWAllowed::Always
DROP ROLEAllowed::Always
DROP USERAllowed::Always
各类根据开头就可以判断返回 Allowed::Always 的表达式
  else if (                // read-only statements
      accept(SELECT_SYM) ||  //
      accept(WITH) ||        //
      accept(TABLE_SYM) ||   //
      accept(DO_SYM) ||      //
      accept(VALUES) ||      //
      accept(USE_SYM) ||     //
      accept(DESC) ||        //
      accept(DESCRIBE) ||    //
      accept(HELP_SYM) ||

      // DML
      accept(CALL_SYM) ||     //
      accept(INSERT_SYM) ||   //
      accept(UPDATE_SYM) ||   //
      accept(DELETE_SYM) ||   //
      accept(REPLACE_SYM) ||  //
      accept(TRUNCATE_SYM) ||

      // User management
      accept(GRANT) ||   //
      accept(REVOKE) ||  //

      // transaction and locking
      accept(BEGIN_SYM) ||      //
      accept(COMMIT_SYM) ||     //
      accept(RELEASE_SYM) ||    //
      accept(ROLLBACK_SYM) ||   //
      accept(SAVEPOINT_SYM) ||  //
                                // START is below.
      accept(XA_SYM) ||         //

      // import
      accept(IMPORT)) {
    return Allowed::Always;
  }
表达式返回值
SELECT(只读)Allowed::Always
WITH(只读)Allowed::Always
TABLE(只读)Allowed::Always
DO(只读)Allowed::Always
VALUES(只读)Allowed::Always
USE(只读)Allowed::Always
DESC(只读)Allowed::Always
DESCRIBE(只读)Allowed::Always
HELP(只读)Allowed::Always
CALL(DML)Allowed::Always
INSERT(DML)Allowed::Always
UPDATE(DML)Allowed::Always
DELETE(DML)Allowed::Always
REPLACE(DML)Allowed::Always
TRUNCATE(DML)Allowed::Always
GRANT(用户管理)Allowed::Always
REVOKE(用户管理)Allowed::Always
BEGIN(事务)Allowed::Always
COMMIT(事务)Allowed::Always
RELEASE(事务)Allowed::Always
ROLLBACK(事务)Allowed::Always
SAVEPOINT(事务)Allowed::Always
XA(事务)Allowed::Always
IMPORTAllowed::Always
其他开头的表达式
  • 当以 FLUSH 开头时:
    • 若下一个 token 为 NO_WRITE_TO_BINLOGLOCAL,则返回 Allowed::Never
    • 若下一个 token 为 TABLES,则遍历后续 token;若其中包含 WITHFOR 则返回 Allowed::Never,否则返回 Allowed::Always
    • 若下一个 token 不是 NO_WRITE_TO_BINLOGLOCALTABLES,则继续遍历后续 token;若 , 之后为 LOGS 则返回 Allowed::Never,否则返回 Allowed::Always
  else if (accept(FLUSH_SYM)) {
    // FLUSH flush_option [, flush option]
    //
    // Not replicated:
    //
    // - if LOCAL or NO_WRITE_TO_BINLOG is specified
    // - LOGS
    // - TABLES ... FOR EXPORT
    // - TABLES WITH READ LOCK

    if (accept(NO_WRITE_TO_BINLOG) || accept(LOCAL_SYM)) {
      return Allowed::Never;
    }

    if (accept(TABLES)) {
      while (auto tkn = accept_if_not(END_OF_INPUT)) {
        // FOR EXPORT
        // WITH READ LOCK
        if (tkn.id() == WITH || tkn.id() == FOR_SYM) return Allowed::Never;
      }

      return Allowed::Always;
    }

    TokenText last_tkn;

    // check for LOGS (after FLUSH ... or after ',')
    while (auto tkn = accept_if_not(END_OF_INPUT)) {
      if (tkn.id() == LOGS_SYM) {
        if (last_tkn.id() == ',' || last_tkn.id() == 0) {
          return Allowed::Never;
        }
      }

      last_tkn = tkn;
    }

    return Allowed::Always;
  }
  • 当以 LOCKUNLOCK 开头时,直接返回 Allowed::Never
  else if (accept(LOCK_SYM) || accept(UNLOCK_SYM)) {
    // per instance, not replicated.
    return Allowed::Never;
  }
  • 当以 LOAD 开头时,若下一个 token 为 XMLDATA 则返回 Allowed::Always,否则返回 Allowed::Never
  else if (accept(LOAD)) {
    if (accept(XML_SYM) || accept(DATA_SYM)) {
      return Allowed::Always;
    }

    return Allowed::Never;
  }
  • 当以 RENAME 开头时,若下一个 token 为 USERTABLE,则返回 Allowed::Always,否则返回 Allowed::Never
  else if (accept(RENAME)) {
    if (accept(USER) || accept(TABLE_SYM)) {
      return Allowed::Always;
    }

    return Allowed::Never;
  }
  • 当以 SET 开头时:
    • 若下一个 token 为 PASSWORDTRANSACTIONDEFAULTNAMESCHAR,则返回 Allowed::Always
    • 若下一个 token 为 RESOURCE,则返回 Allowed::Never
    • 若下一个 token 不是 PASSWORDTRANSACTIONDEFAULTNAMESCHARRESOURCE,则继续遍历后续 token;若在未出现 ,, 后未出现 SETEQ 的情况下,遇到 GLOBALPERSIST_ONLYPERSIST,则返回 Allowed::Never
    • 否则返回 Allowed::Always
  else if (accept(SET_SYM)) {
    // exclude:
    // - SET RESOURCE GROUP: not replicated
    // - SET GLOBAL
    // - SET PERSIST
    if (accept(PASSWORD) ||         // SET PASSWORD = ...
        accept(TRANSACTION_SYM) ||  // SET TRANSACTION READ ONLY
        accept(DEFAULT_SYM) ||      // SET DEFAULT ROLE
        accept(NAMES_SYM) ||        // SET NAMES
        accept(CHAR_SYM)            // SET CHARACTER SET
    ) {
      return Allowed::Always;
    }

    if (accept(RESOURCE_SYM)) {
      return Allowed::Never;
    }

    // forbid SET GLOBAL, but allow SET foo = @@GLOBAL.foo;
    bool is_lhs{true};

    while (auto tkn = accept_if_not(END_OF_INPUT)) {
      if (tkn.id() == SET_VAR || tkn.id() == EQ) {
        // after := or = is the right-hand-side
        is_lhs = false;
      } else if (tkn.id() == ',') {
        // after , back to left-hand-side
        is_lhs = true;
      }

      if (is_lhs && (tkn.id() == GLOBAL_SYM || tkn.id() == PERSIST_ONLY_SYM ||
                     tkn.id() == PERSIST_SYM)) {
        return Allowed::Never;
      }
    }

    return Allowed::Always;
  }
  • 当以 START 开头时,若下一个 token 为 TRANSACTION 则返回 Allowed::Always,否则返回 Allowed::Never
  else if (accept(START_SYM)) {
    // exclude GROUP_REPLICATION|REPLICAS
    if (accept(TRANSACTION_SYM)) {
      return Allowed::Always;
    }
    return Allowed::Never;
  }
  • 当以 CHECKSUMCHECK 开头时,若下一个 token 为 TABLE 则返回 Allowed::Always,否则返回 Allowed::Never
  else if (accept(CHECKSUM_SYM) || accept(CHECK_SYM)) {
    if (accept(TABLE_SYM)) {
      return Allowed::Always;
    }
    return Allowed::Never;
  }
  • 当以 ANALYZEOPTIMIZEREPAIR 开头时,若下一个 token 为 TABLE,则返回 Allowed::Always,否则返回 Allowed::Never
  else if (accept(ANALYZE_SYM) || accept(OPTIMIZE) || accept(REPAIR)) {
    if (accept(NO_WRITE_TO_BINLOG) || accept(LOCAL_SYM)) {
      // ignore LOCAL and NO_WRITE_TO_BINLOG
    }

    if (accept(TABLE_SYM)) {
      return Allowed::Always;
    }
    return Allowed::Never;
  }
  • 当以 ( 开头时,直接返回 Allowed::Always
  else if (accept('(')) {
    return Allowed::Always;
  }
  • 当以 BINLOG 开头时,直接返回 Allowed::Always
  else if (accept(BINLOG_SYM)) {
    return Allowed::Always;
  }
  • 否则,返回 Allowed::Never
  return Allowed::Never;
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值