Pro*C 教程

2025年3月17日 | 阅读18分钟
Pro*C Tutorial

在本教程中,我们将涵盖以下主题


什么是 Pro*C?

Pro*C 意味着创建一个嵌入了 SQL 语句的程序。我们可以借助 Pro*C 访问 Oracle 数据库。C 编程语言通过操作或检索 Oracle 数据库中的数据提供了数据处理的灵活性。因此,我们可以说 Pro*C 允许 C 编程语言C 程序 连接到 Oracle 数据库并根据我们的需求进行操作。


如何编译 Pro*C 程序?

Oracle 软件提供了 PROC 编译器(Oracle Precompiler),该编译器处理包含嵌入式 SQL 语句的 C 程序。

什么是 Oracle 预编译器?

Oracle 预编译器是一种编程工具,允许用户在高级源程序中嵌入 SQL 语句。该编译器将源程序作为输入,将嵌入的 SQL 语句替换为 oracle 运行时库调用,然后可以编译、链接和执行此修改后的程序。

Pro*C 程序的整个编译过程如下

Pro*C Tutorial
  • 首先,我们创建一个包含 SQL 语句的 C 程序,然后将其保存为 '.PC' 扩展名。这里,'.PC' 表示该程序是 Pro*C 程序。
  • 创建程序后,我们使用 Oracle 提供的 PROC 编译器来编译程序。PROC 编译器生成 .c 文件,其中所有 SQL 语句都被 Oracle 运行时库中已预定义的功能替换。
  • 由 PROC 编译器创建的文件将由 Pro*C 支持的 C 编译器再次编译。在 Windows 中,PROC 编译器支持 Microsoft Visual C++ 编译器。
  • C 编译器将创建一个 .exe 文件。
  • 现在,我们最后运行 .exe 文件。

为什么我们需要 Pro*C 编译器?

  • Pro*C 编译器允许您在 C 程序中嵌入 SQL 语句,并提供所需的用户界面。
  • 与许多其他开发工具不同,Pro*C 允许您自定义应用程序。它创建了结合了最新窗口技术和鼠标技术的用户界面。有时,我们可能无法从其他开发工具生成报表,但可以通过从 Oracle 数据库检索数据来实现。

要求

Pro*C 的主要要求是安装 Pro*C 软件。当我们安装 Oracle 数据库时,我们必须确保选择了 Pro*C 组件。要检查 Oracle 的安装是否包含 Pro*C 组件,可以通过检查 Oracle 的 PRECOMP 目录来完成。


目录结构

当我们安装 Oracle 时,会在我们的硬盘上为 Oracle 产品创建一个目录结构。主 Oracle 目录将包含 Pro*C 所需的子目录和文件。

当我们安装 Oracle 中的 Pro*C 时,Oracle Universal Installer 会在 ORACLE_BASE\ORACLE_HOME 目录中创建一个名为 precomp 的目录。此子目录,即 precomp,包含可执行文件、库文件和一些示例如下:

precomp 目录结构

目录描述
\admin包含配置文件。
\demo\proc包含 Pro*C 的示例程序。
\demo\sql包含示例程序的 sql 脚本。
\doc\proc包含 pro*c 的文档文件。
\help\proc包含 Pro*C 的帮助文件。
\lib\msvc包含 Pro*C 的库文件
\mesg包含消息文件。
\misc\proc包含 Pro*C 的杂项文件。
\public包含带有 .h 扩展名的头文件。

限制

所有 Windows 操作系统 都可以包含文件名和目录名中的空格,但 Oracle Pro*C 预编译器不会预编译包含文件名中空格的文件。

例如,如果文件名是 the first program.pc,则此文件名无效。


嵌入式 SQL 语句

这里,嵌入式 SQL 意味着将 SQL 语句放入源程序中。由于我们将语句放在 C 程序中,因此 C 程序也称为宿主程序,而我们使用的语言称为宿主语言。Pro*C 提供了在程序中嵌入 SQL 语句的能力。

嵌入式 SQL 语句有两种类型

  • 可执行语句
  • 指令

可执行语句

可执行语句是允许您操作 Oracle 数据库中数据的 SQL 语句。这些语句调用 Oracle 运行时库。它还允许您的程序连接到 Oracle 数据库、定义查询、操作数据以及处理事务。这些语句可以写在可以放置 C 可执行语句的地方。

指令

指令或声明性语句是既不调用 Oracle 运行时库也不操作 Oracle 数据的 SQL 语句。它用于声明 Oracle 对象、SQL 对象。这些语句可以写在可以声明 C 变量的地方。


Pro*C 语法

在 C 程序中,所有 SQL 语句都必须以 EXEC SQL 开头,并以分号 ; 结尾。我们可以在程序中的任何位置编写 SQL 语句,但有一个限制,即声明性语句不应出现在可执行语句之后。

