返回首页

gbase数据、南大通用产品文档:GBase8sCREATE PROCEDURE 语句

更新日期:2024年09月11日

使用 CREATE PROCEDURE 语句创建用户定义过程。(要从单独文件中的源代
码文本创建过程,请使用 CREATE PROCEDURE FROM 语句。)
该语句是 SQL ANSI/ISO 标准的扩展。
语法

元素
描述
限制
语法
function,
procedure
在此为新的 SPL 例程
函数或过程声明的名称
请参阅 GBase 8s 上的
过程名称
标识符
owner
table_object 的所有

必须拥有
table_object
所有者名

pathname
存储编译时警告的文件 必须存在于数据库驻留
的计算机上
特定于操
作系统
table_object 触发器可以调用 UDR
的表或视图的名称或同
义词
必须存在于本地数据库

标识符
用法

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 308
在 GBase 8s ESQL/C 中,您可以将 CREATE PROCEDURE 仅作为 PREPARE
语句中的文本使用。如果您希望创建编译时文本已知的过程,则必须使用
CREATE PROCEDURE FROM 语句。
如果您包含可选的 IF NOT EXISTS 关键字,且指定名称的过程已经注册于当前
数据库中,则数据库服务器不采取任何操作(而非向应用程序发送异常)(因为
过程的标识符可以被重载,所以它可以不必包含这些关键字,如果数据库服务器
可以将新过程的参数列表解析为与当前数据库中相同名称的任何其他过程的参数
列表不同。)
例程使用创建时有效的对照顺序,请参阅 GBase 8s 的SET COLLATION 语句
语句,获取关于使用非缺省对照的信息。
示例
对于此示例,假设您具有两个如下定义的重载的过程:
CREATE PROCEDURE raise_prices ( per_cent INT)
UPDATE stock SET unit_price = unit_price + (unit_price * (per_cent/100) );
END PROCEDURE

