Oracle Pro*C/C++ (六):嵌入式SQL数据类型

934 阅读4分钟

C语言开发过程中,需要对数据库进行操作,使用 Oracle 数据库一般会采用Oracle Pro*C/C++ 预编译器。

本文章参考Oracle官方文档和自我实践,实验环境为 RHEL7 和 Oracle19c,详细介绍 Oracle Pro*C/C++ 预编译器,了解它在开发操作 Oracle 数据的应用程序中的作用,并了解它使您的应用程序能够做什么,具体如使用。


Oracle数据类型

Oracle 内部数据类型指定 Oracle 如何在数据库表中存储列值,以及用于表示伪列值(如 NULL、SYSDATE、USER 等)的格式。

对于存储在数据库列中的值,Oracle 使用如图所示的内部数据类型:

NameDescription
VARCHAR2变长字符串,<= 4000 字节
NVARCHAR2 or NCHAR VARYING可变长度的单字节或国家字符串,<= 4000 字节
NUMBER具有精度和小数位数的数值,以 base-100 格式表示
LONG变长字符串 <=2**31-1 字节
BINARY_FLOAT32 位浮点数,4 字节
BINARY_DOUBLE64 位浮点数,8 字节
TIMESTAMP日期的年、月和日值,以及时间的时、分和秒值,7 或 11 个字节
DATE定长日期+时间值,7 个字节
INTERVAL YEAR以年和月为单位存储一段时间,5 个字节
INTERVAL DAY以天、小时、分钟和秒为单位存储一段时间,共 11 个字节
RAW可变长度的二进制数据,<=2000 字节
LONG RAW变长二进制数据,<=2**31-1 字节]
ROWID二进制值
UROWID二进制值,<=4000 字节
CHAR定长字符串,<=2000 字节
NCHAR定长单字节或国家字符串,<= 2000 字节
CLOB字符数据,<= 4 GB
NCLOB国家字符集数据,<= 4 GB
BLOB二进制数据,<= 4 GB
BFILE外部文件二进制数据,<= 4 GB

这些内部数据类型可能与 C 数据类型完全不同。例如,C 没有与 Oracle NUMBER 数据类型等效的数据类型。但是,NUMBER 可以在 C 数据类型(例如float和double )之间转换,但有一些限制。例如,Oracle NUMBER 数据类型允许多达 38 位十进制数字的精度,而当前的 C 实现无法表示具有这种精度的double。

Oracle NUMBER 数据类型精确地表示值(在精度限制内),而浮点格式不能精确地表示诸如 10.0 之类的值。

使用 LOB 数据类型存储非结构化数据(文本、图形图像、视频剪辑或声音波形)。BFILE 数据存储在数据库外的操作系统文件中。LOB 类型存储指定数据位置的定位符。

NCHAR 和 NVARCHAR2 用于存储多字节字符数据。

C语言数据类型

可以根据 C 编程语言的规则声明宿主变量,指定 Oracle 程序接口支持的 C 数据类型。
C 数据类型必须与源或目标数据库列的数据类型兼容。

如图显示了在声明宿主变量时可以使用的 C 数据类型和伪类型。只有这些数据类型可用于宿主变量, 主机变量的 C 数据类型:

C 数据类型或伪类型描述
char单个字符
char[n]n 字符数组(字符串)
int整数
short小整数
long大整数
long long非常大的(8 字节)整数
float浮点数(通常是单精度)
double浮点数(总是双精度)
VARCHAR[n]变长字符串

宿主变量

宿主变量是宿主程序和 Oracle 之间通信的关键。通常,预编译器程序将数据从宿主变量输入到 Oracle,然后 Oracle 将数据输出到程序中的宿主变量。Oracle 将输入数据存储在数据库列中,并将输出数据存储在程序主变量中。

宿主变量可以是任何解析为标量类型的任意 C 表达式。但是,宿主变量也必须是左值。还支持大多数主机变量的主机数组。

如图显示了兼容的 Oracle 内部数据类型:

