SQL 语句解析过程详解

news2025/1/13 3:06:34

SQL 语句解析过程详解:

1.输入SQL语句

2.词法分析------flex

        使用词法分析器(由Flex生成)将 SQL 语句分解为一个个单词,这些单词被称为“标记“。标记包括关键字、标识符、运算符、分隔符等。

2.1 flex 原理

1、使用 flex 工具定义正则表达式规则来匹配不同类型的词法单元;例如,可以定义以下规则:

  • 匹配关键字:SELECT、FROM、WHERE、HAVING等。
  • 匹配标识符:由字母或下划线开头,后跟字母、数字或下划线组成。
  • 匹配运算符:比如=、<、>、+、等。
  • 匹配常量:包括整数、浮点数、字符串等。

2、生成词法分析器代码:根据定义的词法规则,使用Flex工具生成对应的词法分析器代码;

3、输入查询字符串:将要解析的查询字符串作为输入提供给同法分析器;

4、扫描和匹配:词法分析器从输入字符串中逐个读取字符,并尝试将其与定义的词法规则进行匹配;

5、生成词法单元:当词法分析器匹配到一个词法规则时,它会生成相应的词法单元并返回给语法分析器。每个词法单元通常包含两部分信息:

  • 词法单元类型(token type):表示该词法单元的种类,比如关键字、标识符、运算符等;
  • 词法单元值(tokenvalue):表示该词法单元具体的取值;

6、继续扫描:词法分析器会持续从输入字符串中读取字符,并重复步骤4和步骤5,直到整个查询字符串被完全解析为一系列词法单元;

7、返回词法单元序列:当整个查询字符串都被解析后,词法分析器将返回一个包含所有词法单元的序列给语法分析器,供后续的语法分析处理;

2.2 flex 文件代码结构

2.2.1 flex 文件介绍

1、flex文件代码

%option noyywrap
%{
definition
%}

%%
rules
%%
Code

(1)%option 指定 flex 扫描时的一些特性。yywrap 通常在多文件扫描时定义使用。常用的一些选项有:

  • Noyywrap:告诉flex不使用yywrap函数;
  • yylineno:会告诉flex生成一个名为yylineno的整型变量来保存当前的行号;
  • case-insensitive 正则表达式规则大小写无关;

(2)definitio部分为定义部分,包括引入头文件,变量声明,函数声明,注释等,这部分会被原样拷贝到输出的.c文件中。

(3)rules部分定义词法规则,使用正则表达式定义词法,后面{}内则是扫描到对应词法时的动作代码;“|”是一个特殊符号,表示下一个模式应用相同的动作;正则表达式后面不指定动作,则相应的模式会被忽略。

(4)code部分为C语言的代码。yylex为flex的函数,使用yylex开始扫描。

2.2.2 flex 文件常用变量

(1)yytext:词法分析程序当前识别到的一些词素,与转换规则部分中的某个模式相匹配;

(2)yylength:词法分析程序当前识别到的词素的长度;

(3)yylval:yylval是在bison中定义的联合类型变量(union),因为Flex生成的词法分析程序yylex()需要向bison生成的语法分析器返回识别到的词法单元,所以需要使用yylval来保存词法单元的属性值;

2.2.3 正则表达式

.        匹配除换行符”\n”以外的任何单个字符;

*        匹配前面表达式的零个或多个拷贝;

[]       匹配括号中任意字符的字符类,如果第一个字符是 “^”,则匹配除括号中的字符以外的任意字符;“-” 指示一个字符范围,例如“[0-9]”和“[0123456789]”含义相同;除了以 “\” 开始的转义序列,元字符在括号内没有任何含义;

^       作为正则表达式的行首匹配行的开头,也用于方括号中的否定;

$       作为正则表达式的行尾匹配行的结尾;

\        用于转义元字符,也作为常用的C转义序列的一部分,例如”\n”表示换行,“\*” 表示非元字符的星号;

+       匹配前面的正则表达式一次或多次出现;

?      匹配前面的正则表达式零次或一次出现;