CREATE PROCEDURE raise_prices ( per_cent INT, selected_unit CHAR )
UPDATE stock SET unit_price = unit_price + (unit_price * (per_cent/100) )
where unit=selected_unit;
END PROCEDURE
为了引用上述过程,您需要在参数列表后提供过程名称,如下所示:
DROP PROCEDURE raise_prices(INT);
DROP PROCEDURE raise_prices(INT, CHAR);
更简便的方法是,使用指定的名称来标识它们。以下示例将会使用指定名称创建
过程:
CREATE PROCEDURE raise_prices ( per_cent INT ) SPECIFIC
raise_prices_all
UPDATE stock SET unit_price = unit_price + (unit_price * (per_cent/100) );
END PROCEDURE
DROP SPECIFIC PROCEDURE raise_prices_all;
CREATE PROCEDURE raise_prices ( per_cent INT, selected_unit CHAR )
SPECIFIC raise_prices_by_unit

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 309
UPDATE stock SET unit_price = unit_price + (unit_price * (per_cent/100) )
where unit=selected_unit;
END PROCEDURE
我们可以简单地使用它们指定的名称来删除它们:
DROP SPECIFIC PROCEDURE raise_prices_by_all;
DROP SPECIFIC PROCEDURE raise_prices_by_unit;
使用 CREATE PROCEDURE 与 CREATE FUNCTION 的对比
在 GBase 8s 中,尽管可以使用 CREATE PROCEDURE 来写入并在注册返回一
个或多个值的 SPL 例程(即SPL 函数),但建议您改为使用 CREATE
FUNCTION 。要注册外部函数,必须使用 CREATE FUNCTION 。
使用 CREATE PROCEDURE 语句来写入并注册 SPL 过程或注册外部过程。
有关类似用户定义的过程和用户定义的函数的术语如何在此手册中使用的信息,
请参阅 例程、函数和过程之间的关系 。
例程、函数和过程之间的关系
过程是可接受参数但不返回任何值的例程。函数是可接受参数并返回一个或多个
值的例程。 用户定义例程(UDR)是包括用户定义的过程和用户定义的函数的一
般术语。关于指定的和未指定的已返回值的信息,请参阅返回子句 。
可以将 UDR 写入数据库服务器为支持的( SPL 例程)或者外部语言(外部例
程)。其中术语 UDR 出现在此手册中,它同时可以指定 SPL 例程和外部例
程。
用户定义的过程指 SPL 过程和外部过程。用户定义函数指 SPL 函数和外部函
数。
在较早发行版的文档中,术语存储过程同时用于 SPL 过程和 SPL 函数。在此手
册中,术语 SPL 例程替换术语存储过程。在有必要区分 SPL 函数和 SPL 过程
函数时,本手册将区分两者。
术语外部例程应用于外部过程或外部函数,这两者都构造指定 UDR ,这些 UDR
由 SPL 以外的编程语言编写。在有必要区分外部函数和外部过程时,本手册将区
分这两者。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 310
使用 CREATE PROCEDURE 的必要特权
必须拥有数据库上的 Resource 特权来在该数据库中创建用户定义的过程。
在能创建 SPL 过程之前,您还必须拥有要编写的过程中的 SPL 、C 或 Java™
语言的 Usage 特权。有关更多信息,请参阅语言级权限。
缺省情况下,SPL 上的 Usage 特权授权为 PUBLIC 。您还必须至少拥有数据库
上的 Resource 特权来在该数据库中创建 SPL 过程。
DBA 关键字和过程上的特权
如果创建带有 DBA 关键字的 UDR ,则其称为 DBA 特权 UDR 。您需要
DBA 特权来创建或者执行 DBA 特权的 UDR 。
在不具有 DBA 特权的用户中,只有 DBA 授予 Execute 权限的用户才能调用
DBA 特权 UDR.。然而,如果 DBA 将 Execute 特权授予 PUBLIC ,则所有的
用户都可以使用 DBA 特权 UDR 。有关 DBA 特权 UDR 的其它信息,请参阅
创建数据库对象的所有权 。
如果您省略 DBA 关键字,则此 UDR 称为所有者特权 UDR 。
当您在兼容 ANSI 的数据库中创建了所有者特权 UDR 时,只有您自己能执行此
UDR。在其它用户可以执行所有者特权 UDR 之前,它的所有者必须将 Execute
特权授权给个别用户或角色或者 PUBLIC 。
如果您在不兼容 ANSI 的数据库中创建了所有者特权 UDR ,则任何人都可以执
行此 UDR ,因为缺省情况下 PUBLIC 被授予 Execute 特权。要限制指定用户
对所有者特权 UDR 的存取,则所有者必须从 PUBLIC 撤销其在 UDR 上的
Execute 特权,然后将它授权给指定的用户或角色。将 NODEFDAC 环境变量设
置成 yes 可以阻止该 UDR 上的权限被缺省授予给 PUBLIC 。如果该环境变量
设置成 yes ,则除了此 UDR 的所有者,其它任何人都不能调用此 UDR ,除
非所有者将此 UDR 的 Execute 特权授权给其他用户。
REFERENCING 和 FOR 子句
REFERENCING 子句可以声明初始值的相关名,以及 FOR 子句指定的
table_object 列中更新的值。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 311
REFERENCING 和 FOR 子句

元素
描述
限制
语法
correlation
在此声明的名称,用于在触
发器例程中限定的旧的或新
的列值(如
correlation.column)
不能是
table_object
标识符
owner
table_object 的所有者
必须拥有
table_object
所有者
名称
table_object 其触发器可以调用此过程的
表或视图的名称或同义词
必须在当前数据库
中存在
标识符
如果在 REATE PROCEDURE 语句的参数列表后面包含 REFERENCING and FOR
table_object 子句,那么您创建的例程为触发器过程(或触发器 UDR 或触发器例
程)。FOR 子句指定表或视图的触发器可以从 Triggered Action 列表的 FOR
EACH ROW 部分调用例程。
在 REFERENCING 子句中,OLD correlation 指定了一个前缀,通过该前缀,触发
器例程可以引用在触发器例程修改该列之前 table_object 的列所具有的值。NEW
correlation 指定一个前缀,用于引用触发器例程分配给列的新值。触发器例程
是否可以使用相关名称来引用 OLD 列值,NEW 列值或这两个列值取决于触发事件
的类型:

由 Insert 触发器调用的触发器例程只能引用 NEW 相关名称。

由 Delete 触发器或 Select 触发器调用的触发器例程只能引用 OLD 相
关名称。

由 Update 触发器调用的触发器例程可引用 OLD 和 NEW 相关名称。
有关在触发器操作中如何使用 correlation.column 表示法的更多信息,请参阅
REFERENCING 子句。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 312
除了以 SPL 语言编写的 GBase 8s UDR 的一般要求外,触发例程还可以支持某
些附加的语法特性,并且受某些限制的约束,这些特性不是对于普通的(或不是
限制)触发程序:

触发器例程必须包含 FOR table_object 子句,该子句指定本地数据库中
的表或视图的名称,其触发器可以调用此例程。

触发器例程还可以包含 REFERENCING 子句以声明 UDR 中的 SPL 语
句可以引用的 OLD 和 NEW 值。

触发器例程只能在触发器定义中触发器动作列表的 FOR EACH ROW 部
分调用。

OLD 或 NEW 值的相关变量可以出现在 SPL 和 CASE 表达式的 IF 语
句中。

OLD 值的相关变量不能位于 LET 表达式的左侧。

如果 FOR 子句指定了其 INSTEAD OF 触发器操作列表调用触发器例程
的视图,那么 NEW 值的相关变量不能位于 LET 表达式的左侧。

只有 NEW 值的相关变量可以位于引用相关变量的 LET 表达式的左
侧。在这种情况下,FOR 子句必须指定一个表而不是一个视图,并且其
操作调用 SPL 例程的触发器不能是 INSTEAD OF 触发器。

OLD 和 NEW 值都可以在 LET 表达式的右侧。

Boolean 运算符 SELECTING 、INSERTING 、DELETING 和
UPDATING 在 Boolean 表达式有效的上下文中的触发例程中(并且仅在
触发例程和触发动作语句中调用其它 UDR)有效。如果触发事件匹配由
操作符的名称引用的 DML 操作,则这些运算符返回 TRUE('t'),否则
返回 FALSE('f')。

如果单个触发事件在同一个表或视图上激活多个触发器,则所有
BEFORE 操作都将在任何 FOR EACH ROW 操作之前发生,并且所有
AFTER 操作在 FOR EACH ROW 操作后发生。不保证同一事件上不同
触发器的执行顺序。

触发器例程必须用 SPL 语言编写。它们不能用外部语言编写(如 C 或
Java™ 语言),但是它们可包含对外部例程的调用。例如用于触发器内
省的 mi_trigger 应用程序编程接口。

触发器例程不能引用保存点。触发操作对数据值或数据库模式的任何更改
必须完全落实或回滚。不支持部分回滚触发的操作。
有关 mi_trigger API 的更多信息,请参阅 GBase 8s DataBlade API 程序员指南和
GBase 8s DataBlade API 函数参考。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 313
如果包含 REFERENCING 子句但省略 FOR 子句,或者包含 FOR 子句但省略
REFERENCING 子句,那么 CREATE PROCEDURE 语句发生错误并失败。.
如果省略 REFERENCING and FOR 子句,则 UDR 不能使用 SELECTING 、
INSERTING 、DELETING 和 UPDATING 运算符,并且不能在触发器定义指定
的表或视图上声明可表示和操作触发动作中的列值的变量。
有关表上的 Delete 、Insert 、Select 和 Update 触发器的 REFERENCING 子句
的语法以及 Delete 、Insert 、Select 和 Update 视图上的 INSTEAD OF 触发器
的语法,请参阅 CREATE TRIGGER 语句说明中的 REFERENCING 子句 部
分。
GBase 8s 上的过程名称
由于 GBase 8s 提供例程重载,您可以使用相同的名称但不同的参数列表来定义
多个用户定义的例程(UDR)。在以下情况中您可能希望重载 UDR :