假设我们想根据学生的 ID 从数据库中检索学生成绩,那么它的程序将这样编写

预处理器指令

当我们在 C 中处理 Pro*C 时,我们可以使用的预处理器指令是 #include 和 #if。但是,Pro*C 不认识 #define 指令。让我们通过下面给出的简单场景来理解这一点。

上面的代码是无效的,因为 Pro*C 不支持 #define 指令。


宿主变量

宿主变量是与嵌入式 SQL 语句一起使用的宿主语言的变量。宿主变量是 Oracle 和 C 程序之间通信的关键。这些变量的声明方式与我们在 C 程序中的声明方式类似,并且可以被我们的程序和 Oracle 引用。

宿主变量可以放置在 SQL 表达式使用的地方,并且这些变量在 BEGIN DECLARE SECTION 和 END DECLARE SECTION 之间声明。当我们编写 SQL 语句时,宿主变量前面会加上冒号 ':'。

以下是 Oracle 支持的 C 数据类型列表

  • char
  • char[n]
  • int
  • short
  • long
  • float
  • double
  • VARCHAR[n]

指针

指针变量也可以用作 SQL 语句中的宿主变量。让我们通过一个简单的例子来理解。

在上面的代码中,我们声明了一个整数类型的指针变量,即 *age。声明后,我们执行一个 SELECT 语句,其中我们从 student 表中检索 age 的值,然后我们将 age 的值存储在宿主变量 age 中。结果将存储在 *age 中,而不是 age 中。

结构

C 结构也用于 Pro*C。结构成员变量可以作为宿主程序中的宿主变量。当我们在 SQL 语句中提供结构名称时,每个宿主变量前面都必须加上冒号 ':',并且必须紧跟在宿主变量之后。

在上面的代码中,我们创建了一个名为 student 的结构,其中包含两个变量,即 student_id 和 name。创建结构后,我们声明了一个类型为 student 的变量 s1。然后,我们使用 insert 命令将这两个变量的值插入数据库。

数组

数组可以用作嵌入式 SQL 语句中的宿主变量。让我们通过一个简单的例子来理解。

在上面的代码中,我们创建了一个整数类型的单维数组。我们实现 SQL INSERT 命令,该命令将一次性插入所有 10 个元组。

让我们看另一个使用二维数组的例子。

在 Pro*C 中,数组只能是单维的。但是,Pro*C 成功预编译了上面的代码,因为它将二维数组视为字符的单维数组,而不是字符的二维数组。

正如我们在上面的示例中所示,我们可以使用指示符变量在 SELECT 语句中确定输出宿主变量是否包含 NULL 或截断值。下表显示了 Oracle 可能返回的指示符变量值及其描述

Oracle 返回的值描述
-1表示列的值为 NULL,则宿主变量的值是不确定的。
0将完整列值赋给宿主变量。
>0将截断值赋给宿主变量。
-2将截断值赋给宿主变量。

如果我们想在 struct 中创建宿主变量的指示符变量,我们可以通过在 struct 中为每个宿主变量创建一个指示符变量来轻松实现。要在 SQL 语句中添加指示符变量的名称,我们需要编写结构指示符变量的名称,该名称前面必须带有冒号 ':',并且必须紧跟在宿主变量之后。


数据类型等价

这是一个非常重要的特性,它增加了应用程序的灵活性。这意味着您可以根据 Oracle 如何解释输入数据和格式化输出数据来定制应用程序。

Oracle 包含两种数据类型

  • 内部数据类型
  • 外部数据类型

内部数据类型: Oracle 使用这些数据类型来定义数据如何在列中存储。

外部数据类型: Oracle 使用这些数据类型来格式化输出数据,然后这些输出数据将存储在宿主变量中。

让我们看看如何等价数据类型。

在逐个变量的基础上,我们使用 var 语句进行等价。var 语句的语法如下

例如,我们想从 student 表中检索学生姓名;然后,我们需要将这些学生姓名传递给接受 C 风格字符串的函数(最后一个字符必须是终止字符 '\0')。为了将宿主变量等价于 String 外部数据类型,我们使用以下代码:

该列,即 student name,包含 11 个字符。由于列 student name 包含 11 个字符,因此我们需要分配 12 个字符(11 个 student name 字符加上终止符 '\0')。我们使用 STRING 数据类型,它提供与 C 风格字符串的接口。Oracle 将自动添加 '\0' 字符。

到目前为止,我们等价了内置数据类型,即在上面的示例中,我们将 char 数组等价于 Oracle 外部数据类型(String)。我们还可以使用 TYPE 命令等价用户定义的数据类型。type 语句的语法如下


