Hive源码阅读--SQL的语法解析和语义分析--Driver

2023-05-16

前面五个类,殊途同归都是CliDriver类,他负责接受用户在命令行上输入的信息,然后准备执行并将执行的结果返回。

而真正底层干事情的是Driver,他将接受到的命令编译,优化为MR(或RDD),真正的调动集群跑作业。

processLocalCmd中有这样一句ret = qp.run(cmd).getResponseCode();,这句中的run不是CliDriverrun,而是Driverrun

org.apache.hadoop.hive.ql.Driver.run

org.apache.hadoop.hive.ql.Driver
----------

	public CommandProcessorResponse run(String command) throws CommandNeedRetryException {
        return this.run(command, false);
    }

    public CommandProcessorResponse run() throws CommandNeedRetryException {
        return this.run((String)null, true);
    }

    public CommandProcessorResponse run(String command, boolean alreadyCompiled) throws CommandNeedRetryException {
        // 这一句调用的runInternal是对sql的执行,下面都是对执行结果的校验
        // 不管对不对,先执行,保证优先性
        CommandProcessorResponse cpr = this.runInternal(command, alreadyCompiled);
        if (cpr.getResponseCode() == 0) {
            return cpr;
        } else {
            SessionState ss = SessionState.get();
            if (ss == null) {
                return cpr;
            } else {
                MetaDataFormatter mdf = MetaDataFormatUtils.getFormatter(ss.getConf());
                if (!(mdf instanceof JsonMetaDataFormatter)) {
                    return cpr;
                } else {
                    try {
                        if (this.downstreamError == null) {
                            mdf.error(ss.out, this.errorMessage, cpr.getResponseCode(), this.SQLState);
                            return cpr;
                        }

                        ErrorMsg canonicalErr = ErrorMsg.getErrorMsg(cpr.getResponseCode());
                        if (canonicalErr != null && canonicalErr != ErrorMsg.GENERIC_ERROR) {
                            mdf.error(ss.out, this.errorMessage, cpr.getResponseCode(), this.SQLState, (String)null);
                            return cpr;
                        }

                        if (this.downstreamError instanceof HiveException) {
                            HiveException rc = (HiveException)this.downstreamError;
                            mdf.error(ss.out, this.errorMessage, rc.getCanonicalErrorMsg().getErrorCode(), this.SQLState, rc.getCanonicalErrorMsg() == ErrorMsg.GENERIC_ERROR ? StringUtils.stringifyException(rc) : null);
                        } else {
                            ErrorMsg canonicalMsg = ErrorMsg.getErrorMsg(this.downstreamError.getMessage());
                            mdf.error(ss.out, this.errorMessage, canonicalMsg.getErrorCode(), this.SQLState, StringUtils.stringifyException(this.downstreamError));
                        }
                    } catch (HiveException var8) {
                        console.printError("Unable to JSON-encode the error", StringUtils.stringifyException(var8));
                    }

                    return cpr;
                }
            }
        }
    }

run只是Driver的入口,处在QL阶段,后面还有:
在这里插入图片描述
所以只看关键部分。

org.apache.hadoop.hive.ql.Driver.runInternal

然后看runInternal方法:

org.apache.hadoop.hive.ql.Driver
----------
   private CommandProcessorResponse runInternal(String command, boolean alreadyCompiled) throws CommandNeedRetryException {
			......
            perfLogger = null;
            PerfLogger perfLogger;
            int ret;
            if (!alreadyCompiled) {
            	// 调用compileInternal方法把SQL编译为QueryPlan
                ret = this.compileInternal(command, true);
                perfLogger = SessionState.getPerfLogger();
                if (ret != 0) {
                    CommandProcessorResponse var8 = this.createProcessorResponse(ret);
                    return var8;
                }
            } else {
                perfLogger = SessionState.getPerfLogger();
                this.plan.setQueryStartTime(perfLogger.getStartTime("Driver.run"));
            }

          	......
				// 调用execute执行QueryPlan中的所有task
                ret = this.execute(true);
                if (ret != 0) {
                    var10 = this.rollback(this.createProcessorResponse(ret));
                    return var10;
                }
			......
    }

org.apache.hadoop.hive.ql.Driver.compileInternal

继续看compileInternal方法

