跳到主要内容

其它语法段

本主题描述 syntax segments,它们是语言元素,例如数据库对象名称或优化程序伪指令,它们在某些 SQL 或 SPL 语句的语法图中作为子图引用显示。

大多数只能在一个语句中出现的段在 SQL 语句或语句描述中的 SPL 语句中描述。然而,为了清楚、易于使用及综合处理的原因,可出现在不同 SQL 或 SPL 语句中的以及非数据类型、非表达式的大多数段在本部分中进行了单独讨论。

前一章描述指定数据类型和表达式的语法段。本章描述不是数据类型、表达式和完整 SQL 语句或 SPL 语句的其它语法段。在出现在本手册的第二章以及其它章节中的各种语法图中引用到这些段。

参数

使用参数段向例程传递一个特定值作为输入。无论何处,只要您在语法图中看到对 argument 的引用,就请使用本段。

语法

参数

元素描述限制语法
parameter由您指定它的值的参数必须和 CREATE FUNCTION 或 CREATE PROCEDURE 语句声明的名称相匹配标识符
singleton _select返回单值的内嵌查询必须返回一个与 parameter 兼容的数据类型和长度的值SELECT 语句

用法

CREATE PROCEDURE 或 CREATE FUNCTION 语句可以为 UDR 定义一个参数列表。如果参数列表非空,则调用 UDR 时必须输入参量。参量是一个特定的值,它的数据类型兼容相应的 UDR 参数。

当执行一个 UDR 时,可以任选下面两种方法之一输入参量:

  • 和参数名一起(以 parameter name = expression) 的形式)输入,即使参量和参数的顺序不同
  • 按照位置输入,不加 parameter 名称,每个 expression 的顺序和参量对应的参数相同。(这有时称为 ordinal 格式。)

在例程的一次单个调用中不能混合使用这两种方法来指定参量。例如:如果为一个参量指定了一个参数名,那么必须对所有参量都使用参数名。

在以下示例中,用户定义的过程要求三个字符参量 tdn,两个语句都是有效的:

EXECUTE PROCEDURE add_col (t ='customer', d ='integer', n ='newint');
EXECUTE PROCEDURE add_col ('customer','newint','integer') ;

比较参量和参数列表

当用 CREATE PROCEDURE 或 CREATE FUNCTION 创建或注册一个 UDR 时,用 UDR 要求的参数名和数据类型声明一个参数列表。(对于用 C 或 Java™ 语言编写的外部例程,参数名是可选的。)有关声明参数的详细信息,请参阅例程参数列表。

如果不同的例程具有相同的标识符但是声明的参数个数不同,用户定义的例程可以是过载的。有关重载的更多信息,请参阅 例程重载以及例程签名。

如果试图以超出 UDR 要求的参量来执行 UDR ,就会接收到一条错误消息。

如果已少于 UDR 要求的参量来调用 UDR,那么就可以将省略的参量说成缺少。数据库服务器将缺少的参量初始化为它们相应的缺省值。这个初始化过程发生在 UDR 主体中第一条可执行语句之前。

如果缺少的参量没有缺省值。则 GBase 8s 发出错误。

已命名的参数不能用于调用在它们的例程特征符中重载数据类型的 UDR。只有例程的特征符具有不同数量的参数时,命名的参数用于解析非唯一的例程名称才是有效的:

func( x::integer, y ); -- VALID if only these 2 routines
func( x::integer, y, z ); -- 具有相同的 'func' 标识
func( x::integer, y ); -- NOT VALID if both routines have
func( x::float, y) ; -- 相同的标识和两个参数

对于顺序和命名的参数,如果两个或更多的 UDR 特征符具有多个数目的缺省值,则会执行参数最少的例程:

func( x, y default 1 )
func( x, y default 1, z default 2 )

如果两个同时称作 func 的已注册的 UDR 具有以上所示的特征符,那么语句 EXECUTE func(100) 调用 func(100,1)

不能使用命名的参数提供缺省值的子集,除非这些参数遵循例程特征符的位置顺序。即,不能跳过一些参量而依赖于数据库服务器提供它们的缺省值。

例如,给定以下特征符:

func( x, y default 1, z default 2 )

可执行:

func( x=1, y=3 )

但不能执行:

func( x=1, z=3 )

表达式的子集作为参量有效

参数的语法图涉及这一节的内容。

除了聚集函数以外,可以使用任何表达式作为参量。如果使用子查询或函数调用作为参量,那么子查询或函数必须返回适当数据类型和大小的单个值。有关 SQL 表达式的用途和语法,请参阅表达式。

远程数据库中的 UDR 参量

远程数据库中的 UDR 参数在大多数上下文中,UDR 在跨数据库和跨服务器分布式操作中有效,但每个参与的数据库必须具有相同的日志记录模式。

除了 BIGSERIAL 、BYTE 、SERIAL 、SERIAL8 和 TEXT,可作为跨服务器的 UDR 的参数的有效的数据类型 包括分布式查询中的数据类型中列出的不透明的内置 SQL 数据类型和这些附加内置透明和 DISTINCT 数据类型:

  • BOOLEAN
  • LVARCHAR
  • 不透明的内置类型的 DISTINCT
  • BOOLEAN DISTINCT
  • LVARCHAR DISTINCT
  • 以上列出的 DISTINCT 类型的 DISTINCT

如果 UDR 是在所有参与的数据库中定义 ,则这些数据类型可以是 SPL 、C 或 Java™ 语言的 UDR 的参数。在这些数据类型上定义的任何隐式或显式转换必须在所有参与的 GBase 8s 实例之间复制。DISTINCT 数据类型必须在参与分布式查询的所有数据库中定义完全相同的数据类型层次结构。

相同的数据类型在调用相同的 GBase 8s 实例的其它数据库中的 UDR 时也作为参数有效,以及以下其它类型的参数:

  • BLOB
  • CLOB
  • 您显式转换为内置类型的 UDT

所有的 UDR 、UDT 、DISTINCT 数据类型 、DISTINCT 类型层次结构、转型和转型函数必须在所有参与的数据库中注册。有关分布式操作中的 DISTINCT 类型的更多信息,请参阅 分布式操作中的 DISTINCT 类型。

新增SQL支持?作为占位符

在SQL语句中,可以使用问号?作为占位符,例如:

INSERT INTO t1 VALUES (?,?,?)

客户程序中可以使用GCI绑定变量传参或者在JDBC中使用PreparedStatement对象调用相关set方法传参。本次扩展支持以下几种方式:

SELECT语句投影列支持?作为占位符

SELECT ?, ? FROM t1

下面是一个包括了5个使用问号?作为占位符的MERGE语句的例子:

MERGE INTO T1
USING (SELECT ? AS a2, ? AS b2 FROM t2) T2 ON (T1.a1=T2.a2)
WHEN MATCHED THEN UPDATE SET T1.v1=?
WHEN NOT MATCHED THEN INSERT (a1, b1) VALUES(?, ?)

投影列的表达式支持?作为占位符

函数参数中可以支持,例如:

SELECT tan(?) FROM t1

运算表达式中可以支持,例如:

SELECT ?+? FROM t1

SELECT语句的分页语法参数支持?作为占位符

分页语法包括SKIP、FIRST、LIMIT、OFFSET、TOP等选项,例如:

SELECT a1, a2 FROM t1 LIMIT ? OFFSET ?
SELECT a1, a2 FROM t1 TOP ?,?

子查询支持?作为占位符

SELECT tabname FROM (SELECT tabname FROM systables WHERE tabname LIKE ?)

集合派生表

集合派生表是一个虚拟表,其中表行中的值等价于集合的各个元素。当您在语法图中看到对集合派生表的引用时,使用本段。该语法是 SQL ANSI/ISO 标准的扩展。

语法

集合派生表

元素描述限制语法
alias作用域与 SELECT 语句的集合派生表的临时名称。缺省值取决于实现。如果存在潜在的多义性,必须把 alias 放在关键字 AS 前面。请参阅 AS 关键字。标识符
collection_expr任何对单个集合的元素求值的表达式请参阅集合表达式格式的限制.表达式
collection_var, row_var已归类或未归类的集合变量名,或者包含集合派生表的 GBase 8s ESQL/C row 变量的名称必须在 GBase 8s ESQL/C 程序中或(对 collection_var)在 0SPL 策略中已声明请参阅 GBase 8s ESQL/C 程序员手册 或 DEFINE.
derived _column表中派生的列的临时名称如果基础集合不是 ROW 数据类型,那么只能指定一个派生列名标识符

用法

集合派生表可以出现在 UPDATEA 语句、SELECT 或 DELETE 语句的 FROM 子句或 INSERT 的 INTO 子句中 table 名称有效的地方。

使用集合派生表段完成这些任务:

  • 如同访问表行一样,访问集合元素。
  • 指定要访问的集合变量,而不是表名。
  • 指定要访问的 ESQL/C row 变量,而不是表名。

TABLE 关键字把一个集合转换成虚拟表。可以使用集合表达式格式来查询集合的列,或则使用 collection 变量或 row 变量格式来操纵集合列中的数据。

通过虚拟表访问集合

当使用集合派生表段的集合表达式格式来访问集合元素时,可以通过虚拟表之间选择集合元素。只能在 SELECT 语句的 FROM 子句中使用这种格式。FROM 子句可在查询或子查询中。

用这种格式可以使用连接、聚集、WHERE 子句、表达式、ORDER BY 子句以及在使用集合变量格式时不可用的其它操作。这种格式减少了对多个游标和临时表的需求。

可能的集合表达式示例包括列的引用、标量子查询、点表达式、函数、运算符(通过重载)、集合子查询、文字集合、集合构造函数和强制转型函数等。

以下示例在 FROM 子句中使用 SELECT 语句,其结果集定义由第五十一到第七十限定行组成的虚拟表,并按照 employee_id 列值排序。

SELECT * FROM TABLE(MULTISET(SELECT SKIP 50 FIRST 20 * FROM employees ORDER BY employee_id)) vt(x,y), tab2 WHERE tab2.id = vt.x;

以下示例使用连接查询创建不超过 20 行(从第 41 行开始)的虚拟表,并按照集合派生表的 salary 列的值排序:

SELECT emp_id, emp_name, emp_salary
FROM TABLE(MULTISET(SELECT SKIP 40 LIMIT 20 id, name, salary FROM e1, e2
WHERE e1.id = e2.id ORDER BY salary ))
AS etab(emp_id, emp_name, emp_salary);

FROM 子句中的 Table 表达式

GBase 8s 支持 SELECT 查询和子查询的 FROM 子句中的表表达式的 ANSI/ISO 标准语法,作为 GBase 8s 扩展集合派生表语法的替代。在版本 10.00 和更早版本的需要关键字 TABLE 和 MULTISET 。支持用于 SQL 的 ANSI/ISO 标准的这些扩展,但不再需要在 SELECT 语句的 FROM 子句中的集合派生表规范。

以下两个查询返回相同的结果集,但只要第二个查询符合 ANSI/ISO 标准:

SELECT * FROM TABLE(MULTISET(SELECT col1 FROM tab1 WHERE col1 = 100)) AS vtab(c1), (SELECT col1 FROM tab1 WHERE col1 = 10) AS vtab1(vc1) ORDER BY c1;

SELECT * FROM (SELECT col1 FROM tab1 WHERE col1 = 100) AS vtab(c1),
(SELECT col1 FROM tab1 WHERE col1 = 10) AS vtab1(vc1)
ORDER BY c1;

同一个 SELECT 语句可以合并派生表的 GBase 8s 扩展和ANSI/ISO 语法的示例:

SELECT * FROM (SELECT col1 FROM tab1 WHERE col1 = 100) AS vtab(c1),
TABLE(MULTISET(SELECT col1 FROM tab1 WHERE col1 = 10)) AS vtab1(vc1) ORDER BY c1;

子查询必须以两种格式的圆括号分隔,但紧跟在 TABLE 关键字后面并包含 MULTISET 集合子查询规范的外部圆括号(( ) )是 ANSI/ISO 语法的扩展。此 ANSI/ISO 语法仅在 SELECT 语句的 FROM 子句中有效。在任何其它上下文中,您不能从集合子查询规范中省略这些关键字和括号。

集合表达式格式的限制

当使用集合表达式格式时,有一定的限制:

  • 集合派生表是只读的。

    • 它不能成为 INSERT 、UPDATE 或 DELETE 语句的目标。

    要执行 INSERT 、UPDATE 或 DELETE 操作,必须使用集合变量格式。

    • 它不能成为可更新游标或视图的基础表。
  • 在 SELECT 语句的 FROM 子句中,SPL 的 CALL 关键字不能优先于表表达式的 TABLE 关键字。

  • 如果集合是 LIST 数据类型,那么由此得到的集合派生表不会保存 LIST 中元素的顺序。

  • 基础集合表达式求值不能等于 NULL。

  • 集合表达式不能包含对远程数据库服务器上集合的引用。

  • 集合表达式不能包含对出现在同一 FROM 子句的表的列引用。也就是说,集合派生表必须独立于 FROM 子句中的其它表。

例如,下面的语句返回了一个错误值。因为集合派生表 TABLE (parents.children),引用了表 parents,这个表也在 FROM 子句中引用:

SELECT COUNT(*) FROM parents,
TABLE(parents.children) c_table
WHERE parents.id = 1001;

要克服此限制,您可能需要写一个在 Projection 子句中包含子查询的查询:

SELECT (SELECT COUNT(*)
FROM TABLE(parents.children) c_table)
FROM parents WHERE parents.id = 1001;

适用于 ESQL/C 的附加限制

除了前面描述的限制以外,在对 GBase 8s ESQL/C 使用集合表达式格式时还有下列限制:

  • 不能将未归类的 COLLECTION 指定为主变量数据类型。
  • 不是使用 TABLE(?) 这种格式。

基本集合变量的数据类型必须是静态确定的。要克制这个限制,可以把变量显式地强制转型成数据库服务器认可的已归类 Collection 数据类型(SET 、MULTISET 或 LIST)。例如:

TABLE(CAST(? AS type))
  • 不是使用 TABLE(:hostvar) 这种格式。

要克服这个限制,必须把变量显式地强制转型成数据库服务器的已归类 Collection 数据类型(SET 、MULTISET 或 LIST),例如:

TABLE(CAST(:**_hostvar_** AS **_type_**))

产生集合派生表的 Row 类型

如果没有指定派生列名,那么数据库服务器的行为取决于基本集合元素的数据类型。

虽然集合派生表看起来包含单独的数据类型的列,但这些列实际上是 ROW 数据类型的字段。ROW 类型的数据类型和列名取决于几个元素。

如果基础集合表达式元素的数据类型是 type,那么数据库服务器通过以下规则来确定集合派生表的 ROW 类型:

  • 如果 type 是 ROW 数据类型,而且没有指定派生列的列表,那么集合派生表的 ROW 类型就是 type
  • 如果 type 是 ROW 数据类型,而且指定了派生列的列表,那么集合派生表的 ROW 类型就是未命名的 ROW 类型,其列数据类型和 type 相同,列名从派生列的列表中获取。
  • 如果 type 不是 ROW 数据类型,那么集合派生表的 ROW 类型就是未命名的 ROW 类型,它包含一个 type 列,并且名称指定在派生列的列表中。如果不能指定名称,数据库服务器会为列分配一个取决于实现的名称。

下表给出的引申示例举例说明了这些规则。该表使用以下模式为例:

CREATE ROW TYPE person (name CHAR(255), id INT);

CREATE TABLE parents
(
name CHAR(255),
id INT,
children LIST (person NOT NULL)
);

CREATE TABLE parents2
(
name CHAR(255),
id INT,
children_ids LIST (INT NOT NULL)
);
ROW 类型显式派生列列表集合派生表产生的 ROW 类型代码示例
TypeSELECT (SELECT c_table.name FROM TABLE(parents.children) c_table WHERE c_table.id = 1002) FROM parents WHERE parents.id = 1001; 在此示例中,c_table 的 ROW 类型是 parents
未命名的 ROW 类型,它的列类型是 Type ,而列名是派生列的列表中的名称SELECT (SELECT c_table.c_name FROM TABLE(parents.children) c_table(c._name, c_id) WHERE c_table.c_id = 1002) FROM parents WHERE parents.id = 1001; 在此示例中,c_table 的 ROW 类型是ROW(c_name CHAR(255), c_id INT)。
NoNo未命名的 ROW ,它包含一个已指定依实现而定的名称的 Type 列在以下示例中,如果不指定 c_id,数据库服务器会为派生列指定一个名称。在这种情况下,表 c_table 的 ROW 类型是 ROW(server_defined_nameINT)。
未命名的 ROW 类型,它包含一个 Type 列。列名在派生列的列表中SELECT(SELECT c_table.c_id FROM TABLE(parents2.child_ids) c_table (c_id) WHERE c_table.c_id = 1002) FROM parents WHERE parents.id = 1001; 这里,c_table 的 ROW 类型是 ROW(c_id INT)。

下面的程序分段用返回单个值的 SPL 函数创建了一个集合派生表:

CREATE TABLE wanted(person_id int);
CREATE FUNCTION
wanted_person_count (person_set SET(person NOT NULL))
RETURNS INT;
RETURN( SELECT COUNT (\*)
FROM TABLE (person_set) c_table, wanted
WHERE c_tabel.id = wanted.person_id);
END FUNCTION;

下面的程序段给出了用返回多个值的 SPL 函数创建一个集合派生表的更通用的示例:

-- Table of categories and child categories,

-- allowing any number of levels of subcategories

CREATE TABLE CategoryChild (
categoryId INTEGER,
childCategoryId SMALLINT
);

INSERT INTO CategoryChild VALUES (1, 2);
INSERT INTO CategoryChild VALUES (1, 3);
INSERT INTO CategoryChild VALUES (1, 4);
INSERT INTO CategoryChild VALUES (2, 5);
INSERT INTO CategoryChild VALUES (2, 6);
INSERT INTO CategoryChild VALUES (5, 7);
INSERT INTO CategoryChild VALUES (7, 8);
INSERT INTO CategoryChild VALUES (7, 9);
INSERT INTO CategoryChild VALUES (4, 10);

-- "R" == ROW type

CREATE ROW TYPE categoryLevelR (
categoryId INTEGER,
level SMALLINT );

-- DROP FUNCTION categoryDescendants (
-- INTEGER, SMALLINT );

CREATE FUNCTION categoryDescendants (
pCategoryId INTEGER,
pLevel SMALLINT DEFAULT 0 )
RETURNS MULTISET (categoryLevelR NOT NULL)

-- "p" == Prefix for Parameter names
-- "l" == Prefix for Local variable names

DEFINE lCategoryId LIKE CategoryChild.categoryId;
DEFINE lRetSet MULTISET (categoryLevelR NOT NULL);
DEFINE lCatRow categoryLevelR;

-- TRACE ON;
-- Must initialize collection before inserting rows

LET lRetSet = 'MULTISET{}' :: MULTISET (categoryLevelR NOT NULL);
FOREACH
SELECT childCategoryId INTO lCategoryId
FROM CategoryChild WHERE categoryId = pCategoryId;
INSERT INTO TABLE (lRetSet)
VALUES (ROW (lCategoryId, pLevel+1)::categoryLevelR);

-- INSERT INTO TABLE (lRetSet);
-- EXECUTE FUNCTION categoryDescendantsR ( lCategoryId,
-- pLevel+1 );
-- Need to iterate over results and insert into SET.
-- See the SQL Tutorial, pg. 10-52:
-- "Tip: You can only insert one value at a time
-- into a simple collection."

FOREACH
EXECUTE FUNCTION categoryDescendantsR ( lCategoryId, pLevel+1 )
INTO lCatRow;

INSERT INTO TABLE (lRetSet)
VALUES (lCatRow);
END FOREACH;
END FOREACH;
RETURN lRetSet;
END FUNCTION
;

-- "R" == recursive
-- DROP FUNCTION categoryDescendantsR (INTEGER, SMALLINT);

CREATE FUNCTION categoryDescendantsR (
pCategoryId INTEGER,
pLevel SMALLINT DEFAULT 0
)

RETURNS categoryLevelR;
DEFINE lCategoryId LIKE CategoryChild.categoryId;
DEFINE lCatRow categoryLevelR;

FOREACH
SELECT childCategoryId
INTO lCategoryId
FROM CategoryChild
WHERE categoryId = pCategoryId
RETURN ROW (lCategoryId, pLevel+1)::categoryLevelR WITH RESUME;

FOREACH
EXECUTE FUNCTION categoryDescendantsR ( lCategoryId, pLevel+1 )
INTO lCatRow
RETURN lCatRow WITH RESUME;
END FOREACH;
END FOREACH;
END FUNCTION;

-- Test the functions:

SELECT lev, col
FROM TABLE ((
categoryDescendants (1, 0)
)) AS CD (col, lev);

通过集合变量访问集合

当使用集合派生表段的集合变量格式时,将使用主变量或程序变量来访问和操纵集合元素。这种格式允许修改变量的内容(如同您对数据库中的表一样)。然后使用 collection 变量的内容更新实际表。

可以使用集合变量格式(关键字 TABLE 在 collection 变量的前面)代替下列 SQL 语句中(或在 SPL 的 FOREACH 语句中)的表名、同义词名或视图名:

  • SELECT 语句的 FROM 子句(用于访问 collection 变量的元素)
  • INSERT 语句的 INTO 子句(用于向 collection 变量添加新元素)
  • DELETE 语句(用于从 collection 变量除去元素)
  • UPDATE 语句(用于修改 collection 变量中的现有元素)
  • DECLARE 语句(用于声明 Select 或 Insert 游标来访问 GBase 8s ESQL/C collection 主变量的多个元素)
  • FETCH 语句(用于检索与 Select 游标相关联的 collection 主变量中的单个元素)
  • PUT 语句(用于检索与 Insert 游标相关联的 collection 主变量中的单个元素)
  • FOREACH 语句(用于声明一个游标来访问 SPL 集合变量的多个元素以及检索此 collection 主变量中的单个元素)