动态与静态 SQL 语句

主要使用静态 SQL 语句处理固定应用程序,但有时程序需要动态创建 SQL 语句。要创建动态 SQL 语句,首先,我们需要将 SQL 语句存储在字符串变量中。存储语句后,我们使用 PREPARE 语句将字符字符串转换为 SQL 语句。最后,我们使用 EXECUTE 语句执行该语句。让我们通过一个例子来理解这个场景。


交易

Oracle Pro*C 也遵循 SQL 标准定义的事务概念。事务是一系列语句,Oracle 使用这些语句来永久保存所有更改或撤销自事务开始以来的所有更改。我们使用两个语句,即 EXEC SQL COMMIT 和 EXEC SQL ROLLBACK。EXEC SQL COMMIT 语句用于永久保存自事务开始以来的所有更改。EXEC SQL ROLLBACK 语句用于撤销自事务开始以来的所有更改。如果我们不编写 EXEC SQL COMMIT 语句就开始下一个事务,那么在此事务期间所做的所有更改都将被丢弃。


错误处理

C 编程提供了我们在源程序中使用的内置错误处理机制。错误处理是一种提供源程序状态的机制。我们需要一种处理错误的机制,因此 Pro*C 包含以下两种错误处理概念:

  • SQLCA (SQL Communication Area)
  • Whenever 语句

SQLCA

SQLCA (SQL Communication Area) 是我们的程序用于检查错误的 C 语言数据结构或区域。此数据结构包含 Oracle 使用的一些预定义变量。这些变量包含在运行时传递的程序的 C 语言状态信息。

sqlca 的结构如下

SQLCA 组件

以下是 SQLCA 的组件

  • sqlcaid:它是一个 char 字符数组,初始化为“SQLCA”,用于确定 SQL 通信区域。
  • sqlcabc:它被声明为整数类型,用于保存 SQLCA 结构的大小(以字节为单位)。
  • sqlcode:它被声明为整数类型,存储最近执行的 SQL 语句的状态代码。状态确定 SQL 语句的 C 语言结果,结果可能 C 语言如下:
结果描述
0语句已成功执行,没有错误。
>0执行语句时发生了一些错误。例如,当我们使用带有 Where 子句的 SELECT 命令时,Where 子句条件中没有找到这样的行。
<0在这种情况下,由于数据库、系统、应用程序或网络错误,语句未执行。
  • sqlerrm:它被定义为 sqlca 内部的一个结构。

此字段包含两个组件

sqlerrml:它被声明为整数类型,用于保存 sqlerrmc 中存储的文本消息的长度。

sqlerrmc:它被声明为字符串,用于保存与 sqlcode 中存储的错误代码相对应的文本消息。

  • sqlerrp:它被声明为字符串,但保留供将来使用。
  • sqlerrd:它被声明为整数数组,包含六个元素。
字段描述
sqlerrp[0]保留供将来使用。
sqlerrp[1]保留供将来使用。
sqlerrp[2]它包含 SQL 语句处理的行数。
sqlerrp[3]保留供将来使用。
sqlerrp[4]它包含最近执行的语句中错误开始的字符位置。
sqlerrp[5]保留供将来使用。
  • sqlwarn:它被声明为具有八个元素的字符数组。这些元素用作 sqlca 中的警告标志。如果设置了标志,Oracle 会为该元素赋值 'W'。
字段描述
sqlwarn[0]仅当另一个标志被设置时才设置它。
sqlwarn[1]当 Oracle 将截断值赋给输出宿主变量时设置。
sqlwarn[2]当在计算 SUM、MAX、MIN、AVG 等 SQL 聚合函数时未考虑 NULL 列值时设置。
sqlwarn[3]当使用 SELECT 语句检索的列数与 INTO 子句中指定的宿主变量数不相等时设置。
  • sqlext:它被声明为保留供将来使用的字符串。

Whenever 语句

Whenever 语句用于错误处理。它执行隐式的错误检查和处理。Whenever 语句的语法如下

当执行 Whenever 语句时,Oracle 将自动检查 SQLCA 是否满足 Whenever 语句中提到的条件。如果在 sqlca 中找到该条件,则将执行 Whenever 语句中给出的操作。

条件可以是 NOT FOUND、SQLERROR、SQLWARNING,动作可以是 CONTINUE、GOTO label、STOP、DO routine。

条件可以是以下类型

  • SQLWARNING:如果 oracle 返回警告,则设置 sqlwarn[0]。
  • SQLERROR:如果 oracle 返回错误,则 sqlcode 的值将为负数。
  • NOT FOUND:如果 Oracle 无法根据 SELECT 语句的 WHERE 子句中提到的条件找到行,则 sqlcode 的值将为正数。

