?

用Go构建一个SQL解析器

为了简单起见,我们将处理子选择、函数、复杂嵌套表达式和所有 SQL 风格都支持的其他特性。这些特性与我们将要使用的策略紧密相关。

1分钟理论

一个解析器包含两个部分:

词法分析:也就是“Tokeniser”

语法分析:AST 的创建

词法分析

让我们用例子来定义一下。“Tokenising”以下查询:

SELECT id, name FROM 'users.csv' 

表示提取构成此查询的“tokens”。tokeniser 的结果像这样:

[]string{"SELECT", "id", ",", "name", "FROM", "'users.csv'"} 

语法分析

这部分实际上是我们查看 tokens 的地方,确保它们有意义并解析它们来构造出一些结构体,以一种对将要使用它的应用程序更方便的方式表示查询(例如,用于执行查询,用颜色高亮显示它)。在这一步之后,我们会得到这样的结果:

query{ 

    Type: "Select", 

    TableName: "users.csv", 

    Fields: ["id", "name"], 

有很多原因可能会导致解析失败,所以同时执行这两个步骤可能会比较方便,并在出现错误时可以立即停止。

策略

我们将定义一个像这样的解析器:

type parser struct { 

  sql             string        // The query to parse 

  i               int           // Where we are in the query 

  query           query.Query   // The "query struct" we'll build 

  step            step          // What's this? Read on... 

 

// Main function that returns the "query struct" or an error 

func (p *parser) Parse() (query.Query, error) {} 

 

// A "look-ahead" function that returns the next token to parse 

func (p *parser) peek() (string) {} 

 

// same as peek(), but advancing our "i" index 

func (p *parser) pop() (string) {} 

直观地说,我们首先要做的是“peek() 第一个 token”。在基础的SQL语法中,只有几个有效的初始 token:SELECT、UPDATE、DELETE等;其他的都是错误的。代码像这样:

switch strings.ToUpper(parser.peek()) { 

 

case "SELECT": 

  parser.query.type = "SELECT" // start building the "query struct" 

  parser.pop() 

  // TODO continue with SELECT query parsing... 

 

case "UPDATE": 

  // TODO handle UPDATE 

 

// TODO other cases... 

 

default: 

  return parser.query, fmt.Errorf("invalid query type") 

 

我们基本上可以填写 TODO 和让它跑起来!然而,聪明的读者会发现,解析整个 SELECT 查询的代码很快会变得混乱,而且我们有许多类型的查询需要解析。所以我们需要一些结构。

有限状态机

FSMs 是一个非常有趣的话题,但我们来这里不是为了讲这个,所以不会深入介绍。让我们只关注我们需要什么。

在我们的解析过程中,在任何给定的点(与其说“点”,不如称其称为“节点”),只有少数 token 是有效的,在找到这些 token 之后,我们将进入新的节点,其中不同的 token 是有效的,以此类推,直到完成对查询的解析。我们可以将这些节点关系可视化为有向图:

用Go构建一个SQL解析器

点转换可以用一个更简单的表来定义,但是:

用Go构建一个SQL解析器

我们可以直接将这个表转换成一个非常大的 switch 语句。我们将使用那个我们之前定义过的 parser.step 属性:

func (p *parser) Parse() (query.Query, error) { 

  parser.step = stepType // initial step 

 

  for parser.i < len(parser.sql) { 

    nextToken :parser.peek() 

 

    switch parser.step { 

    case stepType: 

      switch nextToken { 

      case UPDATE: 

        parser.query.type = "UPDATE" 

        parser.step = stepUpdateTable 

 

      // TODO cases of other query types 

      } 

    case stepUpdateSet: 

      // ... 

    case stepUpdateField: 

      // ... 

    case stepUpdateComma: 

      // ... 

    } 

 

    parser.pop() 

  } 

 

  return parser.query, nil 

相关推荐
新闻聚焦
猜你喜欢
热门推荐
  • 微软AI面试题有多难?这里有一份样卷

      究竟什么样的AI人才能被微软这样的巨头聘用呢?今天,文摘君就淘来了几道微软AI 面试题,同时给出了最基本的解答......

    06-25????来源:澎湃新闻网

    分享
  • 全球最聪明的大脑怎么看AI?他们预测了

      2017年AI领域取得了诸多成果。2018年AI又将何去何从?以下是来自世界顶级研究人员和行业领军人物对2018年AI领域发展作......

    02-20????来源:虎嗅网

    分享
  • 2017JavaScript框架战报 - React分战场

      我们来看看与React有关的软件包的生态系统。当Facebook构建React时,就有许多来自开源社区的第三方软件包。为提供完......

    02-27????来源:湖北新闻网

    分享
  • 小白学数据:教你用Python实现简单监督学

      监督学习作为运用最广泛的机器学习方法,一直以来都是从数据挖掘信息的重要手段。即便是在无监督学习兴起的近......

    03-05????来源:今日头条

    分享
  • 现代编程语言Swift、Kotlin等十大有趣功能

      最近学习了一些现代编程语言,比如Reason,Swift,Kotlin和Dart。这些编程语言提供了许多新功能,本文主要分享了我认......

    04-29????来源:祁东新闻网

    分享
  • 领域场景分析的6W模型

      组成场景的要素常常被称之为6W模型,即描写场景的过程必须包含Who,What,Why,Where,When与hoW这六个要素。......

    04-30????来源:砍柴网

    分享
  • 开源应用服务器WildFly 12发新季度交付模式

      WildFly 12 Final版本现在已经可以下载了,WildFly是一款灵活的开源应用服务器,支持开发人员构建轻量级应用程序。支持......

    05-10????来源:青岛新闻网

    分享
  • 基于Spring Cloud的微服务落地

      微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务。但如果要将微服务架构运用到生产项目上,......

    06-04????来源:广西新闻网

    分享
  • 为什么阿里工程师纷纷在内网晒代码?

      前阵子,在阿里一个小黑屋里,5名对代码有着极致追求的工程师参与阿里代码领域最高荣誉“多隆奖”的最终角逐。......

    06-08????来源:四川新闻网

    分享
  • 超级大汇总!200多个最好的机器学习、

      我把这篇文章分为了四个部分:机器学习,自然语言处理,python和数学。在每个部分中我都列举了一些主题,但是因......

    09-25????来源:洛阳新闻网

    分享
返回列表
Ctrl+D?将本页面保存为书签,全面了解最新资讯,方便快捷。