|         匹配前面的正则表达式或随后的正则表达式;

“…”  引号中的每个字符解释为字面意义,除C转义序列外元字符会失去其特殊含义;

()      将一系列正则表达式组成一个新的正则表达式,例如(01),表示字符序列 01;

{}      当括号中包含一个或两个数字时,指示前面的模式允许被匹配多少次,例如{1,3}表示匹配字母一次到三次;

2.2.4 flex 文件具体案例

1、创建一个名为 lexer.l 的文件,其中包含词法规则;

%{
#include <stdio.h>
%}

%%
SELECT                  { printf("Keyword: SELECT\n"); }
FROM                    { printf("Keyword: FROM\n"); }
WHERE                   { printf("Keyword: WHERE\n"); }
AND                     { printf("Keyword: AND\n"); }
OR                      { printf("Keyword: OR\n"); }

[0-9]+                  { printf("Number: %s\n", yytext); }

[A-Za-z_][A-Za-z0-9_]*  { printf("Identifier: %s\n", yytext); }
[=><]+                  { printf("Operator: %s\n", yytext); }
[ \t\n]                 ; // Skip whitespace

.                       { printf("Unknown: %s\n",yytext); }
 
%%

int main() {    
    yylex();   
    return 0;
}

2、使用 flex 命令编译 lexer.l 文件,生成词法分析器代码 

(1)执行下列语句生成词法分析器代码

flex lexer.l

(2)词法分析器生成结果

lex.yy.c

(3)编译生成的词法分析器代码,生成可执行文件

gcc -o lexer lex.yy.c -lfl

(4)运行可执行文件并输入一些算术表达式进行测试

./lexer

输入:SELECT * FROM table;

(5)执行结果如下

说明:

  • -ll: 这是旧版本的Flex生成器(例如Flex 2.5.4)的链接选项。它指示链接器将使用名为 libl.a 或 libl.so 的库文件。在以前的版本中,Flex生成的词法分析器的默认名称是 lex.yy.c,而库文件的名称以 "l" 开头,因此使用 -ll 是一种传统的方式。
  • -lg: 这是新版本的Flex生成器(例如Flex 2.5.35)的链接选项。类似于旧版本的 -ll,它指示链接器使用名为 libg.a 或 libg.so 的库文件。这种新方式是为了避免与其他工具和库发生命名冲突。
  • -lfl: 这是一个与Flex生成的词法分析器库相关的选项。-lfl 表示链接器将使用名为 libfl.a 或 libfl.so 的库文件。这个库包含了Flex所需的运行时支持函数。

注意:

        如果 flex 词法分析器对 .l 进行编译时报错:

        /opt/h/devtoolset-11/root/usr/ibexec/gcex86.64-redhat-linux/11/ld: cannot find -lfn

解决方案:

        该错误表明链接器无法找到名为 -if 的库文件。这通常是因为在您的系统上缺少libfl库,或者库文件的路径未正确配置。要解决这个问题,您可以尝试以下步骤:

1、确认库是否已安装:首先,请确保您的系统上已安装了libfl库。您可以尝试使用包管理器来安装它。在基于Red Hat的系统中,您可能需要执行类似于以下的命令:

yum install flex-devel

2、检查库文件路径:如果库已安装,但链接器仍然找不到它,可能是因为库文件的路径未正确配置。您可以尝试手动指定库文件的路径。例如,假设libfl库文件位于/usr/lib64目录下,您可以使用以下方式链接:

gcc -o my program lex.yy.c -L/usr/lib64 -1f1

3、更新库文件缓存:如果您最近安装了libfl库,但链接器仍然找不到它,您可能需要更新库文件缓存。运行以下命令以更新库文件缓存:

sudo ldconfig

3.语法分析------bison

        使用语法分析器(由 Bison 生成)根据语法规则进行语法分析,生成抽象语法树。语法树是一种树形结构,它表示 SQL 语句的语法结构。语法分析器会检查语法树是否符合 SQL 语法规则,如果不符合,则会抛出语法错误。

3.1 bison原理

3.2 bison文件代码结构