使用集合变量操纵集合元素

当使用 GBase 8s 的数据操纵语句(SELECT 、INSERT 、UPDATE 或 DELETE)和 collection 变量一起使用时,您可以修改集合中的一个和多个元素。

修改集合中的约束

  1. 在 SPL 例程或 GBase 8s ESQL/C 程序中创建一个 collection 变量。

    有关如何在 GBase 8s ESQL/C 中声明 collection 集合变量的信息,请参阅 GBase 8s ESQL/C 程序员手册。有关如何在 SPL 中定义 COLLECTION 变量,请参阅 DEFINE。

  2. 在 GBase 8s ESQL/C 中,为集合分配内存;请参阅 ALLOCATE COLLECTION 语句。

  3. 可选地,使用 SELECT 语句将一个 COLLECTION 列选择到 collection 变量中。

    如果变量是一个为归类的 COLLECTION 变量,那么在集合派生表段中使用该变量之前,必须从 COLLECTION 列执行 SELECT。SELECT 语句允许数据库服务器获取集合数据类型。

  4. 使用适当的带集合派生表段的数据操纵语句在集合变量中添加、删除或修改元素。

    要在集合中插入多个元素或删除一个指定的元素,必须对集合变量使用游标。

    • 有关如何在 ESQL/C 中使用更新游标的更多信息,请参阅 DECLARE 语句。
    • 关如何在 SPL 中使用更新游标的更多信息,请参阅 FOREACH。
  5. 集合变量具有正确的元素以后,对包含实际集合列的表或视图使用 INSERT 或 UPDATE 语句,来保存集合变量的更改。

    • 使用 UPDATE,在 SET 子句中指定集合变量。
    • 使用 INSERT,在 VALUES 子句中指定集合变量。

集合变量存储集合的元素。不过,它与数据库列之间没有内在连接。一旦集合变量包含了正确的元素,那么必须用 INSERT 或 UPDATE 语句把变量保存到表的实际集合列中。

从 ESQL/C 中的集合执行删除操作的示例

假设把表 table1 某一行的 set_col 列定义为 SET ,并且有一行的值为 {1,8,4,5,2}。下面的 GBase 8s ESQL/C 代码段使用更新游标以及带有 WHERE CURRENT OF 子句的 DELETE 语句来删除值为 4 的元素:

EXEC SQL BEGIN DECLARE SECTION;
client collection set(smallint not null) a_set;
int an_int;
EXEC SQL END DECLARE SECTION;
...
EXEC SQL allocate collection :a_set;
EXEC SQL select set_col into :a_set from table1 where int_col = 6;
EXEC SQL declare set_curs cursor for
select * from table(:a_set) for update;

EXEC SQL open set_curs;
while (i<coll_size)
{
EXEC SQL fetch set_curs into :an_int;
if (an_int = 4)
{
EXEC SQL delete from table(:a_set) where current of set_curs;
break;
}
i++;
}
EXEC SQL update table1 set set_col = :a_set
where int_col = 6;
EXEC SQL deallocate collection :a_set;
EXEC SQL close set_curs;
EXEC SQL free set_curs;

执行 DELETE 语句以后,集合变量包含元素 {1,8,5,2}。位于代码段末尾的 UPDATE 语句把修改后的集合保存到 set_col 列中。如果没有 UPDATE 语句,集合列中的元素 4 就没有删除。

从集合中执行删除操作的示例

假设把表 table1 某一行的 set_col 列定义为 SET ,并且有一行的值为 {1,8,4,5,2}。下面的 SPL 代码段使用 FOREACH 循环和带有 WHERE CURRENT OF 子句的 DELETE 语句来删除值为 4 的元素:

CREATE_PROCEDURE test6()

DEFINE a SMALLINT;
DEFINE b SET(SMALLINT NOT NULL);
SELECT set_col INTO b FROM table1
WHERE id = 6;
-- Select the set in one row from the table
-- into a collection variable
FOREACH cursor1 FOR
SELECT * INTO a FROM TABLE(b);
-- Select each element one at a time from
-- the collection derived table b into a
IF a = 4 THEN
DELETE FROM TABLE(b)
WHERE CURRENT OF cursor1;
-- Delete the element if it has the value 4
EXIT FOREACH;
END IF;
END FOREACH;

UPDATE table1 SET set_col = b
WHERE id = 6;
-- Update the base table with the new collection

END PROCEDURE;

此 SPL 例程声明了两个 SET 变量,ab,每一个都具有一组 SMALLINT 值。第一个 SELECT 语句把 table1 一行中的 SET 列复制到变量 b。然后例程声明了一个名为 cursor1 的游标,它一次把一个元素从 b复制到 SET 变量 a。当游标位于值为 4 的元素时,DELETE 语句就从 SET 变量 b 中删除这个元素。最后,UPDATE 语句把表 table1 的这一行用存储在变量 b 中的新集合替代。

有关如何在 SPL 例程中使用集合变量的信息,请参阅 GBase 8s SQL 教程指南。

更新集合的示例

假设把表 table1 某一行的 set_col 列定义为 SET ,并且有一行的值为 {1,8,4,5,2}。下面的 GBase 8s ESQL/C 程序把值为 4 的元素改为 10:

main
{
EXEC SQL BEGIN DECLARE SECTION;
int a;
collection b;
EXEC SQL END DECLARE SECTION;

EXEC SQL allocate collection :b;
EXEC SQL select set_col into :b from table1
where int_col = 6;

EXEC SQL declare set_curs cursor for
select * from table(:b) for update;
EXEC SQL open set_curs;
while (SQLCODE != SQLNOTFOUND)
{
EXEC SQL fetch set_curs into :a;
if (a = 4)
{
EXEC SQL update table(:b)(x)
set x = 10 where current of set_curs;
break;
}
}
EXEC SQL update table1 set set_col = :b
where int_col = 6;
EXEC SQL deallocate collection :b;
EXEC SQL close set_curs;
EXEC SQL free set_curs;
}

执行这个 GBase 8s ESQL/C 程序以后,表 table1set_col 列具有值 {1,8,10,5,2}。

这个 GBase 8s ESQL/C 程序定义了两个 collection 变量,ab,并且从 table1 中选择了一个 SET 到 b.。WHERE 子句确保只返回一行。然后程序定义一个集合游标,它从 b 中一次选择一个元素到 a。当程序找到值为 4 的元素时,第一个 UPDATE 语句把该元素的值改为 10 并退出循环。

在第一个 UPDATE 语句中,x 是一个派生列名,用来在集合派生表中更新当前元素。第二个 UPDATE 语句用新的集合更新基表 table1

有关如何在 GBase 8s ESQL/C 中使用 collection 主变量的信息,请参阅 GBase 8s ESQL/C 程序员手册 中关于复杂数据类型的讨论。

在多重集合中插入值的示例

假定 GBase 8s ESQL/C 主变量 a_multiset 有下列声明:

EXEC SQL BEGIN DECLARE SECTION;
client collection multiset(integer not null) a_multiset;
EXEC SQL END DECLARE SECTION;

下面的 INSERT 语句把一个新的 MULTISET 元素 142,323 添加到 a_multiset

EXEC SQL allocate collection :a_multiset;
EXEC SQL select multiset_col into :a_multiset from table1
where id = 107;
EXEC SQL insert into table(:a_multiset) values (142323);
EXEC SQL update table1 set multiset_col = :a_multiset
where id = 107;
EXEC SQL deallocate collection :a_multiset;

当要把元素插入到 client-collection 变量中时,不能在 INSERT 语句的 VALUES 子句中指定 SELECT 语句或 EXECUTE FUNCTION 语句。然而,当要把元素插入到 server-collection 变量中时,SELECT 和 EXECUTE FUNCTION 语句在 VALUES 子句中是有效的。有关 client- 和 server-collection 变量的更多信息,请参阅 GBase 8s ESQL/C 程序员手册。

访问嵌套集合

如果集合的元素本身就是复杂类型(collectionrow 类型),那么这个集合就是一个嵌套集合。例如,假设 GBase 8s ESQL/C collection 变量 a_set 是一个嵌套集合,定义如下:

EXEC SQL BEGIN DECLARE SECTION;
client collection set(list(integer not null)) a_set;
client collection list(integer not null) a_list;
int an_int;
EXEC SQL END DECLARE SECTION;

要访问一个嵌套集合的元素(或字段),可以使用匹配元素类型(前面代码段中的 a_listan_int)的 collectionrow 变量和 Select 游标。

访问 Row 变量

TABLE 关键字可以把 GBase 8s ESQL/C row 变量变成集合派生表。也就是说,一行在 SQL 语句中作为表出现。对于变量,把集合派生表看作只有一行的表,类型的每个字段就是行的一列。使用关键字 TABLE 在这些 SQL 语句中代替表、同义词或视图的名称:

  • SELECT 语句的 FROM 子句(用来访问 row 变量的一个字段)
  • UPDATE 语句(用来修改 row 变量中已有的字段)

DELETE 和 INSERT 语句不支持集合派生表段的 row 变量。

例如,假设 ESQL/C 主变量 a_row 有以下声明:

EXEC SQL BEGIN DECLARE SECTION;
row(x int, y int, length float, width float) a_row;
EXEC SQL END DECLARE SECTION;

下面的 ESQL/C 代码段把 a_row 变量中的字段添加到表 tab_rowrow_col 列:

EXEC SQL update table(:a_row)
set x=0, y=0, length=10, width=20;
EXEC SQL update rectangles set rect = :a_row;

数据库名

使用数据库名段来指定数据库的名称。当看到在语法图中引用数据库名时,使用本段。

语法

数据库名

元素描述限制语法
dbname数据库名称(不包括路径名和数据库服务器名)必须在数据库服务器上的数据库名中是唯一的标识符
dbservername数据库 dbname 驻留的数据库服务器必须存在。不能有空格把 @ 和 dbservername 分隔开标识符
db_var主变量,它的值指定数据库环境变量必须是固定长度的字符数据类型特定于语言

用法

数据库名称不区分大小写。数据库名不能使用定界标识符。

dbname 和 dbservername 标识符各自最多可以有 128 字节。

如果数据库服务器的名称是定界标识符或如果它包含大写字母,则数据库服务器不参阅跨服务器分布式 DML 操作。要避免此限制,请在声明数据库服务器的名称或别名时只使用未定界的不包含大写字符的名称。

在非缺省的语言环境中,dbname 可以包含该语言环境代码集中的字母字符。在支持多字节代码集的语言环境中,必须记住数据库名的最大长度是指字节数而不是字符数。有关命名数据库的 GLS 方面的更多信息,请参阅 GBase 8s GLS 用户指南。

使用关键字作为表名

您可以通过指定数据库服务器名称,选择另一个数据库服务器上的数据库作为您的当前数据库。dbservername 指定的数据库服务器必须与您的 sqlhosts 信息中列出的数据库服务器的名称相匹配。

使用 @ 符号

@ 符号是一种文字字符。如果指定一个数据库服务器名,@ 符号和数据库服务器名之间的空格是无效的。可以在 dbname 和 @ 符号之间加一个空格,或者不加空格。

以下示例显示了由数据库服务器名限定的有效数据库规范:

empinfo@personnel
empinfo @personnel

在这些示例中,empinfo 是数据库名,personnel 是数据库服务器名。

使用路径类型命名法

如果指定一个路径名,在引号、斜线和名称之间不要加空格。以下示例指定一个有效的 UNIX™ 路径名:

'//personnel/empinfo'

此处 empinfo 是 dbname ,personnel 是数据库服务器名。

使用主变量

在 GBase 8s ESQL/C 应用程序中可以使用主变量来存储一个代表数据库环境的值。

数据库对象名

使用数据库对象名段来指定数据库对象的名称,例如列、表、视图或用户定义的例程。当看到引用数据库对象名时,使用本段。

语法

Database Object Name

元素描述限制语法
databaseobject 驻留的数据库必须存在数据库名
dbservernamedatabase 的数据库服务器必须存在。在 @ 后面没有空格。标识符
object数据库对象的名称请参阅用法标识符

用法

数据库对象名可以包含限定符和分隔符以指定数据库、服务器、协同服务器(仅对于 XPS)、所有者和(对于某些对象)另一个数据库对象(当前数据库对象是其组成部分)。

GBase 8s 支持使用以冒号(:)—“数据库名:表名”的形式访问指定数据库中的指定表。

例如,以下表达式指定在数据库服务器 butlerstores_demo 数据库中由用户 gbasedbt 拥有的 stock 表的 unit-price 列。

stores_demo@butler:gbasedbt.stock.unit_price

如果创建或重命名一个数据库对象,那么声明的新名称在数据库中相同类型的对象中必须是唯一的。因而,新视图的名称必须在相同数据库内存在的表、视图和序列对象的名称和同义词中是唯一的。(但视图可以和相同服务器的不同数据库中的视图具有相同的名称,或例如和触发器具有相同名称,因为它们是不同类型的对象。)

在兼容 ANSI 的数据库中,owner.object 组合对于对象类型在数据库中必须是唯一的。数据库对象规范必须包含不属于您的数据库对象所有者名称。例如,如果指定了一个不属于您的表,那么也必须指定表的所有者。所有系统目录表的所有者都是 gbasedbt

在 GBase 8s 中,唯一性要求不适用于用户定义的例程(UDR)的名称。有关更多信息,请参阅例程重载以及例程签名。

数据库语言环境代码集中的字符用在数据库对象名中是有效的。有关更多信息,请参阅 GBase 8s GLS 用户指南。

在外部数据库中指定数据库对象

既可以在本地数据库服务器的外部数据库中,也可以在远程数据库服务器的外部数据库中指定数据库对象。

在跨数据库查询中指定数据库对象

要在本地数据库服务器的另一个数据库中指定一个对象,必须使用数据库名(如果外部数据库是符合 ANSI 的,还要加上使用者名称)来限定对象标识符,如此示例所示:

corp_db:hrdirector.executives

在此示例中,外部数据库的名称是 corp_db。表所有者的名称是 hrdirector。表的名称为 executives。这里的冒号分隔符( : )要跟在数据库限定符后面。

在 GBase 8s 中,对本地数据库服务器的其它数据库的查询及其其它数据操纵语言(DML)操纵可以访问在跨数据库事务中的数据类型 中列出的内置不透明数据类型。DML 操作也可以访问能够强制转型为内置类型的用户定义的数据类型(UDT)及基于内置类型的 DISTINCT 类型(如果每个 DISTINCT 类型和 UDT 显式地强制转型为内置类型,并且所有的 DISTINCT 类型、UDT 和强制类型转换在所有参与的数据库中都已定义)。相同的数据类型限制也适用于参量。同时适用于访问本地 GBase 8s 示例的其它数据库的“用户定义的例程”(UDR)的返回值(如果该 UDR 定义在所有参与的数据库中)。

在跨服务器查询中指定数据库对象

要在远程数据库服务器的数据库中指定一个对象,必须除数据库对象名以外,还使用指定数据库、数据库服务器和所有者(如果外部数据库是符合 ANSI 的)的 fully-qualified identifier 。例如,hr_db@remoteoffice:hrmanager.employees 是一个标准的表名称。

这里,数据库是 hr_db,数据库服务器是 remoteoffice,表所有者是 hrmanager,表名是 employees。在 database 和 database server 限定符之间需要不带空格的 at ( @ )分隔符。跨服务器查询只能访问不是不透明数据类型的内置数据类型。在跨服务器操作中不能访问 UDT,也不能访问不透明、复杂或其它扩展数据类型。(有关 GBase 8s 在跨服务器操作中支持的 DISTINCT 和内置的 OPAQUE 数据类型的列表,请参阅跨服务器事务中的数据类型。)

在 GBase 8s 中,如果 UDR 在远程数据库服务器上存在,则必须为 UDR 指定一个标准标识符。与跨服务器 DML 操作相似,远程 UDR 的参量、参数和返回值被限制只能针对内置的非不透明数据类型。(有关 GBase 8s 在跨服务器操作中支持的数据类型的列表,请参阅跨数据库事务中的数据类型。)

只能在下列语句中引用远程数据库。有关这些跨本地服务器的数据库或跨数据库服务器的语句中的支持的信息,请参阅 GBase 8s SQL 教程指南。

  • CREATE DATABASE
  • CREATE SYNONYM
  • CREATE VIEW
  • DATABASE
  • DELETE
  • EXECUTE FUNCTION
  • EXECUTE PROCEDURE
  • INFO
  • INSERT
  • LOAD
  • LOCK TABLE
  • SELECT
  • UNLOAD
  • UNLOCK TABLE
  • UPDATE

如果数据库服务器的名称是分隔标识符,或者如果它包含大写字母,则该数据库服务器不能参与分布式 DML 操作。要避免此限制,在声明数据库服务器的名称或别名时,请仅使用不包含大写字母的未限制名称。

例程重载以及例程签名

因为例程重载,用户定义的例程的名称对于数据库不必唯一。只要每一个 UDR 的 routine signature 是不同的,就可以用同一名称定义多个 UDR 。

UDR 是由它们的特征符唯一标识的。 UDR 的签名包括下列几项信息:

  • 例程类型(函数或过程)
  • 例程的标识符
  • 参数的基数、数据类型和顺序
  • 在兼容 ANSI 的数据库中的所有者名称

对于任何给定的 UDR,例程签名中至少必须有一项在所有在数据库中注册的 UDR 中是唯一的。

在不兼容 ANSI 的数据库中,除非在 sysdbopen( )sysdbclose( ) 例程的特殊情况下,否则具有不同所有者的两个例程不能拥有相同的签名。有关这些会话配置例程的所有者在定义这些例程的数据库连接或断开连接时影响的信息,请参阅 IFX_REPLACE_MODULE 函数。

指定一个已有的 UDR

当引用现有的 UDR 时,如果所使用的名称不能唯一地标识 UDR ,那么您还必须在 UDR 名称后面,以 UDR 创建时声明的相同顺序,指定参数数据类型。然后 GBase 8s 使用例程解析规则来识别 UDR 实例以进行修改、删除或执行。如果在 UDR 创建是已经为它声明了一个名称,则也可以选择指定它的 specific name。具体名称描述在专用名这个部分中。有关例程解析的更多信息,请参阅比较参量和参数列表和 GBase 8s 用户定义的例程和数据类型开发者指南 。

由 UDR 创建的对象的所有者

当在所有者特权的 UDR 的 DDL 已经创建了新数据库对象时,例程所有者(而不是执行它的用户,如果该用户不是例程的所有者)成为新数据库对象的所有者。但是,对于 DBA 特权的 UDR ,执行例程的用户(以及必须具有 DBA 特权的用户)将成为 UDR 创建的任何对象的所有者。

外部例程引用

当编写外部例程时使用外部例程引用。该项对 SPL 例程无效。

外部例程引用

图片1

用法

如果 IFX_EXTEND_ROLE 配置参数设置为 ON 或 1,则只能授予数据库服务器管理员(DBSA)及 DBSA 已经授予 EXTEND 角色的用户使用这个段的权限。缺省情况下,DBSA 是用户 gbasedbt。此外,您不能创建外部例程除非您持有数据库的 Resource 或 DBA 特权,并且还拥有编写此例程的外部程序语言的 Usage 特权。有关 GRANT USAGE ON LANGUAGE C 和 GRANT USAGE ON LANGUAGE JAVA 语句的语法,请参阅 语言级权限。

这个段指定以下关于外部例程的信息:

  • 存储在共享对象文件中的可执行目标代码的路径名

对于 C 例程,这个文件可以是 DLL 或共享库,这取决于您的操作系统。

  • 对于 Java 例程,这个文件是 jar 文件。在能够创建用 Java 语句编写的 UDR 之前,必须用 sqlj.install_jar 过程分配一个 jar 标识符给外部 jar 文件。有关更多信息,请参阅 sqlj.install_jar。
  • 用来编写 UDR 的编程语言的名称
  • UDR 的参数样式

缺省情况下,参数样式是 GBASEDBT。(这意味着如果指定 OUT 或 INOUT 参数,则 OUT 或 INOUT 值通过引用来传递。)

  • VARIANT 或 NOT VARIANT 选项。如果指定其中一个,缺省为 VARIANT。如果例程包含任何 SQL 语句,它是一个 VARIANT 例程。如果包含外部例程引用子句的 DDL 语句还包含例程修改符子句,那么请不要在其中一个子句中将相同的 UDR 分类为 VARIANT ,而在其它子句中将 VARIANT 分类为 NOT VARIANT 。

示例

下面的示例包含 Java 语言编写 UDR 引用的外部例程。您必须首先使用过程 install_jar,)注册 demo_jar

CREATE FUNCTION delete_order(int) RETURNING int
EXTERNAL NAME 'gbasedbt.demo_jar:delete_order.delete_order()'
LANGUAGE JAVA;

VARIANT 或 NOT VARIANT 选项

如果函数以相同参量调用时返回不同结果,或者如果它修改数据库或变量的状态,则函数是 variant。例如,返回当前日期和时间的函数就是一个可变函数。

缺省情况下,用户定义函数是可变的。如果在创建或修改函数时指定 NOT VARIANT,那么函数就不能包含任何 SQL 语句。

如果函数是不变的,数据库服务器可以存储返回可变函数。更多关于函数型索引的信息,请参阅 CREATE INDEX 语句。

