PROC操作DM8达梦数据库

一、简介

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

二、预编译系统的结构与功能

对嵌入的 SQL 语句段和 SQL 声明节进行全面的词法、语法检查,然后将 SQL 语句翻译成主语言语句(即 DPI 函数调用)写入目标文件中,使目标文件成为一个纯由主语言组成的程序。

在这里插入图片描述

在这里插入图片描述

三、预编译系统配置环境+库文件

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

  • 预编译命令行运行程序 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)。

四、dpc_new命令汇总

[dmdba@localhost bin]$ ./dpc_new FILE=/opt/test.pc

## 收集的命令
./dpc_new FILE=$file MODE=ORACLE MACRO=y TYPE=CPP CHAR_MAP=string
./dpc_new FILE=main.pc MODE=ORACLE TYPE=CPP

g++ -m64 -o main main.cpp -I /opt/dmdbms/include -L /opt/dmdbms/bin -Wall -O -ldmdcp -ldmdpc

在这里插入图片描述

五、操作步骤

1、dmdba配置用户的环境变量

## 修改
vim ~/.bash_profile										

export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/opt/dmdbms/bin:/opt/dmdbms/include:/opt/dmdbms/drivers/dci"
export DM_HOME="/opt/dmdbms"
export PATH=$PATH:/opt/dmdbms/bin

## 生效:
source ~/.bash_profile

2、创建表结构

CREATE TABLE "REGISTRY"
(
"REGKEY_ID" VARCHAR2(32) NOT NULL,
"REGKEY_TYPE" CHAR(1) NOT NULL,
"REGKEY_NAME" VARCHAR2(128) NOT NULL,
"REGKEY_STATUS" CHAR(1) NOT NULL,
"REGKEY_PARENT" VARCHAR2(32) NOT NULL,
"REGKEY_VAL" VARCHAR2(256) NOT NULL,
"DATA_TYPE" VARCHAR2(16) NOT NULL,
"VALID_LEN" NUMBER(5,0) DEFAULT 0 NOT NULL,
"VALID_DEC" NUMBER(5,0) DEFAULT 0 NOT NULL,
"MAX_VAL" VARCHAR2(32) NOT NULL,
"MIN_VAL" VARCHAR2(32) NOT NULL,
"DFT_VAL" VARCHAR2(32) NOT NULL,
"VALID_CHAR" VARCHAR2(256) NOT NULL,
"CTRL_ID" VARCHAR2(32) NOT NULL,
"CTRL_DATA" VARCHAR2(256) NOT NULL,
"SUBSYS" NUMBER(5,0) DEFAULT 0 NOT NULL) STORAGE(ON "MAIN", CLUSTERBTR) ;