如果 Oracle 找到任何上述条件,则可以采取以下操作

  • CONTINUE:如果可能,程序将继续执行下一条语句。
  • DO:在此操作中,控制将转移到程序中的错误处理函数。当控制到达错误处理函数的末尾时,控制将转移到失败的 SQL 语句之后的语句。
  • DO BREAK:此 break 语句主要在我们的程序中使用,并且可以作为循环中的操作。当 WHENEVER 语句中的条件得到满足时,我们的程序将退出循环。
  • DO CONTINUE:此 continue 语句主要在我们的程序中使用,并且可以作为循环中的操作。当 WHENEVER 语句中的条件得到满足时,我们的程序将在循环内继续下一迭代。
  • GOTO:程序控制转移到带标签的语句。
  • STOP:我们的程序停止运行。当满足 WHENEVER 条件时,将调用 exit() 函数来停止程序的执行。

创建程序的步骤

以下是创建和运行程序所需的步骤

  • 首先,我们需要安装 Oracle 数据库和 Microsoft Visual C++。在 Visual C++ 中,我们将创建包含嵌入式 SQL 语句的 C 程序。该程序将连接到 Oracle 数据库。
  • Oracle 数据库包含内置的 PROC 组件。要检查 PROC 是否已成功安装,请打开 cmd 并输入 'proc' 命令。
Pro*C Tutorial

在命令提示符中输入 proc 命令后,我们按 Enter 键

Pro*C Tutorial

上面的屏幕显示 proc 已成功安装。

  • 现在,我们将在 Visual C++ 中创建 C 程序。打开 Visual C++。当我们打开 Visual C++ 时,将出现下图
Pro*C Tutorial
  • 单击顶部菜单上的 File。将鼠标移到 New 上,然后单击 Project。
    Pro*C Tutorial
  • 当我们单击 Project 时,将出现下图
Pro*C Tutorial

在上面的屏幕中,单击 Visual C++ 类别下左侧的 General,然后单击 Empty Project。现在,我们需要为此空项目提供一个名称。

Pro*C Tutorial

在上面的屏幕中,我们可以看到我们将项目名称命名为 Demo。

  • 为项目命名后,我们单击 OK 按钮。
    Pro*C Tutorial

在上面的屏幕中,我们可以看到我们的项目工作区已创建。在最左侧,我们可以看到项目层次结构,其中包含 External Dependencies、Header Files、Resource Files 和 Source Files。

  • 现在,我们需要添加 Oracle 的库文件,因此右键单击 Header Files,然后将鼠标光标悬停在 Add 上,然后单击 Existing item。
Pro*C Tutorial
  • 导航到包含 precomp 作为子目录的 oracle 文件夹。单击 precomp。
Pro*C Tutorial

当我们单击 precomp 文件夹时,将出现下图

Pro*C Tutorial

单击上图中显示的 lib 文件夹。

现在添加两个对象库文件,即 orasql19,以及另一个是 orasqx19,它们位于 msvc 文件夹中。

Pro*C Tutorial
Pro*C Tutorial

添加上述两个库文件后,我们的 Solution Explorer 窗口将如下所示

Pro*C Tutorial

在上图中,高亮显示的区域表明这两个库文件已成功添加到我们的项目中。

  • 现在,我们在项目中添加源代码。为此,右键单击 Source files,将鼠标光标悬停在 Add 上,然后单击 New item
    Pro*C Tutorial
  • 单击 New item 后,将出现下图
Pro*C Tutorial

在上面的屏幕中,单击左侧的 Code,然后单击 C++ File。我们还为文件提供了名称 first,并带有 .pc 扩展名。

  • 为源文件命名后,我们单击 Add 按钮。
Pro*C Tutorial

在上面的屏幕中,我们可以看到我们添加的文件的工作区已创建。

  • 以下是 pc 文件的代码
  • 打开 cmd,然后导航到存储 first.pc 文件的文件夹,即 E:\Demo\Demo
Pro*C Tutorial
  • 现在,我们使用 proc 编译器预编译 first.pc 程序,如下图所示
Pro*C Tutorial
Pro*C Tutorial

在上面的屏幕中,我们可以观察到 after first.pc by Oracle precompiler 编译后,first.c 已被创建。

  • 现在,我们将 first.c 文件添加到 Visual C++ 中。要添加此文件,请右键单击 Source files,然后将鼠标光标悬停在 Add 上,然后单击 Existing item。下图显示 first.c 文件已添加到 Visual C++ 中。
Pro*C Tutorial
  • first.pc 编译后,first.c 的代码将是

运行

我们可以通过单击顶部菜单中的 Debug,然后单击 Start Debugging 来运行我们的程序。

Pro*C Tutorial