要注册一个不变函数,在这个子句或例程修饰符讨论的例程修饰符子句中添加 NOT VARIANT 选项。然而,如果在两处都指定修饰符,必须在两个子句中都使用同一修饰符(VARIANT 或 NOT VARIANT)。

用户定义的函数的示例

下面的例子注册了一个名为 equal( ) 的外部函数,接受两个 point 数据类型值作为参量。在这个例子中,point 是不透明数据类型,指定一个二维点的 xy 坐标。

CREATE FUNCTION equal( a point, b point ) RETURNING BOOLEAN;
EXTERNAL NAME "/usr/lib/point/lib/libbtype1.so(point1_equal)"
LANGUAGE C
END FUNCTION;

函数返回一个 BOOLEAN 类型的值。外部名称指定存储函数目标代码的 C 共享对象文件的路径。外部名称指出库包含另一个函数 point1_equal( ),它在 equal( ) 执行时调用。

标识符

identifier 指定数据库对象的未限定名称,例如存取方法、聚集、别名、blobspace 、强制转型、列、约束、相关性、数据类型、索引、运算符类、优化程序伪指令、分区、过程、表、触发器、序列、同义词或视图。当看到在语法图表中引用标识符时,使用标识符段。

语法

标识符

元素描述限制语法
digit范围在 0 到 9 之间的整数不能作为第一个字符精确数值
dollar_sign美元($)符号不能作为第一个字符从键盘输入的文字符号
letter字母表中的大小或小写字母在缺省的语言环境下,必须是从 A 到 Z 或 a 到 z 范围内的 ASCII 字符。从键盘输入的文字符号
underscore下划线 ( _ ) 字符不能代替空格、连字号或其它非字母数字字符从键盘输入的文字符号

用法

这是数据库对象名的一个逻辑子集,这一段详细说明了外部对象的所有者、数据库和数据库服务器。

要在标识符中包含其它非字母数字符号,例如空格(ASCII 32),必须使用定界标识符。建议在标识符中不要使用美元符号($),因为这是一个特殊字符,在标识符中使用它可能会导致和其它语法元素的冲突。有关更多信息,请参阅定界标识符。

标识符长度至少要为 1 字节,但不超过 128 字节。例如,employee_information 作为表名称是有效的。如果使用的是多字节代码集,必须记住标识符的最大长度是指字节数而不是逻辑字符个数。

对于非缺省语言环境下的字母字符的情况,请参阅标识符中对非 ASCII 字符的支持。有关标识符 GLS 方面的更多信息,请参阅 GBase 8s GLS 用户指南的第三章。

当在 GBase 8s 中使用 ESQL/C 时,数据库服务器通过检查客户机应用程序的内部版本号和环境变量 IFX_LONGID 的设置,来确定客户端应用程序是否支持长标识符(最大长度为 128 字节)。有关更多信息,请参阅 《GBase 8s SQL 指南:参考》。

当数据库服务器使用长标识符时,您可能会遇到在 SQL 标识符或消息文本的错误消息、警告消息或其它消息。但是,如果标识符具有 18 个或更少的字节,通常可以避免截断。如果不同 SQL 对象的标识符在前 18 个字符中相同,那么您的代码可能很难读取或维护。

大写字符的使用