1、bison文件代码

%{
// C 代码和头文件的声明
#include <stdio.h>
// 在这里可以定义全局变量和函数等
%}
// Bison 的选项部分
%option verbose   		// 控制 Bison 解析器的详细输出

// Bison 的声明部分    
%token NAME       	    // 定义终结符或标记的名称
%token NUMBER

%left ‘+’ ‘-‘           // 定义运算符的优先级和结合性
%left ‘*’ ‘/’

%{
// 在这里可以编写更多的 C 代码
%}// Bison 的规则部分

%%
// 语法规则的定义
expression : expression '+' expression           
            | expression '-' expression           
            | expression '*' expression           
            | expression '/' expression           
            | '(' expression ')'           
            | NUMBER           ;
// 更多的语法规则...
%%

// C 代码部分(选项中的 %{ ... %} 和规则部分中的 %% 之间的部分)
// 在这里可以编写与语法规则相关的 C 代码
int main() {    
    yyparse();  // 调用 Bison 生成的解析函数    
    return 0;
}

  bison文件的书写格式与flex文件的书写格式基本一致,只是规则的定义语法不同。

3.3 规则语法介绍

(1)终结符(Terminals)

        终结符是语法规则中的基本符号,通常是语言中的关键字、运算符、标识符等。可以使用%token来定义终结符。以下是一个示例:

%token NUMBER 
%token PLUS MINUS TIMES DIVIDE 
%token IDENTIFIER 
%token SEMICOLON

        在这个示例中,我们定义了几个终结符,包括数字(NUMBER)、加号(PLUS)、减号(MINUS)、乘号(TIMES)、除号(DIVIDE)、标识符(IDENTIFIER)和分号(SEMICOLON)等。终结符是语法规则中的基本符号,代表语言中的最小单元或词汇元素。终结符在语法分析的过程中与输入字符串的实际内容进行匹配,帮助构建解析树或语法分析树。在 Bison 文件中,终结符通常以大写字母或使用引号括起来的字符串表示。

(2)非终结符(Non-terminals)

        非终结符表示语法规则中的抽象结构,可以由其他非终结符和/或终结符组成。您可以使用 %type 来定义非终结符的类型。以下是一个示例:

%type <expr> expression

%type <term> term

%type <factor> factor

        在这个示例中,我们定义了三个非终结符 expression、term 和 factor,并指定了它们的类型。这些类型标记可以在产生式的操作部分使用,以便对解析树节点进行更复杂的操作。非终结符在语法分析树中代表了一些更高级的结构,可以用来执行语义操作、构建解析树,并帮助描述语言的抽象语法结构。在 Bison 文件中,非终结符通常以小写字母开头。

        终结符和非终结符在 Bison 文件中共同定义了语法规则,帮助我们描述和分析特定编程语言或语言的一部分。终结符代表了实际的词法单元,而非终结符则代表了更高层次的语法结构。通过将终结符和非终结符组合起来,我们可以创建复杂的语法规则,用于生成和解析语言的有效字符串。

(3)“文法”

        “文法”是一组规则,用于描述编程语言或语言的语法结构。这些规则定义了语言的句法(syntax),即哪些组合是有效的、合法的语句和表达式,以及它们如何组合在一起。文法规则使用产生式(productions)的形式来表示,其中包含终结符(terminals)和非终结符(non-terminals)的组合。

        文法规则在 Bison 文件中是使用 BNF(巴科斯-诺尔范式)或 EBNF(扩展巴科斯-诺尔范式)的形式表示的。BNF 是一种形式化的表示方法,用于定义上下文无关文法(Context-Free Grammar),这些文法用于指定编程语言的语法规则。

expression : expression '+' term
          		| expression '-' term
           		| term;

(4) %start

        %start 指令用于指定文法的起始非终结符。起始非终结符是语法分析的入口点,也就是从哪个语法规则开始构建解析树或语法分析树。

%start program

%%

statements : statement

                   | statements statement;