使用与内置例程相同的名称创建 UDR (如 equal( ))来处理新的用户定
义的数据类型。

您创建在其中子类型从超类型继承数据表示和 UDR 的 type
hierarchies。

您创建 distinct 类型,它是拥有与现有数据类型相同的内部存储表示的数
据类型,但是名称不同,并且没有强制转型就无法与源类型相比较。
Distinct 类型从它们的源类型继承 UDR 。
关于唯一标识每个 UDR 的例程特征符的简述,请参阅例程重载以及例程签名 。
使用 SPECIFIC 子句来指定特定名称
可以为用户定义的过程声明一个在数据库中唯一的特定名称。特定名称当您重载
过程时有用。
DOCUMENT 子句
DOCUMENT 子句中带引号的字符串提供对 UDR 的摘要和描述。该字符串存储
在 sysprocbody 系统目录表中,适用于 UDR 的用户。
拥有对数据库访问权限的任何人均可查询 sysprocbody 系统目录表,以获取对存
储在数据库中的一个或全部 UDR 描述。
例如,以下查询获取对 SPL 函数 所显示的 SPL 过程 raise_prices 的描述:

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 314
SELECT data FROM sysprocbody b, sysprocedures p
WHERE b.procid = p.procid
--join between the two catalog tables
AND p.procname = 'raise_prices'
-- look for procedure named raise_prices
AND b.datakey = 'D';-- want user document
先前的查询返回以下文本:
USAGE: EXECUTE PROCEDURE raise_prices( xxx )
xxx = percentage from 1 - 100
对于外部过程,无论您是否使用 END PROCEDURE 关键字,均可以在 CREATE
PROCEDURE 语句末尾包含 DOCUMENT 子句。
使用 WITH LISTING IN 选项
WITH LISTING IN 子句指示编译时发送警告的文件名。编译 UDR 之后,此文件
包含一条或多条警告消息。该列表文件创建于数据库驻留的计算机上。
如果您不使用 WITH LISTING IN 子句,则编译器不生成警告列表。
在 UNIX™ 上,如果您指定文件名而非目录,将在数据库驻留的计算机上的主目
录中创建此列表文件。如果您在此计算机上没有主目录,则在根目录中(名为 "/"
的目录)创建此文件。
在 Windows™ 上,如果果您指定文件名而非目录,则在数据库位于本地计算机
的情况下,在当前工作目录中创建此列表文件。否则,缺省目录
为 %GBASEDBTDIR%\bin 。
SPL 函数
SPL 函数是用存储过程语言(SPL)编写的 UDR ,且不会返回一个值。要编写
并注册 SPL 例程,请使用 CREATE PROCEDURE 语句。在 CREATE
PROCEDURE 和 END PROCEDURE 关键字之间嵌入适当的 SQL 和 SPL 语
句。还可以将 DOCUMENT 和 WITH FILE IN 选项放在该函数后面。
分析 SPL 例程,(尽可能)优化例程,并以可执行文件的形式存储在系统目录表
中。SPL 函数的主题存储在 sysprocbody 系统目录表中。关于函数的其他信息存
储在其它系统目录表中,包括 sysprocedures 、sysprocplan 和 sysprocauth 。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 315
如果 CREATE PROCEDURE 语句的 Statement Block 部分为空,则当调用函数
时,没有操作发生。当您试图建立未编码的过程,可能在开发阶段使用如“虚拟”
过程。
如果在参数列表后面指定了可选子句,则您必须在此子句之后紧邻 Statement
Block 之前加上分号。
以下示例创建了 SPL 函数:
CREATE PROCEDURE raise_prices ( per_cent INT )
UPDATE stock SET unit_price =
unit_price + (unit_price * (per_cent/100));
END PROCEDURE
DOCUMENT "USAGE: EXECUTE PROCEDURE raise_prices( xxx )",
"xxx = percentage from 1 - 100 "
WITH LISTING IN '/tmp/warn_file';
外部过程
外部过程是用数据库服务器支持的外部语言写的过程。(使用 SPL 语言编写的过
程不是外部过程。)
要创建 C 的用户定义的过程:
1. 编写不返回值的 C 函数。
2. 编译 C 函数并将编译过的代码存储在共享库中(C 的共享对象文件)。
3. 在数据库服务器中使用 CREATE PROCEDURE 语句注册 C 函数。
要创建以 Java™ 语言编写的用户定义的过程:
1. 写一个 Java 静态方法,它能使用 JDBC 函数与数据库服务器交互。
2. 编译 Java 源并创建一个 JAR 文件(共享对象文件)。
3. 用 EXECUTE PROCEDURE 语句执行 install_jar( ) 过程,在当前数据库
中安装 JAR 文件。
4. 如果 UDR 使用用户定义类型,则使用在 EXECUTE PROCEDURE 语句
中说明的 setUDTextName( ) 过程在 SQL 数据类型和 Java 类别之间创
建映射。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 316
5. 使用 CREATE PROCEDURE 语句注册 UDR 。(如果外部例程返回一个
值,则您必须使用 CREATE FUNCTION 语句而非 CREATE
PROCEDURE 来注册它。)
并非将外部例程的主体直接存储在数据库中,数据库服务器仅存储包含已编译版
本例程的共享对象文件的路径名。数据库服务器通过调用外部目标代码执行外部
例程。
您还必须持有要注册的外部过程所在数据库的 Resource 特权或 DBA 特权,和
对编写的例程所有的程序语言的 Usage 特权。(有关在 C 语言或 Java 语言上
将 Usage 特权授予用户或角色或 PUBLIC 组的语法的信息,请参阅 语言级权
限。)
当 IFX_EXTEND_ROLE 配置参数设置成 1 或 ON 时,只有拥有内置 EXTEND
角色的用户才可以创建外部过程。
注册用户定义的过程
此示例注册了一个取得类型 LVARCHAR 的一个自变量的名为 check_owner( )
的 C 用户定义的过程。外部例程参考指定了到存储目标代码的 C 共享库的路
径。此库包含一个 C 函数 unix_owner( ) ,它在 check_owner( ) 过程执行期
间被调用。
CREATE PROCEDURE check_owner ( owner lvarchar )
EXTERNAL NAME "/usr/lib/ext_lib/genlib.so(unix_owner)"
LANGUAGE C
END PROCEDURE;
此示例注册了一个以 Java™ 语言编写的名为 showusers( ) 的用户定义过程:
CREATE PROCEDURE showusers()
WITH (CLASS = "jvp") EXTERNAL NAME 'admin_jar:admin.showusers'
LANGUAGE JAVA;
EXTERNAL NAME 子句指定了 showusers( ) 过程的 Java 实现是名为
showusers( ) 的方法,它驻留在驻留于admin_jar JAR 文件的 admin Java 类
中。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 317
创建数据库对象的所有权
创建所有者特权 UDR 的用户拥有 UDR 执行时它所创建的任何数据库对象,除
非已经为该对象指定了某个其他的所有者。换句话说,UDR 所有者,而非执行拥
有所有者特权的 UDR 用户,是 UDR 创建的任何数据库对象的所有者,除非在
创建数据库对象的 DDL 语句中指定了另一个所有者。
然而在拥有 DBA 特权的 UDR 情况下,执行 UDR 的用户,而非 UDR 所有
者,拥有 UDR 创建的任何数据库对象,除非在 UDR 中为数据库对象指定某个
其他的所有者。
有关示例,请参阅已创建数据库对象的所有权的 CREATE FUNCTION 语句的描
述。