org.apache.hadoop.hive.ql.Driver
----------

	private int compileInternal(String command, boolean deferClose) {
        ReentrantLock compileLock = this.tryAcquireCompileLock(this.isParallelEnabled, command);
        if (compileLock == null) {
            return ErrorMsg.COMPILE_LOCK_TIMED_OUT.getErrorCode();
        } else {
            int ret;
            try {
            	// Driver的run方法最终会执行compile()操作,Compiler作语法解析和语义分析。
            	// compile()是Driver最关键的方法,单个方法代码近300行。
                ret = this.compile(command, true, deferClose);
            } finally {
                compileLock.unlock();
            }

            if (ret != 0) {
                try {
                    this.releaseLocksAndCommitOrRollback(false, (HiveTxnManager)null);
                } catch (LockException var8) {
                    LOG.warn("Exception in releasing locks. " + StringUtils.stringifyException(var8));
                }
            }

            PerfLogger perfLogger = SessionState.getPerfLogger();
            this.queryDisplay.setPerfLogStarts(Phase.COMPILATION, perfLogger.getStartTimes());
            this.queryDisplay.setPerfLogEnds(Phase.COMPILATION, perfLogger.getEndTimes());
            return ret;
        }
    }

org.apache.hadoop.hive.ql.Driver.compile

org.apache.hadoop.hive.ql.Driver
----------

public int compile(String command, boolean resetTaskIds, boolean deferClose) {
	  ......
	  // 将SQL转换为ASTNode
      ParseDriver pd = new ParseDriver();
      ASTNode tree = pd.parse(command, ctx);
      tree = ParseUtils.findRootNonNullToken(tree);
	  ......
	  // 对ASTNode进行封装
      BaseSemanticAnalyzer sem = SemanticAnalyzerFactory.get(queryState, tree);
	  ......
	  // 将ASTNode转化为Task,包括可能的optimize,过程比较复杂
      sem.analyze(tree, ctx);
	  ......
  
      // 记录所有符合ACID的FileSinkOperators,这样我们就可以将事务ID添加到acidSinks 
      acidSinks = sem.getAcidFileSinks();

      LOG.info("Semantic Analysis Completed");

      // 验证Plan
      sem.validate();
      acidInQuery = sem.hasAcidInQuery();
      perfLogger.PerfLogEnd(CLASS_NAME, PerfLogger.ANALYZE);

      if (isInterrupted()) {
        return handleInterruption("after analyzing query.");
      }

      // 将BaseSemanticAnalyzer传入QueryPlan构造函数来创建QueryPlan
      schema = getSchema(sem, conf);
      plan = new QueryPlan(queryStr, sem, perfLogger.getStartTime(PerfLogger.DRIVER_RUN), queryId,queryState.getHiveOperation(), schema);
	  ......
}

Driver主要进行SQL的语法解析和语义分析,他调用parse将语句转换为ASTNode,调用analyzeASTNode转换为Task。然后使用Task构建QueryPlan