statement : assignment

                   | if_statement

                   | while_statement

                   | /* ... other statement types ... */ ;

        %start program 指定了起始非终结符为 program。这意味着语法分析将从 program 规则开始,逐步展开其他非终结符,最终构建解析树。在实际语法规则中,起始非终结符的选择取决于您想要分析的语言的语法结构。

(5)$

        在语法规则中,$ 用于引用当前产生式的右侧的符号或值。例如,在产生式的右侧,$1 表示该产生式右侧的第一个元素(终结符或非终结符),$2表示第二个元素,依此类推。这些引用用于将产生式右侧的值传递给产生式左侧。注意:生产式的起始下标为1。

(6)$$

        在语法规则中,$$ 用于引用当前产生式的结果。当 Bison 解析器完成一个产生式的分析并计算出其结果时,该结果会被赋值给 $$。这通常用于构建解析树的节点或为更高层次的语法规则提供结果。

(7)|

        | 用于表示多个产生式之间的选择。它在上下文无关文法中用于定义非终结符的不同产生式形式。每个产生式通过竖线分隔,表示它们是该非终结符的可能形式之一。

3.4 bison文件具体案例

1、创建一个名为parser.l的文件,其中包含词法规则;

%{
#include <stdio.h>
#include <stdlib.h>
%}

//定义终结符
%token SELECT INSERT UPDATE DELETE FROM WHERE 
%token INTO VALUES SET
%token ID INT STRING

%%

//定义规则
	
statement: SELECT columns FROM table WHERE condition ';'
         	| INSERT INTO table '(' columns ')' VALUES '(' values ')' ';'
         	| UPDATE table SET assignments WHERE condition ';'
         	| DELETE FROM table WHERE condition ';'
         	;

columns: ID
       	| columns ',' ID
       	;

table: ID
     	;

assignments: ID '=' value
           	| assignments ',' ID '=' value
           	;

values: value
      	| values ',' value
      	;

value: INT
     	| STRING
     	;

condition: ID '=' value
         	;

%%

int main() {
    	yyparse();
    	return 0;
}

int yyerror(const char *s) {
    	printf("Error: %s\n", s);
    	return 0;
}

2、使用 bison 命令编译 lexer.l 文件

bison -d parser.y

        这将生成 parser.tab.c 和 parser.tab.h 两个文件。接下来,你可以将这些文件与你的编译器项目一起编译,并链接到你的代码中。

3.5 抽象语法树(AST)

AST构建步骤:

1、从前缀表达式构建函数关系表里获取当前Token的构建函数,调用该函数构建出一个前缀表达式;

2、查看下一个Token的优先级,如果下一个Token的优先级比当前Token的优先级更高,则说明这可能是一个中缀表达式,或后缀表达式;

3、如果是中缀表达式,则从中缀表达式构建函数关系表里获取下一个Token的构建函数,调用该函数构建出一个中缀表达式;

4、如果是后缀表达式,则从后缀表达式构建函数关系表里获取下一个Token的构建函数,调用该函数构建出一个后缀表达式;

5、通过递归方式,将这些表达式建立起父子关系,最终形成一个抽象语法树。

4.语义分析

        在语法分析的基础上,对生成的抽象语法树进行语义分析。语义分析器会检查SQL语句是否符合数据库的语义规则,例如表是否存在、列是否存在、数据类型是否匹配等。如果不符合,则会抛出语义错误。

5.优化器

        在语义分析的基础上,进行优化。优化器会对SQL语句进行优化,以提高查询效率。优化器会选择最优的执行计划,包括选择最优的索引、选择最优的连接方式等。

6.执行计划生成器

        在优化器的基础上,生成执行计划。执行计划是一组计算机指令,用于执行SQL语句。执行计划包括访问表、过滤数据、排序数据等操作。

7.执行计划执行器

        执行计划执行器会按照执行计划执行SQL语句。执行计划执行器会访问表、过滤数据、排序数据等操作,最终返回查询结果。

8.结果集返回

        执行计划执行器会将查询结果返回给客户端。查询结果可以是一张表、一组记录或一个标量值。

9.清理

        在查询结束后,数据库管理系统会清理执行计划、释放资源等。

