概述

本章概要介绍PRO*C与嵌入式SQL的基本概念,以及PRO*C程序的工作机制即DM的预编译系统。

1.1 功能简介

SQL语言作为结构化的查询语言,可以完成对数据库的定义、查询、更新、控制、维护、恢复、安全管理等一系列操作,充分体现了关系数据库的特征。但SQL语言是非过程性语言,本身没有过程性结构,大多数语句都是独立执行,与上下文无关,而绝大多数完整的应用都是过程性的,需要根据不同的条件来执行不同的任务。因此,单纯用SQL语言很难实现这样的应用。为此,DM数据库提供了SQL的两种使用方式:一种是交互方式,另一种是嵌入方式。

嵌入方式是将SQL语言嵌入到高级语言中,这样一来,既发挥了高级语言数据类型丰富、处理方便灵活的优势,又以SQL语言弥补了高级语言难以描述数据库操作的不足,从而为用户提供了建立大型管理信息系统和处理复杂事务所需要的工作环境。在这种方式下使用的SQL语言称为嵌入式SQL,而嵌入SQL的高级语言称为主语言或宿主语言。DM数据库允许C作为嵌入方式的主语言。在DM系统中,我们将嵌有SQL语句的C语言程序称为PRO*C程序。

嵌入在主语言程序中的SQL语句并不能直接被主语言编译程序识别,必须对这些SQL语句进行预处理,将其翻译成主语言语句,生成由主语言语句组成的目标文件,然后再由编译程序编译成可执行文件,执行该文件,方可得到用户所需要的结果。

DM的PRO*C嵌入工作方式支持的功能如下:

  • 支持国家和军用标准关系数据库语言SQL;
  • 支持嵌入SQL语言的多模块程序设计;
  • 提供对用户透明的查询优化功能;
  • 支持对远程数据库的访问。

1.2 预编译系统的结构与功能

1.2.1 预编译系统的结构

预编译系统的结构如下图所示。

预编译系统的结构

图1.1 预编译系统的结构

1.2.2 预编译系统的功能

预编译系统主要包括词法分析、语法分析、消息生成等几个子系统。

  • 词法分析子系统

在嵌入工作方式下,词法分析子系统从指定的主语言源程序中逐段找出嵌入的SQL声明节或语句段,将它们进行分解,得到一个个单词,顺序填入单词表,供语法分析时使用;而对非SQL嵌入段的主语言正文则直接写入目标文件。在交互工作方式下,词法分析子系统只需要接受用户输入的单个SQL语句或SQL语句块,将它们分解成单词串并顺序填入单词表。

  • 语法分析子系统

语法分析子系统在词法分析的基础上,对单词表中所存入的SQL单词串按SQL语言文本进行初步的合法性检查,并对各种单词进行分类,识别语句中的嵌入变量并进行相应的语法检查。

  • 消息生成模块

在DM中,客户端对数据库的操作都是以消息方式传送给数据库服务器,因此预编译系统应具有将SQL语句转换为消息的功能,这就是消息生成。消息生成的任务是将SQL语句翻译成主语言消息生成语句和消息发送及回收语句,并将它们写入目标文件。需要说明的是,预编译系统并不直接生成消息,而是利用对DPI接口的函数调用实现,这样可以进行必要的封装,模块性也更强。

1.2.3 预编译系统的处理流程

在嵌入工作方式下,预编译系统的功能是:对嵌入的SQL语句段和SQL声明节进行全面的词法、语法检查,然后将SQL语句翻译成主语言语句(即DPI函数调用)写入目标文件中,使目标文件成为一个纯由主语言组成的程序。整个预编译的处理流程如图所示:

预编译系统的处理流程

图1.2 预编译系统的处理流程

1.3 预编译系统配置

1.3.1 预编译系统包含的程序和文件

预编译系统提供的软件有:

  • 预编译命令行运行程序dpc_new.exe;
  • 编译时要使用的文件dpc_dll.h、DPI.h、DPItypes.h、sqlca.h;若兼容ORACLE,则需另外添加sqlca_ora.h、sqlda_ora.h、dpc_ora_dll.h;若兼容DB2,则需另外添加sqlca_db2.h、sqlda_db2.h;
  • 连接时需要的库文件dmdpc.lib(Windows操作系统)或者libdmdpc.a(Linux);
  • 执行时需要的动态库文件dmdpc.dll(Windows操作系统)或者libdmdpc.so(Linux)。

1.3.2 预编译命令的使用方法

预编译时,在命令提示符窗口中输入带参数的dpc_new命令,语法如下:

dpc_new parameter=value {parameter=value}

dpc_new支持的参数含义如下表所示。

