
# record
#### record类型的变量
定义一个record类型 ，然后使用该类型来声明一个变量，该变量即为record变量。
#### 语法
定义record类型的语法为：
```
TYPE type_name IS_RECORD (field_declaration [,...] );
```
![](https://support.huaweicloud.com/centralized-devg-v8-gaussdb/figure/zh-cn_image_0000002526900336.png "点击放大")
其中field_declaration为：
```
field_name datatype [ [NOT_NULL] { := | DEFAULT } expression]
```
![](https://support.huaweicloud.com/centralized-devg-v8-gaussdb/figure/zh-cn_image_0000002558060183.png "点击放大")
对以上语法格式的解释如下：
- type_name：声明的类型名称。
- field_name：record类型中的成员名称。
- datatype：record类型中成员的类型。
- expression：设置默认值的表达式。
 
#### 使用约束
在GaussDB中：
- record类型变量的赋值支持：
  - 在函数或存储过程的声明阶段，声明一个record类型，并且可以在该类型中定义成员变量。
  
  - 一个record变量到另一个record变量的赋值。
  
  - SELECT INTO和FETCH向一个record类型的变量中赋值。
  
  - 将一个NULL值赋值给一个record变量。
   
- record类型构造器赋值时支持使用=\>，约束如下：
  - record类型构造器赋值时使用=\>功能，仅在兼容A模式数据库下（即sql_compatibility='A'）支持。
  
  - 支持在package内部定义record类型。
  
  - record类型构造器赋值时使用=\>功能，仅在入参赋值连续使用=\>到结尾时支持，如record_name(elename1 =\> val1, elename2 =\> val2, elename3 =\> val3)或record_name(val1, elename2 =\> val2, elename3 =\> val3)；不支持非连续使用=\>赋值或者使用=\>赋值时未到最后一个入参，如record_name(elename1 =\> val1, elename2 =\> val2, val3)或record_name(val1, elename2 =\> val2, val3)。
   
- 不支持INSERT和UPDATE语句使用record变量进行插入数据和更新数据。
- 不支持record类型的构造器作为函数或存储过程参数的默认值。
- 如果成员有复合类型，在声明阶段不支持指定默认值，该行为同声明阶段的变量一样。
- 如果成员有record类型，则内层record类型的默认值不支持传递至外层record类型中。
- 设置GUC参数enable_recordtype_check_strict为on后，成员是record类型，且record类型有列具有NOT NULL属性或DEFAULT属性，在存储过程或PACKAGE编译时会报错。
- 设置GUC参数enable_recordtype_check_strict为on后，当PACKAGE里有record类型，且record类型有列具有NOT NULL属性或DEFAULT属性会在创建或编译时报错。
- 设置GUC参数enable_recordtype_check_strict为on后，存储过程里的record类型NOT NULL功能生效。
- datatype可以为存储过程中定义record类型、数组类型和集合类型（匿名块不支持）。
- 设置GUC参数behavior_compat_options启用proc_outparam_override选项后：
  - 带有out出参且返回record的函数，支持在外部SQL使用SELECT、CALL调用，在存储过程内支持使用PERFORM、表达式调用。
  
  - 在函数直接返回未定义的record类型时，至少需要带有一个out参数；如果返回的是已经定义的record类型，则可以不带out参数。详见[示例]。
  
  - 带out出参返回复合类型或record的函数，需要保持函数的预期返回类型与实际返回类型一致。
   
 
 #### 示例
```
-- 创建一个表，并插入一些数据。
gaussdb=# create table emp_rec(
gaussdb not null,
gaussdb
gaussdb;
CREATE TABLE
gaussdb=# insert into emp_rec values(111, 'aaa'), (222, 'bbb'), (333, 'ccc');
INSERT 0 3
-- 表定义如下。
gaussdb=# \d emp_rec
           Table "public.emp_rec"
 Column |         Type          | Modifiers 
--------+-----------------------+-----------
 empno  | numeric(4,0)          | not null
 ename  | character varying(10) |
-- 演示在函数中对record进行操作。
gaussdb=# CREATE OR REPLACE FUNCTION regress_record(p_w VARCHAR2) RETURNS VARCHAR2 AS $$
gaussdb$# DECLARE
gaussdb$#     -- 声明一个record类型。
gaussdb$#     type rec_type is record (name  varchar2(100), epno int);
gaussdb$#     employer rec_type;
gaussdb$#     -- 使用%type声明record类型。
gaussdb$#     type rec_type1 is record (name  emp_rec.ename%type, epno int :=10);
gaussdb$#     employer1 rec_type1;
gaussdb$#     -- 声明带有默认值的record类型。
gaussdb$#     type rec_type2 is record (
gaussdb$#         name varchar2 not null := 'SCOTT',
gaussdb$#         epno int not null :=10
gaussdb$#     );
gaussdb$#     employer2 rec_type2;
gaussdb$#     CURSOR C1 IS  select ename,empno from emp_rec order by 1 limit 1;
gaussdb$# BEGIN
gaussdb$#     -- 对一个record类型的变量的成员赋值。
gaussdb$#     employer.name := 'WARD';
gaussdb$#     employer.epno = 18;
gaussdb$#     raise info 'employer name: % , epno:%', employer.name, employer.epno;
gaussdb$# 
gaussdb$#     -- 将一个record类型的变量赋值给另一个变量。
gaussdb$#     employer1 := employer;
gaussdb$#     raise info 'employer1 name: % , epno: %',employer1.name, employer1.epno;
gaussdb$# 
gaussdb$#     -- 将一个record类型变量赋值为NULL。
gaussdb$#     employer1 := NULL;
gaussdb$#     raise info 'employer1 name: % , epno: %',employer1.name, employer1.epno;
gaussdb$# 
gaussdb$#     -- 获取record变量的默认值。
gaussdb$#     raise info 'employer2 name: % ,epno: %', employer2.name, employer2.epno;
gaussdb$# 
gaussdb$#     -- 在for循环中使用record变量。
gaussdb$#     for employer in select ename,empno from emp_rec order by 1 limit 1 loop 
gaussdb$#         raise info 'employer name: % , epno: %', employer.name, employer.epno;
gaussdb$#     end loop;
gaussdb$# 
gaussdb$#     -- 在select into中使用record变量。
gaussdb$#     select ename,empno  into employer2 from emp_rec order by 1 limit 1;
gaussdb$#     raise info 'employer name: % , epno: %', employer2.name, employer2.epno;
gaussdb$# 
gaussdb$#     -- 在cursor中使用record变量。
gaussdb$#     OPEN C1;
gaussdb$#     FETCH C1 INTO employer2;
gaussdb$#     raise info 'employer name: % , epno: %', employer2.name, employer2.epno;
gaussdb$#     CLOSE C1;
gaussdb$#     RETURN employer.name;
gaussdb$# END; $$
gaussdb-# LANGUAGE plpgsql;
CREATE FUNCTION
-- 调用该函数。
gaussdb=# CALL regress_record('abc');
INFO:  employer name: WARD , epno:18
INFO:  employer1 name: WARD , epno: 18
INFO:  employer1 name: <NULL> , epno: <NULL>
INFO:  employer2 name: SCOTT ,epno: 10
INFO:  employer name: aaa , epno: 111
INFO:  employer name: aaa , epno: 111
INFO:  employer name: aaa , epno: 111
 regress_record 
----------------
 aaa
(1 row)
-- 删除函数。
gaussdb=# DROP FUNCTION regress_record;
DROP FUNCTION
-- 删除表。
gaussdb=# DROP TABLE emp_rec;
DROP TABLE
-- 打开兼容性参数proc_outparam_override时，返回已定义的record类型，函数可以不需out参数。
gaussdb=# create type rec_type is (c1 int, c2 int);
CREATE TYPE
gaussdb=# set behavior_compat_options = 'proc_outparam_override';
SET
gaussdb=# create or replace function func(a in int) return rec_type is
gaussdb$#     r rec_type;
gaussdb$# begin
gaussdb$#     r.c1:=1;
gaussdb$#     r.c2:=1;
gaussdb$#     return r;
gaussdb$# end;
gaussdb$# /
CREATE FUNCTION
gaussdb=# call func(0);
 c1 | c2 
----+----
  1 |  1
(1 row)
gaussdb=# drop function func;
DROP FUNCTION
gaussdb=# drop type rec_type;
DROP TYPE
-- 打开兼容性参数proc_outparam_override时，函数直接返回未定义的record类型时，至少需要带有一个out参数。
gaussdb=# set behavior_compat_options = 'proc_outparam_override';
SET
gaussdb=# create or replace function func(a out int) return record is
gaussdb$#     type rc is record(c1 int, c2 int);
gaussdb$#     r rc;
gaussdb$# begin
gaussdb$#     r.c1 := 1;
gaussdb$#     r.c2 := 1;
gaussdb$#     a := 999;
gaussdb$#     return r;
gaussdb$# end;
gaussdb$# /
CREATE FUNCTION
gaussdb=# call func(1);
 func  |  a  
-------+-----
 (1,1) | 999
(1 row)
gaussdb=# drop function func;
DROP FUNCTION
-- 创建A兼容模式数据库，并切换到此数据库。
gaussdb=#  CREATE DATABASE ora_compatible_db DBCOMPATIBILITY 'A';
CREATE DATABASE
gaussdb=#  \c ora_compatible_db;
Non-SSL connection (SSL connection is recommended when requiring high-security)
You are now connected to database "ora_compatible_db" as user "omm".
-- record在pkg内部定义，record构造器全部入参赋值时使用=>。
ora_compatible_db=# 
CREATE or REPLACE package PA_TEST1
AS
 PROCEDURE P_DISPLAY1(a NUMBER, b  VARCHAR);
 TYPE t1 IS record(va int,vb int);
 v1 t1;
END PA_TEST1;
/
ora_compatible_db=# CREATE or REPLACE package body PA_TEST1
AS
  PROCEDURE P_DISPLAY1(a NUMBER, b  VARCHAR) AS
 BEGIN
  v1 := t1(va => 1, vb => 2);
  dbe_output.put_line('pkg test1');
 END;
END PA_TEST1;
/
ora_compatible_db=#  CALL PA_TEST1.P_DISPLAY1(b => 'm', a => 1);
 p_display1 
------------
(1 row)
-- record在pkg内部定义，record构造器入参赋值未连续使用=>，提示错误。
ora_compatible_db=# 
CREATE or REPLACE package PA_TEST1
AS
 PROCEDURE P_DISPLAY1(a NUMBER, b  VARCHAR);
 TYPE t1 IS record(va int,vb int);
 v1 t1;
END PA_TEST1;
/
CREATE or REPLACE package body PA_TEST1
AS
  PROCEDURE P_DISPLAY1(a NUMBER, b  VARCHAR) AS
 BEGIN
  v1 := t1(va => 1, 2);
  dbe_output.put_line('pkg test1');
 END;
END PA_TEST1;
/
ora_compatible_db=# CALL PA_TEST1.P_DISPLAY1(b => 'm', a => 1);
ERROR:  positional argument cannot follow named argument
LINE 1: SELECT "17347.t1"(va => 1, 2)
                                   ^
QUERY:  SELECT "17347.t1"(va => 1, 2)
CONTEXT:  referenced column: 17347.t1
PL/pgSQL function p_display1(numeric,character varying) line 2 at assignment
-- 切换回原数据库，并删掉创建的数据库。
ora_compatible_db=# \c postgres;
Non-SSL connection (SSL connection is recommended when requiring high-security)
You are now connected to database "postgres" as user "omm".
gaussdb=# DROP DATABASE ora_compatible_db;
DROP DATABASE
```