未完,writing……

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/870095.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CCLINK转MODBUS-TCP网关cclink通讯接线图 终端电阻

大家好&#xff0c;今天我们要聊的是生产管理系统中的CCLINK和MODBUS-TCP协议&#xff0c;它们的不同使得数据互通比较困难&#xff0c;但捷米JM-CCLK-TCP网关的出现改变了这一切。 1捷米JM-CCLK-TCP是一款自主研发的CCLINK从站功能的通讯网关&#xff0c;它的主要功能是将各种…

JavaWeb 中对 HTTP 协议的学习

HTTP1 Web概述1.1 Web和JavaWeb的概念1.2 JavaWeb技术栈1.2.1 B/S架构1.2.2 静态资源1.2.3 动态资源1.2.4 数据库1.2.5 HTTP协议1.2.6 Web服务器 1.3 Web核心 2 HTTP2.1 简介2.2 请求数据格式2.2.1 格式介绍2.2.2 实例演示 2.3 响应数据格式2.3.1 格式介绍2.3.2 响应状态码2.3.…

linux中的ifconfig和ip addr

在linux操作系统中ifconfig和ip addr都是显示网卡配置信息的命令&#xff0c;好多人有疑惑它们有什么区别呢 区别1&#xff1a;对于linux发行的版本不一样 ip addr是对新发行版本的linux使用会比较多&#xff1b;而ifconfig是老版本遇到使用的会比较多。 区别2&#xff1a;显…

mysql8和mysql5的安装过程都有!!!超多图超详细保姆级教程最新教程新手小白轻松上手,带你了解清楚你安装过程的每一个术语

目录 前言mysql5和mysql8的区别1.官网下载2.mysql8的安装2.1安装程序打开前2.2Choosing a Setup Type选择安装模式2.3Select Products选择组件2.3.1Select Products的组件解释2.3.2Select Products的组件选择2.3.3电脑操作系统位数查看2.3.4Select Products的组件的内容配置2.3…

锐捷设备密码管理、密码恢复、恢复出厂设置

目录 配置登录用户名密码以及Enable密码 只需要密码登录 需要用户名和密码登录&#xff08;无AAA&#xff09; 需要用户名和密码登录&#xff08;有AAA&#xff09; 密码恢复 Web密码忘记 Telnet/SSH密码忘记 Console密码忘记 所有密码都忘记&#xff0c;通过Console进…

微信小程序在使用vant组件库时构建npm报错

在跟着vant官方进行使用步骤一步步操作时&#xff0c;由于要构建NPM&#xff0c;但NPM包在App配置文件的外部 所以在做下图这一步时&#xff1a; 接着再进行npm构建时会报错 message:发生错误 Error: F:\前端学习\前端框架\小程序\project\demo\miniprogram解决方法 &#xf…

Offset Explorer

Offset Explorer 简介下载安装 简介 Offset Explorer&#xff08;以前称为Kafka Tool&#xff09;是一个用于管理和使Apache Kafka 集群的GUI应用程序。它提供了一个直观的UI&#xff0c;允许人们快速查看Kafka集群中的对象以及存储在集群主题中的消息。它包含面向开发人员和管…

1、深入理解Mysql索引底层数据结构与算法(前置课程)

1.表中数据看似挨在一起&#xff0c;本质写在磁盘里&#xff0c;随着时间和其他程序占用可能分散分布 k为值 v为磁盘空间地址 2.为什么mysql选择B树 假如b树存放2k万数据 一个节点16KB&#xff0c;里面带有data的话存的太少&#xff0c;导致树的高度过高&#xff0c;所以让…

配置:Terminal和oh-my-posh