使用“存储过程管理”功能,您可以对数据库中的存储过程进行管理。
用户存储过程管理功能只能对用户数据库下的存储过程进行操作。
下面的章节将根据如下功能详细介绍存储过程管理功能:

新建存储过程

编辑存储过程

删除存储过程

复制存储过程名称

刷新存储过程

生成SQL

过滤存储过程

背景信息
在SQL 语言中,每个数据都与一个决定其行为和用法的数据类型相关。GBase 8c 提供
一个可扩展的数据类型系统,
该系统比其它SQL 实现更具通用性和灵活性。
因而,GBase 8c
中大多数类型转换是由通用规则来管理的,这种做法允许使用混合类型的表达式。
GBase 8c 扫描/分析器只将词法元素分解成五个基本种类:整数、浮点数、字符串、标
识符和关键字。大多数非数字类型首先表现为字符串。SQL 语言的定义允许将常量字符串
声明为具体的类型。例,下面查询:
gbase=#SELECT text 'Origin' AS "label", point '(0,0)' AS "value"; label | value
--------+-------
Origin | (0,0)
(1 row)
示例中有两个文本常量,
类型分别为text 和point。
如果没有为字符串文本声明类型,则
该文本首先被定义成一个unknown 类型。
在GBase 8c 分析器里,有四种基本的SQL 结构需要独立的类型转换规则:

