00:00
好,那我们接下来的话呢,我们就开始自己来定义一个小的CQL语法文件啊,就是说当然你学会自己定义语法文件的时候呢。以后呢,那实际上你就可以做很多事情了,对吧?呃,也就是说按台RR这个工具,如果你掌握的非常熟练的话呢,它几乎可以做你能想到的所有的事情,对吧?就说再复杂的血缘关系他都可以分析的出来,因为你实际上你掌握了如何定义语法文件的话,那呃,很多语法文件对吧?呃,其实你都是可以看得懂了对吧?其实你都是可以看懂了,也就是我们在这边,如果我们打开get up的话,呃。对吧,如果你打开github的话呢。那么实际上gib上面。是有几乎所有的语言的,这样的一个什么呢?呃,就是说。呃,语法文件对吧,语言的语法文件,比方说这个是安台R的,呃,主页对吧,安台的仓库的主页,呃,那么在这的话呢,你可以让他点击这有一个additional grammars。
01:11
里边呢,就包含了几乎所有语言的语法定义文件,对吧,比方这个是C语言对不对?呃,比方说还有什么呢,我们可以看一下找一下CQ对吧?呃,我们来看一下这个CQ语法定义文件。呃,那么你在这里边的话呢,你就会发现什么呢,比方说我们来看一下。对不对,这里边有derbyq haveq myq,什么Phoenix呀,什么post gra啊等等,几乎所有,呃,就是说CQ语法对吧,几乎所有引擎的CQ语法,比方这个have对吧?有第二版的,有第三版的对不对,有第二版的有第三版的好。所以说你在这边你就可以点进去,对吧,这个是HAVE3的一个,呃,就是说语法定义文件对吧,你可以看到这,诶have lecture g4have passer,这次你点进去的话呢,当然你会发现说这个语法文件很长,因为本身have CQ它的语法比较复杂,对吧?呃,在这的话,你可以看到它会有1400行的,呃,这个语法文件对吧,以及。
02:22
可能有很多很多的词法文件对吧,这个leer也有500多行对吧,就是它关键字,各种关键字啊。所以我们这里面呢,我们选择自己来定义一个CQ语法,那当然在这的话呢,呃,首先我们要在哪里呢?我们要在government里边,对吧?呃,你在这个government里边的话呢。呃,然后在service下面对吧,你在这个service下面的话呢,比如说我在这边我新建一个语法文件,呃,那这个文件的话呢,我就叫做一个Cq.G4吧,对吧,我们自己来定义一个,呃,小的这样的一个CQ语法文件,当然在这的话,这个站文件夹我先给它删掉。
03:07
我先给它删掉,因为它没用了,好Cq.G4,然后呢,我们怎么来定义呢?这个其实就是我花了大概几分钟时间,呃,大概定义一下,呃,当然它也比较简单啊,非常简单,Grammarq。对吧,然后呢,它的这个语句呢,有两种,第一种是插入语句。对吧,第一种是插入语句,那么第二种是什么呢?第二种是select statement对吧?查询语句,好啊,当然你这个插入语句和查询语句的语法规则呢,都没有进行定义,对吧?所以我们在这的话呢,我们要继续定义插入语句和查询语句的语法规则,当然在定义之前呢,我们先定一些关键字对吧,哪些关键字,比方说t insert。那这个关键字呢,就是insert这样的一个字符串对吧?好然后呢,T select,对,那你一看你应该就知道这个是一个C代关键字啊,那么当然了,还有就是T,呃,Into对吧,那么这个就是into关键字,而且我这里边啊都是关键字都是大写啊,我我并不是区不区分大小写的那种语法定义啊,要求所有关键字都必须是大写,那比如说在还有一个是。
04:30
Override。冒号。然后呢,这个是一个over right好。呃,当然除了overri以后呢,还有比如说from,对吧,我们这个from也需要定义,然后呢,除了from以外呢,那还有就是。Table对吧,Table关键字好。当然呢,还有类似于像照应这样的关键字,对吧?呃,还有呢,像什么暗的这样的关键字。
05:09
呃,然后呢,还有像or这样的关键字对吧?呃,当然你这里面or的话,我们这儿用不着,我们就用on吧,On这个关键字肯定是要用的,OK,那么还有呢,就是。LPAR,那这个是什么呢?这个就是左括号,左圆括号,那么TRPAR对吧,右圆括号,这个parent就是括号的意思啊,一般代表哈t dot,对,这是点,然后t comma。当然,这个是逗号。对不对,然后呢,T_q identifier对吧?这个是关键,这个是标识符或者说表明对不对啊,那么它表名是什么呢?它表名的话,可能是一个单个的表名,也可能也可能是一个库名加一个点加一个表名对吧?所以说我们这个tqent呢,等于ti identify five。
06:19
对不对,然后呢,加上一个点,当然一般来说这个点的话呢,你可能不止一个对吧,T_identity。对吧,这应该是ENT啊,Fair好,然后呢,加一个星号对吧,就是零次或者多次正则表达的语法,然后我们呢,TQ ient呢,我们已经定义好了,对吧,比如说那么它就可以识别什么呢?类似于像这样的一些字符串j Mo点。比如说云台左源table对吧。那这个就是说库名表名对吧,它就可以用这个语法规则来来识别出来,呃,当然这个ti单发的话呢,我们还要继续。
07:08
来定义一下这个t identifier是什么东西,对吧?QI范我们定义了,然后这个ti identity范呢,就很简单了。I单体F它等它是一个什么呢?那它就是一个,比如说A到Z大写A到大写在对吧,然后呢,这是第一个字母,然后后面的话呢,那就是一个呃A到Z对吧,然后大写A到大写Z。啊。然后呢,或者也就是除了26个字母以外呢,或者呢,是一个下划线对吧,这个实际上是标准的标识符,或者说变量的定义对吧。A刚刚在大写A杠刚在,那这个是第一个字符,那后面的话呢,就是零个或者多个大小写字母,或者说是下划线,哎,这样的话我们标识符就定义好了。
08:06
OK,接下来的话呢,当然我们还需要去把这个,呃,就是说空白字符呢,给它直接跳过对吧,空格斜杠N。斜杠T,斜杠R,我们都给它跳过对吧,然后加号,也就是说一个或者多个空白字符呢,我们就给它跳过好,那这样的话,我们的关键字呢,呃,就定义好了,然后接下来的话呢,我们就来定义一下这个插入语句。对吧?呃,我们定义一下这个插入语句,那么这个插入语句的话就是insert statement冒号T。Insert,当然这个insert的话呢,我们来看一下啊,这个似乎。应该没有任何问题的啊,这里应该是T下划线影射。对吧,这个insert是什么呢?当然我们后面的话呢,它跟的是一个insert into,或者说是overri,对吧,你这个影射的后面呢,要么就是into,要么就是overri嘛,对吧,要么就是插入,要么就是覆盖,然后呢,它这有一个表名,对吧?当然这个表名的话呢,我们是可选的,所以说是一个问号,然后呢,后面的话呢。
09:22
Q identifier对吧,然后再跟一个什么呢?表名后面这个是一个呃,就是说呃,字段名对吧,字段名或者说嗯。对,是个字段名,OK。那这个的话呢,这个不是表名,这个T下方table是table这个关键字。也就这个关键字呢,可以有也可以没有,那后面呢,这个是表名。对吧,后面这个是表名,然后呢,那最后跟一个什么呢?跟一个。Select statement对吧?跟一个查询语句,跟一个查询语句,因为我们插入这个操作的后面,那肯定你是要跟一个查询语句,所以我们现在影射我们定义好以后呢,我们就来定义select statement对吧,也就是查询语句,那么查询语句呢,就是首先是一个select的关键字,然后呢是TQ and fair,也就是表名,然后呢,这是一个逗号。
10:21
是吧,逗号呢,是继续KTQ的identifier对吧?然后呢,星号,因为我们select的后面呢,一般是跟的是一个字段名,或者说字段名逗号字段名逗号都字段名对吧?所以我们在这的话,我们的语法规则呢,要定义成这个样子的,你要注意我这里边我这个语法文件没有支持select芯对吧,我只支持呢select的字段名对吧,Select字段名然后呢,T from关键字,然后呢是一个from class。对吧,From class这样的一个from语句这样的一个,呃。
11:04
啊,那我们定义了这个。就是说select语句的语法以后呢,当然就是呃,From对吧,这个是一个from的呃这样的一个子句对吧,那这个语法其实我们也得定义对吧,因为我们都知道说。我们的form关键字后面呢,那你应该是从一张表呀之类的,或者说连表查询里面去,呃,就是说呃查询一些数据对吧,所以说在这的话呢,我们from class,我们来把它给它定义一下from cross冒号。对吧?那么from class的话呢?呃,当然我们不一定就是从一张表里面去取数据对吧?你也有可能是从一个子查询里面去数据的,所以在这的话呢,我们给它定义一个select statement对吧,然后呢,一个右括号,然后一个右括号,呃,那么我们除了从一个子查询里边去查询数据的话呢?呃,那么还有一个呢,就是我们可以从表里边查询数据对吧?呃,当然的话呢,我们在这的话就是TQ identifier对吧?那么这个是表名,那你除了可以从表里边查询数据以外呢?呃,那么我们还可以从哪里去查询呢?对吧?也就是说你在这儿的话呢,我们还可以去照应其他的语句对吧?我们还可以去照应其他的语句,好,然后呢,一个心,对吧,然后在这的话呢,我我有一个on这样的一个关键字,对吧,来捕获照应的这样。
12:45
的一个呃语句,当然在这儿的话,可能这个语法定义的并不是特别严谨啊,定义的并不是特别严谨,呃,好,然后呢,在这儿的话,我继续来一个on class对吧,也就是on语句好啊,当然这个join class和on class的话呢,显然我们也需要给它定义上对吧,这个就是照应子句,那么它是一个T照应这样的一个关键字,然后呢,后面加上一个表名。
13:15
然后呢,On,子句的话,当然在这儿的话,应该是我们把它敲对了对吧?子句的话,那应该是t q t Qi identify fire对吧,也就是说表名,然后呢,加上一个等于对吧?这个不一定是表名,这应该是一个字段名对吧?这应该是字段名,呃。那么字段名呢,后面跟上一个等于号,然后再来一个呃字段名对吧,然后再来一个字段名,呃,然后呢,后面的话呢,我们就是呃什么呢?因为你这个呃就是说on class的话呢,它还有可能有一些暗的条件,所以说在这的话呢,我们来一个暗的关键字,然后TQ idifier,对吧,然后还是一个等于号,然后呢,还是t identifier对吧,这个是一个字段名,然后呢加一个星号,也就是说后面的这一部分的话呢,呃,它可以出现零次或者多次啊,那这样的话呢,呃,我们的一个CQ语法的呃,就是说非常非常简单的一个CQ语法,对吧,你可以看到他。
14:22
这个语法呢,和。真实的CQ语法对不对?呃,它实际上还离着十万八千里对吧,实际上离着十万八千里好。呃,但是在这儿的话呢,其实我们定义这样的语法文件,就是你自己去学着去定义这个语法文件的话呢,呃,那实际上是可以学到很多东西的,对吧?你就在这儿可以去呃测试一下对吧,可以去测试一下test rule statement对吧?呃,那么在这里面的话呢,我们来看一下,比如说我们就可以select。对吧,然后T。
15:00
点,或者说tone.id from。对吧,Tone。对不对,那这样的话呢,我们可以加上一个分号对吧?呃,当然在这的话,你就可以看到它,诶这个好像它就分析出了,呃,一个语法数对吧,按照我们的这个啊,就是说。定义的这样的一个语法对吧?那么它就分析出了一个语法数,好啊,当然我们这个语法是非常简单的,但是它可以在一定程度上呢说明一些问题,对吧?可以在一定程度上说明一些问题,OK啊,那我们来大概检查一下这个语法文件,定义的应该是没有毛病的对吧?定义的该是没有毛病的好,接下来的话呢,我们就可以根据这个语法文件呢,来给它生成一些对吧,词法分析器和语法分析器,但是我们在这的话,我们可以先做一个按台R的配置,我们把这个listener呢,还是给它勾选掉,对吧?我们只需要使用访问者的模式,然后generate。
16:04
好,那这样的话呢,哎,我们在这个站文件夹里边呢,它就已经,呃,把这些代码都生成好了,然后我们把还是把这个账号文件呢,给它移动过来。对吧,给它移动到这个service里边,然后点击重构对吧?呃,然后呢,你这个实际上这个站文件它就没有用了,我们就可以给它删掉了。好,我们可以给它删掉了,OK。好,那这样的话呢,我们就就把它给删除了,对吧,把它给删除了,然后呢,在这的话呢,我们可以看到我们把这个base visitor呀,包括呃,词法分析器,语法分析器以及访问者模式的这样的一个接口,对吧?呃,还有一个基本实现对不对,我们都给它导进来了,那么导进来之后的话呢。我们就可以来,哎,来分析一下这个血缘关系了,对吧,找几个语句呢给他分析一下,当然我在这儿的话呢,我会新建一个Java类,那么这个Java类的名字呢,叫做table line对吧,或者是line,那这个类的话呢,其实就是我们的。
17:12
呃,这个table line table是表的意思是,呃,血缘关系的意思对吧?那在这的话呢,我们就需要来实现一个什么呢?CQ base visitor,对吧?呃,当然在这的话你会加一个泛型,我们在这的话就直接是一个object吧,也就是说它的返回值呢,是一个object,好。呃,然后呢,我们在这里边做两个全局变量对吧?那么第一个的话呢,是输入表的呃,组成列表对吧?输入表的表明组成的列表对吧?那这个的话就是private final list string好,然后呢,是input tables等于new一个list OK,然后呢,输出表的表明对吧?当然因为你输出表的话肯定你是呃,只有一张表,所以我们在这面呢,就是private string,然后呢,Output table好啊,那这样的话呢,我们的输出表呢,也呃的这个表明对吧?我们也放了一个全局变量,然后接下来的话呢。
18:26
呃,我们需要访问抽象语法数的哪几个节点呢?对不对?我们需要访问抽象语法数哪几个节点呢?那在这的话呢,我们首先visit insert,对吧?我们肯定是需要访问这个insert语句的,因为我们要从这个insert语句或者说insert这个语句里边,对吧?你要插入那个表名,我们要把那个表名呢,给它提取出来,对不对?那么在这里边的话呢,我们如何去提取表名呢?提取输出表的表名对吧?我们如何去提取呢?那在这的话就是output table等于Ctx.TQ ientif.get text,对吧,非常简单。
19:16
提取输出表的表名呢,我们直接选取上下文里面的qdentif,然后获取它的这个文本字符串就可以了,呃,然后呢,我们return的时候呢,我们就直接调用它负类的visit insert statement就OK了,对吧?呃,不需要改变它这个代码,好,那第二个的话呢,我们要访问的是,呃。Over。Right visit,我们要访问的是什么呢?From对吧?当然我们这个点visit from呢,我们给它留着,呃,那我们从这个from class呢,我们主要是提取输入表的表明,当然输入表的话呢,呃,它的可能它的名字可能并不止一个对吧,它的名字可能并不止一个,所以我们在这儿的话呢,我们就是input tables.i ctx点呃,tqent.get text对吧?那这样的话呢,我们就把输入表的表名也给它,呃,提取出来了,当然就是我们除了from子句里边有输入表的表明以外呢,那么还有就是。
20:30
呃,我们的这个draw应子句对吧?就是连表查询的子句呢,里边也有输入表的表明,所以说在这儿的话,我们也需要提取输入表的表明,对吧?Input tables.r的Ctx.t q identify2点get text,好,这个我们这儿也就提取了输入表的表,然后把它放到了input tables这个列表里面,OK,那这样的话呢,其实我们通过这三个visit方法呢,我们就已经提取出了它的输入表和输出表对吧?好,实际上也就是简单的分析了它的一个,呃,就是说血缘关系,当然就是说你对这个语法分析对吧,我们CQ,呃,本身它的语法是特别复杂的,对吧,如果你要是。
21:18
你的CQ语法文件呢,非常非常复杂,比方说像have,它基本上有2000行语法定义对吧,那么你可以非常深入的去分析它的这个什么呢?呃,分析他的,呃,就是说各种各样的对吧,血缘关系对吧,其实都是可以分享出来的啊。然后呢,我们现在有了这样的一个,呃,就是说几个位的方法呢,我们接下来的话呢,我们就可以来实现一个静态方法,对吧?呃实现一个静态方法呢,来把它的这个输入表和输出表呢,呃给它打印出来,当然我们在这儿的话呢,我们,呃实际上我们会创建一个扎阿病这样的一个类,那么扎阿病的这样的一个类呢,呃,它的名字叫做什么呢?呃,那么它的名字呢,叫做source target。
22:12
对吧,叫做source target,也就是我们在这儿我们新建一个Java类,那么它的名字叫做source target,也就是说原顶点和目标顶点,或者说原表和目标表在这儿的话我们可以,对吧,顺便来学习一下,呃,扎va时期的它的一个新特性就是记录类型,对吧?所以说在这的话呢,呃,这个记录类型的话,其实它有点像我们的类对吧,只不过它是省去了我们编写代码的很多功夫,那在这的话呢,我们有两个字段,第一个是S,第二个是target,对吧,也就是S呢,是原表字符串对吧?那么target是输出表字符串对吧?所以这个S呢,实际上它相当于代表了原表到输出表的一个什么呢?
23:12
呃,一条边对吧,它实际上是代表了这样的一条边,然后呢,我们在service里边呢,我们就可以写一个方法对吧,我们反呃把这个血缘关系里面的所有的。边呢,都给它返回对吧?所有的边都给它返回,然后呢,我在这儿的话呢,呃,我可以创建一个静态方法,那么它返回值呢,是一个source target的列表对吧?然后它的函数名呢,我们就起成一个link吧,然后它接收的参数呢,是一条CQ对吧?我们根据呃,这条CQ呢来分析出它,呃,就是说来返回什么呢?返回出所有的原表,呃到目标表的这样的一条这样的边的集合对吧,或者说边的列表OK,然后one stream,我们首先还是把它转化成流,呃,Char streams.from string对吧?我们先把这个CQ呢给它转化成一个流,然后呢,我们实例化一个什么呢?实例一个这个磁法分析器,呃,那我们实例化一个磁法分器呢,我们对它做一个词法分析,然后呢,返回标记流。
24:25
Common token stream对吧?把这个词词法分析器给它传进去,然后呢,我们在这里边,我们在实例化一个语法分析器对吧?呃,当然你要把这个tokens呢给它放进去,我们实例化一个语法分器以后呢,我们就可以挖一个tree对吧,那这个就是我们的。呃,就是说分析出来的抽象语法数pass.statement对吧?那么这个的话呢,呃,我们调用它这个方法,那么它返回的呢,就是我们针对这条CQ对吧,分析生成的一个抽象语法数,然后呢,我们在一个。
25:03
Table。Line等于new一个table line对吧?我们再实例化一下啊,那实例画完以后呢,我们就是table.visit tree对吧?好,呃,那这样的话,我们通过访问呃这棵树的话呢,或者说访问这个抽象语法树的话呢,实际上我们就构建好了输入表和输出表对吧?实际上我们已经构建好了输入表和输出表,呃,然后呢,我们根据这个输入表和输出表,那我们再给它把边给它拼接起来,所以说这个edge呢,等于new一个a list,当然里边的泛型呢是一个s target,然后呢,我们在这的话呢,我们for一个腕S冒号。table.input tables,对吧?那么它里边的每一张输入表呢,都是一个S,然后呢,edges.add new,一个source target,对吧?然后呢,我们是一个S。
26:06
然后呢,是table.output table对吧,因为这个输出表呢,它就只有一个好,那这样的话呢,我们就呃把所有的这个从输入表到输出表的边呢,我们就都已经给它找出来了,然后我们return一个A对吧?好,这个静态方法我们就写完了,然后我们使用一个main函数呢,来进行一个测试,对吧?比如说我在这里边的话呢,我随便建了一个CQ,呃,用来做测试,那么这个CQ呢,是一个insert into追帽。第二,Table one。对吧,然后呢,Select ID from j ma table two啊对吧,那这个C非常非常简单,我们就知道它的输入表示table two,输出表是呃,Table one对吧,我们在这边我们调用它来看一下它能不能计算正确,对不对,它能不能计算正确,呃,好。
27:10
呃,当然在这的话呢,呃,我们为了做测试的话,其实我们在这的话,我们可以把呃这个呢给它打印出来,对吧,给它打印出来。OK,我们现在的话,我们运行一下这个程序,看一下能不能正确的执行,对吧,看一下能不能正确的执行。好,那你可以看到。South呢是table two对吧,Target是table one。对吧,你可以看到它的原表示table two对吧,Target呢是呃这个table one对吧,所以说你可以看到我们这里边它分析出来的,呃这个结果呢,是没有任何问题的,对吧,没有任何问题的,所以说我们现在的话呢,我们就已经呃就是说定义完了这个CQ语法,并且我们还写了一个非常非常简单的分析它的血缘关系的,呃这样的一个程序,对吧,这样的一个程序。
我来说两句