目录 命令行安装oh-my-posh查看安装情况配置PowerShell启用oh-my-posh、设置主题配色安装字体Terminal中的配置 命令行安装oh-my-posh Set-ExecutionPolicy Bypass -Scope Process -Force; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString(https://ohmy…

Java四大查找(二)插值查找

Java四大查找 一. 插值查找1.1 题目1.2 思路分析&#xff08;图解加文字&#xff09;1.3 代码演示 一. 插值查找 1.1 题目 给定一个有序数组&#xff0c;在有序数组中找到该数字。如果有&#xff0c;则返回该数字的下标&#xff0c;如果没有&#xff0c;则返回-1. 1.2 思路分析…

模拟IIC——关于模拟IIC的IO口的配置选取推挽输出还是开漏输出,以及是否需要更改IO口输入输出模式和是否需要对IO配置上拉

问题如下 当时我以为引脚配错了&#xff0c;原理图明明是B引脚&#xff0c;为何程序是C呢 查了一下资料&#xff0c;顿悟了 https://blog.csdn.net/m0_62243928/article/details/125779308 在使用模拟IIC的时候&#xff0c;观看别人的程序的时候发现了程序之间的一些不一…

RabbitMQ工作流程详解

1 生产者发送消息的流程 (1)生产者连接RabbitMQ&#xff0c;建立TCP连接(Connection)&#xff0c;开启信道(Channel) (2)生产者声明一个Exchange (交换器)&#xff0c;并设置相关属性&#xff0c;比如交换器类型、是否持久化等 (3)生产者声明一个队列井设置相关属性&#xf…

2023国赛数学建模B题思路分析

文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 全国大学生数学建模…

2023国赛数学建模A题思路分析

文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 全国大学生数学建模…

安卓:网络框架okhttp

目录 一、okhttp介绍 1. OkHttpClient类&#xff1a; 常用方法&#xff1a; 2. Request类&#xff1a; 常用方法&#xff1a; 3. Response类&#xff1a; 常用方法&#xff1a; 4. Call类&#xff1a; 常用方法&#xff1a; 5. Interceptor接口&#xff1a; 常用方法&…

Web 服务器 -【Tomcat】的简单学习

Tomcat1 简介1.1 什么是Web服务器 2 基本使用2.1 下载2.2 安装2.3 卸载2.4 启动2.5 关闭2.6 配置2.7 部署 3 Maven创建Web项目3.1 Web项目结构3.2 创建Maven Web项目 4 IDEA使用Tomcat4.1 集成本地Tomcat4.2 Tomcat Maven插件 Tomcat 1 简介 1.1 什么是Web服务器 Web服务器是…

【MySQL】并发执行事务可能存在的问题, 事务的四种隔离级别

文章目录 前言一、并发执行事务可能存在的问题1, 脏读问题2, 不可重复读3, 幻读 二、MySQL 的四种隔离级别1, READ UNCOMMITTED 读未提交2, READ COMMITTED 读已提交3, REPEATABLE READ 可重复读 (MySQL 的默认事务隔离级别)4, SERIALIZABLE 串行化 总结 前言 各位读者好, 我是…

Mac如何打开隐藏文件中Redis的配置文件redis.conf

Redis下载(通过⬇️博客下载的Redis默认路径为&#xff1a;/usr/local/etc) Redis下载 1.打开终端进入/usr文件夹 cd /usr 2.打开/local/文件夹 open local 3.找到redis.conf并打开,即可修改配置信息

MATLAB算法实战应用案例精讲-【图像处理】图像分类模型Swin TrasnformerViT

目录 Swin Trasnformer 1. 模型介绍 2. 模型结构 3. 模型实现 4. 模型特点 5. 模型效果 ViT( Vision Transformer) 模型介绍 模型结构与实现 1. 图像分块嵌入 2. 多头注意力 3. 多层感知机&#xff08;MLP&#xff09; 4. DropPath 5. 基础模块 6. 定义ViT网络 …

gulimall-缓存-缓存使用

文章目录 前言一、本地缓存与分布式缓存1.1 使用缓存1.2 本地缓存1.3 本地模式在分布式下的问题1.4 分布式缓存 二、整合redis测试2.1 引入依赖2.2 配置信息2.3 测试 三、改造三级分类业务3.1 代码改造 四、高并发下缓存失效问题4.1 缓存穿透4.2 缓存雪崩4.3 缓存击穿 五、分布…