1.1.1 概述
GBase 8a MPP Cluster的存储过程仍在不断地完善中。本章中所描述的所有语法都被有效地支持,其局限性和扩展要求将被记录备案。
1.1.1.1 存储过程
定义
存储过程是一组可以完成特定功能的SQL语句集,经编译后存储在数据库中。用户在执行存储过程时,需要指定存储过程的名称并给出参数(如果存储过程里包含参数)。
应用场景
在如下情况中,存储过程非常有用:
l 当多个客户端应用程序是由不同的语言编写,或者运行在不同的平台,但需要执行同样的数据库操作时;
l 当安全非常重要时。例如,银行对所有常用的操作都使用存储过程。这提供了一个一致的和安全的环境,并且存储过程可以保证每一个操作都正确的写入日志。如此设置,应用程序和用户将不能直接访问数据表,只能执行特定的存储过程;
l 存储过程可以提高性能,这是因为只需要在服务器和客户端之间传递更少的信息。负面影响是增加了数据库服务器的负担,因为在服务器端执行更多的任务而在客户端(应用程序)则只需执行较少的任务。这在一个或很少的数据库服务器连接有大量客户端(比如Web服务器)的情况下则更明显;
l 存储过程允许用户在数据库服务器中使用函数库。这正是现代应用程序语言具有的特性,例如,通过使用类来进行程序设计。这些客户端应用程序语言特性不论是否应用于数据库端的设计,对程序员来说采用这样的方法还是很有益处的。
GBase 8a MPP Cluster的存储过程遵循SQL:2003标准。
1.1.1.2 函数
GBase 8a MPP Cluster支持函数(FUNCTION)的定义和使用。
1.1.2 创建存储过程、函数
l 存储过程和函数是由CREATE PROCEDURE和CREATE FUNCTION语句所创建的程序;
l 存储过程通过CALL语句来调用程序,而且只能通过输出变量得到返回值。函数可以像其它函数一样从语句内部来调用(通过调用函数名),并返回一个标量值。存储程序(过程和函数)也可以调用其它存储程序(过程和函数);
l 每个存储过程或函数都与一个特定的数据库相联系。当存储程序(过程和函数)被调用时,隐含的USE database_name被执行(当存储程序(过程和函数)结束时完成),不允许在存储程序(过程和函数)中使用USE语句。用户能使用数据库名来限定存储程序(过程和函数)名。这可以用来指明不在当前数据库中的存储程序(过程和函数)。例如,要调用一个与gbase数据库相关联的存储过程p或函数f,用户可以使用CALL gbase.p()或gbase.f()。当一个数据库被删除了,所有与它相关的存储程序(过程和函数)也都被删除了;
l GBase 8a MPP Cluster允许在存储过程中使用标准的SELECT语句。这样,一个查询的结果简单直接地传送到客户端。多个SELECT语句产生多个结果集,所以客户端必须使用一个支持多结果集的GBase 8a MPP Cluster客户端库;
l 要创建一个存储程序(过程和函数),必须具有CREATE ROUTINE权限,ALTER ROUTINE和EXECUTE权限自动的授予给它的创建者。如果开启更新日志,用户可能需要SUPER权限;
l 在默认情况下,存储程序(过程和函数)与当前的数据库相关联。要显式的将过程与数据库联系起来,那用户创建存储程序(过程和函数)时需要将它的名字的格式写为database_name.sp_name;
l 在括号中必须要有参数列表。如果没有参数,应该使用空的参数列表();默认参数为IN参数。如果要将一个参数指定为其它类型,则请在参数名前使用关键字;
l 使用RETURNS子句(只有FUNCTION才能指定RETURNS子句)指明函数的返回类型时,函数体中必须包含一个RETURN语句;
l 如果一个存储过程或函数对同样的输入参数得到同样的结果,则被认为它是"确定的"(DETERMINISTIC),否则就是"非确定"的(NOT DETERMINISTIC)。默认是NOT DETERMINISTIC;
l 就复制来说,使用NOW()函数(或它的同义字)或RAND()并不会生成一个非确定性程序。对于NOW(),更新日志包括时间戳并能进行正确的复制。如果在一个程序中只调用一次,RAND()也能正确地复制;
l 当前DETERMINISTIC特性是可接受的,但并不被优化器所使用。然而,如果更新日志被激活,这个特性将影响到GBase 8a MPP Cluster是否接受过程的定义;
l 以下几个特征参数提供了程序的数据使用信息:
1. SQL SECURITY参数用来指明,此程序的执行权限是赋予创建者还是调
用者。默认的值是DEFINER。创建者和调用者必须要有对与程序相关的数据库的访问权。要执行存储程序(过程和函数)必须具有EXECUTE权限,必须具有这个权限的用户要么是定义者,要么是调用者,这依赖于如何设置SQLSECURITY特征;
2. COMMENT语句是GBase 8a MPP Cluster的扩展,可以用来描述存储过
程。可以使用SHOW CREATE PROCED URE、SHOW CREATE FUNCTION语句来显示这些信息。
l GBase 8a MPP Cluster允许存储程序(过程和函数)包含DDL语句(比如CREATE和DROP)和SQL事务语句(比如COMMIT)。这不是标准所需要的,只是特定的实现;
l 返回结果集的语句不能用在函数中。这些语句包括不使用INTO将列值赋给变量的SELECT语句,SHOW语句等。对于在函数定义时就返回结果集的语句返回一个“Not allowed to return a result set from a function”错误(ER_SP_NO_RETSET_IN_FUNC)。对于在函数运行时才返回结果集的语句,返回“PROCEDURE%s can't return a result set in the given context”错误(ER_SP_BADSELECT)。
存储过程语法格式
存储过程语法格式如下示例:
CREATE PROCEDURE <proc_name>([<parameter_1>[,…] [,parameter_n]]) [characteristic ...] BEGIN <过程定义> END |
函数语法格式
函数语法格式如下示例:
CREATE FUNCTION <func_name>([<parameter_1>[,…] [,parameter_n]]) RETURNS type BEGIN <函数定义> END |
参数说明
l <proc_name>、<func_name>要创建的存储过程的名称。在同一数据库内,存储过程的名称必须唯一。存储过程名称只允许a~z、A~Z、0~9、下划线,且不能只包含数字;
l ([<parameter_1>[,...] [,parameter_n]])定义存储过程的参数,每一个参数的定义格式是:<参数方向><参数名称><参数数据类型>;
l 存储过程的<参数方向>确定参数是输入、输出还是输入输出,只能取IN、OUT、INOUT中的一个。函数的<参数方向>只能是输入IN;
l <参数名称>在同一个存储过程中必须唯一,只允许a~z、A~Z、0~9、下划线,且不能只包含数字;
l <参数数据类型>指定参数的数据类型;
l <过程定义>、<函数定义>是一系列的SQL语句的组合,其中包含一些数据操作以完成一定的功能逻辑;
l 定义存储过程时,存储过程名后面的括号是必需的,即使没有任何参数,也不能省略;
l 如果存储过程、函数中的<过程定义>仅包含一条SQL语句,则可以省略BEGIN和END,否则,在定义存储过程时,必须使用BEGIN...END结构把相关的SQL语句组织在一起形成<过程定义>;
l 存储过程、函数可以嵌套;
l type是GBase 8a MPP Cluster支持的数据类型。
示例
下面是一个使用IN,OUT参数的简单的存储过程的示例。这个示例在存储过程定义前,使用delimiter命令来把语句定界符从“;”变为“//”。这样就允许用在存储程序体中的“;”定界符传递到服务器,而不是被解释。
示例1
创建proce_count存储过程,并调用。
gbase> DELIMITER // gbase> CREATE PROCEDURE proc_count (OUT param1 INT,IN param2 VARCHAR(10)) BEGIN SELECT COUNT(*) INTO param1 FROM ssbm.customer WHERE c_nation= param2; END // Query OK, 0 rows affected gbase> CALL proc_count(@count1,'JORDAN')// Query OK, 0 rows affected gbase> DELIMITER ; gbase> SELECT @count1; +---------+ | @count1 | +---------+ | 1182 | +---------+ 1 row in set |
当使用定界符命令时,用户应该避免使用反斜杆(在GBase 8a MPP
Cluster中表示转义字符)。
示例2
创建含有参数的hello函数,使用SQL函数执行操作并返回结果。
gbase> DELIMITER // gbase> CREATE FUNCTION hello (s CHAR(20)) RETURNS CHAR(50) RETURN CONCAT('Hello, ',s,'!');// Query OK, 0 rows affected gbase> DELIMITER ; gbase> SET @result = hello('world'); Query OK, 0 rows affected gbase> SELECT @result; +----------------------------------------------------+ | @result | +----------------------------------------------------+ | Hello, world ! | +----------------------------------------------------+ 1 row in set |
如果一个函数的RETURN语句返回的值与函数中RETURNS子句指明的值类型不同,返回的值强制为正确的类型。
示例3
创建fn_count函数,过程定义中包含SQL语句。
gbase> DELIMITER // gbase> CREATE FUNCTION fn_count (param varchar(10)) RETURNS INT BEGIN SELECT COUNT(*)/5 INTO @count FROM ssbm.customer WHERE c_nation= param; RETURN @count; END// Query OK, 0 rows affected gbase> DELIMITER ; gbase> SET @result = fn_count('JORDAN'); Query OK, 0 rows affected gbase> SELECT @result; +---------+ | @result | +---------+ | 236 | +---------+ 1 row in set |