表1.1 dpc_new参数
参数 介绍
FILE .pc文件的完整路径,必须指定
TYPE 指定生成文件类型。C代表C源文件,CPP代表C++源文件;默认为C
MODE 编译模式。STD表示标准编译模式;DM表示达梦编译模式;ORACLE表示兼容部分ORACLE语法的编译模式;DB2表示兼容部分DB2语法的编译模式。默认STD编译模式
MACRO 解析宏,如果源pc文件中有##define定义的宏,在文件中使用了宏,若不加此命令,文件中的宏将不能识别
DEFINE 条件编译宏,如果源pc文件中有##defWIN32等条件编译宏,可以根据需要在DEFINE命令中设置对应的条件编译宏,来解析对应的内容。如果要使用多个宏用分号分隔,例如:define=WIN32;DM64
INCLUDE_DIR/INCLUDE 包含的头文件目录,指定pc文件中include的头文件所在的目录。指定多个目录时用分号隔开,例如include_dir=d:\test1;d:\test2
WRITE_DIRECT 解析的文件是否立即可见,缺省为N。当为N时,dpc_new工具解析pc文件时解析完部分就会立即写入C文件;当为Y时,整个pc文件解析完,才会一起写入生成的C文件
OCI_CONNECT 是否使用OCI连接(Y/N),缺省为N
INCLUDE_SQLCA 是否包含sqlca(Y/N),缺省为N
CHAR_MAP 字符串的处理方式,目前只支持STRING、CHARZ
TYPE_MODE 数据类型兼容模式。STD表示标准数据类型;DM表示达梦数据类型;ORACLE表示兼容部分ORACLE数据类型;DB2表示兼容DB2数据类型。缺省为STD(目前仅用来兼容oracle的count(*) sqlda返回类型与长度)
DEL_TMP_FILE 预编译报错时是否删除临时文件,缺省为Y,删除临时文件。使用了INCLUDE_DIR、MACRO参数进行预编译会生成临时文件,报错信息里的行数信息基于临时文件,保留临时文件有利于定位问题
XA_CONNECT 是否使用XA连接,缺省为N
UNSAFE_NULL 允许不使用指示符表列的 NULL 提取,缺省为N,表示不允许不绑定指示符获取NULL值,执行会报错。置为Y表示允许不绑定指示符获取NULL值,执行不会报错
DYN_STMT_WITHOUT_INTO 是否去掉动态绑定的SELECT INTO语句中INTO内容。缺省为N,表示 不去掉INTO。例如: EXEC SQL PREPARE S FROM SELECT C1 INTO :a FROM TEST; 本参数置为Y时会将“INTO :a”去掉
USE_GLOBAL_CTX 是否使用全局变量登记USE上下文(Y/N)。缺省为N,若设置为Y,EXEC SQL CONTEXT USE :ctx 操作不生成C接口,将ctx登记到全局变量,在具体数据库操作时再生成USE ctx的C接口
PARSE 控制对哪一处非SQL代码进行语法分析。可选值FULL/NONE/PARTIAL,暂时实际仅支持FULL,缺省为FULL
VARCHAR_RTRIM 动态绑定插入字符串数据是否按指定长度插入(Y/N)。缺省为N,表示不去掉结尾0,按指定长度插入;Y表示截断字符串结尾0,不按指定长度插入
HELP 打印帮助信息

例1:

假设已有文件为test.pc,则编译命令如下。

./dpc_new FILE=test.pc

如果编译成功将会生成test.c文件,否则dpc_new工具会报错。

例2:

本例说明如何根据设置的define命令,来解析对应的内容。

假设原始文件test.pc内容如下:

##include <stdio.h>

##include <time.h>

##ifdef WIN32

##include <Windows.h>

##include <PROCESS.H>

typedef HANDLE os_thread_t;

typedef LPTHREAD_START_ROUTINE os_thread_fun_t;

##else

##include <pthread.h>

##endif

使用如下命令进行编译:

./dpc_new FILE=test.pc DEFINE=WIN32

则生成的test.c的内容为如下所示。可以看到,因为DEFINE参数指明了使用WIN32条件编译宏,因此编译结果中正确解析了源文件中“ifdef WIN32”部分。

##include <stdio.h>

##include <time.h>

##include <Windows.h>

##include <PROCESS.H>

typedef HANDLE os_thread_t;

typedef LPTHREAD_START_ROUTINE os_thread_fun_t;

若没有使用DEFINE=WIN32参数,使用如下命令进行编译

./dpc_new FILE=test.pc

则生成的test.c的内容为:

##include <stdio.h>

##include <time.h>

##include <pthread.h>

例3:

本例说明MACRO参数的作用。

假设原始文件test.pc内容如下

##define BUFFERMAX 20971520 /* 缓存 1024*1024*20 */

unsigned char buffer[BUFFERMAX];

如果编译命令中不加MACRO=Y,那么在嵌入式SQL语句中使用buffer变量就无法识别BUFFERMAX。使用MACRO=Y后,生成的C文件将所有使用BUFFERMAX地方用20971520替代。上面的pc将解析为下面内容:

##include "dpc_dll.h"

/* Thread Safety */

typedef void * sql_context;

typedef void * SQL_CONTEXT;

unsigned char buffer [ 20971520 ] ;
注意

如果指定了INCLUDE_DIR目录,则默认MACRO=Y

1.3.3 编译目标代码文件时的编译选项

_OciConnect:目标文件需要使用dci.dll时,包含头文件dci.h,在编译时应该加上该选项。

DM64:如果在64位机器上编译,需要加上该选项。由于dpc_new在编译时需要使用DPItypes.h,而在DPItypes.h中定义了slength和ulength类型,如下所示:

##ifdef DM64

typedef sdint8 slength;

typedef udint8 ulength;

##define SLENGTH_MAX SDINT8_MAX

##define ULENGTH_MAX UDINT8_MAX

##else

typedef sdint4 slength;

typedef udint4 ulength;

##define SLENGTH_MAX SDINT4_MAX

##define ULENGTH_MAX UDINT4_MAX

##endif

因此,如果64位环境下编译应用时没加DM64宏,会导致DPI接口调用异常。

微信扫码
分享文档
扫一扫
联系客服