CREATE UNIQUE  INDEX "REGISTRY_UI1" ON "REGISTRY"("REGKEY_ID" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;


insert into "REGISTRY" ("REGKEY_ID","REGKEY_TYPE","REGKEY_NAME","REGKEY_STATUS","REGKEY_PARENT","REGKEY_VAL","DATA_TYPE","VALID_LEN","VALID_DEC","MAX_VAL","MIN_VAL","DFT_VAL","VALID_CHAR","CTRL_ID","CTRL_DATA","SUBSYS") values ('VERSION', '1', '1', '1', '1', '1', '1', 1, 1, '1', '1', '1', '1', '1', '1', 1);

3、demo用户

main.pc

#include "main.h"

//  gcc -m64 -o ./main -I ./../../ref-linux/include/dm/ ./main.cpp -ldl -lstdc++ -Wl,-rpath,. -L. -ldl -L./../../ref-linux/lib-x86 -ldmdcp -ldmdpc
//  dpc_new FILE=main.sqx MODE=ORACLE TYPE=CPP

int main(int argc, char **argv) 
{
  signal(SIGSEGV, server_backtrace); // SIGSEGV    11       Core Invalid memory reference  
  signal(SIGABRT, server_backtrace); // SIGABRT     6       Core Abort signal from 
  
  testDM(); 
  return 0;
}

int testDM()
{
  EXEC SQL BEGIN DECLARE SECTION;
    varchar server[32];
    varchar username[32];
    varchar password[32];
  EXEC SQL END DECLARE SECTION;
    
  strncpy((char *)server.arr, "127.0.0.1:5236", sizeof(server.arr)-1); 
  server.len = strlen((const char *)server.arr);
  strncpy((char *)username.arr, "SYSDBA", sizeof(username.arr)-1); 
  username.len = strlen((const char *)username.arr);
  strncpy((char *)password.arr, "SYSDBA", sizeof(password.arr)-1); 
  password.len = strlen((const char *)password.arr);
    
  EXEC SQL CONNECT :username IDENTIFIED BY :password USING :server;
  if (sqlca.sqlcode != 0)
  {
    printf("connetDM fail!\n");
    printf("file=[%s:%d] func=[%s] sqlca.sqlcode=%d\n",__FILE__,__LINE__,__FUNCTION__, sqlca.sqlcode);
    return -1;
  }
  printf("connetDM success!\n");
  printf("file _ success =[%s:%d] func=[%s] sqlca.sqlcode=%d\n",__FILE__,__LINE__,__FUNCTION__, sqlca.sqlcode);
    
  ST_REGISTRY stRegistry;
  ST_REGISTRY_UIDX1 stRegistryUidx1;
  DAO_MEMSET(stRegistry);
  DAO_MEMSET(stRegistryUidx1);
  DAO_SET_VCHAR(stRegistryUidx1, szRegkeyId, "VERSION");
  Select_ESQL(stRegistry, stRegistryUidx1);
  printf("VERSION=[%s]\n", stRegistry.szRegkeyVal); 
  
  return 0;
}

int Select_ESQL(ST_REGISTRY &p_refstRegistry, const ST_REGISTRY_UIDX1 &p_refstRegistryUidx1)
{
  EXEC SQL INCLUDE SQLCA;
  EXEC SQL BEGIN DECLARE SECTION;
    char szRegkeyId_UI1[32 + 1];                                                // 注册项标识
    char szRegkeyType_UI1[1 + 1];                                               // 注册项类型
    char szRegkeyName_UI1[128 + 1];                                             // 注册项名称
    char szRegkeyStatus_UI1[1 + 1];                                             // 注册项状态
    char szRegkeyParent_UI1[32 + 1];                                            // 注册项上级
    char szRegkeyVal_UI1[256 + 1];                                              // 注册项数值
    char szDataType_UI1[16 + 1];                                                // 数据类型
    short siValidLen_UI1;                                                       // 有效长度
    short siValidDec_UI1;                                                       // 有效精度
    char szMaxVal_UI1[32 + 1];                                                  // 最大数值
    char szMinVal_UI1[32 + 1];                                                  // 最小数值
    char szDftVal_UI1[32 + 1];                                                  // 缺省数值
    char szValidChar_UI1[256 + 1];                                              // 有效字符
    char szCtrlId_UI1[32 + 1];                                                  // 控件标识
    char szCtrlData_UI1[256 + 1];                                               // 控件数据
    short siSubsys_UI1;                                                         // 子系统
  EXEC SQL END DECLARE SECTION;

  int iRetCode = RTMSG_OK;

  // 输出数据结构复位
  memset((void *)&p_refstRegistry, 0x00, sizeof(p_refstRegistry));

  // 主键宿主变量赋值
  DAO_STRNCPY(szRegkeyId_UI1, p_refstRegistryUidx1.szRegkeyId, sizeof(szRegkeyId_UI1));

  // 执行SELECT语句
  EXEC SQL SELECT REGKEY_TYPE, REGKEY_NAME, REGKEY_STATUS, REGKEY_PARENT, REGKEY_VAL, 
                  DATA_TYPE, VALID_LEN, VALID_DEC, MAX_VAL, MIN_VAL, 
                  DFT_VAL, VALID_CHAR, CTRL_ID, CTRL_DATA, SUBSYS
                  INTO :szRegkeyType_UI1, :szRegkeyName_UI1, :szRegkeyStatus_UI1, :szRegkeyParent_UI1, :szRegkeyVal_UI1, 
                       :szDataType_UI1, :siValidLen_UI1, :siValidDec_UI1, :szMaxVal_UI1, :szMinVal_UI1, 
                       :szDftVal_UI1, :szValidChar_UI1, :szCtrlId_UI1, :szCtrlData_UI1, :siSubsys_UI1
                  FROM REGISTRY
                  WHERE REGKEY_ID = :szRegkeyId_UI1;
  if (SQLCODE == SQLCODE_NO_DATA)
  {
    iRetCode = RTMSG_NO_DATA;
    printf("file _ 1=[%s:%d] func=[%s] sqlca.sqlcode=%d\n",__FILE__,__LINE__,__FUNCTION__, sqlca.sqlcode);
    goto __end;
  }
  else if (SQLCODE != SQLCODE_OK)
  {
    printf("file _ != sqlcode_ok =[%s:%d] func=[%s] sqlca.sqlcode=%d\n",__FILE__,__LINE__,__FUNCTION__, sqlca.sqlcode);
    return -1;
  }

  // 输出数据结构赋值
  DAO_SET_VCHAR(p_refstRegistry, szRegkeyId, szRegkeyId_UI1);
  DAO_SET_CHAR1(p_refstRegistry, chRegkeyType, szRegkeyType_UI1[0]);
  DAO_SET_VCHAR(p_refstRegistry, szRegkeyName, szRegkeyName_UI1);
  DAO_SET_CHAR1(p_refstRegistry, chRegkeyStatus, szRegkeyStatus_UI1[0]);
  DAO_SET_VCHAR(p_refstRegistry, szRegkeyParent, szRegkeyParent_UI1);
  DAO_SET_VCHAR(p_refstRegistry, szRegkeyVal, szRegkeyVal_UI1);
  DAO_SET_VCHAR(p_refstRegistry, szDataType, szDataType_UI1);
  DAO_SET_VALUE(p_refstRegistry, siValidLen, siValidLen_UI1);
  DAO_SET_VALUE(p_refstRegistry, siValidDec, siValidDec_UI1);
  DAO_SET_VCHAR(p_refstRegistry, szMaxVal, szMaxVal_UI1);
  DAO_SET_VCHAR(p_refstRegistry, szMinVal, szMinVal_UI1);
  DAO_SET_VCHAR(p_refstRegistry, szDftVal, szDftVal_UI1);
  DAO_SET_VCHAR(p_refstRegistry, szValidChar, szValidChar_UI1);
  DAO_SET_VCHAR(p_refstRegistry, szCtrlId, szCtrlId_UI1);
  DAO_SET_VCHAR(p_refstRegistry, szCtrlData, szCtrlData_UI1);
  DAO_SET_VALUE(p_refstRegistry, siSubsys, siSubsys_UI1);
  p_refstRegistry.bInitialized = true;

__end:
  return iRetCode;
}

static void WidebrightSegvHandler(int signum)  
{  
    void *array[512];  
    size_t size;  
    char **strings;  
    size_t i, j;  
  
    signal(signum, SIG_DFL); /* 还原默认的信号处理handler */  
  
    size = backtrace (array, 512);  
    strings = (char **)backtrace_symbols (array, size);  
  
    fprintf(stderr, "widebright received SIGSEGV! Stack trace:\n");  
    for (i = 0; i < size; i++) {  
        fprintf(stderr, "%d %s \n",i,strings[i]);  
    }  
      
    free (strings);  
}

void server_backtrace(int sig)
{
  WidebrightSegvHandler(sig);
    //打开文件
    time_t tSetTime;
    time(&tSetTime);
    struct tm* ptm = localtime(&tSetTime);
    char fname[256] = {0};
    sprintf(fname, "./dump.%04d-%02d-%02d_%02d_%02d_%02d.log",
            ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,
            ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,
            ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
    FILE* f = fopen(fname, "a");
    if (f == NULL){
        return;
    }
    int fd = fileno(f);

    //锁定文件
    struct flock fl;
    fl.l_type = F_WRLCK;
    fl.l_start = 0;
    fl.l_whence = SEEK_SET;
    fl.l_len = 0;
    fl.l_pid = getpid();
    fcntl(fd, F_SETLKW, &fl);

    //输出程序的绝对路径
    char buffer[4096];
    memset(buffer, 0, sizeof(buffer));
    int count = readlink("/proc/self/exe", buffer, sizeof(buffer));
    if(count > 0){
        buffer[count] = '\n';
        buffer[count + 1] = 0;
        fwrite(buffer, 1, count+1, f);
    }

    //输出信息的时间
    memset(buffer, 0, sizeof(buffer));
    sprintf(buffer, "Dump Time: %d-%d-%d %d:%d:%d\n",
            ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,
            ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
    fwrite(buffer, 1, strlen(buffer), f);

    //线程和信号
    sprintf(buffer, "Curr thread: %u, Catch signal:%d\n",
            (int)pthread_self(), sig);
    fwrite(buffer, 1, strlen(buffer), f);

    //堆栈
    void* DumpArray[256];
    int    nSize =    backtrace(DumpArray, 256);
    sprintf(buffer, "backtrace rank = %d\n", nSize);
    fwrite(buffer, 1, strlen(buffer), f);
    if (nSize > 0){
        char** symbols = backtrace_symbols(DumpArray, nSize);
        if (symbols != NULL){
            for (int i=0; i<nSize; i++){
                fwrite(symbols[i], 1, strlen(symbols[i]), f);
                fwrite("\n", 1, 1, f);
            }
            free(symbols);
        }
    }

    //文件解锁后关闭
    fl.l_type = F_UNLCK;
    fcntl(fd, F_SETLK, &fl);
    fclose(f);
  
    exit(1);  
}

main.h

#include <stdlib.h>
#include <dlfcn.h>
#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <string.h>
#include <string>
#include <unistd.h>
#include <signal.h>
#include <execinfo.h>
#include <dirent.h>
#include <fcntl.h>
#include <sqlca.h>

using namespace std;

#define RTMSG_OK                0
#define RTMSG_NO_DATA           100
#define RTMSG_NO_DATA           100
#define SQLCODE_OK            0
#define SQLCODE_NO_DATA       100
#define SQLCODE  sqlca.sqlcode
#define DAO_STRNCPY(szDest, szSource, iCount) \
{\
  if ((szDest) != NULL && (szSource) != NULL) \
  { \
    memset((void *)(szDest), 0x00, (iCount)); \
    strncpy((szDest), (szSource)[0] == 0x00 ? " " : (szSource), (iCount) - 1); \
  } \
}
#define DAO_SET_CHAR1(vTable, vColumn, vValue) \
{ \
  (vTable).vColumn = (vValue) == ' ' ? 0x00 : (vValue); \
  (vTable).siInd_##vColumn = 1; \
}

#define DAO_SET_VCHAR(vTable, vColumn, vValue) \
{ \
  strncpy((vTable).vColumn, (vValue) == NULL || ((vValue)[0] == ' ' && (vValue)[1] == 0x00) ? "" : (vValue), sizeof((vTable).vColumn) - 1); \
  (vTable).vColumn[sizeof((vTable).vColumn) - 1] = 0x00; \
  (vTable).siInd_##vColumn = 1; \
}
#define DAO_SET_VALUE(vTable, vColumn, vValue) \
{ \
  (vTable).vColumn = (vValue); \
  (vTable).siInd_##vColumn = 1; \
}
#define DAO_MEMSET(vTable) \
{\
  memset((void *)&(vTable), 0x00, sizeof(vTable)); \
}
// 定义数据结构
struct ST_REGISTRY
{
  bool bInitialized;

  char szRegkeyId[32 + 1]; short siInd_szRegkeyId;                              // 注册项标识
  char chRegkeyType; short siInd_chRegkeyType;                                  // 注册项类型
  char szRegkeyName[128 + 1]; short siInd_szRegkeyName;                         // 注册项名称
  char chRegkeyStatus; short siInd_chRegkeyStatus;                              // 注册项状态
  char szRegkeyParent[32 + 1]; short siInd_szRegkeyParent;                      // 注册项上级
  char szRegkeyVal[256 + 1]; short siInd_szRegkeyVal;                           // 注册项数值
  char szDataType[16 + 1]; short siInd_szDataType;                              // 数据类型
  short siValidLen; short siInd_siValidLen;                                     // 有效长度
  short siValidDec; short siInd_siValidDec;                                     // 有效精度
  char szMaxVal[32 + 1]; short siInd_szMaxVal;                                  // 最大数值
  char szMinVal[32 + 1]; short siInd_szMinVal;                                  // 最小数值
  char szDftVal[32 + 1]; short siInd_szDftVal;                                  // 缺省数值
  char szValidChar[256 + 1]; short siInd_szValidChar;                           // 有效字符
  char szCtrlId[32 + 1]; short siInd_szCtrlId;                                  // 控件标识
  char szCtrlData[256 + 1]; short siInd_szCtrlData;                             // 控件数据
  short siSubsys; short siInd_siSubsys;                                         // 子系统
};

struct ST_REGISTRY_UIDX1
{
  char szRegkeyId[32 + 1]; short siInd_szRegkeyId;                              // 注册项标识
};

int testDM();
void server_backtrace(int sig);
int Select_ESQL(ST_REGISTRY &p_refstRegistry, const ST_REGISTRY_UIDX1 &p_refstRegistryUidx1);

4、编译并运行文件

[dmdba@localhost bin]$ ./dpc_new FILE=main.pc MODE=ORACLE TYPE=CPP
[dmdba@localhost bin]$ g++ -m64 -o main main.cpp -I /opt/dmdbms/include -L /opt/dmdbms/bin -Wall -O -ldmdcp -ldmdpc
[dmdba@localhost bin]$ ./main
connetDM success!
file _ success =[main.cpp:58] func=[testDM] sqlca.sqlcode=0
VERSION=[1 

六、Q&A

1. proc编译为c++报出很多警告

先编译加-Wno-write-strings取消警告,避免警告太多无法定位err

2. proc 预编译报错:cannot execute binary file

在这里插入图片描述

碰到这种错误第一反应可能是数据库版本和操作系统版本不匹配,或者安装包不完整,然后查操作系统版本和数据库版本,发现是版本和安装包的 MD5 都是匹配的。
在这里插入图片描述

其他例子

达梦Proc*操作达梦数据库-Fetch例子 https://blog.csdn.net/qq_35349982/article/details/127211857

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
达梦数据库是中国自主研发的商业数据库产品,类似于国际知名的Oracle数据库达梦数据库中的proc pc程序是一种用于实现数据库存储过程和触发器的编程语言。它允许用户在数据库服务器上创建和执行存储过程,以及定义触发器来响应数据库中的事件。 一个典型的达梦数据库proc pc程序的例子是创建一个简单的存储过程,用于查询并返回指定员工的薪水信息。 首先,我们需要在达梦数据库中创建一个存储过程。假设我们有一个名为"get_salary"的存储过程,输入参数是员工的ID,输出参数是薪水。 ``` CREATE PROCEDURE get_salary(IN emp_id INT, OUT salary FLOAT) BEGIN SELECT salary INTO salary FROM employees WHERE employee_id = emp_id; END; ``` 以上代码中,我们定义了一个存储过程"get_salary",它接受一个整型参数"emp_id"作为输入,将找到的薪水值赋给浮点型参数"salary"。 下一步,我们可以在达梦数据库中执行这个存储过程,并传入参数来获取薪水信息。 ``` CALL get_salary(1001, @salary); SELECT @salary; ``` 以上代码中,我们使用"CALL"语句来执行存储过程"get_salary",传入参数"1001"作为员工ID,并将返回的薪水值存储在变量"@salary"中。最后,我们使用"SELECT"语句输出变量"@salary"的值。 通过使用达梦数据库proc pc程序语言,我们可以编写复杂的存储过程和触发器,实现数据库的高级功能,提高数据库的性能和安全性。这是达梦数据库在实际应用中的一个简单例子。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值