函数调用
多数SQL 类型系统是建筑在一套丰富的函数上的。函数调用可以有一个或多个参数。
因为SQL 允许函数重载,所以不能通过函数名直接找到要调用的函数,分析器必须根据函
数提供的参数类型选择正确的函数。

操作符
SQL 允许在表达式上使用前缀或后缀(单目)操作符,也允许表达式内部使用双目操
作符(两个参数)
。像函数一样,操作符也可以被重载,因此操作符的选择也和函数一样取
决于参数类型。

值存储

GBase 8c SQL 参考手册
南大通用数据技术股份有限公司
612
INSERT 和UPDATE 语句将表达式结果存入表中。
语句中的表达式类型必须和目标字段
的类型一致或者可以转换为一致。

UNION,CASE 和相关构造
因为联合SELECT 语句中的所有查询结果必须在一列里显示出来,所以每个SELECT
子句中的元素类型必须相互匹配并转换成一个统一类型。
类似地,
一个CASE 构造的结果表
达式必须转换成统一的类型,这样整个case 表达式会有一个统一的输出类型。同样的要求
也存在于ARRAY 构造以及GREATEST 和LEAST 函数中。
系统表pg_cast 存储了有关数据类型之间的转换关系以及如何执行这些转换的信息。详
细信息请参见《GBase 8c V5_3.0.0_开发者手册》中系统表PG_CAST。
语义分析阶段会决定表达式的返回值类型并选择适当的转换行为。
数据类型的基本类型
分类,
包括:
Boolean,
numeric,
string,
bitstring,
datetime,
timespan,
geometric 和network。
每种类型都有一种或多种首选类型用于解决类型选择的问题。
根据首选类型和可用的隐含转
换,就可能保证有歧义的表达式(那些有多个候选解析方案的)得到有效的方式解决。
所有类型转换规则都是建立在下面几个基本原则上的:

隐含转换决不能有奇怪的或不可预见的输出。

如果一个查询不需要隐含的类型转换,
分析器和执行器不应该进行更多的额外操作。

就是说,任何一个类型匹配、格式清晰的查询不应该在分析器里耗费更多的时间,
也不
应该向查询中引入任何不必要的隐含类型转换调用。

另外,
如果一个查询在调用某个函数时需要进行隐式转换,
当用户定义了一个有正确参
数的函数后,解释器应该选择使用新函数。