构建的QueryPlan将会被保存在Driver中,然后交由execute进行执行。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Hive源码阅读--SQL的语法解析和语义分析--Driver 的相关文章

  • 如何将 sql 数据输出到 QCalendarWidget

    我希望能够在日历小部件上突出显示 SQL 数据库中的一天 就像启动程序时突出显示当前日期一样 在我的示例中 它是红色突出显示 我想要发生的是 当用户按下突出显示的日期时 数据库中日期旁边的文本将显示在日历下方的标签上 这是我使用 QT De
  • 合并sql中的列

    我正在使用 SQL Server 2017 有一个存储过程 其中我有一个带有连接的简单选择 例如 SELECT p legacyKey AS JobNumber p Name AS JobName G Label AS DesignStat
  • RANK() OVER PARTITION 并重置 RANK

    如何获得在分区更改时重新启动的 RANK 我有这张表 ID Date Value 1 2015 01 01 1 2 2015 01 02 1
  • 如何在 PostgreSQL 中使用条件和子查询创建唯一索引?

    我使用 PGSQL 并尝试添加下面的索引 CREATE UNIQUE INDEX fk client ON user client fk client WHERE fk client NOT IN SELECT fk client FROM
  • 如何使用第二行中的值填充第一行中的空值?

    我正在尝试编写一个查询 仅显示每个名称的第一行 但这些行的标题为空 因此我想从紧邻的下一行中提取它们的标题 table1 Name Title Row Dan NULL 1 Dan Engineer 2 Dan Developer 3 Ja
  • 如何将事物的组合映射到关系数据库?

    我有一个表 其记录代表某些对象 为了简单起见 我假设该表只有一列 这是唯一的ObjectId 现在我需要一种方法来存储该表中的对象组合 组合必须是唯一的 但可以是任意长度 例如 如果我有ObjectIds 1 2 3 4 我想存储以下组合
  • 通过 SQLAlchemy 获取随机行

    如何使用 SQLAlchemy 从表中选择一个或多个随机行 这在很大程度上是一个特定于数据库的问题 我知道 PostgreSQL SQLite MySQL 和 Oracle 具有通过随机函数排序的能力 因此您可以在 SQLAlchemy 中
  • 使用条件 SQL 统计每月汇总记录

    我有一张桌子 我们就叫他们桌子吧SUMMARYDATA NIP NAME DEPARTMENT STATUSIN STATUSOUT TOTALLOSTTIME A1 ARIA BB 2020 01 21 08 06 23 2020 01
  • 如何计算 Postgres 上图表中所有连接的节点(行)?

    我的桌子有account id and device id One account id可以有多个device ids 反之亦然 我正在尝试计算每个连接的多对多关系的深度 Ex account id device id 1 10 1 11
  • SQLite (Android):使用 ORDER BY 更新查询

    Android SQLite 我想要在 myTable 中的其他行之间插入行在android中使用SQLite 为此 我尝试增加从第 3 行开始的所有行的 id 这样 我就可以在位置 3 处插入新行 myTable 的主键是列 id 表中没
  • 如何连续添加起始行和下一行的值

    我只想创建一个 sql 查询 结果就像图片上的那样 类似于 SQL 中的斐波那契数列 Ex Column 1 10 则 Result 列的值为 Result 10 因为这是第一行 然后假设column1第二行的值为50 那么Result第二
  • java库维护数据库结构

    我的应用程序一直在开发 所以偶尔 当版本升级时 需要创建 更改 删除一些表 修改一些数据等 通常需要执行一些sql代码 是否有一个 Java 库可用于使我的数据库结构保持最新 通过分析类似 db structure version 信息并执
  • SQL Server 2008 错误 233

    我正在使用以下 sql 脚本在 SQL Server 2008 中创建新登录名 CREATE LOGIN xyz WITH PASSWORD xyz DEFAULT DATABASE master DEFAULT LANGUAGE us e
  • 将两个表合并为一个输出

    假设我有两张表 已知营业时间 ChargeNum CategoryID Month Hours 111111 1 2 1 09 10 111111 1 3 1 09 30 111111 1 4 1 09 50 222222 1 3 1 09
  • 3 个表的 SQL 查询(或联接)

    第一次在 Stack Overflow 上问问题 很棒的资源 但是只有一件事真正让我作为 SQL 新手感到困惑 我有三个表 我想获取与鲍勃的学生相关的所有导师的姓名 表 1 教师 ID Name 1 Bob 表 2 学生 STUDENT I
  • SQL Server:为什么 ISO-8601 格式的日期依赖于语言?

    我需要一些帮助来理解 SQL Server 中的日期格式处理 如果您尝试以下操作 它将返回正确的结果 SET LANGUAGE English SELECT CAST 2013 08 15 AS DATETIME 2013 08 15 00
  • 将布尔参数传递给 SQL Server 存储过程

    我早些时候问过这个问题 我以为我找到了问题所在 但我没有 我在将布尔参数传递给存储过程时遇到问题 这是我的 C 代码 public bool upload false protected void showDate object sende
  • 使用来自另一个数据库的选择查询更新 mysql 表

    我有两个数据库 我想用另一个数据库表中的值更新一个表 我正在使用以下查询 但它不起作用 UPDATE database1 table1 SET field2 database2 table1 field2 WHERE database1 t
  • Oracle:按月分区表

    我的解决方案 德语几个月 PARTITION BY LIST to char GEBURTSDATUM Month PARTITION p1 VALUES JANUAR PARTITION p2 VALUES Februar PARTITI
  • 在同一查询中选择 Count of ip 和 Count of DISTINCT ip

    我有一个这样的表结构 TABLE NAME counter id datetime url ip 1 2013 04 12 13 27 09 url1 ip01 2 2013 04 13 10 55 43 url2 ip02 3 2013

随机推荐