Internal TypeC TypeDescription
VARCHAR2(Y)
(Note 1)
char单个字符
CHAR(X)
(Note 1)
char[n]
VARCHAR[n]
int
short
long
long long
float
double
n 字节字符数组
n 字节变长字符数组
整数
小整数
大整数
非常大的(8 字节)整数
浮点数
双精度浮点数
数字
NUMBERint整数
NUMBER(P,S)
(Note 2)
short
int
long
float
double
char
char[n]
VARCHAR[n]
小整数
整数
大整数
浮点数
双精度浮点数
数字
单个字符
n 字节字符数组
n 字节变长字符数组
DATEchar[n]
VARCHAR[n]
n 字节字符数组
n 字节变长字符数组
LONGchar[n]
VARCHAR[n]
n 字节字符数组
n 字节变长字符数组
RAW(X)
(Note 1)
unsigned char[n]
VARCHAR[n]
n 字节字符数组
n 字节变长字符数组
LONG RAWunsigned char[n]
VARCHAR[n]
n 字节字符数组
n 字节变长字符数组
ROWIDunsigned char[n]
VARCHAR[n]
n 字节字符数组
n 字节变长字符数组
Notes:
1. X 的范围是 1 到 2000。1 是默认值。Y 的范围是 1 到 4000。
2. P 范围从 1 到 38。S 范围从 -84 到 127。

简单 C 类型的一维数组也可以用作宿主变量。对于 char[n] 和 VARCHAR[n],n指定最大字符串长度,而不是数组中的字符串数。二维数组只允许用于 char[m][n] 和 VARCHAR[m][n],其中m指定数组中的字符串数,n指定最大字符串长度。

支持指向简单 C 类型的指针。指向 char[n] 和 VARCHAR[n] 变量的指针应该声明为指向 char 或 VARCHAR 的指针(没有长度说明)。但是,不支持指针数组。

宿主结构

可以使用 C 结构来包含主变量。您在 SELECT 或 FETCH 语句的 INTO 子句以及 INSERT 语句的 VALUES 列表中引用包含主变量的结构。宿主结构的每个组件都必须是合法的 Pro*C/C++ 宿主变量,如主机变量的 C 数据类型所定义。

当结构体用作宿主变量时,SQL 语句中仅使用结构体的名称。但是,该结构的每个成员都会向 Oracle 发送数据,或者在查询时从 Oracle 接收数据。以下示例显示了用于将员工添加到 EMP 表的主机结构:

typedef struct 
{ 
    char  emp_name[11]; /* one greater than column length */ 
    int   emp_number; 
    int   dept_number; 
    float salary; 
} emp_record; 
... 
/* define a new structure of type "emp_record" */ 
emp_record new_employee; 
 
strcpy(new_employee.emp_name, "CHEN"); 
new_employee.emp_number = 9876; 
new_employee.dept_number = 20; 
new_employee.salary = 4250.00; 
 
EXEC SQL INSERT INTO emp (ename, empno, deptno, sal) 
    VALUES (:new_employee); 

成员在结构中声明的顺序必须与关联列在 SQL 语句中出现的顺序相匹配,如果省略了 INSERT 语句中的列列表,则在数据库表中出现的顺序必须匹配。

宿主结构和数组

一个阵列是相关的数据项,被称为的集合的元素,具有单个变量名相关联。当声明为宿主变量时,该数组称为宿主数组。同样,声明为数组的指标变量称为指标数组。指标数组可以与任何主机数组相关联。

主机数组可以让使用单个 SQL 语句操作整个数据项集合,从而提高性能。除了少数例外,可以在任何允许标量宿主变量的地方使用宿主数组。此外,可以将指标数组与任何主机数组相关联。

可以使用主机数组作为主机结构的组件。在以下示例中,使用包含数组的结构向 EMP 表中插入三个新条目:

struct 
{ 
    char emp_name[3][10]; 
    int emp_number[3]; 
    int dept_number[3]; 
} emp_rec; 
... 
strcpy(emp_rec.emp_name[0], "ANQUETIL"); 
strcpy(emp_rec.emp_name[1], "MERCKX"); 
strcpy(emp_rec.emp_name[2], "HINAULT"); 
emp_rec.emp_number[0] = 1964; emp_rec.dept_number[0] = 5; 
emp_rec.emp_number[1] = 1974; emp_rec.dept_number[1] = 5; 
emp_rec.emp_number[2] = 1985; emp_rec.dept_number[2] = 5; 
 
EXEC SQL INSERT INTO emp (ename, empno, deptno) 
    VALUES (:emp_rec); 
...