可以使用大写字符来指定数据库对象的名称,但是数据库服务器会把名称改为小写字符,除非设置环境变量 DELIMIDENT 并且数据库对象的标识用双引号(")括起。在这种情况下,数据库服务器把数据库对象名作为定界标识符,保持其中的大写字符的形式,如定界标识符中所述。

如果数据库服务器包含大写字符,则数据库服务器不能参与分布式 DML 操作。要避免此限制,请在您声明数据库服务器的名称或别名时,仅使用不包含大写字符的未定界的名称。

使用关键字作为标识符

虽然几乎可以使用任何词作为标识符,但是在 SQL 语句中使用关键字作为标识符可能导致语法二义性。语句可能出错或不能产生期望结果。对于使用关键字作为标识符可能导致语法二义性的讨论以及这些问题的变通方法的说,请参阅潜在的多义性和语法错误。

定界标识符提供了最简单和最安全的方法来使用关键字作为标识符而不产生语法多义性。关键字作为定界标识符不需要变通方法。关于定界标识符的语法和使用,请参阅定界标识符。然而,定界标识符要求代码总是使用单引号(')而非双引号(")来划定字符串文字的界限。

关于在 GBase 8s SQL 实现的关键字,请参阅 GBase 8s 的 SQL 关键字。

提示

如果错误消息看起来和导致错误的语句无关,那么请检查一下语句中是否使用了关键字作为未定界的标识。

标识符中对非 ASCII 字符的支持

在非缺省的语言环境下,可以在 SQL 标识符中使用该 语言环境识别字母的任何字符。这一特性允许在某些数据库对象名中使用非 ASCII 字符。有关支持非 ASCII 字符的对象,请参阅 GBase 8s GLS 用户指南。

定界标识符

缺省情况下,有效的 SQL 标识符的字符集限制为字母、数字、下划线和美元符号。但是如果设置了 DELIMIDENT 环境变量,SQL 标识符也可以包含 DB_LOCALE 环境变量设置所指示的代码集中的附加字符。

定界标识符

元素描述限制语法
digit范围在 0 到 9 之间的整数不能是第一个字符精确数值
letter组成定界标识符的字母定界标识符中的字母是区分大小写的从键盘输出的文字值
other _character非字母数字字符,如 # 、$ 或空格必须是数据库语言环境代码集中的元素从键盘输出的文字值
underscore在定界标识符中的下划线 ( _ )不能包含超过 128 个从键盘输出的文字值

如果数据库服务器支持定界标识符,在代码中必须使用双引号(")括起每个 SQL 标识符,并使用单引号(')而非双引号( ")为所有字符串文字定界。

定界标识符使您可以声明以其它方式相同与 SQL 关键字的名称,例如 TABLE 、WHERE 、DECLARE 等等。唯一不能指定定界标识的对象类型是数据库名称。

定界标识符中的字母是区分大小的。如果使用缺省的语言环境,字母必须是在 A 到 Z 或 a 到 z 范围内的大写和小写字符(在 ASCII 代码集中)。如果使用非缺省语言环境,字母必须是语言环境支持的字母字符。有关更多信息,请参阅定界标识中对非 ASCII 字符的支持(GLS)。

定界标识符服从 ANSI/ISO 标准中关于 SQL 的部分。

当创建一个数据库对象时,避免在定界标识符的第一个定界引号和第一个非空格或其它空白字符。(否则,可能无法在某些上下文中引用该对象)

如果数据库服务器的名称是定界标识符或如果它包含大写字符,则数据库服务器不能参与分布式 DML 操作。要避免此限制,请在您声明数据库服务器的名称或别名时,仅使用不包含大写字符的未定界的名称。

对非字母数字字符的支持

缺省情况下,SQL 标识符和所有语言环境的存储对象标识符中都支持 ASCII 、数字和下划线(ASCII 95)字符。要在数据库对象的名称中包含 DB_LOCALE 设置所隐含的代码集的其它字符,必须使用定界标识符。

然而,在声明或引用存储对象的名称(例如:dbspace 、partition 、blobspace 或 sbspace)时,不能使用定界标识符指定那些不是字母、数字或下划线(_ )字符的字符。

定界标识中对非 ASCII 字符的支持(GLS)

当使用的非缺省语言环境其代码集支持非 ASCII 字符时,可以在定界标识符中指定非 ASCII 字符。规则是如果可以在标识符的非定界形式中指定非 ASCII 字符,那么也可以在同一标识符的定界形式中指定非 ASCII 字符。有关支持非 ASCII 字符的标识符列表以及在定界标识符中的非 ASCII 字符的信息,请参阅 GBase 8s GLS 用户指南。

启用定界标识符

要使用定界标识符,必须设置 DELIMIDENT 环境变量。当设置了 DELIMIDENT,将双引号( " )中的字符串视为数据库对象的标识符,单引号中的字符串视为文字字符串。但是,如果未设置 DELIMIDENT 环境变量,则双引号中的字符串也将视为文字字符串。

如果设置了 DELIMIDENT ,则为了将以下示例中的 SELECT 语句视引用字符串则必须将其放在单引号中:

PREPARE ... FROM 'SELECT * FROM customer';

如果在定义视图的 SELECT 语句中使用定界标识符,那么必须设置 DELIMIDENT 环境变量才能访问视图,即使视图名称本身不包含特殊字符也是如此。

在 UNIX™ 和 Linux™ 系统中,您可以通过设置环境变量的过程来设置 DELIMIDENT ,这些过程在 《GBase 8s SQL 指南:参考》中描述。

定界标识符的示例

以下示例显示了如果创建一个名称区分大小写的表:

CREATE TABLE "Proper_Ranger" (...);

下面的示例创建了一个表,它的名称包含一个空白字符。如果表的名称没有用双引号(")括起来。并且没有设置 DELIMIDENT ,就不能在标识符中使用空格。

CREATE TABLE "My Customers" (...);

下一个例子创建了一个以关键字作名称的表:

CREATE TABLE "TABLE" (...);

下面的 GBase 8s 示例说明了当 DELETE 语句中省略了关键字 FROM 时,如何从名为 FROM 的表中删除所有行:

DELETE "FROM";

在定界标识中使用双引号

为了在定界标识符中包含双引号("),您必须在双引号(")前面加另一个双引号(" )。如以下示例语句段指定 My "Good" Data 作为表名:

CREATE TABLE "My ""Good"" Data" (...);

潜在的多义性和语法错误

GBase 不建议使用 SQL 的任何关键字作为标识符,因为这样做容易使代码更难阅读及维护。但如果您忽略这个对阅读者潜在的问题,您几乎可以使用任何关键字作为 SQL 标识符,但可能会出现各种形式的语法多义性,一个多义性的语句可能不能产生期望的结果。下面几节说明了当将关键字声明为标识符或当不同的数据库对象就相同的标识符时一些潜在的多义性和解决方法。

使用内置函数的名称作为列名

下面的两个例子列出了用 SELECT 语句把内置函数作为列名的一个变通方法。这种变通方法应用于聚集函数(AVG 、COUNT 、MAX 、MIN 、SUM)和函数表达式(代数、指数和对数、time 、HEX 、length 、DBINFO 、trigonometric 和 TRIM 函数)。

使用 avg 作为列名导致下面这个例子的失败因为数据库服务器把 avg 解释为聚集函数而不是列名:

SELECT avg FROM mytab; -- fails

如果设置了 DELIMIDENT 环境变量,就可以使用 avg 作为列名,如下面的例子所示:

SELECT "avg" from mytab; -- successful

下面的例子中的变通方法通过在列名中包含表名,去除多义性:

SELECT mytab.avg FROM mytab;

如果您使用 TODAY 、CURRENT 、SYSDATE 或 USER 关键字作为列名,就可能产生多义性,如下面的例子所示:

CREATE TABLE mytab (user char(10),
CURRENT DATETIME HOUR TO SECOND,TODAY DATE);
INSERT INTO mytab VALUES('josh','11:30:30','1/22/2008');
SELECT user,current,today FROM mytab;

数据库服务把 SELECT 语句中的 usercurrenttoday 解释成内置函数 USER 、CURRENT 和 TODAY。于是 SELECT 语句返回了当前用户名、当前时间和当前日期而不是 josh, 11:30:30,1/22/2008。SYSDATE 关键字在 GBase 8s 数据库中具有类似的效果。

如果想选择表中实际的列,必须把 SELECT 语句写成下面几句之一:

SELECT mytab.user, mytab.current, mytab.today FROM mytab;
EXEC SQL select * from mytab;

使用关键字作为列名

有特定的变通方法在 SELECT 语句或其它 SQL 语句中使用关键字作为列名。在某些情况下,有不止一个变通方法可用。

使用 ALL 、DISTINCT 或 UNIQUE 作为列名

如果想要在 SELECT 语句中使用 ALL 、DISTINCT 或 UNIQUE 这些关键字作为列名,可以采用一种变通方法。

首先,考虑一下当不采用变通方法时试图使用这些关键字之一会发生什么情况。在下面的例子中,使用 all 作为列名导致 SELECT 语句失败,因为数据库服务器将 all 解释成关键字而不是列名:

SELECT all FROM mytab -- fails;

必须使用一个变通方法来使这个 SELECT 语句执行成功。如果设置了环境变量 DELIMIDENT ,就可以通过吧 all 用双引号括起来使用 all 作为列名。在下面的例子里,SELECT 语句执行成功,因为数据库服务器把 all 解释为列名:

SELECT "all" from mytab; -- successful

下面的例子中的变通方法把关键字 ALL 和列名 all 一起使用:

SELECT ALL all FROM mytab;

下面的示例给出了几种在 CREATE TABLE 语句中使用关键字 UNIQUE 或 DISTINCT 作为列名的变通方法。

下一示例没能声明一个名为 unique 的列,因为数据库服务器将 unique 解释成关键字而不是列名:

CREATE TABLE mytab (unique INTEGER); -- fails

下面的变通方法使用了两个 SQL 语句。第一个语句创建列 mycol;第二个语句将列 mycol 重命名为 unique

CREATE TABLE mytab (mycol INTEGER);
RENAME COLUMN mytab.mycol TO unique;

下面的变通方法也使用了两个 SQL 语句。第一个语句创建列 mycol;第二个语句修改表,在其中 unique,并删除列 mycol

CREATE TABLE mytab (mycol INTEGER);
ALTER TABLE mytab
ADD (unique INTEGER),
DROP (mycol);

使用 INTERVAL 或 DATETIME 作为列名

这一节的例子给出了在 SELECT 语句中使用关键字 INTERVAL(或 DATETIME)作为列名的变通方法。

使用 interval 作为列名导致下面的例子失败,因为数据库服务器把 interval 解释为关键字并认为后面应该跟一个 INTERVAL 限定符:

SELECT interval FROM mytab; -- fails

如果设置了 DELIMIDENT 环境变量,则您可以使用 interval 作为列名,如下例所示:

SELECT "interval" from mytab; -- successful

下面例子的变通方法通过在列名中指定表名,去除了多义性:

SELECT mytab.interval FROM mytab;

下面例子的变通方法在表名中包含了所有者的名称:

SELECT josh.mytab.interval FROM josh.mytab;

使用 rowid 作为列名

每个非分片表都有一个名为 rowid 的虚拟列。为了避免多义性,不可用使用 rowid 作为列名。执行以下操作会导致出错:

  • 创建一个名为 rowid 的表或视图
  • 通过提交列名为 rowid 来修改表
  • 把一列重命名为 rowid

然而,您可以使用术语 rowid 作为表名:

CREATE TABLE rowid (column INTEGER, date DATE, char CHAR(20));
重要

建议将主键用作存取方法而不是利用 rowid 列。

使用关键字作为表名

数据库服务器在表对象的未限定的标识符也是有效的 SQL 关键字的上下文中发出错误。您可以通过使用表的所有者的授权标识符对其进行限定来消除表名称的歧义。

以下示例来说明当关键字 STATISTICS 、OUTER 或 FROM 已声明为表名或同义词时,所有者名称限定符作为解决方法。(如果任何关键字是视图的标识符,则也适用于这些示例。)

statistics 作为表标识符会导致以下 UPDATE 语句示例失败。发生异常是因为数据库服务器将统计信息解释为语法不正确的 UPDATE STATISTICS 语句中的关键字,而不是 UPDATE 语句中的目标表名:

UPDATE statistics SET mycol = 10; -- fails

以下示例中的解决方法使用所有者名称限定表名称,以避免多义性:

UPDATE josh.statistics SET mycol = 10;

使用 outer 作为别名会导致下列示例失败,因为数据库服务器将 outer 解释为执行执行语法不正确的外部连接:

SELECT mycol FROM outer; -- fails

下面这个成功的示例使用所有者命名来避免多义性:

SELECT mycol FROM josh.outer;

下面的 DELETE 语句,其目标表在创建时使用 from 作为它的标识符,返回一个语法错误:

DELETE from; -- fails

因为 FROM 也是一个可选的关键字,紧跟在要记录其记录的表的名称之前,所以数据库服务器在 FROM 之后需要一个表名。找不到,它会发生异常。

相反,下面的示例从正确识别为 from 表的行中删除行,因为该表名由其所有者的名称限定:

DELETE zelaine.from;

如果在数据库服务器上设置了 DELIMIDENT 环境变量,则代替的变通方法为使用双引号(")作为分隔符。

DELETE "from";

这通过指示 from 是 SQL 标识符,而不是字符串文字或 SQL 关键字。

尽管有这些解决方法,如果您避免声明 SQL 关键字作为表、视图或其它数据库对象的标识符,那么您的代码将更容易阅读和维护。

使用关键字 AS 的变通方法

在某些情况下,虽然语句并没有多义性而且语法也正确,但是数据库服务器却返回语法错误的信息。前页给出了几种情况下现有的语法变通方法。可以使用关键字 AS 来提供对于异常的一种变通方法。

可以在列标号或表别名前面使用 AS 关键字。

下面的例子把关键字 AS 和列标号一起使用:

SELECT column_name AS display_label FROM table_name;

下面的例程使用 AS 关键字作为表的别名:

SELECT select_list FROM table_name AS table_alias;

将 AS 和列标签一起使用

这一节的例子给出了关键字 AS 和列标签一起使用的变通方法。前面两个例子给出了如何使用关键字 UNITS (或 YEAR 、MONTH 、DAY 、HOUR 、MINUTE 、SECOND 或 FRACTION)作为列标签。

使用 units 作为列标签导致下一示例失败,因为数据库服务器将它解释成 INTERVAL 表达式的一部分,在这个表达式中 mycol 列是 UNITS 运算符的操作数:

SELECT mycol units FROM mytab;

下面例子中的变通方法包含了关键字 AS :

SELECT mycol AS units FROM mytab;

以下示例使用了关键字 AS 或 FROM 作为列标签。

使用 as 作为列标签导致下一示例失败,因为数据库服务器将 as 解释成把 from 作为列标签,于是发现不需要的 FROM 子句:

SELECT mycol as from mytab; -- fails

下面这个成功的例子重复使用了一次关键字 AS :

SELECT mycol AS as from mytab;

使用 from 作为列标签导致下一示例失败,因为数据库服务器认为第一个 from 后面应该跟一个表名:

SELECT mycol from FROM mytab; -- fails

这个例子使用关键字 AS 把第一个 from 看作列标签:

SELECT mycol AS from FROM mytab;

将 AS 和表别名一起使用

本节中的示例显示了将 AS 关键字和表别名一起使用的变通方法。开始的两个例子说明了如果使用 ORDER 、FOR 、GROUP 、HAVING 、INTO 、UNION 、WITH 、CREATE 、GRANT、KEY、ROLE 或 WHERE 关键字作为表别名。

使用 order 作为表别名导致下面的例子失败,因为数据库服务器把 order 解释为 ORDER BY 子句的一部分:

SELECT * FROM mytab order; -- 失败

下面例子的变通方法使用关键字 AS 把 order 看作表别名:

SELECT * FROM mytab AS order;

接下来两个例子说明了如何使用关键字 WITH 作为表别名。

使用 with 作为表别名导致下面的例子失败,因为数据库服务器把 with 解释为 WITH CHECK OPTION 语法的一部分:

EXEC SQL select * from mytab with; -- 失败

下面例子的变通方法使用关键字 AS 把 with 作为表别名:

EXEC SQL select * from mytab as with; -- 成功

下面的两个示例使用关键字 CREATE 作为表别名。使用 create 作为表别名导致下面的例子失败,因为数据库服务器将此关键字解释成超级新数据库对象的语法的一部分,如创建表、同义词或视图:

EXEC SQL select * from mytab create; -- 失败
EXEC SQL select * from mytab as create; -- 成功

变通方法使用关键字 AS 将 create 识别为表别名。(使用 grant 作为别名将同样失败,但在 AS 关键字之后是有效的。)

调取以关键字作为名称的游标

在某些情况下,对于关键字用作 SQL 程序标识符时产生的多义性没有现成的变通方法。

在下面的例子中,FETCH 语句指定了一个游标名为 next ,FETCH 语句产生了语法错误,因为预处理器把 next 解释为关键字,标记为活动集中的下一行,并认为 next 后面要跟一个游标名。只有当关键字 NEXT 、PREVIOUS 、PRIOR 、FIRST 、LAST 、CURRENT 、RELATIVE 或 ABSOLUTE 用作游标名时都会发生这种情况:

/* This code fragment fails */
EXEC SQL declare next cursor for
select customer_num, lname from customer;
EXEC SQL open next;
EXEC SQL fetch next into :cnum, :lname;

调取以关键字作为名称的游标

如果使用下列关键字中的任何一个作为用户定义的例程(UDR)中变量的标识符,就会产生语法歧义:

  • CURRENT
  • DATETIME
  • GLOBAL
  • INTERVAL
  • NULL
  • OFF
  • OUT
  • PROCEDURE
  • SELECT
  • SYSDATE

在 INSERT 语句中使用 CURRENT 、DATETIME 、INTERVAL 和 NULL

UDR 例程中不能插入用关键字 CURRENT 、DATETIME 、INTERVAL 或 NULL 作为名称声明的变量。例如,如果声明了一个名为 null 的变量,当试图把值 null 插入一列时,就会收到语法错误,如下面的例子所示:

CREATE PROCEDURE problem()
. . .
DEFINE null INT;
LET null = 3;
INSERT INTO tab VALUES (null); -- error, inserts NULL, not 3

在条件中使用 NULL 和 SELECT

如果声明了一个用 nullselect 命名的变量,则将它包含在使用关键字 IN 的条件中,就会产生多义性。下面的例子给出了产生问题的三种条件:在 IF 语句中,在 SELECT 语句的 WHERE 子句中,以及在 WHILE 条件中:

CREATE PROCEDURE problem()
. . .
DEFINE x,y,select, null, INT;
DEFINE pfname CHAR[15];
LET x = 3; LET select = 300;
LET null = 1;
IF x IN (select, 10, 12) THEN LET y = 1; -- problem if

IF x IN (1, 2, 4) THEN
SELECT customer_num, fname INTO y, pfname FROM customer
WHERE customer IN (select , 301 , 302, 303); -- problem in

WHILE x IN (null, 2) -- problem while
. . .
END WHILE;

如果可以确保不是列表中的第一个元素,就可以在 IN 列表中使用变量 select。下面例子中的变通方法改正了前面例子中的 IF 语句:

IF x IN (10, select, 12) THEN LET y = 1; -- problem if

对于把 null 用作变量名并试图把该变量用在 IN 条件的情况,没有可用的变通方法。

将关键字或例程名称声明为 SPL 变量

如果声明一个变量与关键字或例程的名称相同,可能会出现歧义。 GBase 8s 使用以下规则来解析 SPL 变量、UDR 名称和内置 SQL 函数名称之间的名称冲突。

  • 在 DEFINE 语句中声明的变量名采用最高优先级。
  • 在 CREATE PROCEDURE 或 CREATE FUNCTION 语句中定义的用户定义例程优先于内置 SQL 函数。
  • 在 DEFINE 语句中使用 PROCEDURE 关键字声明的过程优先于内置 SQL 函数。
  • 内置 SQL 函数优先于数据库中存在的 SQL 过程,但在 DEFINE 语句中未显式标识为过程。

如果您需要调用 SQL 函数,请不要使用内置 SQL 函数的名称作为 SPL 变量。 例如,如果您还需要调用这些聚集函数,则不要声明名称为 countmax 的变量。

与列名冲突的变量

如果对 SPL 变量和列名称使用相同的标识符,则在变量引用范围内,数据库服务器将未限定标识符的任何实例解释为变量。要使用标识符指定列名称,请使用 table.column 表示法将列名称与表名称进行限定。在以下示例中,过程变量 lname 与列名称相同。在以下 SELECT 语句中,customer.lname 是数据库中的一个列,lname 是一个 SPL 变量:

CREATE PROCEDURE table_test()
DEFINE lname CHAR(15);
LET lname = "Miller";
SELECT customer.lname FROM customer INTO lname
WHERE customer_num = 502;

此示例有效,但依赖 GBase 8s 的优先级规则来解决 SPL 变量和列名称之间的名称冲突可能会使您的代码难以解读和维护。重复使用与变量和列名称相同的标识符的替代方法是,DEFINE 语句声明标识符的一些前缀,例如本示例中的 v_lname,以指示此变量存储列 lname 的值。

在 TRACE 语句中使用 ON 、OFF 或 PROCEDURE

如果定义了一个 SPL 变量命名为 onoffprocedure,并且试图把它用在 TRACE 语句中,就不能跟踪得到变量的值。而是执行了 TRACE ON 、TRACE OFF 或 TRACE PROCEDURE 语句。可以通过把变量标记在一个更复杂的表达式中来得到变量的值。

下面的例子给出了使用算术或字符串表达式计算变量产生歧义的语法和变通方法:

DEFINE on, off, procedure INT;

TRACE on; --产生多义性
TRACE 0+ on; --正确
TRACE off; --产生多义性
TRACE ''||off; -- 正确

TRACE procedure; --产生多义性
TRACE 0+procedure; -- 正确

使用 GLOBAL 作为变量名

如果试图以 global 作为名称来定义变量,define 操作会失败。下面例子中给出的语法和定义全局变量的语法冲突:

DEFINE global INT; -- 失败;

如果设置了环境变量 DELIMIDENT ,就可以使用 global 作为变量名,如下面的例子所示:

DEFINE "global" INT; -- successful
重要

虽然前几节给出的变通方法可以在关键字用作标识符时避免编译或运行时语法冲突,但是必须记住这种标识符容易把代码变得更加难以理解和维护。

使用 EXECUTE 、SELECT 或 WITH 作为游标名

请勿使用 EXECUTE 、SELECT 或 WITH 关键字作为游标名。如果试图在 FOREACH 语句中使用这些关键字之一作为游标名,那么游标名会被解释成 FOREACH 语句中的关键字。没有可用的变通方法。

下面的例子不能生效:

DEFINE execute INT;
FOREACH execute FOR SELECT col1 -- 错误,解析器将视为 INTO var1 FROM tab1; -- 'FOREACH EXECUTE PROCEDURE'

WHILE 和 FOR 语句中的 SELECT 语句

如果在 WHILE 或 FOR 循环中使用 SELECT 语句,并且需要用括号把它括起来,那么应该把整个 SELECT 语句括在 BEGIN…END 语句块中。在下面的例子中,第一个 WHILE 语句中的 SELECT 语句被解释为调用过程 var1;对第二个 WHILE 语句的解释是正确的:

DEFINE var1, var2 INT;
WHILE var2 = var1
SELECT col1 INTO var3 FROM TAB -- error, interpreted as call var1()
UNION
SELECT co2 FROM tab2;
END WHILE;

WHILE var2 = var1
BEGIN
SELECT col1 INTO var3 FROM TAB -- ok syntax
UNION
SELECT co2 FROM tab2;
END
END WHILE;

SPL 的 ON EXCEPTION 语句中的 SET 关键字

如果在 ON EXCEPTION 语句中使用以关键字 SET 开头的语句,必须把它包括在 BEGIN ... END 语句块中。

下面的列表给出了一些以关键字 SET 开头的 SQL 语句:

  • SET AUTOFREE
  • SET CONNECTION
  • SET CONSTRAINTS
  • SET DATASKIP
  • SET DEBUG FILE
  • SET DEFERRED_PREPARE
  • SET DESCRIPTOR
  • SET ENCRYPTION
  • SET ENVIRONMENT
  • SET EXPLAIN
  • SET INDEXES
  • SET ISOLATION
  • SET LOCK MODE
  • SET LOG
  • SET OPTIMIZATION
  • SET PDQPRIORITY
  • SET ROLE
  • SET STATEMENT CACHE
  • SET TABLE
  • SET TRANSACTION
  • SET TRIGGERS

下面的例子给出了 SET LOCK MODE 语句在 ON EXCEPTION 语句中的错误和正确用法。

下面的 ON EXCEPTION 语句返回了错误,因为 SET LOCK MODE 语句没有包括在 BEGIN ... END 语句块中:

ON EXCEPTION IN (-107)
SET LOCK MODE TO WAIT; -- error, value expected, not 'lock'
END EXCEPTION;

下面的 ON EXCEPTION 语句执行成功,因为 SET LOCK MODE 语句被包括在 BEGIN ... END 语句块中:

ON EXCEPTION IN (-107)
BEGIN
SET LOCK MODE TO WAIT; -- ok
END
END EXCEPTION;

Jar 名称

使用 Jar 名称段来指定 jar ID 的名称。当看到在语法图表中引用 Jar 名称时,使用本段。

语法

Jar 名称

元素描述限制语法
database要在其中安装或访问 jar_id 的数据库标准的 database.package.jar_id 标识符不能超过 255 字节数据库名
jar_id包含要访问的 Java™ 类的 .jar 文件文件必须在 database.package 中存在标识符
package数据包的名称数据包必须在 database 中存在标识符

如果 jar 名称被指定为 sqlj.install_jarsqlj.replace_jarsqlj.remove_jar 过程的字符串参量,那么 jar 名称中所有定界标识符将包含两边的双引号字符。

在可以用任何方法访问 jar_id 之前(包括在 CREATE FUNCTION 或 CREATE PROCEDURE 语句中使用),必须在当前数据库中用 install_jar( ) 过程对它进行定义。有关更多信息,请参阅 EXECUTE PROCEDURE 语句。

优化程序伪指令

优化程序伪指令段指定可用以部分或完全指定优化程序查询计划的关键字。当看到语法图表中引用优化程序伪指令时,使用本段。

语法

优化程序伪指令

用法

使用一个或多个优化程序伪指令来部分或完全规定优化程序查询计划。伪指令的作用域只有当前查询。

伪指令缺省是启用的。要获得关于如何处理指定的伪指令的信息,可以查看 SET EXPLAIN 语句的输出。要禁用伪指令,可以把环境变量 IFX_DIRECTIVES 设置成 0,或者把 ONCONFIG 文件中的 DIRECTIVES 参数设置成 0。

上述的语法图被简化,并且不显示结束注释指示符必须遵循与开始注释指示符相同额注释样式。有关更多信息,请参阅优化程序伪指令作为注释。

优化程序伪指令作为注释

优化程序伪指令需要有效的注释指示符作为定界符。

您使用的结束的定界符取决于开始的定界符:

  • 如果 { 表示开始的定界符,那么必须使用 } 作为结束的定界符。
  • 如果 /* 是开始的定界符,那么必须使用 */ 作为结束的定界符。
  • 如果 -- 是开始的定界符,就不需要结束的定界符。

一条优化程序伪指令或一列优化程序伪指令以注释形式紧跟在关键字 DELETE 、SELECT 或 UPDATE 后面,在注释符号后面,优化程序伪指令的第一个字符总是加号(+)。在注释指示符和加号之间不允许有空格或其它空字符。

可以使用下列任何一种注释指示符:

  • 双连字号(--)定界符

双连字号不需要结束符,因为它表示只有当前行的剩余部分是注释。当使用这种符号时,只包括当前行的优化程序伪指令。

  • 括号({ . . . })定界符

从左括号( { )到右括号(})之间的部分都是注释的;可以在同一行也可以在后面的几行。

  • C 语言风格斜线和星号(/* . . . */)定界符

从开始的斜线-星号(/*)对到同一行或下面几行的下一个星号-斜线(*/)字符之间都是注释。

在 GBase 8s ESQL/C 中,esql 编译器的 -keepccomment 命令可选项在使用 C 语言样式的注释时必须指定。

有关其它信息,请参阅如何输入 SQL 注释。

如果在同一查询中指定多个伪指令,那么必须使用空格、逗号或所选择的任何字符把它们分隔开。建议用逗号分隔连续的指令。

如果查询为表声明了别名,那么在优化程序伪指令规范中使用这个别名(而不是实际的表名)。因为系统生成的索引名是以空字符开头的,所以要用引号为这种名称定界。

优化程序伪指令中的语法错误不会导致合法查询的失败。使用 SET EXPLAIN 语句可以获得这种错误的相关信息。

在分布式查询中,优化程序伪指令可以通过使用 database:table or database:owner.table 表示法来引用同一服务器实例中的其它数据库的对象,以限定本地数据库服务器的另一个数据库中的表的名称。

GBase 8s的ORACLE模式(SQLMODE=ORACLE)支持使用DATABASE.OBJECT方式引用数据库对象。数据库对象包括:表、视图、索引、序列、存储过程、存储函数、内置函数、包、内置包。

优化程序伪指令上的限制

除非包含下列语法元素的任何一项,否则可以对 DELETE 、SELECT 或 UPDATE 语句的任何查询指定优化程序伪指令:

  • 访问当前数据库以外的表的查询
  • 在 GBase 8s ESQL/C 中,带有 WHERE CURRENT OF cursor 子句的语句

对于使用符合 ANSI/ISO 语法指定连接的查询,该查询优化程序不遵守某些伪指令:

  • 将忽略 join-method 伪指令(USE_NL 、AVOID_NL 、USE_HASH 、AVOID_HASH 、/BUILD 和 /PROBE),除非优化程序重写查询以使其不再使 ANSI/ISO 语法。
  • 在指定 RIGHT OUTER JOIN 或 FULL OUTER JOIN 关键字的符合 ANSI 的连接查询中忽略连接顺序指定(ORDERED)。

存取方法伪指令

使用存取方法伪指令来指定优化程序搜索表的方式。

存取方法伪指令

表参考

元素描述限制语法
aliasFROM 子句中声明的临时备用表名如果声明了一个 alias,它必须用在优化程序伪指令中(而不是table or synonym)标识符
comments为优化程序伪指令提供文档的文本必须在括号外面但在注释符号里面字符串
index要指定查询计划伪指令的索引必须存在。对 AVOID_INDEX 、AVOID_INDEX_SJ 和 INDEX_SJ ,至少需要一个 index标识符
synonym, table要指定伪指令的查询中的同义词或表同义词以及它所指向的表必须存在标识符

用逗号或空格来分隔括号中的元素。

下面的表说明了每个存取方法伪指令并指出了它如何影响优化的查询计划。

关键字作用优化程序的操作
AVOID_FULL列出的表没有全表扫描优化程序考虑它能扫描的不同索引,如果没有索引,优化程序执行全表扫描。
AVOID_INDEX不使用任何列出的索引优化程序考虑剩余的索引和全表扫描。如果一个表的所有索引都指定了,优化程序就使用全表扫描来访问表。
AVOID_INDEX_SJ对指定的索引不使用索引自连接路径优化程序不考虑用于在索引自连接路径中扫描表的指定索引。
AVOID_MULTI_INDEX对指定的表不使用多索引扫描优化程序不考虑指定表的多索引扫描路径。
FULL实行全表扫描即使一列存在一个索引,优化程序也使用全表扫描来访问表。
INDEX使用指定的索引来访问表如果指定了多个索引,优化程序会选择产生最小成本的索引。如果没有指定索引,那么所有可用的索引都会被考虑。
INDEX_ALL 或 MULTI_INDEX使用指定索引来访问表(多索引扫描)这些关键字是同义词。有关其用法信息,请参阅下面的“多索引扫描”。
INDEX_SJ使用指定使用扫描索引自连接路径中的表优化程序被强制使用具有指定索引的索引自连接路径(或者索引自连接路径在索引列表中选择成本最低的索引)扫描表。

AVOID_FULL 和 INDEX 关键字都表示优化程序应该避免全表扫描。然而,建议使用关键字 AVOID_FULL 来表示避免全表扫描的意图。

AVOID_MULTI_INDEX 伪指令不接受索引的列表作为它的参数。这是因为 AVOID_INDEX 伪指令还会阻止在多索引扫描执行路径中使用指定的索引。

多索引扫描

可在表上定义多达十六个(16)索引。基于在同一表上使用多个索引的访问方法的搜索路径被称为多索引扫描。 MULTI_INDEX 或 INDEX_ALL 伪指令强制查询优化程序考虑多索引扫描以搜索指定的表以进行限定。MULTI_INDEX 或 INDEX_ALL 指令的参数列表具有以下语义:

  • 如果指定表作为指令的唯一参数,则优化程序会考虑该表上的所有可用的索引,并在搜索表中的限定行时使用所有这些索引(或子集)。
  • 如果指定表且仅指定单个索引,则优化程序会考虑仅使用该索引来扫描表。
  • 如果指定表和多个索引,则优化程序会考虑使用所有指定索引的搜索路径。

使用 skip-scan 存取方法的多索引扫描

多索引扫描路径通过跳过扫描访问方法使用 ROWID 的排序列表访问。排序列表通常使用 INDEX_ALL 或 MULTI_INDEX 指令指定的所有索引从多索引扫描存取方法生成。

例如,如果查询谓词指定 col1 <= 10 和 col2 BETWEEN 15 AND 25,则执行计划可以使用两个索引:col1 上的第一个索引,col2 上的第二个索引。每个索引扫描返回满足相应索引的搜索条件的所有 ROWID。ROWID 的两个列表的逻辑交叉仅包括满足两个搜索条件的行。然后,数据库服务器对组合的 ROWID 列表进行排序,并使用此排序列表来扫描表查询的结果集。

如果查询包含多于两个索引列的谓词,则每个索引扫描返回的 ROWID 列表必须合并,以生成所有限定行的排序 ROWID 列表。

因为每个 ROWID 表示一行的物理位置(在哪个页面上和哪个 slot 中),执行路径简单地访问该物理位置以检索该行。由于术语 "skip-scan" 建议,在排序列表中通常存在从一个 ROWID 到下一个 ROWID 的间隙,是的数据库服务器从结果集合的一个合格行“跳过”到下一个合格行。

排序的 ROWID 的列表可以从多个索引扫描生成,如上所述,或者从单个索引扫描生成。在单个索引的情况下,跳过扫描执行路径执行以下操作:

  1. 单索引扫描创建所有限定行的 ROWID 的未排序列表。
  2. 此未排序的列表按 ROWID 值排序。
  3. 数据库服务器按照 ROWID 的顺序检索合格行。

Skip-scan 存取方法类似于顺序扫描,但是有时可能更有效。顺序扫描检索表中的每一行,但跳过扫描只检索限定的 ROWID 的行。

查询执行的多索引扫描路径的限制

事务隔离级别影响 MULTI_INDEX 或 INDEX_ALL 伪指令是否可强制多索引扫描执行路径,当隔离级别为 Cursor Stability 时,或者使用 LAST COMMITTED 选项的 Committed Read 时无效。(但是,在 Dirty Read 和 Repeatable Read 隔离级别,和不带有 LAST COMMITTED 选项的 Committed Read 隔离级别中支持这些伪指令)。

以下附加的限制适用于多索引扫描访问路径:

  • 该索引必须是 B-tree 索引。它们可以是连接的或拆离的索引。
  • 这些伪指令忽略 R-tree 索引、函数使用和基于虚拟索引接口(VII)的索引。
  • 该表不能是远程表、伪表、系统目录表、外部表或层次结构表。
  • 多索引扫描不支持连接谓词为基于索引扫描的索引过滤器。
  • 多索引扫描忽略除主列之外的复合索引的所有列。
  • 执行级联删除或声明语句局部变量(SLV)的 DML 语句不能使用多索引扫描s。
  • 更新激活 FOR EACH ROW 触发操作的查询不能使用多索引扫描。
  • 在兼容 ANSI 的数据库中, 如果 FROM 子句只指定一个表,那么对于没有 GROUP BY 子句和没有 FOR READ ONLY 子句的 SELECT Y语句,不遵循 MULTI_INDEX 或 INDEX_ALL 伪指令。(在这种特殊情况下,查询具有与多索引扫描访问路径冲突的隐式游标行为。)

存取方法伪指令组合

通常,您只能为一个表指定一个存取方法。只有下列存取方法伪指令的组合在同一查询的同一表中有效:

  • INDEX, AVOID_INDEX_SJ
  • AVOID_FULL, AVOID_INDEX
  • AVOID_FULL, AVOID_INDEX_SJ
  • AVOID_INDEX, AVOID_INDEX_SJ
  • AVOID_FULL, AVOID_INDEX, AVOID_INDEX_SJ
  • AVOID_FULL, AVOID_MULTI_INDEX
  • AVOID_INDEX, AVOID_MULTI_INDEX
  • AVOID_INDEX_SJ, AVOID_MULTI_INDEX
  • AVOID_FULL, AVOID_INDEX_SJ, AVOID_MULTI_INDEX
  • AVOID_INDEX, AVOID_INDEX_SJ, AVOID_MULTI_INDEX

当指定 AVOID_FULL 和 AVOID_INDEX 存取方法伪指令时,优化程序避免表的全表扫描并且它避免使用指定的索引。此负指令的组合允许优化程序使用指定的存取方法伪指令之后创建的索引。

因为如果指定 INDEX 或 AVOID_FULL 伪指令,优化程序会自动考虑索引自连接路径,所以 INDEX_SJ 伪指令只是强制使用指定索引的索引自连接路径(或者在逗号分隔的列表中选择成本最低的索引的索引)。当多列索引包括仅提供低选择性的列作为索引键过滤时,INDEX_SJ 伪指令可以提高性能。

指定 INDEX_SJ 伪指令规避了索引引导键上数据分布统计信息的常见优化程序要求。此指令使优化程序考虑索引自连接路径,即使数据分布统计信息不可用于索引键列。在这种情况下,优化程序仅包括索引键列的最小数量作为满足指令的引导键。

例如,如果在列 c1c2c3c4 上定义了索引,并且查询为这四个列指定了过滤器,但没有数据分布在任何列上可用,则在此索引上指定 INDEX_SJ 会导致列 c1 被用作索引自连接路径中的引导键。如果希望优化程序使用索引但不考虑索引自连接路径,则必须指定 INDEX 或 AVOID_FULL 伪指令选择索引,并且还必须指定 AVOID_INDEX_SJ 伪指令以防止优化程序考虑任何其它索引自连接路径。

如果 AVOID_INDEX_SJ 与 INDEX 伪指令一起使用,作为显式 INDEX 或等效的 AVOID_FULL 和 AVOID_INDEX 组合,则 AVOID_INDEX_SJ 伪指令中指定的索引必须是 INDEX 伪指令中指定的索引的子集。有关 INDEX_SJ 和 AVOID_INDEX_SJ 伪指令的作用的更多信息,请参阅描述优化程序伪指令的 GBase 8s 性能指南 一章。

指定 MULTI_INDEX 或 INDEX_ALL 伪指令规避了指定表上统计信息的常见优化程序要求。在考虑表上的多索引扫描路径之前,优化程序通常至少需要对表进行低级统计。

存取方法伪指令的示例

假设您有一个名为 emp 的表,它包含列 emp_nodept_nojob_no ,并且在 dept_no 列上定义了 ids_dept_no 索引,在 job_no 列上定义了 idx_job_no 索引。当您执行在 FROM 子句中包含 emp 表的 SELECT 查询时,可能命令优化程序以以下几种方法存取该表:

  • 例如使用正指令:
SELECT {+INDEX(emp idx_dept_no)} ...

在上述示例中,此存取方法伪指令强制优化程序考虑扫描 dept_no 列上的 idx_dept_no 索引的执行路径。

在下面的示例中,存取方法伪指令强制优化程序考虑使用多索引扫描,它是基于扫描 dept_no 列上的 idx_dept_no 索引和 job_no 列上的 idx_job_no 索引的组合结果。

SELECT {+MULTI_INDEX(emp idx_dept_no ids_job_no)} ...
  • 例如使用负指令:
SELECT {+AVOID_INDEX(emp idx_loc_no, idx_job_no), AVOID_FULL(emp)} ...

该示例包含多个存取方法伪指令。这些伪指令通过指示优化程序不扫描 idx_loc_no 和 idx_job_no 索引,页不执行 emp 表的全表扫描来强制扫描 dept_no 列的 idx_dept_no 索引。但是,如果为表 emp 创建了一个新的 idx_emp_no ,则这些伪指令不会阻止优化程序考虑它。

还请注意,术语负指令引用存取方法伪指令中的字符串 "AVOID_" ,并且与开始每个优化程序指令的注释指示符之后的 + 号无关。

连接顺序伪指令

使用 ORDERED 连接顺序伪指令强制优化程序以它们在查询的 FROM 子句中出现的顺序连接表或视图。

连接顺序伪指令

元素描述限制语法
comments用于记录伪指令的文本必须出现在注释符号之间字符串

例如,下面的查询强制数据库服务器连接表 deptjob ,然后表结果和表 emp 连接起来:

SELECT --+ ORDERED
name, title, salary, dname
FROM dept, job, emp WHERE title = 'clerk' AND loc = 'Palo Alto'
AND emp.dno = dept.dno
AND emp.job= job.job;

因为在表 dept 和表 job 之间没有出现谓词,所以这个查询强制数据库服务器构造一个笛卡尔积。

当查询涉及视图时,ORDERED 连接顺序伪指令的位置决定所指定的是部分还是完全连接顺序。

  • 创建视图时指定部分连接顺序

如果在创建视图时使用 ORDERED 伪指令,基表就以视图定义的顺序相邻连接。

对于后面所有关于视图的查询,数据库服务器以视图定义中指定顺序相邻地连接基表。当使用在视图中时,ORDERED 伪指令不影响查询中的 FROM 子句命名的其它表的连接顺序。

  • 创建视图时指定完全连接顺序

当在使用视图的查询中指定 ORDERED 连接顺序伪指令时,所有表都以指定顺序连接,即使 是组成视图的那些表。如果视图包含在查询中,基表就以视图定义的顺序相邻地连接。ORDERED 用于示例的例子,可以参考 GBase 8s 性能指南

因为 OUTER 连接的顺序要求,在符合 ANSI 的连接查询中,指定 RIGHT OUTER JOIN 或 FULL OUTER JOIN 关键字,忽略 ORDERED 连接顺序伪指令,但它在解释输出文件中的 Directives Not Followed 下列出。

连接方法伪指令

使用连接方法伪指令影响表在 GBase 8s 扩展的连接查询中如何连接。

连接方法伪指令

元素描述限制语法
comments用于记录伪指令的文本必须出现在注释符号之间字符串

使用逗号或空格分隔括号内置的元素。

下表描述了每个连接方法伪指令。

关键字 作用

USE_NL 使用指定的表作为嵌套循环连接的内部表

如果在 FROM 子句中指定了 n 个表,那么 USE_NL 连接方法伪指令中最多可以指定(n-1)个表。

USE_HASH 使用哈希连接访问指定的表

也可以选择表是用来创建哈希列表或探测哈希表。

AVOID_NL 请勿在嵌套循环连接中使用指定的表作为内部表

这个伪指令列出的表仍然可以作为外部表参与嵌套循环连接。

AVOID_HASH 不要使用哈希连接访问指定的表

可以选择使用哈希连接,但是要对哈希连接中表的作用强行加以限制。

连接方法伪指令优先于 OPTCOMPIND 配置参数强制的连接方法。

当指定 USE_HASH 或 AVOID_HASH 伪指令(分别表示使用或避免使用哈希连接)时,也可以指定每个表的的作用:

  • /BUILD

和 USE_HASH 伪指令一起使用,这个关键字表示指定的表用来构造一个哈希表,和 AVOID_HASH 伪指令一起使用,这个关键字表示指定的表不用来构造哈希表。

  • /PROBE

和 USE_HASH 伪指令一起使用,这个关键字表示指定的表用来探测一个哈希表。和 AVOID_HASH 伪指令一起使用,这个关键字表示指定的表不用来探测一个哈希表。只要至少有一个表没有指定为 PROBE,就可以指定多个探测表。

为使优化程序找到有效的连接查询计划,必须至少为在连接中涉及的每个表运行 UPDATE STATISTICS LOW ,以提供适当的开销估计。否则,优化程序可能会选择将整个表广播给所有实例,即使表非常大。

如果没有指定 /BUILD 关键字也没有指定 /PROBE 关键字,那么优化程序使用成本估计来确定表的作用。

在这个例子中,USE_HASH 伪指令强制优化程序在 dept 表上构造一个哈希表,并且只考虑用哈希表来连接 dept 和其它表。因为没有指定其它伪指令,所以优化程序为查询中的其它连接选择花费最小的连接方法。

SELECT /*+ USE_HASH (dept /BUILD)
The optimizer must use dept to construct a hash table */
name, title, salary, dname
FROM emp, dept, job WHERE loc = 'Phoenix'
AND emp.dno = dept.dno AND emp.job = job.job;

您为符合 ANSI 连接查询的指定的连接方法优化程序伪指令会被忽略,但是它在解释输出文件中的 Directives Not Followed 下列出。

星型连接伪指令

使用星型连接伪指令指定优化程序应连接具有星型模式的表的方式。

星型连接伪指令

表引用

元素描述限制语法
aliasFROM 子句中声明的临时的可代替的表名如果声明了 alias ,那么它必须被使用(而不是使用 table 或 synonym)标识符
comments用于记录伪指令的可选文本必须在括号外但是注释符号内字符串
synonym, table要应用伪指令的表的名称或同义词它指向的表和同义词必须存在标识符

在指定多个表的 AVOID_FACT 伪指令中,使用逗号或空格分隔括号内的元素。

下表描述了每种星连接伪指令并说明了它是如何影响优化程序的查询计划。

关键字作用优化程序操作
AVOID_FACT必须指定至少一个表。不使用将表(或表列表中的任何表)作为星连接优化程序中的事实表优化程序不考虑将指定的表(或表列表中的任何表)视为事实表的星型连接执行计划。
AVOID_STAR_JOIN优化程序不会考虑星连接执行计划。优化程序选择一个不是星型连接计划的查询执行计划。
FACT必须指定正确的一个表。只能将指定的表视为星型连接执行计划中的事实表这些优化程序考虑查询计划,其中指定的表是星型连接执行计划中的事实表。
STAR_JOIN如果可能,优先选择星型连接计划。如果可能,优化程序优先选择星型连接计划。

星型连接伪指令要求启用并行数据库查询功能(PDQ)。当 PDQ 关闭时,禁用星型连接查询优化程序。

星型连接伪指令要求查询中的所有表具有至少低级别的统计。如果查询中的任何表的表统计信息不可用,则禁用星型连接优化程序

SQL 的 SET OPTIMIZATION ENVIRONMENT STAR_JOIN DISABLED 语句会禁用当前会话中的星型连接伪指令。(有关优化程序环境设置的其它信息,请参阅 ENVIRONMENT 选项。)

单独指定 FACT 伪指令不会自动支持星型连接执行计划。您可以通过指定 STAR_JOIN 伪指令和 FACT 伪指令的组合来指示优化程序更喜欢使用特定事实表的星型连接执行计划。

您可以在 SET EXPLAIN 语句的输出文件中查看一个查询的星型连接优化程序路径,也可以使用 GBase Data Studio 获得 Visual Explain 输出。

在集群环境中,星型查询优化程序伪指令在这些类型的辅助服务器上可用:

  • 共享磁盘辅助服务器(SDS)
  • 远程独立辅助服务器(RSS)
  • 高可用数据复制辅助服务器(HDR)。

星型伪指令的限制

下列限制适用于尝试连接具有星型模式依赖关系的表的查询:

  • 必须启用并行数据库查询(PQD)功能才能使星型连接指令有效。
  • 查询中的所有表必须至少具有低级别统计信息。
  • 星型连接伪指令不支持连接多个事实表。
  • 当事务隔离级别为 Committed Read Last Committed 或 Cursor Stability 时,星型连接伪指令无效。(支持所有其它事务隔离级别。)

优化目标伪指令

使用优化目标伪指令来指定用于确定查询结果性能的方法。

优化目标伪指令

元素描述限制语法
comments用于记录伪指令的文本必须出现在注释符号之间字符串

两种优化目标伪指令是:

  • FIRST_ROWS

告诉优化程序选择一个对只查找满足查询的第一屏内容的进程进行优化的方案。使用这个选项来减少那些使用交互模式或只需要返回几行的查询的初始响应时间。

  • ALL_ROWS

这个伪指令告诉优化程序选择一个对查找满足查询的所有含的进行进行优化的方案。

这种形式的优化是缺省的。

优化目标伪指令优先于 OPT_GOAL 环境变量设置和 OPT_GOAL 配置参数。

有关如何在整个会话中设置优化目标的信息,请参阅 SET OPTIMIZATION 语句。

下列上下文中不能使用优化目标伪指令:

  • 在视图定义中
  • 在子查询中

下列查询返回得到奖金最多的是前 50 位雇员名称。优化目标伪指令引导优化程序尽可能地返回第一屏内容。

SELECT {+FIRST_ROWS
Return the first screenful of rows as fast as possible}
LIMIT 50 fname, lname FROM employees ORDER BY bonus DESC;

说明方式伪指令

使用说明方式伪指令来测试和调试查询计划并把关于查询计划的信息打印到说明输出文件。

说明方式伪指令

元素描述限制语法
comments用于记录伪指令的文本必须出现在注释符号之间字符串

下面的表列出了每一个说明方式伪指令的作用。

关键字 作用

EXPLAIN 对指定的查询启动 SET EXPLAIN ON

AVOID_EXECUTE 放置执行数据操作语句;代替为把查询计划打印到说明输出文件

EXPLAIN 伪指令主要用于测试和调试查询计划。在 SET EXPLAIN ON 已经有效的情况下,它是多余的。在视图定义或子查询中使用是不合法的。

下面的查询执行查询计划并把它打印到说明输出文件:

SELECT {+EXPLAIN} c.customer_num, c.lname, o.order_date
FROM customer c, orders o WHERE c.customer_num = o.customer_num;

如果远程表是查询的一部分,AVOID_EXECUTE 伪指令防止在本地或远程位置执行查询。这个伪指令不会防止对查询中的不变函数求值。

下面的查询不返回数据,但把查询计划写到说明输出文件:

SELECT {+EXPLAIN, AVOID_EXECUTE}
c.customer_num, c.lname, o.order_date
FROM customer c, orders o WHERE c.customer_num = o.customer_num;

不执行查询,必须同时使用 EXPLAIN 和 AVOID_EXECUTE 伪指令来查看优化程序的查询计划(在说明输出文件中)。用来分隔这两个伪指令的逗号(, )是可选的。

如果在指定 AVOID_EXECUTE 伪指令时省略 EXPLAIN 伪指令,不会报错,但是查询计划不会写到说明输出文件,并且不执行 DML 语句。

下列上下文中不能使用说明方式伪指令:

  • 在视图定义中
  • 在触发器中
  • 在子查询中

然而,在 INSERT 语句的 SELECT 语句中,它们是合法的。

外部伪指令

可以使用 SAVE EXTERNAL DIRECTIVES 语句将优化程序伪指令存储在系统目录的 sysdirectives 表中。 GBase 8s 自动将这些外部伪指令应用到随后的查询和符合 SELECT 语句的子查询中。

可以设置 EXT_DIRECTIVES 配置参数和 IFX_EXTDIRECTIVES 环境变量,以控制是为数据库服务器实例还是为会话启用或禁用外部伪指令。将这些设置为零将禁用外部伪指令;将两者设置为 1 启用外部伪指令。

还可以使用 SET ENVIRONMENT 语句的 EXTDIRECTIVES 选项启用或禁用会话期间的外部例程。有关更多信息,请参阅为会话启用或禁用外部伪指令。

所有者名称

所有者名称指定数据库对象的所有者。当您在语法图表中引用所有者名称时使用本段。

语法

所有者名称

元素描述限制语法
owner数据库中对象所有者的用户名最大长度为 32 个字节必须遵守操作系统的规则。

用法

在兼容 ANSI 的数据库中,必须指定您不拥有的数据库对象的所有者。在对数据库对象的引用中,所有者名称的 ANSI/ISO 同义词时授权标识符。(然而,在对模式对象的引用中, GBase 8s 文档调用的所有者名称的 ANSI/ISO 术语是模式名称。)

在不兼容 ANSI 的数据库中,所有者名称是可选的。当创建数据库对象或用户数据范围语句时,您不需要指定所有者。如果在创建数据库对象时不指定所有者,那么在大多数情况下,数据库服务器将您的登录名指定为对象的所有者。 有关此规则的例外,请参阅 CREATE FUNCTION 语句描述中的已创建数据库对象的所有权和 CREATE PROCEDURE 语句描述中的创建数据库对象的所有权。当在所有者特权 UDR 中的 DDL 语句创建一个新的数据库对象时,例程的所有者(而非执行它的用户,如果此用户不是例程的所有者)成为新数据库对象的所有者。

如果您在数据访问语句中指定所有者,那么数据服务器会检查它的正确性,不加引号时,所有者是不区分大小写的。下面的四个查询都可以访问表 kaths.tab1 的数据:

SELECT * FROM tab1;
SELECT * FROM kaths.tab1;
SELECT * FROM KATHS.tab1;
SELECT * FROM Kaths.tab1;

在兼容 ANSI 的数据库中,只有表的所有者,用户 kaths,可以发出第一个示例中的查询,其指定了一个未限定的表名,但是持有 tab1 上的 Select 特权的任何用户可以在不兼容 ANSI 的数据库中发出该查询。有关在兼容 ANSI 数据库中所有者名称的更多信息,请参阅符合 ANSI 的数据库的限制和区分大小写。

CREATE ROLE 语句声明的角色是授权标识符,因而会收到所有者名称的语法限制,但是角色不能是数据库对象的所有者。同样,关键字 PUBLIC,它指定所有用户的群组,不能是数据库对象的所有者,除了在特殊的 sysdbopen( )sysdbclose( ) 过程的情况中。有关这些内置会话配置 UDR 的更多信息,请参阅会话配置过程。

使用引号

当使用引号时,所有者是区分大小写的。换句话说,引号指示数据库服务器在您创建或访问数据库对象时,确切地按照输入读取或存储名称。例如,假设有一个表,它的所有者是 Sam。可以使用下面两个语句中的任何一个来访问表中的数据:

SELECT * FROM table1;
SELECT * FROM 'Sam'.table1;

第一个查询成功,因为不需要所有者名称。第二个查询成功,因为指定的所有者名称和存储在数据库中的所有者名称匹配。

引用 gbasedbt 用户拥有的表

如果使用所有者名称作为从一个系统目录表访问数据库对象信息的选择条件,则所有者名称是区分大小写的。要保留字母大小写,必须将所有者用单引号或双引号括起来,并且必须完全按照其存储在系统目录表中的方式键入所有者名称。在以下两个示例中,只有第二个成功访问表 Kaths.table1 上的信息。

SELECT * FROM systables WHERE tabname = 'tab1' AND owner = 'kaths';
SELECT * FROM systables WHERE tabname = 'tab1' AND owner = 'Kaths';

用户 gbasedbt 是系统目录表的所有者。并且当 SQL 语句引用系统目录时,在兼容 ANSI 的数据库中必须指定 gbasedbt 作为限定符,除非您是用户 gbasedbt

SELECT * FROM "gbasedbt".systables WHERE tabname = 'tab1' AND owner = 'Kaths';

GBase 8s 接受以下任何符号,以指定符合 ANSI 的数据库的系统目录表:

  • "gbasedbt".system_table
  • gbasedbt.system_table
  • 'gbasedbt'.system_table

然而,在这三种格式中,只有第一种,其中所有者被指定为定界标识符,可以与大多数其它数据库服务器直接交互。对于不带分隔符的格式,SQL 的 ANSI/ISO 标准将小写字母升级为 GBASEDBT,同一标准不支持单引号(')作为所有者名称或模式名称的有效分隔符。

相反, GBase 8s 将 gbasedbt 的名称视为一种特殊情况,并且在指定 gbasedbt 时保留小写字母,带或不带分隔符,无论数据库是否符合 ANSI。但是,要编写可移植到非 GBase 8s 数据库服务器的 SQL 代码,应始终使用双引号(" )将数据库对象的所有者名称分隔开。

以下 SQL 示例使用未定界的所有者名称:

CREATE TABLE gbasedbt.t1(i SERIAL NOT NULL);
CREATE TABLE someone.t1(i SERIAL NOT NULL);

如果这些语句成功执行,第一个表将在 systables 中注册的 gbasedbt 作为所有者,第二个表将 SOMEONE 注册为所有者。当所有者的指定字母大小写,但所有者名称未限定时,字母大小写无关紧要,因为 GBase 8s 将未分隔的所有者名称变成大写,但将未定界的 gbasedbt (或 GBASEDBT)所有者名称变为小写的 gbasedbt。

例如,假设之前两个 CREATE TABLE 语句成功执行后,用户 gbasedbt 发出下列语句:

CREATE TABLE GBASEDBT.t1(i SERIAL NOT NULL);

该语句失败,因为所有者名称和表名称的组合不是唯一的,如果之前注册的 gbasedbt 用户拥有的表已经在数据库中存在。

提示

USER 操作符返回当前用户在系统上存储的登录名。如果所有者名称与登录名不同(例如,混合大小写所有者名称和全小写登录名),则 owner = USER 语法失败。

符合 ANSI 的数据库的限制和区分大小写

下表描述了当您创建、重命名或访问数据库对象时数据库服务器如何读取和存储所有者。

所有者名称规范兼容 ANSI 的数据库的做法
忽略严格按照登录名存储在系统中的方式读取或存储所有者,但如果用户不是所有者,则会返回错误。
不带引号指定以大写字母读取或存储所有者
包括在引号中完全按照输入读取或存储所有者 。另见使用引号和引用 gbasedbt 用户拥有的表。

如果在兼容 ANSI 的数据库中创建或重命名数据库对象时指定所有者名称,必须在数据访问语句中包含所有者名称。当访问不属于您的数据库对象时您必须包含所有者名称。

因为如果所有者不在引号之间,则数据库服务器自动将所有者转换为大写字母,区分大小写错误会导致查询失败。例如,如果您是用户 nancy 并且使用以下语句,则产生的视图具有名称 nancy.njcust

CREATE VIEW 'nancy'.njcust AS
SELECT fname, lname FROM customer WHERE state = 'NJ';

以下 SELECT 语句失败,因为它试图将 NANCY.njcust 和实际所有者和表名 nancy.njcust 相匹配:

SELECT * FROM nancy.njcust;

在 GBase 8s 分布式查询中,如果所有者名称不在引号中,则远程数据库遵循本地数据库的大小写约定。如果本地数据库是兼容 ANSI 的,则远程数据库将所有者名称处理为 uppercase。如果本地数据库是不兼容 ANSI 的,则远程数据库将所有者名称处理为 lowercase。

提示

使用所有者名称作为查询中的选择标准之一(例如,WHERE owner = 'kaths')时,必须确保带引号字符串和存储在数据库中的所有者名称完全匹配。如果数据库服务器找不到数据库对象或数据库,可能需要修改查询使引用字符串使用大写字母(例如,WHERE owner = 'KATHS')。

因为所有者名称是授权标识符,而不是 SQL 标识符,因此可以在数据库的 SQL 语句中的单引号(')之间包含所有者,其中 DELIMIDENT 环境变量指定支持分隔标识符,从而需要双引号(")围绕 SQL 标识符。

为兼容 ANSI 的数据库设置 ANSIOWNER

兼容 ANSI 的数据库的缺省行为是将在任何 owner 规范中的所有不在引号中的小写字母替换为大写字母。可以通过在数据库服务器初始化之前设置 ANSIOWNER 环境变量为 1 ,来阻止这个行为。这将保持您在不加引号指定 owner 字符串时所使用的任意大小写形式。

缺省所有者名称

如果您在不符合 ANSI 的数据库中创建数据库对象时未显式地指定所有者名称,则您的授权标识符(作为对象的缺省所有者)将存储到数据库的系统目录中,如同您已经加上引号指定您的授权标识(即,保持大小写形式)。

如果您在符合 ANSI 的数据库中创建建数据库对象时未显式地指定所有者名称,则您的授权标识符(作为对象的缺省所有者)将以大写字符存储到数据库的系统目录中,除非 ANSIOWNER 环境变量在数据库服务器初始化之前已设置为 1 。但如果 ANSIOWNER 已设置为 1 ,则数据库服务器将存储对象的缺省所有者作为您的授权标识符,保持其大小写形式。

所有者名称的大小写形式规则总结

要创建数据库对象,例如名为 mytab 的表,登录名为 Otho 的用户可以以下列几种方式声明新数据库对象的名称:

  1. CREATE TABLE mytab . . .
  2. CREATE TABLE Otho.mytab . . .
  3. CREATE TABLE "Otho".mytab . . .

未分隔的所有者名称(第二个示例中)存储在 systables 系统目录表的 owner 列的形式取决于本地数据库是否符合 ANSI 。

  • 在情况 1 中,未指定所有者名称。表的隐式所有者是 Otho,创建该表的用户,并且所有者名称以与所有者的用户标识相同的格式(Otho)存储在 systables 表中,与数据库的 ANSI 兼容状态无关。
  • 在情况 2 中,指定未定界的所有者名称。systables 表对于不符合 ANSI 的数据库的数据库,将所有所有者名称字母存储为小写(此处为 otho)。对于兼容 ANSI 的数据库(其中不将 ANSIOWNER 设置为 1), systables 表将所有所有者名称字母存储为大写(此处为 OTHO)。但是,如果 ANSIOWNER 设置为 1,则名称以与 DDL 语句中指定的相同大小写形式存储(此处为 Otho)。
  • 在情况 3 中,定界的所有者名称按照其指定的相同的形式(此处为 Otho)存储在 systables 表中,与数据库的 ANSI 兼容状态无关。

请注意用户标识符是区分大小写的,但是数据库名称不区分大小写。因此,同一个用户不能用于表 tab 和表 TAB

除了这些示例中的 CREATE TABLE 语句之外,所有 SQL 语句和 SPL 语句都遵循这些规则。例如,使用 DROP TABLE 时,在处理语句时所有者名称出现的格式取决于以下相同的条件:

  • 是否指定了显式所有者名称。
  • 如果指定了显式所有者名称,是否使用引号将所有者名称分隔开。
  • 如果没有使用引号将显式所有者名称分隔开,则数据库是否符合 ANSI 标准。
  • 如果数据库是符合 ANSI 的,则在数据库初始化之前是否将 ANSIOWNER 设置为 1。

用途选项

GBase 8s 的 CREATE ACCESS_METHOD 、CREATE XADATASOURCE TYPE 和 ALTER ACCESS_METHOD 语句可以以下列语法指定用途选项。

语法

用途选项

元素描述限制语法
external _routine执行 task 的用户定义的函数必须在数据库中注册数据库对象名
flag指出标志所启用的功能的关键字接口指定标志名Flag 用途分类在用途函数、标志和值表中。
numeric _value实数值必须在数字数据类型范围内精确数值
string _value表示成一个或多个字符的值字符必须是数据库代码集里面的引用字符串
task标识用途函数的关键字可以对它分配函数(函数名不能和关键字相同)的关键字Task 用途分类在 用途函数、标志和值的表中。
value标识配置选项的关键字可以赋值的预定义配置关键字Value 用途分类在 用途函数、标志和值的表中。

用法

GBase 8s 支持在两类上下文中的用途选项:

  • 定义或修改本地或远程表、视图和索引的主和辅存取方法
  • 定义对符合 XA 的外部数据源的访问方法。

存取方法的用途选项

已注册的存取方法是一组属性,包含名称和称为 purpose options 的选项,它们可用于完成以下任务:

  • 指定哪一个函数执行是数据访问和操作任务,如打开、读取和关闭一个数据源。
  • 设置配置选项,例如存储空间类型。
  • 设置标志、如允许 rowid 解释。

用 CREATE ACCESS_METHOD 语句创建存取方法时指定用途选项。要改变一个存取方法的用途选项,使用 ALTER ACCESS_METHOD 语句。

每一个 task 、value 或 flag 关键字对应一个 sysams 系统目录表中的列名。这些关键字允许设置下列属性:

  • 用途函数

purpose-function attribute 将用户定义的函数或方法的名称映射到 task 关键字,例如 am_createam_beginscanam_getnext。这些关键字的完整列表,请参阅用途函数、标志和值中表中的 "Task" 分类。external_routine 指定提供给存取方法的对于函数(C)。设置举例

am_create = FS_create

  • 用途标志

purpose flag 指示存取方法是否支持一个给定的 SQL 语句或关键字。设置举例:

am_rowids

  • 用途值

这些字符串、字符或数字值给出标志不能提供的配置选项。设置举例:

am_sptype = 'X'

要允许一个用户定义函数或方法作为用途函数,必须首先使用 CREATE FUNCTION 语句注册执行适当任务的 C 函数或 Java™ 方法,然后把用途关键字设置成等价于已注册的函数或方法名。这将创建一个新的存取方法。 ALTER ACCESS_METHOD 语句页上的示例向现有的存取方法添加用途方法。

要允许使用用途标志,把名称指定为没有对应的值。

要清除 sysams 表中的用途选项设置,使用 ALTER ACCESS_METHOD 语句的 DROP 子句。

用途函数、标志和值

用途函数、方法和标志定义了存取方法的属性。

下表描述了 sysams 列可能的设置,包括用途函数或方法、标志和值。输入项出现的顺序和对应的 sysams 列相同。

表 1. 用途函数、用途标志和用途值

关键字说明类别缺省值
am_sptype一个字符,指定主要和辅助存取方法可以从哪一种类型的存储空间访问数据。am_sptype 字符可以具有下列一种设置:
● 'X' 表示只能访问外部空间的方法。
● 'S ' 表示只能访问 sbspace 的方法。
● 'A' 表示能够访问外部空间和 sbspace 的方法。 只有对新的存取方法是有效的。不能用 ALTER ACCESS_METHOD 更改或添加一个 am_sptype 值。不要把 am_sptype 设置为 'D' 或试图在 dbspace 中存储一个虚拟表。
虚拟表接口(C): 'A'
am_defopclass辅助存取方法的缺省运算符类。在定义运算符类之前,存取方法必须存在,然后在 ALTER ACCESS_METHOD 语句中设置这个值。
am_keyscan如果设置了标志,它表示 am_getnext 返回辅助存取方法的索引键行。如果查询只选择索引键的列,数据库服务器不读取表而是使用辅助方法在共享存储器的索引键行。标志没有设置
am_unique如果辅助存取方法支持检查单键,设置此标志标志没有设置
am_cluster如果主或辅助存取方法支持表的集群,设置此标志标志没有设置
am_rowids如果主或辅助存取方法可以从指定地址检索行,设置此标志标志没有设置
am_readwrite如果辅助存取方法支持数据交换,设置此标志。如果没有设置缺省设置,表示虚拟表是只读的。如果应用程序要写数据,为 C 虚拟表接口设置此标志,避免产生下列问题:
● INSERT 、DELETE、UPDATE 或 ALTER FRAGMENT 语句导致 SQL 错误。
● 不执行函数 am_insertam_deleteam_update
标志没有设置
am_parallel数据库服务器设置此标志以表示哪一个用途函数或方法可以在主或辅助存取方法中并行执行。如果设置,十六进制am_parallel 位图包含一个或多个下列位设置:
● 第 1 位设置为可并行扫描。
● 第 2 位设置为可并行删除。
● 第 4 位设置为可并行修改。
● 第 8 位设置为可并行插入。 在Java™ Virtual-Table Interface 中不支持插入、删除和修改。
标志没有设置
am_expr_pushdown启用使用参数描述符的标志标志没有设置
am_costfactor数据库服务器把这个值乘以 am_scancost 用途函数或方法返回给主或辅助存取方法的成本。从 0.1 到 0.9 的 am_costfactor 值把成本减少到 am_scancost 计算得到的值的几分之一。 1.1 或更大的 am_costfactor 值增加 am_scancost1.0
am_create和用来创建虚拟表或虚拟索引的用户定义函数或方法(UDR)名相关联的关键字任务
am_drop和用来删除虚拟表或虚拟索引的 UDR 名相关联的关键字任务
am_open和用来使分片、extspace 或 sbspace 可用的 UDR 名相关联的关键字任务
am_close和反向 am_open 实行的初始化的 UDR 名相关联的关键字任务
am_insert和用来插入行或索引输入项的 UDR 名相关联的关键字任务
am_delete和用来删除行或索引输入项的 UDR 名相关联的关键字任务
am_update和用来修改行或索引输入项的 UDR 名相关联的关键字任务
am_stats和用来建立基于存储空间值分布的统计信息的 UDR 名相关联的关键字任务
am_scancost和用来计算限定及检索数据成本的 UDR 名相关联的关键字任务
am_check和用来测试表的物理结构或执行索引的完整性检查的 UDR 名相关联的关键字任务
am_beginscan和用来建立扫描的 UDR 名相关联的关键字任务
am_endscan和用来反向建立 am_beginscan 初始化的 UDR 名相关联的关键字任务
am_rescan和用来扫描前一次扫描的下一项以完成一次连接或子查询的 UDR 名相关联的关键字任务
am_getnext和扫描满足查询的下一项需要的 UDR 名相关联的关键字任务
am_getbyid和从指定物理地址取回数据的 UDR 名相关联的关键字;am_getbyid 只可用于存取方法任务
am_truncate和删除虚拟表所有行(主存取方法)或删除虚拟索引所有对应键(辅助存取方法)的 UDR 名相对应的关键字任务

下面的规则应用于 CREATE ACCESS_METHOD 和 ALTER ACCESS_METHOD 语句的用途选项规范::

  • 要在一个语句中指定多个用途选项,用逗号分隔。
  • CREATE ACCESS_METHOD 语句必须指定和 am_getnext 关键字对应的用户定义的函数或方法名。

ALTER ACCESS_METHOD 语句不能删除与 am_getnext 对应的函数或方法,但是可以修改它。

  • ALTER ACCESS_METHOD 语句不能添加、删除或修改 am_sptype 值。
  • 只能用 ALTER ACCESS_METHOD 语句指定 am_defopclass 值。

在分配缺省运算符类之前,必须首先使用 CREATE ACCESS_METHOD 语句注册一个辅助存取方法。

XA 数据源类型的用途选项

CREATE XADATASOURCE TYPE 语句指定用于访问来自符合 X/Open XA 标准的外部数据源的数据的目的函数。这些函数还使外部数据能够处理根据 GBase 8s 的事务语义进行处理。只有使用事务日志记录的数据库(如符合 ANSI 的数据库和支持显式事务的 GBase 8s 数据库)才支持事务协调。

下面的示例创建一个新的 XA 数据源类型 MQSeries®,其所有者是用户 gbasedbt

CREATE XADATASOURCE TYPE 'gbasedbt'.MQSeries(
xa_flags = 1,
xa_version = 0,
xa_open = gbasedbt.mqseries_open,
xa_close = gbasedbt.mqseries_close,
xa_start = gbasedbt.mqseries_start,
xa_end = gbasedbt.mqseries_end,
xa_rollback = gbasedbt.mqseries_rollback,
xa_prepare = gbasedbt.mqseries_prepare,
xa_commit = gbasedbt.mqseries_commit,
xa_recover = gbasedbt.mqseries_recover,
xa_forget = gbasedbt.mqseries_forget,
xa_complete = gbasedbt.mqseries_complete);

这些值表示 XA Switch Structure 中的字段,如文件 $GBASEDBTDIR/incl/public/xa.h 中所列。此示例中的规范的顺序遵循 sysxasourcetypes 系统目录表中的列名称的顺序,但是它们可以按任何顺序列出,前提是不重复任何项目。xa_flagsxa_version 值必须是数字;其余的必须是事务管理器可以调用的 UDR 的名称。这些 UDR 必须已存在于数据库中,然后才能发出 CREATE XADATASOURCE TYPE 语句,以在其用途选项规范中引用它们。

DROP FUNCTION 或 DROP ROUTINE 语句不能删除在 CREATE XADATASOURCE TYPE 语句的目的选项中列出的 UDR ,直到删除使用 UDR 定义的所有 XA 数据源类型。

有关如何使用上一示例中的 UDR 来协调与外部 XA 数据源的事务的信息,请参阅 GBase 8s DataBlade API 程序员指南。

有关 MQDataBlade 模块的信息,请参阅 GBase 8s 数据库扩展用户指南。

返回子句

返回子句指定用户定义函数返回的一个或多个值的数据类型。可以在 UDR 定义中使用本段。

语法

返回子句

元素描述限制语法
parameter在这里为 UDR 返回的参数声明的名称必须在 UDR 返回的参数中是唯一的。如果 UDR 任何一个返回值有名称,那么所有返回值都要有名称。标识符

用法

在 GBase 8s 中,对于向后兼容性,您可以使用 CREATE PROCEDURE 语句创建 SPL 函数。(即,可以在 CREATE PROCEDURE 语句中包含 Return 子句)。但使用 CREATE FUNCTION 创建返回一个或多个值的新的 SPL 例程。

在返回子句表明返回何种数据类型以后,可以在语句块的任何位置使用 SPL 的 RETURN 语句,返回和返回子句中的值对应的 SPL 变量。

对返回值的限制

SPL 函数可以在 Return 子句中指定多个数据类型。

外部函数(以 C 或 Java™ 语言编写的函数)在 Return 子句中只能指定一个数据类型。但如果外部函数是迭代函数,那么它可以返回多行数据。有关更多信息,请参阅 ITERATOR。

SQL 数据类型的子集

用户定义的函数(UDF)可以返回的内置 SQL 数据类型取决于语言。

有关更多信息,请参阅下面的列表。另见数据类型*。*

用给定的语言编写的 UDF 可以返回除下表中标记为 X 的类型的任何数据类型的值。

数据类型CJava™SPL
BIGSERIALXXX
BLOBX
CLOBX
BYTEXX
TEXTXX
COLLECTIONX
LISTX
MULTISETX
ROWX
SETX
SERIALXXX
SERIAL8XXX

在 GBase 8s ,中如果在 Return 子句中使用复杂数据类型,那么发出调用的用户定义例程必须定义相应的复杂类型的变量,以容纳 C 或 SPL 用户定义函数返回的值。

用户定义的函数可以返回数据库中定义的 opaque 或 distinct 数据类型的值。

SPL 函数返回的 DECIMAL 值的缺省精度是 16 位数字。要让函数以不同的有意义的数字位数返回 DECIMAL ,您必须在 Return 子句中显式地指定返回精度。

使用 REFERENCES 子句指向一个简单大对象

用户定义函数不能返回一个 BYTE 或 TEXT 值(总称为简单大对象)。然而,用户定义函数可以使用 REFERENCES 关键字,返回一个包含 BYTE 或 TEXT 对象指针的描述符。下面的例子说明了如何在 SPL 例程中选择 TEXT 列然后返回一个值:

CREATE FUNCTION sel_text()
RETURNING REFERENCES text;
DEFINE blob_var REFERENCES text;
SELECT blob_col INTO blob_var
FROM blob_table WHERE key_col = 10;
RETURN blob_var;
END FUNCTION;

对于作为查询的 Projection 列表中的列值的简单大对象,如在此示例中,返回的描述符中的指针根据 BYTE 或 TEXT 列定义从系统目录引用 sysblobs.spacename 值。

然而,对于不对应于永久表的列的简单大对象,指针引用定义了 UDR 的数据库的 dbspace 。这是当数据库服务器不指定 sysblobs 表的位置时,UDR 返回的 BYTE 或 TEXT 对象的缺省存储位置。

以下示例中的 DB-Access 会话创建两个例程 udr1 和 udr2,每个返回一个 TEXT 对象:

CREATE DATABASE db WITH LOG;

CREATE TABLE t (c2 TEXT);
CREATE TABLE t1 (c2 TEXT);
LOAD FROM "t.unl" INSERT INTO t;

CREATE FUNCTION udr1 ( param_1
REFERENCES TEXT DEFAULT NULL )
RETURNING REFERENCES TEXT
WITH (NOT VARIANT)
DEFINE var1 REFERENCES TEXT;
ON EXCEPTION
RETURN param_1;
END EXCEPTION;
SELECT t.c2 udr1_col1
INTO var1 FROM t;
RETURN var1;
END FUNCTION;

CREATE PROCEDURE udr2 ( OUT param_1
REFERENCES TEXT DEFAULT NULL )
RETURNING INT;
SELECT t.c2 udr1_col1
INTO param_1 FROM t;
RETURN 1;
END PROCEDURE;

SELECT udr1(t.c2) query_1_col1 FROM t
INTO TEMP mytemp;

SELECT c2, slv1 FROM t1
WHERE udr2(slv1#TEXT) > 0
INTO TEMP mytemp;

在调用这些 UDR 的 SELECT 语句中,每个查询返回到 mytemp 临时表的 TEXT 对象存储在 db 数据库的 dbspace 中。

从另一个数据库返回值

对于存取本地数据库值为的表和视图的 UDR,只有下列数据类型可作为返回值:

元素描述限制语法
built-in _ non-opaque非 Opaque 的内置数据类型的名称不能是 BIGSERIAL、 BYTE 、SERIAL 、SERIAL8 或 TEXT数据类型
max最大大小(字节)。缺省值为 2048。必须是整数,1 ≤ max ≤ 32,739精确数值
opaque_UDT用户定义的 Opaque 数据类型的名称必须显式强制转型为内置类型,通过在每个参与的数据中定义强制转型标识符

如果 Return 子句从本地 GBase 8s 示例的另一个数据库返回一个值(或多个值,在 SPL 函数的情况中),返回的数据类型支持为下列数据类型:

  • 不 Opaque 的内置数据类型
  • 大多数内置 opaque 数据类型,在跨数据库事务中的数据类型 中列出
  • 基于在此列表中标识的内置类型的 DISTINCT 类型
  • 基于此列表中任一 DISTINCT 类型的 DISTINCT 类型
  • 显式转换为此列表中的任一数据类型的用户定义类型(UDT)

UDF 和所有的 DISTINCT 类型、透明 UDT 、不数据类型层次结构和强制转型在每个数据库中必须具有相同的定义。相同的数据类型限制适用于外部函数从本地 GBase 8s 实例的另一个数据库返回的值。有关跨同一个数据库服务器实例的两个或多个数据库的分布操作中支持的数据类型的详细信息,请参阅跨数据库事务中的数据类型。有关在分布式事务中对 DISTINCT 数据类型有效的数据类型层次结构,请参阅分布式操作中的 DISTINCT 类型。

但是,从其他 GBase 8s 实例的数据库,UDF 只能指定以下作为参数或返回的数据类型:

  • 内置不透明的数据类型
  • BOOLEAN
  • LVARCHAR
  • DISTINCT 的透明的内置类型
  • DISTINCT BOOLEAN
  • DISTINCT LVARCHAR
  • DISTINCT 在此列表中的 DISTINCT 类型

UDF 的定义和任何数据类型层次结构、强制转型和 DISTINCT 类型必须在每个参与的数据库中一致。除了在上一列表中标识的 BOOLEAN 、DISTINCT 和 LVARCHAR 数据类型之外,UDF 不能在跨服务器函数调用中返回其他内置不透明数据类型或不透明 UDT。

有关跨两个或多个 GBase 8s 实例的分布式操作中支持的数据类型的详细信息,请参阅跨服务器事务中的数据类型。有关在分布式事务中对 DISTINCT 数据类型有效的数据类型层次结构,请参阅 分布式操作中的 DISTINCT 类型。

命名返回参数

可以为 SPL 例程返回的参数或外部函数返回的单个值声明名称。

如果 SPL 例程返回多个值,您必须为所有返回参数声明名称,否则就一个都不声明。名称必须唯一。这里是一个已命名参数的实例:

CREATE PROCEDURE p (inval INT DEFAULT 0)
RETURNING INT AS serial_num,
CHAR(10) AS name,
INT AS points;
RETURN (inval + 1002), "Newton", 100;
END PROCEDURE;

执行此 UDR 将会返回:

serial_num name points

1002 Newton 100

返回参数名和例程实体中的任何变量名之间没有关系。例如,可以定义一个函数返回 INTEGER as xval,但是在同一函数中,叫做 xval 的变量可以是 INTERVAL YEAR TO MONTH 数据类型。

游标函数和非游标函数

游标函数允许从返回值生成的结果集中反复依次取得各返回值。这样的函数是隐式迭代函数。

只返回一组值(如表的一行中的一列或几列)的函数是非游标函数。

返回子句可以出现在游标函数或非游标函数中。在下面的例子中,返回子句如果出现在非游标函数中,可以返回零个(0)或一个值。但如果这个子句和游标函数相关联,则它会返回表的多行,返回的每一行包含零个或一个值:

RETURNING INT;

在以下示例中,Return 子句如果出现在非游标函数中,可以返回零个(0)或两个值。然而,如果这个子句和游标函数相关联,则它会返回表的多行,返回的每一行包含零个或两个值:

RETURNING INT, INT;

在前面的两个示例中,接收函数或程序都必须适当编写以接受函数返回的信息。

例程修饰符

例程修饰符指定用户定义的例程(UDR)如何工作的特征。

语法

删除例程修饰符

元素描述限制语法
parameter在这里为 UDR 返回的参数声明的名称必须在 UDR 返回的参数中是唯一的。如果 UDR 任何一个返回值有名称,那么所有返回值都有名称。标识符

用法

如果在 ALTER FUNCTION 、ALTER PROCEDURE 或 ALTER ROUTINE 语句中删除修饰符,那么如果存在缺省值,数据库服务器就会将修饰符的值设置为缺省值。

有些修饰符只可用于用户定义函数。关于指定的例程修饰符是否只能用于用户定义函数(即,是否不能用于用户定义的过程),请参阅后面一节对修饰符的说明。在这些部分(如同本手册的其它地方)中,外部指的是以 C 或 Java™ 语言编写的 UDR 。只对于一种语言有效的功能在前面的图表中作这样的指定。

除了 VARIANT 和 NOT VARIANT 修饰符,在此段中的其它选项对于 SPL 例程都无效。

示例

以下语句包含了 Java 语言的外部例程引用。您必须首先使用过程 install_jar,)注册 demo_jar。

CREATE FUNCTION delete_order(int) RETURNING int
WITH (NOT VARIANT)
EXTERNAL NAME 'gbasedbt.demo_jar:delete_order.delete_order()'
LANGUAGE JAVA;

添加或修改例程修饰符

在 ALTER FUNCTION 、ALTER PROCEDURE 或 ALTER ROUTINE 语句中使用此段添加或修改 UDR 的例程修饰符的值。

添加或修改例程修饰符

元素描述限制语法
class_name运行外部例程的虚拟处理器(VP)任何 C UDR 都必须在 CPU VP 或用户定义的 VP 类中运行引用字符串.
cost每次调用 C 语言的 UDR 的 CPU 使用成本。缺省值为 0 。整数: 1 ≤ cost ≤ 231-1 (最高成本)。精确数值
cost_func要调用的伴随用户定义成本函数名必须具有和 UDR 相同的所有者。需要拥有 Execute 特权。标识符
neg_func可以代替 UDR 调用的否定函数必须具有和 UDR 相同的所有者。需要拥有 Execute 特权。标识符
sel_func要调用的伴随用户定义选择性函数名必须具有和 UDR 相同的所有者。需要拥有 Execute 特权。标识符
selectivity每次调用 C 语言的 UDR 的 CPU 的使用成本。缺省值为 0。请参阅 选择性的概念.精确数值
stack_size执行 C 语言的 UDR 的 线程堆栈大小(以字节计算)必须是正整数精确数值

可以用任意顺序添加这些修饰符。如果同一修饰符列出多次,那么最后的设置会覆盖前面所有的值。

修饰符说明

下面几节说明了可以用来帮助数据库服务器最好地执行 UDR 的修饰符。

CLASS

使用 CLASS 修饰符指定运行外部例程的虚拟处理器(VP)类的名称。用户定义的 VP 类必须在调用 UDR 之前定义。

可以使用下列几种 VP 类执行 C UDR:

  • CPU 虚拟处理器类(CPU VP)
  • 用户定义的虚拟处理器类。

如果省略 CLASS 修饰符来为用 C 语言编写的 UDR 指定 VP 类,那么 UDR 就在 CPU VP 中运行。用户定义的 VP 类可以保护数据库服务器不受恶意工作的 C UDR 影响。行为不良的 C UDR 至少具有下列特征中的一个:

  • 长时间运行在 CPU VP 中不肯退出。
  • 不是安全线程。
  • 调用不安全的操作系统例程。

正常工作的 C UDR 不具有这些特征中的任何一项。在 CPU VP 中只执行正常工作的 C UDR。

警告

在 CPU VP 中执行表现不佳的 C UDR 会导致对数据库服务器运行的严重干扰,并且 UDR 可能不会产生正确的结果。有关表现不佳的 UDR 的讨论,请参阅 GBase 8s DataBlade API 程序员指南。

缺省情况下,用 Java™ 编写的 UDR 在 Java 虚拟处理器类(JVP)中运行。因此,CLASS 修饰符对 Java 编写的 UDR 是可选的。然而,在注册一个用 Java 编写的 UDR 时使用 CLASS 修饰符,可以提高 SQL 语句的可读性。

COSTFUNC (C)

使用 COSTFUNC 修饰符指定 UDR 的成本。UDR 的成本是对所需执行时间的估计。

有时候,UDR 的成本取决于它的输入。在这种情况下,可以使用用户定义函数来计算取决于输入值的成本。

要执行 cost_func,您必须拥有对它以及对 UDR 的 Execute 特权。

HANDLESNULLS

使用 HANDLESNULLS 修饰符指定 C UDR 可以处理作为参数传递给它的 NULL 值。如果不对 C 语言的 UDR 指定 HANDLESNULLS ,并且传递它的参数具有 NULL 值,那么 UDR 不执行,并返回一个 NULL 值。

缺省情况下,C 语言的 UDR 不处理 NULL 值。

HANDLESNULLS 修饰符不可用于 SPL 例程,因为 SPL 例程缺省情况下处理 NULL 值。

INTERNAL

对外部例程使用 INTERNAL 修饰符,表示 SQL 或 SPL 语句不能调用外部例程。在例程解析期间不考虑将外部例程指定为 INTERNAL 。对定义存取方法和语言管理等的外部例程使用 INTERNAL 修饰符。

缺省情况下,外部例程不是 internal;也就是说,SQL 或 SPL 语句可以调用例程。

ITERATOR

对外部例程使用 ITERATOR 修饰符,表示该函数是迭代函数。迭代函数是每次函数调用返回单个元素的返回一组数据的函数;也就是说,它的调用包含一个初始调用和零个或多个后续调用,直到完成这一组。

缺省情况下,外部 C 或 Java™ 语言函数不是迭代函数。

SPL 迭代函数需要 RETURN WITH RESUME 语句,而不是 ITERATOR 修饰符。

在 ESQL/C 中,迭代函数需要游标。游标允许客户端应用程序用 FETCH 语句一次检索一个值。

有关如何编写迭代函数的更多信息,请参阅 GBase 8s 用户定义的例程和数据类型开发者指南 和 GBase 8s DataBlade API 程序员指南。

有关在查询的 FROM 子句中通过虚拟表接口使用迭代函数的信息,请参阅 迭代器函数。

NEGATOR

对返回布尔值的 UDR 使用 NEGATOR 修饰符。

NEGATOR 修饰符为当前函数命名一个伴随用户定义函数,叫做否定函数。否定函数以相同的顺序采用相同的参数作为它的伴随函数,但是返回布尔补数。

也就是说,如果一个函数对一组给定的参数返回 TRUE ,那么以相同顺序传递相同的参数时,它的否定函数返回 FALSE 。例如,下面的函数就是否定函数:

equal(a,b)

notequal(a,b)

两个函数都以相同顺序接受相同的参数,但是返回互补的布尔值。在效率更高时,优化程序可以使用否定函数代替指定的函数。

要调用具有否定函数的用户定义函数,必须对两者都有执行权限。此外,函数的所有者必须和它的否定函数相同。

PARALLELIZABLE

使用 PARALLELIZABLE 修饰符,表示外部例程可以在并行数据查询(PDQ)的上下文中并行执行。

缺省情况下,外部例程是不能并行执行的;即,它要按顺序执行。

如果 UDR 具有复杂或智能大对象数据类型作为参数或返回值,则不能使用 PARALLELIZABLE 修饰符。

如果对一个不能并行的外部例程指定 PARALLELIZABLE 修饰符,数据库服务器会返回一个运行时错误。

只调用 PDQ 线程安全 DataBlade API 函数的 C 语言 UDR 是可并行的。这些类别的 DataBlade API 函数是 PDQ 线程安全的:

  • 数据处理

这个类别的一个例外是集合操作函数(mi_collection_*)不是 PDQ 线程安全的。

  • 会话、线程和事务管理
  • 函数执行
  • 内存管理
  • 异常处理
  • 回叫
  • 其它

每种类别 DataBlade API 函数的详细信息,请参阅 GBase 8s DataBlade API 函数参考。

如果 C 语言 UDR 调用不包含在这些类别之一中的函数,那么它就不是 PDQ 线程安全的,因此不是可并行的。

要并行 Java™ 语言 UDR 调用,数据库服务器必须具有多个 JVP 实例。用 Java 语言编写的打开一个 JDBC 连接的 UDR 不是可并行的。

PERCALL_COST (C)

使用 PERCALL_COST 修饰符指定每次执行 C 语言 UDR 导致的近似的 CPU 使用成本。

优化程序使用指定的成本来确定评估 UDR 中 SQL 谓词的顺序以获得最佳性能。例如,下面的查询有两个谓词,由逻辑 AND 连接:

SELECT * FROM tab1 WHERE func1() = 10 AND func2() = 'abc';

在此示例中,如果一个谓词返回 FALSE,则优化程序就不需要评估另一个谓词了。

优化程序使用指定的成本来排列谓词的顺序,以便成本最小的谓词可以最先评估。CPU 使用成本必须是在 1 和 231-1 之间的整数,1 是最低成本,231-1 是最高成本。

要计算每次调用的近似成本,把下面两个数字相加:

  • 每次调用 C UDR 执行代码的行数
  • 需要一次 I/O 访问的谓词数

一次执行的缺省成本是 0。当删除 PERCALL_COST 修饰符时,一次执行的成本回到 0。

SELCONST (C)

使用 SELCONST 修饰符指定 UDR 的选择性,UDR 的选择性是对查询选择的行所占分数的估计。

选择性常数的值 selconst 是在 0 和 1 之间的浮点数,代表希望 UDR 返回 TRUE 的行所占的分数。

SELFUNC (C)

在 C UDR 中使用 SELFUNC 修饰符,为当前 UDR 命名一个伴随用户定义函数,称为选择性函数。选择性函数为优化程序提供当前 UDR 的选择性信息。

UDR 的选择性是对查询选择的行所占分数的估计。即,它是对 UDR 执行次数的估计。

要执行 sel_func,您必须具有对它以及 UDR 的 Execute 特权。

选择性的概念

选择性指的是符合基于等式条件执行搜索的查询的属性。查询的选择性反过来取决于合格行的比例。FROM 子句中表对象所有行中限定行的比例越小。查询的选择性越高。

例如,下面的查询有一个基于 customer 表的 customer_num 列的搜索条件:

SELECT * FROM customer WHERE customer_num = 102;

因为表中的每行具有不同的客户编号,所以查询的选择性很高。相反,下面的查询具有低选择性:

SELECT * FROM customer WHERE state = 'CA';

因为 customer 表的大多数行都是 California 的顾客,所以会返回超过半数的行。

SELFUNC 修饰符的限制

用 SELFUNC 指定的选择性函数具有特定要求。

指定的选择性函数必须满足以下条件:

  • 必须采用与当前 UDR 相同数量的参数。
  • 每个参数的数据类型必须是 SELFUNCARGS。
  • 必须返回一个范围在 0 到 1 之间的 FLOAT 类型的值。它代表函数选择性百分比。(1 是高选择性;0 是没有选择性。)
  • 它可以用数据库服务器支持的任何语言编写。

调用 UDR 的用户必须对这个 UDR 和 SELFUNC 修饰符指定的选择性函数都具有执行特权。

UDR 和此选择性函数必须具有相同的所有者。

有关如何使用 mi_funcarg* 函数来提取选择性函数的参数信息,请参阅 GBase 8s DataBlade API 程序员指南

STACK (C)

同 C UDR 一起使用 STACK 修饰符,覆盖由 STACKSIZE 配置参数指定的缺省堆栈打下。

STACK 修饰符指定线程堆栈的大小(以字节单位),执行 UDR 的用户线程用线程堆栈来保存信息,如例程参量和函数返回值。

UDR 需要足够的堆栈空间来容纳所有本地变量。对一个待定的 UDR,可能需要指定比缺省值更大的堆栈打下以防止堆栈溢出。

当包含 STACK 修饰符的 UDR 执行时,数据库服务器会分配大小为指定字节数的线程堆栈。一旦 UDR 执行结束,后面的 UDR 以 STACKSIZE 配置参数指定的堆栈打下(除非后面的 UDR 中任何一个也指定 STACK 修饰符)在线程中执行。

更多有关线程堆栈的信息,请参阅 GBase 8s 管理员指南GBase 8s DataBlade API 函数参考

VARIANT 和 NOT VARIANT

对 C 用户定义的函数和 SPL 函数使用 VARIANT 和 NOT VARIANT 修饰符。如果以相同参数调用时返回不同结果或者修改数据库或变量状态的函数是可变的。例如,返回当前日期和时间的函数就是一个可变函数。

缺省情况下,用户定义函数是可变的。如果在创建或修改用户定义函数时指定 NOT VARIANT ,则该函数不能包含任何 SQL 语句。

如果用户定义函数是不可变的,那么数据库服务器可以存储成本高的函数的返回值。只能对不变函数创建函数型索引。有关函数型索引的更多信息,请参阅 CREATE INDEX 语句。

在 ESQL/C 中,可以在这个子句或 EXTERNAL 例程引用中指定 VARIANT 或 NOT VARIANT。有关更多信息,请参阅外部例程引用。如果在两处都指定修饰符,必须在两个子句中都使用同一修饰符。

例程参数列表

当看到在语法图表中引用例程参数列表时,使用例程参数列表段的适当部分。

语法

例程参数列表

参数

元素描述限制语法
column数据类型声明为 parameter 的列名在指定表中必须存在数据库对象名
parameterUDR 的参数的名称SPL 例程需要名称标识符
table包含 column 的表表必须存在于数据库中标识符
value如果 UDR 调用对 parameter 没有值时缺省使用必须是和 parameter 相同数据类型的文字,对于不透明类型,必须定义一个输入函数精确数值

用法

参数是 UDR 声明中的形式参数。(接着调用一个带有参数的 UDR 时,必须用实际参量代替参数,除非参数具有缺省值。)

参数名对于 GBase 8s 的外部例程是可选的。

当创建 UDR 时,为每个参数声明 name 和 data type。您可以直接指定数据类型,或者使用 LIKE 或 REFERENCES 子句指定数据类型。您可以可选地指定缺省值。

可以定义任意数量的 SPL 例程参数,但是传递给 SPL 例程的所有参数的总长度必须小于 2 千兆字节。

在传递给以 Java™ 语言编写的 UDR 的参量中,不能有多于 9 个是 UDR 声明为 Java 语言 BigDecimal 数据类型的 SQL DECIMAL 数据类型。

任何返回透明数据类型的 C 语言 UDR 必须在 C 主变量 var binary 声明中指定 opaque_type

SQL 数据类型的子集

连续和大对象数据类型作为参数是不合法的。UDR 可以声明一个在数据库中定义过的任意数据类型的参数,包括除 BIGSERIAL 、BLOB 、BYTE 、CLOB 、SERIAL 、SERIAL8 或 TEXT 以外的任何内置数据类型。

在 GBase 8s 中,参数也可以是复制数据类型或 UDT ,但复杂数据类型对于用 Java™ 语言编写的外部 UDR 的参数无效。

有关 GBase 8s 数据类型的信息,这些数据类型作为访问本地数据库外部表或视图的例程的参数或返回值,请参阅从另一个数据库返回值。

使用 LIKE 子句

使用 LIKE 子句指定参数的数据类型,它与数据库中定义的列相同。如果 ALTER TABLE 语句改变列的数据类型,那么参数的数据类型也会改变。

在 GBase 8s 中,如果使用 LIKE 子句声明参数,就不能重载 UDR。例如,假设您创建以下用户定义过程:

CREATE PROCEDURE cost (a LIKE tableX.colY, b INT)
. . .
END PROCEDURE;

在同一个 GBase 8s 数据库中不能创建另一个名为 cost( ) 的带有两个参数的过程。然而,可以创建一个名为 cost( ) 带有一个参数而不是两个参数的过程。(另一种克服 LIKE 子句限制的方法是通过用户定义的数据类型。)

使用 REFERENCES 子句

使用 REFERENCES 子句指定包含 BYTE 或 TEXT 数据的参数。REFERENCES 关键字允许您使用 BYTE 或 TEXT 对象的指针作为参数。如果在 REFERENCES 子句中使用 DEFAULT NULL 选项,并且不带参数地调用 UDR ,那么 NULL 值就用作缺省值。

使用 DEFAULT 子句

使用 DEFAULT 关键字后面跟一个表达式自动参数的缺省值。如果为参数提供缺省值,并且以少于 UDR 定义的参量来调用这个 UDR 时,就是要缺省值。如果不为参数提供缺省值,并且以少于 UDR 定义的参数来调用这个 UDR 时,调用应用程序会收到错误。

下面的示例显示了 CREATE FUNCTION 语句,它为参数指定了缺省值。这个函数查找参数 i 的平方。如果函数调用时不指定 i 参数的参量,数据库服务器使用 0 作为参数 i 的缺省值。

CREATE FUNCTION square_w_default
(i INT DEFAULT 0) {Specifies default value of i}
RETURNING INT; {Specifies return of INT value}
DEFINE j INT; {Defines routine variable j}
LET j = i * i; {Finds square of i and assigns it to j}
RETURN j; {Returns value of j to calling module}
END FUNCTION;
警告

当指定一个日期值作为参数的缺省值时,必须确保对年份指定 4 位数而不是 2 位数字。当指定 2 位数字的年份时,环境变量 DBCENTURY 的设置会影响数据库服务器如何解释日期值,所以 UDR 可能不使用希望的缺省值。有关更多信息,请参阅 《GBase 8s SQL 指南:参考》

为用户定义例程指定 OUT 参数

注册一个 GBase 8s 的用户定义的例程时,可以使用关键字 OUT 来指定列表中的任何一个参数是 OUT 参数。每个 OUT 参数对应例程通过指针直接返回的一个只。例程通过指针返回的值是显式返回的任何值以外的一个额外值。

在注册了带有一个或多个 OUT 参数的用户定义函数以后,可以在 SQL 语句中把函数和语言-局部变量(SLV)一起使用。(关于语句-局部变量的信息,请参阅语句本地的变量表达式。)

如果指定了任何 OUT 参数,并且使用 GBase 8s 样式的参数,参量会通过引用传递给 OUT 参数。OUT 参数在确定例程特征符时没有意义。

例如,下面对 C 用户定义函数的声明允许通过参数 y 返回一个额外值:

int my_func( int x, int *y );

用 CREATE FUNCTION 语句注册一个 C 函数与此类似:

CREATE FUNCTION my_func( x INT, OUT y INT )
RETURNING INT
EXTERNAL NAME "/usr/lib/local_site.so"
LANGUAGE C
END FUNCTION;

下一个示例中,该 Java™ 方法通过传递返回一个额外值:

public static String allVarchar(String arg1, String[] arg2)
throws SQLException
{
arg2[0] = arg1;
return arg1;
}

要将这作为 UDF 注册,请使用与以下示例相似的语句:

CREATE FUNCTION all_varchar(VARCHAR(10), OUT VARCHAR(7))
RETURNING VARCHAR(7)
WITH (class = "jvp")
EXTERNAL NAME 'gbasedbt.testclasses.jlm.Param.allVarchar(java.lang.String,
java.lang.String[ ])'
LANGUAGE JAVA;

为用户定义的例程指定 INOUT 参数

用 SPL 、C 或 Java™ 语言编写的 UDR 也可以支持 INOUT 参数。当调用 UDR 时,每个 INOUT 参数的值作为参量通过引用传递给 UDR 。

当 UDR 执行完成时,它能够为 INOUT 参数返回一个修改后的值给调用上下文。INOUT 参数可以是 GBase 8s 支持的任意数据类型,包括用户定义的和复杂数据类型和以下例外:

  • Serial 类型(BIGSERIAL 、SERIAL 和 SERIAL8)
  • 简单大对象类型(BYTE 和 TEXT)。

在以下示例中,CREATE PROCEDURE 语句注册一个带有单个 INOUT 参数的 C 例程:

CREATE PROCEDURE CALC ( INOUT param1 float )
EXTERNAL NAME "$GBASEDBTDIR/etc/myudr.so(calc)"
LANGUAGE C;

SPL 例程可以调用具有 OUT 和 INOUT 参数的其它 UDR,如果这些 UDR 用 SPL 或 C 语言编写。然而,SPL 例程不能调用参量包含 OUT 或 INOUT 参数的 Java UDR。

支持从 SPL 例程调用具有命名或未命名 ROW 参数的 UDR ,对 ROW 参数类型和调用的 UDR 的编程语言有以下依赖性:

SPL 例程可以调用 ROW 参量是 IN 参数的 C UDR。但是不能调用 ROW 参量是 OUT 或 INOUT 参数的 C UDR 。

SPL 例程可以调用具有任意参数类型(包括 IN 、OUT 和 INOUT)的 ROW 参量的 SPL UDR。

可以将 INOUT 参数分配给语句-局部变量(SLV),语句-局部变量在语句本地的变量表达式部分中描述。

共享对象文件名

在注册或更改外部例程时使用共享对象文件名指定一个可执行对象文件名的路径名。

语法

共享对象文件

用法

如果 IFX_EXTEND_ROLE 配置参数设置为 1 或 ON,只有 DBSA 已授予内置 EXTEND 角色的用户才有权使用此段。(无论是否启用 IFX_EXTEND_ROLE,必须对数据库保留 Resource 特权或 DBA 特权,然后才能创建、删除或更改外部 UDR。)

DB_LIBRARY_PATH 配置参数设置中包括安全策略授权 DataBlade 模块和 UDR 驻留的每个文件系统。除非缺失 DB_LIBRARY_PATH 或没有设置,否则数据库服务器无法访问此段指定的文件,除非其路径名以与 DB_LIBRARY_PATH 的值完全匹配的字符串开头。

例如,如果 "$GBASEDBTDIR/extend" 是 Linux™ 系统上的 DB_LIBRARY_PATH 值之一,则共享对象文件可以在 $GBASEDBTDIR/extend 文件系统或其子目录中具有路径名。此目录也是内置 DataBlade 模块所在的文件系统。

指定共享对象文件名的语法取决于该外部例程是按 C 语言还是 Java 语言编写。以下几节描述了这些外部语言。

有关出现在 ALTER FUNCTION 、ALTER PROCEDURE 、ALTER ROUTINE、 CREATE FUNCTION 和 CREATE PROCEDUREF 语句的 EXTERNAL NAME 子句中上下文的更多信息,请参阅相关的引用,外部例程引用。

C 共享对象文件

要指定 C 共享对象文件的位置,在引用路径名中指定动态载人可执行文件的路径或把它作为一个变量。

语法:

C 共享对象文件

元素描述限制语法
environment_var取决于平台的指示符必须以美元符号($)开头标识符
pathname文件的路径名请参阅后面的注释必须符合操作系统约定
quote单引号(')或双引号(''开始和结束引号必须匹配文字符号('''
symbol文件的入口点必须用括号括起来必须符合操作系统约定
variable取决于平台的指示符必须以美元符号($)开头必须符合 C 语言约定

下列规则影响路径名和 C 语言中的文件名规范:

  • 文件名(不带路径名)可以指定一个内部函数。
  • 当 CREATE 或 ALTER 语句运行时,如果路径名和当前目录相关可以省略句号(. )。
  • 在 UNIX™ 中,绝对路径必须以斜杠(/)符号开头,而且每一个目录名必须以斜杠(/)符号结尾。
  • 在 Windows™ 中,绝对路径必须以反斜杠(\)符号开头,而且每一个目录名必须以反斜杠( \ )符号结尾。
  • 路径名结尾处的文件名必须有 .so 文件扩展名并且必须指向共享对象库中的一个可执行文件。
  • 只在动态可载人的可执行对象文件入口点的名称和用 CREATE FUNCTION 或 CREATE PROCEDURE 注册的 UDR 名称不同时,使用 symbol。
  • 如果指定一个变量,它必须包含可执行文件的完整路径名。
  • 在引用路径名中可以包含空白字符,如空格或制表符。

Java 共享对象文件

要指定 Java™ 更新对象文件,需要指定 UDR 对应的静态 Java 方法和定义这个方法的 Java 二进制文件。

Java 共享对象文件:

元素描述限制语法
class_id方法实现 UDR 的 Java™ 类类必须在 Jar 名标识的 .jar 文件中存在必须遵守 Java 标识符的规则
java_type在 Java™ 方法特征符中参数的 Java 数据类型必须在 JDBC 类中定义或通过 SQL-to-Java 映射定义必须遵守 Java 标识符的规则
method_id实现 UDR 的 Java 方法名必须在 java_class_name 指定的 Java 类中存在必须遵守 Java 标识符的规则
package_id包含 Java 类的数据包名必须存在必须遵守 Java 标识符的规则
quote单引号(')或双引号('')定界符开始和结束引号必须匹配从键盘输入的文字符号( ' 或 '')

在创建用 Java 语言编写的 UDR 之前,必须用 sqlj.install_jar 过程分配一个 jar 标识符给外部 jar 文件。(有关更多信息,请参阅 sqlj.install_jar。)在共享对象文件名中可以包含实现 UDR 的方法的 Java 特征符。

  • 如果不指定 Java 特征符,例程管理器从 CREATE FUNCTION 或 CREATE PROCEDURE 语句中的 SQL 特征符确定隐式 Java 特征符。

它用 JDBC 和 SQL-to-Java 映射把 SQL 数据类型映射到对应的 Java 数据类型。有关吧用户定义的数据类型映射到 Java 数据类型的信息,请参阅 sqlj.setUDTextName。

  • 如果指定了 Java 特征符,例程管理使用这个显式 Java 特征符作为要使用的 Java 方法名。

例如,如果 Java 方法 explosiveReaction( ) 实现 Java UDR sql_explosive_reaction( )(如 sqlj.install_jar 中所讨论),则它的共享对象文件名可以是:

course_jar:Chemistry.explosiveReaction

前面的共享对象文件名提供了隐式 Java 特征符。下面的共享对象文件名等价于一个显式 Java 特征符:

course_jar:Chemistry.explosiveReaction(int)

专用名

使用专用名为 UDR 声明一个在数据库或名称空间中唯一的标识符。当看到在语法图表中引用专用名时,使用专用名段。

语法

专用名

元素描述限制语法
ownerUDR 的所有者不超过 32 个字节。必须和这个 UDR 的函数或过程名的所有者相同。另见对所有者名称的限制。所有者名称
specific_idUDR 的唯一名称不能超过 128 字节长。另见对专用名的限制。标识符

用法

专用名是由 CREATE PROCEDURE 或 CREATE FUNCTION 语句声明的唯一标识符,作为 UDR 的一个替换名。

因为可以重载例程,所以数据库可以有多个具有相同名称和不同参数列表的 UDR。可以为 UDR 分配一个专用名,唯一标识指定的 UDR 。

如果在创建 UDR 时声明一个专用名,以后在对 UDR 进行更改、删除、授权或取消特权或更新统计信息时可以使用这个名称。否则,如果只有一个名称不能唯一标识 UDR 时,需要对 UDR 名包含参数数据类型。

对所有者名称的限制

当声明专用名时,所有者必须和限定所创建的 UDR 的函数或过程名的授权标识符相同。即,无论是否指定名称限定 UDR 名称或专用名或者同时限定两者。所有者名称必须匹配。

当在创建 UDR 的 DDL 语句中未指定所有者名称时, GBase 8s 使用创建 UDR 的用户的登录名。因此,如果您在一个地方指定所有者名称而在另一个地方没有指定,那么所指定的所有者名称必须和您的用户 ID 匹配。

对专用名的限制

在不符合 ANSI 的数据库中,specific_id 在数据库的例程名中必须是唯一的。两个 UDR 不能具有相同的 specific_id ,即使它们有不同的所有者。

在符合 ANSI 的数据库中,owner.specific_id 组合必须是唯一的。即,专用名在具有相同所有者的 UDR 中必须是唯一的。

语句块

使用语句块指定,当执行一个包含本段的 SPL 语句时,进行 SPL 和 SQL 操作。

语法

语句块

用法

SPL 和 SQL 语句可以出现在语句块中,语句块是能够定义变量或 SPL 的 ON EXCEPTION 语句的范围的零个或多个语句。如果语句块为空,当 SPL 例程中的执行控制传递给空的 SPL 语句块时不会发生任何操作。

SPL 语句的子集在语句块中有效

语句块的语法引用了此节。您可以在语句块中使用下列任何 SPL 语句:

  • <
  • CALL
  • CASE
  • CONTINUE
  • EXIT
  • FOR
  • FOREACH
  • GOTO
  • IF
  • LET
  • LOOP
  • RAISE EXCEPTION
  • RETURN
  • SYSTEM
  • TRACE
  • WHILE

但是,GOTO 和 << Label >> 在 ON EXCEPTION 语句块中无效。

SQL 语句在 SPL 语句块中有效

语句块的图表涉及这一节的内容。大多数 SQL 语句在 SPL 语句块中有效,除了以下列出的语句。下列 SQL 语句在 SPL 语句块中无效:

  • CLOSE DATABASE
  • CONNECT
  • CREATE DATABASE
  • CREATE FUNCTION
  • CREATE FUNCTION FROM
  • CREATE PROCEDURE
  • CREATE PROCEDURE FROM
  • CREATE ROUTINE FROM DATABASE
  • DISCONNECT
  • EXECUTE
  • FLUSH
  • INFO
  • LOAD
  • OUTPUT
  • PUT
  • RENAME DATABASE
  • SET AUTOFREE
  • SET CONNECTION
  • UNLOAD

UPDATE STATISTICS例如,您不能在 SPL 例程中关闭数据库或连接新的数据库。同样,您不能在同一例程中删除当前 SPL 例程。然而,您可以删除另一个 SPL 例程。

只能在两种情况下使用 SELECT 语句:

  • 可以使用 INTO TEMP 子句把 SELECT 语句的结果放进一个临时表。
  • 可以使用 SELECT 语句的 SELECT ... INTO 形式把结果值放进 SPL 变量。

当在 SELECT ... INTO TEMP 或 SELECT ... INTO variable 语句中包含 ORDER BY 子句时,这表示此查询返回多行。如果您指定没有 FOREACH 循环的 ORDER BY 子句来在 SPL 例程中单独处理返回的行,那么数据库服务器会发出错误。

如果后面 SPL 例程要作为数据操纵语言(DML)语句的一部分被调用,还有附加的限制。有关更多信息,请参阅在数据操纵语句中 SPL 例程的限制。

嵌套语句块

可以使用 BEGIN 和 END 关键字来定界嵌套在另一个语句块中的语句块。

引用 SPL 变量和异常处理程序的作用域

BEGIN 和 END 关键字可以限制 SPL 变量和异常处理程序的作用域。在 BEGIN 和 END 语句块中的变量声明和异常处理程序定义是语句块局部的,在语句块外面不可见。下面的代码使用了 BEGIN 和 END 语句块来限定变量引用的作用域:

CREATE DATABASE demo;
CREATE TABLE tracker (
who_submitted CHAR(80), -- Show what code was running.
value INT, -- Show value of the variable.
sequential_order SERIAL -- Show order of statement execution.
);
CREATE PROCEDURE demo_local_var()
DEFINE var1, var2 INT;
LET var1 = 1;
LET var2 = 2;
INSERT INTO tracker (who_submitted, value)
VALUES ('var1 param before sub-block', var1);
BEGIN
DEFINE var1 INT; -- same name as global parameter.
LET var1 = var2;
INSERT INTO tracker (who_submitted, value)
VALUES ('var1 var defined inside the "IF/BEGIN".', var1);
END
INSERT INTO tracker (who_submitted, value)
VALUES ('var1 param after sub-block (unchanged!)', var1);
END PROCEDURE;
EXECUTE PROCEDURE demo_local_var();
SELECT sequential_order, who_submitted, value FROM tracker
ORDER BY sequential_order;

这个示例声明了三个变量,其中两个名为 var1。(这里创建的名称冲突是为了说明哪种变量是可见的。通常建议对不同变量不要使用相同的名称。因为冲突的变量名会造成代码可读性差并且难维护。)

因为语句块的关系,每次只有一个 var1 变量在作用域中。

在语句块中声明的 var1 变量是唯一可以在语句块中引用的 var1 变量。

在语句块外面声明的 var1 变量在语句块中是不可见的。因为它在作用域之外,所以发生在语句块内部的 var1 变量值的更改对它没有影响。所有语句运行以后,外面的 var1 的值仍然是 1。

var2 变量在语句块中可见,因为它没有因名称冲突而被块专用变量替代。

在数据操纵语句中 SPL 例程的限制

如果在非数据操纵语言(DML)语句(即 EXECUTE FUNCTION 或 EXECUTE PROCEDURE)的 SQL 语句中调用 SPL 例程,那么 SPL 例程可以执行未列在 SQL 语句在 SPL 语句块中有效一节中的任何语句。

如果 SPL 例程作为 DML 语句(即 INSERT 、UPDATE 、DELETE 、MERGE 或 SELECT 语句)的一部分调用,那么例程不能执行下面列表中的任何 SQL 语句:

  • ALTER ACCESS_METHOD
  • ALTER FRAGMENT
  • ALTER INDEX
  • ALTER SEQUENCE
  • ALTER TABLE
  • BEGIN WORK
  • COMMIT WORK
  • CREATE ACCESS_METHOD
  • CREATE AGGREGATE
  • CREATE DISTINCT TYPE
  • CREATE OPAQUE TYPE
  • CREATE OPCLASS
  • CREATE ROLE
  • CREATE ROW TYPE
  • CREATE SEQUENCE
  • CREATE TRIGGER
  • DELETE
  • DROP ACCESS_METHOD
  • DROP AGGREGATE
  • DROP INDEX
  • DROP OPCLASS
  • DROP ROLE
  • DROP ROW TYPE
  • DROP SEQUENCE
  • DROP SYNONYM
  • DROP TABLE
  • DROP TRIGGER
  • DROP TYPE
  • DROP VIEW
  • INSERT
  • MERGE
  • RENAME COLUMN
  • RENAME DATABASE
  • RENAME SEQUENCE
  • RENAME TABLE
  • ROLLBACK WORK
  • SET CONSTRAINTS
  • TRUNCATE
  • UPDATE

如果 SPL 例程的调用上下文是试图执行以上列出的任何 SQL 语句的 DML 语句,则 GBase 8s 发出错误 -675。

这些限制不适用于触发器调用的 SPL 例程,因为在这些情况下 SPL 例程不是由 DML 语句调用,因而可以包含任意未列在 SQL 语句在 SPL 语句块中有效中的 SQL 语句,例如 UPDATE 、INSERT 和 DELETE。

SPL 例程中的事务

在不符合 ANSI 的数据库中,可以在 SOL 语句中使用 BEGIN WORK 和 COMMIT WORK 语句启动事务、结束事务、或者在同一 SPL 例程中启动和终止的事务。如果在远程执行的例程中启动一个事务,必须在例程退出之前结束这个事务。

然而,就像前面提到的,ROLLBACK WORK 语句在 SPL 语句块中是无效的。

对用户身份和角色的支持

可以在 SPL 例程中使用角色。可以在 SPL 例程中执行角色相关语句(CREATE ROLE 、DROP ROLE 、GRANT 、REVOKE 和 SET ROLE)并且持有 SETSESSIONAUTH 特权的用户可以发出 SESSION AUTHORIZATION 语句。在 SPL 例程中,您可以使用 GRANT 语句

  • 授予角色自由访问权限,
  • 或向角色授予基于标签的访问凭证(LBAC),
  • 或向角色授予其它角色。

SPL 例程还可以使用 REVOKE 语句撤销角色的访问特权、LBAC 凭证或角色。

在授予访问特权、角色和 LBAC 凭证的 SPL 例程完成执行后,用户通过启用角色或通过 SET SESSION AUTHORIZATION 语句在 SPL 例程中获取的访问权限,角色和 LBAC 凭证不会自动退出。所授予的内容持续存在,直到后续的 REVOKE 操作取消 GRANT 操作的效果。

有关角色的更多信息,请参阅第二章中的 CREATE ROLE 语句 、DROP ROLE 语句 、GRANT 语句 、REVOKE 语句 和 SET ROLE 语句。

HASH分区

创建分区已有4种分区方式,包括:轮转法(ROUND ROBIN)、表达式(EXPRESSION)、范围(RANGE)及列表(LIST),在此基础上新增HASH分区方式。

HASH分区表是按分区列的HASH计算结果来决定其分区的,而特定的分区列其HASH值是固定的,也就是说HASH分区表的数据是按分区列值来聚集的,同样的分区列肯定在同一分区。例如在证券行业,我们经常查询某一只股票的K线,建成HASH分区表,则数据按HASH分区列聚集,就更适合K线数据的查询,因为同样id的记录必定在同一分区,同时,同样id值的记录落在同一数据块的几率也增大了,从而一定程度上减少IO,提高查询效率。

创建HASH分区

其中:

元素描述限制
fragment_key分区列名称必选项; 必须是表中的列
partition_name分区名称可选项;
dbspace_namedbspace名称不指定dbspase则为当前数据库默认的表空间;指定的dbspase需存在,可重复

例如,人员表user中,按照部门字段departmentID作为分区列进行HASH分区,如下:

CREATE TABLE USER(
name varchar(20),
departmentID int,
age int,
address varchar(50)
)PARTITION BY HASH(departmentID)
(
partition p1 DBSPACE dbs1,
partition p2 DBSPACE dbs2,
partition p3 DBSPACE dbs3
);

管理HASH分区

HASH分区的管理支持增加分区(add子句)、截断分区(truncate子句)和结合分区(coalesce子句)。

增加分区

增加分区,数据会重新在增加分区后的所有分区中根据哈希运算结果重新分布。

在alter fragment on table…主干语法基础上:

其中partition_name是分区名称,dbspace_name是dbspace名称,均可省略。

例如,人员表user增加一个分区p4:

ALTER FRAGMENT ON TABLE USER ADD PARTITION p4 DBSPACE dbs4;

截断分区

主要功能为清空哈希分区表中的数据,但哈希分区表本身并不删除。

在alter fragment on table…主干语法基础上:

其中partition_name是分区名称,不可省略。

例如,人员表user清空掉p1分区数据

ALTER FRAGMENT ON TABLE USER TRUNCATE PARTITION p1;

人员表user清空掉p2、p3分区数据

ALTER FRAGMENT ON TABLE USER TRUNCATE PARTITIONS p2,p3;

结合分区

结合分区是针对哈希分区或者包含哈希分区的复合分区的,目的是减少分区数。被结合的分区是由数据库自动选择的,结合完成后该分区会被删除,数据会被合并至其它某个数据库指定分区中,分区数大于等于2个才支持结合操作。

在alter fragment on table…主干语法基础上:

例如,人员表user执行1次结合分区,从而自动减少1个分区:

ALTER FRAGMENT ON TABLE USER COALESCE PARTITION;

HASH分区使用

HASH分区插入数据

HASH分区表的数据插入跟其他分区表(如列表或范围分区表)的插入方式相同,数据库根据HASH分区规则自动计算分区。

例如,向user表中插入数据:

INSERT INTO USER VALUES(‘张三’,2,25,’北京市海淀区’);

HASH分区更新数据

HASH分区表的更新数据时跟普通表的更新方式相同,更新分区列数据时数据重新按照HASH规则排列。

例如,user表中更新某类数据:

UPDATE USER SET departmentID=1 WHERE AGE=25;

HASH分区删除数据

哈希分区表的数据删除跟其他分区表(如列表或范围分区表)的删除方式相同。

例如,user表中删除某类数据:

DELETE FROM USER WHERE departmentID=1;

虚拟列

虚拟列是指使用表达式或函数进行定义的数据列。逻辑上,表的虚拟列与普通列具有相同的语法含义,但虚拟列的值并不保存在任何物理存储介质上,而是在SQL的执行过程中,根据定义虚拟列的表达式或函数进行计算而获得。

虚拟列语法图:

元素描述限制
column虚拟列的列名不可与该表其它列重名,不可省略
datatype虚拟列数据类型
GENERTATED ALWAYS显式声明虚拟列关键字可省略
AS显式声明虚拟列关键字不可省略
column_expression定义虚拟列的列表达式或常量表达式引用当前表中的列
VIRTUAL显式声明虚拟列关键字可省略

创建一个带虚拟列的表

例如,创建带虚拟列的表employee,其中total_sal为表达式定义的虚拟列:

CREATE TABLE employee
(
empl_ID INT,
empl_Nm VARCHAR(50),
monthly_Sal DECIMAL(10,2),
bonus DECIMAL(10,2),
total_Sal DECIMAL(10,2) GENERATED ALWAYS AS (monthly_Sal*12 + bonus)
);

向带虚拟列的表中插入数据

对虚拟列执行 INSERT 操作,需明确写出插入表的各字段名称。

例如,向带虚拟列的表中正确插入数据:

INSERT INTO employee(empl_ID,empl_Nm,monthly_Sal,bonus)
VALUES(1,'zhangSan',9000,560);

返回结果:成功

只写表名不明确写出各字段名称:

INSERT INTO employee VALUES(1,'zhangSan',9000,560);

返回结果:报错误代码-981

插入字段中包含虚拟列:

INSERT INTO employee(empl_ID,empl_Nm,monthly_Sal,bonus,total_Sal)
VALUES(1,'zhangSan',9000,560)

返回结果:报错误代码-981

支持在UPDATE/DELETE的WHERE语句中使用虚拟列,不允许在虚拟列上执行UPDATE语句

例如,更新虚拟列,会报错误:

UPDATE employee SET total_sal = 2000;

返回结果:报错误代码-982

UPDATE employee SET monthly_Sal = 2000 where total_Sal>100000;

返回结果:成功

修改虚拟列

支持使用ALTER TABLE语句新增虚拟列,不支持NOT NULL约束。

例如,向employee表中新增一列虚拟列monthly_Avg:

ALTER TABLE employee ADD (monthly_Avg AS ((monthly_Sal * 12 + bonus)/12));

支持使用RENAME COLUMN子句修改虚拟列名称,要求不可与当前表中已有列名重复。

例如,修改虚拟列total_Sal列名为total:

RENAME COLUMN employee.total_Sal TO total;

支持使用通过ALTER MODIFY语句修改虚拟列的数据类型,包括显示修改和隐式修改,显示修改虚拟列数据类型需要确保AS子句的返回值数据类型与虚拟列数据类型一致或支持隐式类型转换,隐式修改虚拟列数据类型可省略数据类型仅通过调整AS子句实现,当且仅当只修改数据类型长度时——如varchar(15)改为varchar(20),float改为int——可以省略AS语句,其他情况不允许省略AS子句。

例如,显示修改虚拟列类型:

ALTER TABLE employee MODIFY( monthly_Avg FLOAT AS ((monthly_Sal\*12 + bonus)/12));

隐式修改虚拟列类型:

ALTER TABLE employee MODIFY( monthly_Avg AS ((monthly_Sal*12 + bonus)/12));

省略AS子句修改虚拟列类型:

ALTER TABLE employee MODIFY( monthly_Avg INT);

支持使用ALTER MODIFY语句修改虚拟列定义表达式,此时虚拟列的数据类型与表达式一致。

例如,修改employee表中虚拟列monthly_Avg的表达式:

ALTER TABLE employee MODIFY( monthly_Avg AS ((monthly_Sal*12 + bonus*0.9)/12));

删除虚拟列和普通列

删除某列时,需要先删除引用该列的所有虚拟列,再删除该列。

例如,emplyee表中删除虚拟列mothly_Avg和普通列monthly_Sal:

ALTER table employee DROP monthly_Sal;

返回结果:报错

ALTER table employee DROP (monthly_Avg, monthly_Sal);

返回结果:报错

ALTER table employee DROP monthly_Avg;
ALTER table employee DROP monthly_Sal;

返回结果:成功

虚拟列上建索引

支持在虚拟列上创建索引。

例如,在emplyee表的虚拟列total_Sal上创建索引:

CREATE INDEX idx_total_sal ON employee(total_Sal);

虚拟列安全策略

虚拟列不继承定义该虚拟列所涉及普通列上的安全策略。

注意
  • CREATE TABLE AS SELECT…FROM...时不支持SELECT中含虚拟列;
  • WITH AS子句中不支持使用虚拟列;
  • 临时表中不支持使用虚拟列;
  • 虚拟列表达式中不支持加密解密函数;
  • 虚拟列仅支持 CREATE TABLE 建表语句或 ALTER TABLE ADD 语句添加CHECK约束。