摘要:在数据库管理系统GKD-BASE上设计并实现了兼容Oracle PL/SQL V2.3语言规范的PL/SQL引擎,扩展了GKD-BASE过程处理功能。
GKD-BASE数据库是一个具有自主知识产权的数据库管理系统,具有兼容SQL89标准的SQL引擎,能够为用户提供一个统一、有效的数据库访问接口,实现对数据库的各种 *** 作。但是SQL语言缺乏对算法的描述能力,难以胜任复杂的程序设计。为了融合SQL语言强大的集合数据处理能力和第三代语言(3GL)灵活的过程处理能力,主流数据库管理系统产品都已提供了对过程式SQL语言的支持,如Oracle的PL/SQL[1]。为了使GKD-BASE适应发展现状,满足管理人员和开发人员的需求,急需开发GKD-BASE自身的PL/SQL引擎。
本文在数据库管理系统GKD-BASE上设计并实现了兼容Oracle PL/SQL V2.3语言规范的PL/SOL引擎,扩展了GKD-BASE过程处理功能。
1 GKD-BASE PL/SQL引擎的体系结构
GKD-BASE PL/SQL引擎的基本功能是将用户用PL/SQL语言编写的程序通过词法分析程序、语法分析程序进行解析,生成中间代码并解释执行。如果在分析阶段或解释执行阶段发现错误,则向用户报告错误号及相应的错误信息,以便用户排错[2]。根据PL/SQL语言兼有过程式语句和SQL语句的特点,采取分治策略,把过程语句和SQL语句分开处理。PL/SQL引擎在对PL/SQL源程序编译执行时,首先进行预处理,把SQL语句和过程语句分开;然后对SQL语句和过程语句分别解析,生成语法树;最后通过执行模块对中间代码进行解释执行。
图1
GKD-BASE PL/SQL引擎对源程序编译生成中间代码,不能直接在目标机器上执行,需要一个解释中间代码的环境,以提供对PL/SQL语言中的数据类型的支持,保证PL/SQL正确执行。因此GKD-BASE PL/SQL引擎可分为编译器和解释器两部分,如图1。编译器接收到PL/SQL语句块后进行预处理,将句子分为SQL语句和过程语句。对于SQL语句,编译器建立SQL语句节点,进行相应的变量绑定和语法检查;检查无误后产生中间代码。对于过程语句,编译器对语句成分进行语法分析并建立相应的符号表,也生成中间代码。因此,可以把编译器划分为SQL语言解析、过程语言解析、符号表生成与管理、中间代码表示与管理等模块。解释器的作用是对编译器生成的中间代码进行解释执行[3],与编译器对应,具有独立的SQL语句解释模块和过程语句解释模块。解释器还包括执行状态堆栈的管理、与GKD-BASESQL引擎的调用接口。异常处理模块主要实现程序运行时的错误检查和报告,并支持用户自定义异常和预定义异常的检查和处理。
2 GKD-BASE PL/SQL编译器实现中的一些关键问题
GKD-BASE PL/SQL编译器主要是对PL/SQL源程序进行词法分析、语法分析和语义处理[4]。本文借助构建词法分析器的Lex和编译程序自动产生工具Yacc[5],实现了对PL/SQL源程序的编译。下面分别说明符号表的设计与管理、SQL语句解析以及游标解析。
2.1 符号表的设计与管理
符号表是一个包含程序中的变量、自定义类型和函数信息的数据库。通过索引对应于库中的一条记录;每条记录对应着一个对象的信息,如变量的类型或函数的返回值等[2]。
考虑到PL/SQL语言的块结构和名字作用域,可以使用名字堆栈存放源程序中所使用的标志符的索引、名字和类型。每个项目只包括名字本身和用来表明它的类型的标志值,以及该名字在符号表中的项目索引。名字堆栈采用层次结构,是链表型的堆栈,堆栈的每一层存放了解析的语句块嵌套层内的所有名字信息,如图2。在进入或退出一个嵌套层时调用相应的压栈和d栈 *** 作;查找符号时,从栈顶向栈底搜索。名字堆栈实现了标志符名称与相应的符号表索引间的映射,解决了标志符的作用域问题和可见性问题,满足了对符号表管理和调用的要求。
2.2 SQL语句的解析
为了避免SQL语句在执行时出现语法错误,需要提前检查其语法的正确性。SQL语句是面向集合的数据 *** 作语言,只能交由SQL引擎处理。但是PL/SQL语言为了增强SQL语句与过程式语句的交互能力,在SQL语句中引入变量,GKD-BASE的SQL引擎无法识别,必须在提交之前提取出变量,替换为SQL引擎可以识别的格式。如:SELECT empno,name INTO v_empno, v_name FROM empWHERE birthday=v_date;
这个SELECT语句首先把变量v_date绑定到列名birthday,然后根据条件查出相应的结果 (empno,name),并赋值给预先定义的变量(v_empno,v_name)。对于GKD-BASE的SQL引擎来说,只能识别出如下格式的SELECT语句:
SELECT empno,name INTO:v_empno,:v_nameFROM emp WHERE birthday=:1;
在把SQL语句交由GKD-BASE SQL引擎处理之前,识别出变量v_empno、v_name及v_date进行格式转换,在into之后的变量前面添加“:”,where后面的变量用带有冒号的数字序号代替,构造出符合SQL引擎要求的语句;完成这些处理之后,把新的语句作为字符串交由SQL引擎进行语法分析,检查这条语句的语法是否正确,以及语句中的变量与对应的列是否匹配;最后返回结果,报错或者生成语法树。
2.3 游标的解析
游标是指向内存中上下文区的句柄或指针。借助于游标,PL/SQL程序可以控制上下文区和语句处理过程中游标的变化。PL/SQL游标按使用方式可以分为显式游标和隐式游标。
显式游标的使用包括声明游标、打开游标、游标检索、关闭游标四个步骤。编译游标声明语句时,首先调用SQL引擎分析SQL语句成分,转换为SQL引擎可以识别的格式,把游标的索引信息加入名字堆栈和符号表中。游标打开 *** 作在名字堆栈中搜索游标名字,获取声明阶段在符号表保存的相关信息并加入到语法树中。游标检索语句的编译首先获取游标的符号表的信息;然后关联游标中SQL语句的信息和取值变量链表的信息,检查游标变量与游标引用列是否匹配;最后保存相关信息,加入语法树。游标的关闭 *** 作释放资源并把游标状态初始化,把游标在符号表中的信息保存并加入语法树。
隐式游标一般用于对DML语句的处理。每条DML语句对应于一个隐式游标,编译时可以作为一般的SQL语句来处理,直接调用GKD-BASE的SQL引擎对其进行编译。这些语句的游标处理是由SQL引擎自动完成的,不需要PL/SQL引擎对干涉。
图3
3 GKD-BASE PL/SQL解释器实现中的一些关键问题
解释器实现中的关键问题有语句的执行、执行状态堆栈的设计以及返回值的处理。
对于语句的执行,可分为SQL语句执行和过程语句执行两部分,根据语法树上相应节点分别编写函数来完成解释任务。这些函数例程之间也是树状的层次调用结构,树根的解释执行依赖于其子树上各个节点的解释函数的成功运行。
在GKD-BASE PL/SQL引擎的解释执行器中,设计了“执行状态”的数据结构来记载函数的执行状态信息。解释器中所有的解释函数都拥有一个指针参数指向这个结构,需要在这些函数间传递的信息将被拷贝到这个结构。PL/SQL引擎调用子程序的过程中,构造“执行状态堆栈”。调用之前,保存现场,将执行状态压栈;调用结束后恢复现场,d出当前执行状态,回到上一层继续,如图3。
在语句块执行完毕后,解释器会根据情况给出三种类型的返回状态:ok、exit、return。当正常执行完一条过程语句或SQL语句后,返回ok;或者当执行状态当前层中所有语句都执行正常,向上一层返回ok。当执行时遇到EXIT关键字,如果执行状态中的退出标号与输人参数中的退出标号一致时,说明是正常退出,返回exit。当执行时遇到RETURN关键字,说明语句链中所有语句执行完毕,返回return。直到到达执行状态顶层并给出返回值,结束整个解释执行过程。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)