Oracle的学习心得和知识总结(三十一)| ODBC开放式数据库连接概述及应用程序开发

注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下:

1、参考书籍:《Oracle Database SQL Language Reference》
2、参考书籍:《PostgreSQL中文手册》
3、EDB Postgres Advanced Server User Guides,点击前往
4、PostgreSQL数据库仓库链接,点击前往
5、PostgreSQL中文社区,点击前往
6、Microsoft 开放式数据库连接 (ODBC),点击前往
7、ODBC 程序员参考,点击前往
8、ODBC 概述,点击前往


1、本文内容全部来源于开源社区 GitHub和以上博主的贡献,本文也免费开源(可能会存在问题,评论区等待大佬们的指正)
2、本文目的:开源共享 抛砖引玉 一起学习
3、本文不提供任何资源 不存在任何交易 与任何组织和机构无关
4、大家可以根据需要自行 复制粘贴以及作为其他个人用途,但是不允许转载 不允许商用 (写作不易,还请见谅 💖)


ODBC开放式数据库连接概述

  • 文章快速说明索引
  • 开放式数据库连接
  • 如何开发应用程序
    • 建立 ODBC DSN
    • 编写 ODBC 程序
    • 编写 OCI 程序



文章快速说明索引

学习目标:

目的:接下来这段时间我想做一些兼容Oracle数据库Real Application Testing (即:RAT)上的一些功能开发,本专栏这里主要是学习以及介绍Oracle数据库功能的使用场景、原理说明和注意事项等,基于PostgreSQL数据库的功能开发等之后 由新博客进行介绍和分享!


学习内容:(详见目录)

1、ODBC开放式数据库连接概述


学习时间:

2023年12月17日 14:07:20


学习产出:

1、ODBC开放式数据库连接概述
2、CSDN 技术博客 1篇


注:下面我们所有的学习环境是Centos7+PostgreSQL16.1+Oracle19c+MySQL5.7

postgres=# select version();version                                                 
---------------------------------------------------------------------------------------------------------PostgreSQL 16.1 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-15), 64-bit
(1 row)postgres=##-----------------------------------------------------------------------------#SQL> select * from v$version; BANNER									    BANNER_FULL 								BANNER_LEGACY									CON_ID
--------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- ----------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production	    Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production	Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production		     0Version 19.3.0.0.0SQL>
#-----------------------------------------------------------------------------#mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.19    |
+-----------+
1 row in set (0.06 sec)mysql>

开放式数据库连接

开放式数据库连接 (ODBC) 是一种广泛接受的应用程序编程接口 (API),适用于数据库访问。其基于 Open Group 和 ISO/IEC 的数据库 API 调用级别接口 (CLI) 规范,并使用结构化查询语言 (SQL) 作为其数据库访问语言。

ODBC 旨在实现最大的互操作性,即单个应用程序能够使用相同的源代码访问不同的数据库管理系统 (DBMS)。数据库应用程序会在 ODBC 接口中调用函数,这些函数在特定于数据库的模块(称为“驱动程序”)中实现。驱动程序的使用将应用程序与特定于数据库的调用隔离,就像打印机驱动程序将字处理程序与特定于打印机的命令隔离一样。由于驱动程序在运行时加载,因此用户需要添加新驱动程序才能访问新的 DBMS;无需重新编译或重新链接应用程序。

ODBC 是为客户应用程序访问关系数据库时提供的一个标准的接口,对于不同的数据库,ODBC 提供了统一的 API,使应用程序调用提供的 API 来访问任何提供了 ODBC 驱动程序的数据库:

  • 应用程序(Application,即对应下图的客户程序):应用程序本身不直接与数据库打交道,主要负责处理并调用ODBC函数,发送对数据库的SQL请求及获取结果
  • 驱动程序管理器(Driver Manager,即对应下图的 ODBC 驱动管理程序):驱动程序管理器是一个带有输入程序的动态链接库(DLL),主要目的是加载驱动程序,处理ODBC调用的初始化调用,提供ODBC调用的参数有效性和序列有效性
  • 驱动程序(Driver,即对应下图的 ODBC 驱动程序):驱动程序是一个完成ODBC函数调用并与数据库相互影响的DLL,这些驱动程序可以处理对于特定的数据的数据库访问请求。对于应用驱动程序管理器送来的命令,驱动程序再进行解释形成自己的数据库所能理解的命令。驱动程序将处理所有的数据库访问请求,对于应用程序来讲不需要关注所使用的是本地数据库还是网络数据库

在这里插入图片描述


总结一下,ODBC 体系结构有四个主要组成部分:

  1. 应用程序:执行处理并调用 ODBC 函数来提交 SQL 语句并检索结果
  2. 驱动程序管理器:代表应用程序加载和卸载驱动程序。 处理 ODBC 函数调用或将其传递给驱动程序
  3. 驱动程序:处理 ODBC 函数调用,将 SQL 请求提交到特定数据源,并将结果返回到应用程序。 如有必要,驱动程序会修改应用程序的请求,以便该请求符合关联的 DBMS 支持的语法
  4. 数据源:由用户想要访问的数据及其关联的操作系统、DBMS 和用于访问 DBMS 的网络平台(如果有)组成

如何开发应用程序

一个ODBC应用程序的编写,通常步骤如下所示:

在这里插入图片描述

任何应用程序都不太可能完全按此顺序调用所有这些函数。但是,大多数应用程序使用这些步骤的一些变体。下图显示了基本的应用程序步骤:

在这里插入图片描述

简单解释一下,例如:

  1. 步骤 1:连接数据源
  2. 步骤 2:初始化应用程序
  3. 步骤 3:生成并执行 SQL 语句
  4. 步骤 4a:提取结果;步骤 4b:提取行计数
  5. 步骤 5:提交事务
  6. 步骤 6:从数据源断开连接

建立 ODBC DSN

DSN(Data Source Name)是用于指定ODBC与相关的驱动程序相对应的一个入口,所有DSN的信息由系统进行管理。一般来讲当应用程序要使用ODBC访问数据库时,就需要指定一个DSN以便于连接到一个指定的ODBC驱动程序。


下面列出了 ODBC Driver for SQL Server 中提供的连接字符串和 DSN 的关键字以及 SQLSetConnectAttr 和 SQLGetConnectAttr 的连接属性:

  • 受支持的 DSN/连接字符串关键字和连接属性

我们这里以连接oracle数据库为例,编写一个odbc应用测试程序。作为服务端的Oracle数据库 机器1如下:

[oracle@dbserver ~]$ ifconfig 
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500inet 192.168.1.14  netmask 255.255.255.0  broadcast 192.168.1.255inet6 2409:8a71:abc:ed70:250:56ff:fe2b:6b00  prefixlen 64  scopeid 0x0<global>inet6 fe80::250:56ff:fe2b:6b00  prefixlen 64  scopeid 0x20<link>ether 00:50:56:2b:6b:00  txqueuelen 1000  (Ethernet)RX packets 3711  bytes 2060244 (1.9 MiB)RX errors 0  dropped 5  overruns 0  frame 0TX packets 1374  bytes 168460 (164.5 KiB)TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536inet 127.0.0.1  netmask 255.0.0.0inet6 ::1  prefixlen 128  scopeid 0x10<host>loop  txqueuelen 1000  (Local Loopback)RX packets 415  bytes 64588 (63.0 KiB)RX errors 0  dropped 0  overruns 0  frame 0TX packets 415  bytes 64588 (63.0 KiB)TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0virbr0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500inet 192.168.122.1  netmask 255.255.255.0  broadcast 192.168.122.255ether 52:54:00:3b:26:0a  txqueuelen 1000  (Ethernet)RX packets 0  bytes 0 (0.0 B)RX errors 0  dropped 0  overruns 0  frame 0TX packets 0  bytes 0 (0.0 B)TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0[oracle@dbserver ~]$
[oracle@dbserver ~]$ sqlplus / as sysdbaSQL*Plus: Release 19.0.0.0.0 - Production on Tue Dec 19 09:57:49 2023
Version 19.3.0.0.0Copyright (c) 1982, 2019, Oracle.  All rights reserved.Connected to an idle instance.SQL> startup;
ORACLE instance started.Total System Global Area 1157624440 bytes
Fixed Size		    9134712 bytes
Variable Size		  352321536 bytes
Database Buffers	  788529152 bytes
Redo Buffers		    7639040 bytes
Database mounted.
Database opened.
SQL> 
SQL> select * from v$version;BANNER									    BANNER_FULL 								BANNER_LEGACY	  CON_ID
--------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- ----------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production	    Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production	Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production		     0Version 19.3.0.0.0SQL>

机器2(CentOS8)配置ODBC连接oracle,步骤如下:

一、安装oracle客户端及oracle ODBC驱动程序(这里一定要注意别下错了,32位还是64位)

// 下载oracle客户端包:https://www.oracle.com/cn/database/technologies/instant-client/linux-x86-64-downloads.html
https://download.oracle.com/otn_software/linux/instantclient/1921000/oracle-instantclient19.21-basic-19.21.0.0.0-1.x86_64.rpmhttps://download.oracle.com/otn_software/linux/instantclient/1921000/oracle-instantclient19.21-sqlplus-19.21.0.0.0-1.x86_64.rpmhttps://download.oracle.com/otn_software/linux/instantclient/1921000/oracle-instantclient19.21-tools-19.21.0.0.0-1.x86_64.rpmhttps://download.oracle.com/otn_software/linux/instantclient/1921000/oracle-instantclient19.21-devel-19.21.0.0.0-1.x86_64.rpmhttps://download.oracle.com/otn_software/linux/instantclient/1921000/oracle-instantclient19.21-odbc-19.21.0.0.0-1.x86_64.rpm

提前安装相关依赖,如下:

[postgres@localhost:~/odbcloc]$ sudo yum install libaio*
...
[postgres@localhost:~/odbcloc]$ sudo yum install libnsl*
...
[postgres@localhost:~/odbcloc]$ sudo yum install libaio.so.1* -y
...
[postgres@localhost:~/odbcloc]$ sudo yum install libnsl.so.1* -y
...
[root@localhost odbc]# ll
total 54924
-rw-rw-r--. 1 postgres postgres 53832016 Dec 19 00:17 oracle-instantclient19.21-basic-19.21.0.0.0-1.x86_64.rpm
-rw-rw-r--. 1 postgres postgres   614204 Dec 19 00:17 oracle-instantclient19.21-devel-19.21.0.0.0-1.x86_64.rpm
-rw-rw-r--. 1 postgres postgres   246728 Dec 19 00:17 oracle-instantclient19.21-odbc-19.21.0.0.0-1.x86_64.rpm
-rw-rw-r--. 1 postgres postgres   703388 Dec 19 00:17 oracle-instantclient19.21-sqlplus-19.21.0.0.0-1.x86_64.rpm
-rw-rw-r--. 1 postgres postgres   837556 Dec 19 00:17 oracle-instantclient19.21-tools-19.21.0.0.0-1.x86_64.rpm
[root@localhost odbc]#
[root@localhost odbc]# rpm -ivh oracle-instantclient19.21-basic-19.21.0.0.0-1.x86_64.rpm 
Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...1:oracle-instantclient19.21-basic-1################################# [100%]
[root@localhost odbc]# 
[root@localhost odbc]# rpm -ivh oracle-instantclient19.21-sqlplus-19.21.0.0.0-1.x86_64.rpm 
Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...1:oracle-instantclient19.21-sqlplus################################# [100%]
[root@localhost odbc]# 
[root@localhost odbc]# rpm -ivh oracle-instantclient19.21-devel-19.21.0.0.0-1.x86_64.rpm 
Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...1:oracle-instantclient19.21-devel-1################################# [100%]
[root@localhost odbc]# 
[root@localhost odbc]# rpm -ivh oracle-instantclient19.21-tools-19.21.0.0.0-1.x86_64.rpm 
Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...1:oracle-instantclient19.21-tools-1################################# [100%]
[root@localhost odbc]# 
[root@localhost odbc]# rpm -ivh oracle-instantclient19.21-odbc-19.21.0.0.0-1.x86_64.rpm 
Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...1:oracle-instantclient19.21-odbc-19################################# [100%]
[root@localhost odbc]#

执行如下命令查看rpm安装后,生成文件及安装路径:

[root@localhost odbc]# rpm -qpl oracle-instantclient19.21-odbc-19.21.0.0.0-1.x86_64.rpm 
/usr/lib/oracle
/usr/lib/oracle/19.21
/usr/lib/oracle/19.21/client64
/usr/lib/oracle/19.21/client64/bin
/usr/lib/oracle/19.21/client64/bin/odbc_update_ini.sh
/usr/lib/oracle/19.21/client64/lib
/usr/lib/oracle/19.21/client64/lib/libsqora.so.19.1
/usr/share/oracle
/usr/share/oracle/19.21
/usr/share/oracle/19.21/client64
/usr/share/oracle/19.21/client64/doc
/usr/share/oracle/19.21/client64/doc/ODBC_LICENSE
/usr/share/oracle/19.21/client64/doc/ODBC_README
[root@localhost odbc]# 

配置环境变量,如下:

[root@localhost odbcloc]# vim /etc/profile
...
#根据实际安装路径配置export ORACLE_HOME=/usr/lib/oracle/19.21/client64export TNS_ADMIN=/usr/lib/oracle/19.21/client64/network/adminexport LD_LIBRARY_PATH=/usr/lib/oracle/19.21/client64/libexport ORACLE_SID=orclexport PATH=$ORACLE_HOME:$PATHexport PATH=$PATH:$HOME/bin:$ORACLE_HOME/bin

source /etc/profile 使其生效

配置监听配置文件,如下:

[postgres@localhost:~/odbc]$ sudo mkdir -p /usr/lib/oracle/19.21/client64/network/admin
[sudo] password for postgres: 
[postgres@localhost:~/odbc]$ 
[postgres@localhost:~/odbc]$ cd /usr/lib/oracle/19.21/client64/network/admin/
[postgres@localhost:/usr/lib/oracle/19.21/client64/network/admin]$ 
[postgres@localhost:/usr/lib/oracle/19.21/client64/network/admin]$ vim tnsnames.ora 
[postgres@localhost:/usr/lib/oracle/19.21/client64/network/admin]$ 
[postgres@localhost:/usr/lib/oracle/19.21/client64/network/admin]$ sudo vim tnsnames.ora 
[postgres@localhost:/usr/lib/oracle/19.21/client64/network/admin]$ 
[postgres@localhost:/usr/lib/oracle/19.21/client64/network/admin]$ cat tnsnames.ora 
ORCL =
(DESCRIPTION =(ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.14)(PORT = 1521)))(CONNECT_DATA =(SERVICE_NAME = ORCL))
)[postgres@localhost:/usr/lib/oracle/19.21/client64/network/admin]$

二、安装 unixODBC 驱动程序管理器,如下:

[root@localhost admin]# yum install unixODBC unixODBC-devel -y
...

若是选择源码编译安装,则获取 unixODBC-2.3.1.tar.gz。 可以从 http://www.unixodbc.org 获取 unixODBC-2.3.1.tar.gz放到/usr/local下,然后运行下述命令:

注:如果自定义其他安装目录,需要配置环境变量,否则使用时可能会出现找不到库的问题

tar zxvf unixODBC-2.3.1.tar.gz
cd unixODBC-2.3.1 
./configure --prefix=/usr/local/unixODBC-2.3.1 --includedir=/usr/include 
--libdir=/usr/lib -bindir=/usr/bin --sysconfdir=/etc
make
make install

三、安装之后运行odbcinst -j,如下:

[postgres@localhost:~]$ odbcinst -j
unixODBC 2.3.7
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
FILE DATA SOURCES..: /etc/ODBCDataSources
USER DATA SOURCES..: /home/postgres/.odbc.ini
SQLULEN Size.......: 8
SQLLEN Size........: 8
SQLSETPOSIROW Size.: 8
[postgres@localhost:~]$

根据odbcinst -j 显示的路径,配置 odbcinst.iniodbc.ini 文件

[postgres@localhost:~]$ sudo vim /etc/odbcinst.ini
[postgres@localhost:~]$ 
[postgres@localhost:~]$ cat /etc/odbcinst.ini
# Example driver definitions# Driver from the postgresql-odbc package
# Setup from the unixODBC package
[PostgreSQL]
Description	= ODBC for PostgreSQL
Driver		= /usr/lib/psqlodbcw.so
Setup		= /usr/lib/libodbcpsqlS.so
Driver64	= /usr/lib64/psqlodbcw.so
Setup64		= /usr/lib64/libodbcpsqlS.so
FileUsage	= 1[ORACLE]
Description = ODBC for Oracle
Driver      = /usr/lib/oracle/19.21/client64/lib/libsqora.so.19.1
FileUsage   = 1[postgres@localhost:~]$

[postgres@localhost:~]$ ls /usr/lib/oracle/19.21/client64/lib/libsqora.so.19.1
/usr/lib/oracle/19.21/client64/lib/libsqora.so.19.1
[postgres@localhost:~]$ 
[postgres@localhost:~]$ ldd /usr/lib/oracle/19.21/client64/lib/libsqora.so.19.1linux-vdso.so.1 (0x00007ffc2750b000)libdl.so.2 => /lib64/libdl.so.2 (0x00007f0dec769000)libm.so.6 => /lib64/libm.so.6 (0x00007f0dec3e7000)libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f0dec1c7000)libnsl.so.1 => /lib64/libnsl.so.1 (0x00007f0debfae000)librt.so.1 => /lib64/librt.so.1 (0x00007f0debda6000)libaio.so.1 => /lib64/libaio.so.1 (0x00007f0debba3000)libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f0deb98b000)libclntsh.so.19.1 => /usr/lib/oracle/19.21/client64/lib/libclntsh.so.19.1 (0x00007f0de777c000)libclntshcore.so.19.1 => /usr/lib/oracle/19.21/client64/lib/libclntshcore.so.19.1 (0x00007f0de71d7000)libodbcinst.so.2 => /lib64/libodbcinst.so.2 (0x00007f0de6fc1000)libc.so.6 => /lib64/libc.so.6 (0x00007f0de6bfc000)/lib64/ld-linux-x86-64.so.2 (0x00007f0decc27000)libnnz19.so => /usr/lib/oracle/19.21/client64/lib/libnnz19.so (0x00007f0de6583000)libltdl.so.7 => /lib64/libltdl.so.7 (0x00007f0de6379000)
[postgres@localhost:~]$

在机器2上先行验证一下,如下:

[postgres@localhost:~]$ sqlplus c##oracle/123456@192.168.1.14:1521/orclSQL*Plus: Release 19.0.0.0.0 - Production on Mon Dec 18 18:54:13 2023
Version 19.20.0.0.0Copyright (c) 1982, 2022, Oracle.  All rights reserved.Last Successful login time: Mon Dec 18 2023 18:53:33 -08:00Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0SQL> show user;         
USER is "C##ORACLE"
SQL> 
SQL> Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
[postgres@localhost:~]$

[postgres@localhost:~]$ sudo vim /etc/odbc.ini
[postgres@localhost:~]$ 
[postgres@localhost:~]$ cat /etc/odbc.ini
[pg]
Description = Test to pg
Driver = PostgreSQL
Database = postgres
Servername = 127.0.0.1
UserName = postgres
Password = 1
Port = 5432
ReadOnly = 0
ConnSettings = set client_encoding to UTF8[oracle_test]
driver = ORACLE
server = 192.168.1.14
port = 1521
ServerName = orcl
UserID = c##oracle
password = 123456[postgres@localhost:~]$

连接测试

[postgres@localhost:~]$ isql -v oracle_test
+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> create table t_a(id int, name varchar(64));
SQLRowCount returns -1
SQL> insert into t_a values(1, 'a');
SQLRowCount returns 1
SQL> insert into t_a values(2, 'b');
SQLRowCount returns 1
SQL> insert into t_a values(3, 'c');
SQLRowCount returns 1
SQL> insert into t_a values(4, 'd');
SQLRowCount returns 1
SQL> insert into t_a values(5, 'jj');
SQLRowCount returns 1
SQL> select * from t_a;
+-----------------------------------------+-----------------------------------------------------------------+
| ID                                      | NAME                                                            |
+-----------------------------------------+-----------------------------------------------------------------+
| 1                                       | a                                                               |
| 2                                       | b                                                               |
| 3                                       | c                                                               |
| 4                                       | d                                                               |
| 5                                       | jj                                                              |
+-----------------------------------------+-----------------------------------------------------------------+
SQLRowCount returns -1
5 rows fetched
SQL>

编写 ODBC 程序

#include <stdio.h>
#include <sqlext.h>int main() {SQLHENV env; // ODBC环境句柄SQLHDBC dbc; // ODBC连接句柄SQLRETURN ret;// Step 1: 初始化环境ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);ret = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, SQL_IS_INTEGER);// Step 2: 分配连接句柄ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);// Step 3: 建立连接ret = SQLDriverConnect(dbc, NULL,(SQLCHAR*)"DRIVER={Oracle};SERVER=<server>;DATABASE=<database>;UID=<username>;PWD=<password>;",SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {printf("Connected to Oracle.\n");// Step 4: 执行SQL查询SQLHSTMT stmt; // SQL语句句柄ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);ret = SQLExecDirect(stmt, (SQLCHAR*)"SELECT * FROM my_table", SQL_NTS);if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {// 处理结果集// ...printf("SQL executed successfully.\n");} else {// 处理错误// ...printf("SQL execution failed.\n");}// Step 5: 释放语句句柄ret = SQLFreeHandle(SQL_HANDLE_STMT, stmt);} else {// 处理连接失败// ...printf("Failed to connect to Oracle.\n");}// Step 6: 断开连接ret = SQLDisconnect(dbc);// Step 7: 释放连接句柄ret = SQLFreeHandle(SQL_HANDLE_DBC, dbc);// Step 8: 释放环境句柄ret = SQLFreeHandle(SQL_HANDLE_ENV, env);return 0;
}

要编译以上的代码,首先需要确保已经安装了ODBC驱动和相关的开发库。接下来,可以使用gcc或其他支持C编译的工具进行编译。例如,使用gcc命令编译该代码:

gcc -o odbc_demo odbc_demo.c -lodbc
gcc -o odbc_demo odbc_demo.c -L/odbc库的路径 -lodbc
#可通过下面的命令查找odbc库的路径
sudo find / -name "libodbc*"

其中,odbc_demo为输出的可执行文件名,odbc_demo.c为上述代码保存的文件名。-lodbc用于链接ODBC库。请注意,编译时可能需要配置包含路径和连接选项,具体取决于所使用的操作系统和ODBC驱动程序。


下面是一个示例,源码odbctest.c如下:

#include <stdio.h>#include <sql.h>
#include <sqlext.h>static void
test_SQLConnect()
{SQLRETURN ret;SQLHENV env;SQLHDBC conn;HSTMT hstmt = SQL_NULL_HSTMT;SQLSMALLINT sdwNative;SQLINTEGER swMsgLen;char buffer[256];char message[1000];SQLCHAR *dsn = (SQLCHAR *) "oracle_test";//CHAR* queryStr="create table t_odbc(id int);";SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);SQLAllocHandle(SQL_HANDLE_DBC, env, &conn);printf("Connecting with SQLConnect...\n");ret = SQLConnect(conn, dsn, SQL_NTS, NULL, 0, NULL, 0);if (SQL_SUCCEEDED(ret)) {printf("connected success!\n");} else {printf("SQLConnect failed.\n");return;}ret = SQLSetConnectAttr(conn,SQL_ATTR_AUTOCOMMIT,(SQLPOINTER)SQL_AUTOCOMMIT_OFF,SQL_IS_UINTEGER);if (SQL_SUCCEEDED(ret)) {printf("set autommit off success!\n");} else {printf("set autommit failed.\n");return;}ret = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt);ret = SQLExecDirect(hstmt, (SQLCHAR *)"create table t_odbc(id int)", SQL_NTS);if (SQL_SUCCEEDED(ret)) {printf("create table success!\n");}else {printf("create table failed.\n");return;}ret = SQLExecDirect(hstmt, (SQLCHAR *) "INSERT INTO t_odbc VALUES (10000)", SQL_NTS);if (SQL_SUCCEEDED(ret)) {printf("insert table success!\n");}else {printf("insert table failed.\n");return;}SQLEndTran(SQL_HANDLE_DBC, conn, SQL_COMMIT);if (SQL_SUCCEEDED(ret)) {printf("SQLEndTran success!\n");}else {printf("SQLEndTran failed.\n");return;}ret = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);if (SQL_SUCCEEDED(ret)) {printf("SQLFreeHandle success!\n");}else {printf("SQLFreeHandle failed.\n");return;}ret = SQLDisconnect(conn);if (SQL_SUCCEEDED(ret)) {printf("SQLDisconnect success!\n");}else {printf("SQLDisconnect failed.\n");SQLError(env, conn, hstmt, buffer, &swMsgLen,message, 256, &sdwNative);printf("%s\n%s\n", buffer, message);return;}ret = SQLFreeHandle(SQL_HANDLE_DBC, conn);if (!SQL_SUCCEEDED(ret)){printf("SQLFreeHandle failed\n");return;}conn = NULL;ret = SQLFreeHandle(SQL_HANDLE_ENV, env);if (!SQL_SUCCEEDED(ret)){printf("SQLFreeHandle failed\n");return;}env = NULL;
}int main(int argc, char **argv)
{test_SQLConnect();return 0;
}

通过以下命令进行编译,第一条命令用于将UnixODBC驱动库安装在系统路径下,第二条命令可用于源码编译安装时,将UnixODBC安装在自定义路径下,可找到对应的odbc动态库路径,通过-L指定库的路径,-I指定所需头文件的路径等等

gcc -o odbctest odbctest.c -lodbc -g -O0
gcc -o odbctest odbctest.c -L/usr/lib64/ -lodbc

执行可执行程序

[postgres@localhost:~/odbc]$ vim odbctest.c
[postgres@localhost:~/odbc]$ 
[postgres@localhost:~/odbc]$ gcc -o odbctest odbctest.c -lodbc -g -O0
[postgres@localhost:~/odbc]$ 
[postgres@localhost:~/odbc]$ ls
odbctest                                                  oracle-instantclient19.21-odbc-19.21.0.0.0-1.x86_64.rpm
odbctest.c                                                oracle-instantclient19.21-sqlplus-19.21.0.0.0-1.x86_64.rpm
oracle-instantclient19.21-basic-19.21.0.0.0-1.x86_64.rpm  oracle-instantclient19.21-tools-19.21.0.0.0-1.x86_64.rpm
oracle-instantclient19.21-devel-19.21.0.0.0-1.x86_64.rpm
[postgres@localhost:~/odbc]$ 
[postgres@localhost:~/odbc]$ ./odbctest 
Connecting with SQLConnect...
connected success!
set autommit off success!
create table success!
insert table success!
SQLEndTran success!
SQLFreeHandle success!
SQLDisconnect success!
[postgres@localhost:~/odbc]$

编写 OCI 程序

oci应用程序的编写步骤和odbc流程一致,只是调用的接口不同,示例 如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include "oci.h" //引用OCI接口的头文件,因此编译时需要指定该头文件的路径/*user name and password*/
static text* username=(text *)"c##oracle";
static text* password=(text *)"123456";
static text* oracle=(text *)"192.168.1.14/orcl";/* Define SQL statements to be used in program. */
static text* SQL=(text *)"insert into t_oci(id1, id2) values (:1, :2)";/*handle define*/
static OCIEnv             *p_env;                                        //OCI environment handle
static OCIError         *p_err;                                        //OCI error handle
static OCISvcCtx        *p_svc;                                        //OCI service context handel
static OCIServer        *p_ser;                                        //OCI server handle
static OCISession        *p_usr;                                        //OCI user session handle
static OCIStmt            *p_sql;                                        //OCI statement handle
static OCIDefine        *p_dfn = (OCIDefine *)NULL;            //OCI define handle
static OCIBind            *p_bnd = (OCIBind *)NULL;                //OCI bind handle/*create OCI environment*/
int create_env()
{int swResult;            //Return valueif(swResult = OCIEnvCreate(&p_env,OCI_DEFAULT,NULL,NULL,NULL,NULL,0,NULL)){printf("environment create error!\n\n");return -1;}else{printf("environment create success!\n\n");return 0;}
}/*init handle*/
int init_handle()
{int swResult;if(swResult = OCIHandleAlloc(p_env,(dvoid *)&p_ser,OCI_HTYPE_SERVER,0,NULL))    //服务器句柄{printf("init server handle error!\n\n");return -1;}else{printf("init server handle success!\n\n");}if(swResult = OCIHandleAlloc(p_env,(dvoid *)&p_err,OCI_HTYPE_ERROR,0,NULL))    //错误句柄{printf("init error handle error!\n\n");return -1;}else{printf("init error handle success!\n\n");}if(swResult = OCIHandleAlloc(p_env,(dvoid *)&p_usr,OCI_HTYPE_SESSION,0,NULL))    //事务句柄{printf("init session handle error!\n\n");return -1;}else{printf("init session handle success!\n\n");}if(swResult = OCIHandleAlloc(p_env,(dvoid *)&p_svc,OCI_HTYPE_SVCCTX,0,NULL))    //上下文句柄{printf("init service context handle error!\n\n");return -1;}else{printf("init service context handel success!\n\n");}if(swResult = OCIHandleAlloc(p_env,(dvoid *)&p_sql,OCI_HTYPE_STMT,0,NULL))        //SQL语句句柄{printf("init statement handle error!\n\n");return -1;}else{printf("init statement handle success!\n\n");}return 0;
}/*connect server*/
int conn_server()
{int swResult;if(swResult = OCILogon(p_env,p_err,&p_svc,(text *)username,strlen(username),(text *)password,strlen(password),(text *)oracle,strlen(oracle))){printf("connect error!\n\n");return -1;}elseprintf("connect success!\n\n");return 0;
}/*SQL statements*/
int oci_exec()
{int swResult;sb4 errcodep;ub4 recordno = 1;OraText bufp[1024];sword retcode = 0;//准备SQL语句if(swResult = OCIStmtPrepare(p_sql,p_err,SQL,strlen(SQL),OCI_NTV_SYNTAX,OCI_DEFAULT)){printf("prepare SQL statements error!\n\n");}else{printf("prepare SQL statements success!\n\n");}//设置绑定变量int getId1 ;int getId2;//char getName[10];OCIBind     *p_bndp1 = NULL;OCIBind     *p_bndp2 = NULL;printf("输入ID1,ID2:\n");scanf("%d %d",&getId1,&getId2);if(swResult = OCIBindByPos(p_sql,&p_bndp1,p_err,1,(dvoid *)&getId1,(sb4)sizeof(getId1),SQLT_INT,NULL,NULL,NULL,0,NULL,OCI_DEFAULT)){printf("Bind p1 error!\n\n");return -1;}else{printf("bind success!\n\n");}if(swResult = OCIBindByPos(p_sql,&p_bndp2,p_err,2,(dvoid *)&getId2,(sb4)sizeof(getId2),SQLT_INT,NULL,NULL,NULL,0,NULL,OCI_DEFAULT)){printf("Bind p1 error!\n\n");return -1;}else{printf("bind success!\n\n");}/*if(swResult = OCIBindByPos(p_sql,&p_bndp2,p_err,2,&getName,(sb4)sizeof(getName),SQLT_STR, (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT)){printf("Bind p2 error!\n\n");return -1;}else{printf("bind success!\n\n");}*///执行SQL statementsif(swResult = OCIStmtExecute(p_svc,p_sql,p_err,1,0,NULL,NULL,OCI_DEFAULT)){//printf("execute SQL statement error!\n\n");if (OCIErrorGet(p_err, recordno++, NULL, &errcodep, (OraText *)bufp, sizeof(bufp), OCI_HTYPE_ERROR) == OCI_SUCCESS)printf("error msg:%s\n", bufp);return -1;}else{printf("execute SQL statement success!\n\n");}return 0;
}/*quit server*/
void quit_server()
{OCILogoff(p_svc,p_err);printf("Quit success!\n");
}/*free handle*/
void free_handle()
{OCIHandleFree(p_ser,OCI_HTYPE_SERVER);            //释放服务器句柄OCIHandleFree(p_err,OCI_HTYPE_ERROR);            //释放错误句柄OCIHandleFree(p_usr,OCI_HTYPE_SESSION);        //释放事务句柄OCIHandleFree(p_svc,OCI_HTYPE_SVCCTX);            //释放上下文句柄OCIHandleFree(p_sql,OCI_HTYPE_STMT);            //释放SQL语句句柄
}int main()
{if(create_env() == -1)                //创建环境return -1;if(init_handle() == -1)                //初始化句柄return -1;if(conn_server() == -1)                //连接数据库return -1;if(oci_exec() == -1)return -1;/*quit_server();                            //退出数据库free_handle();                            //释放句柄 */return 0;
}

如上示例中可以看到调用OCI相关接口需要引用oci.h这个头文件,那么 这个头文件在哪?该头文件是在安装完oracle客户端之后,对应oracle-instantclient19.21-devel-19.21.0.0.0-1.x86_64.rpm软件包,可以通过如下命令查看其安装之后的路径,如下:

[postgres@localhost:~/odbc]$ rpm -qpl oracle-instantclient19.21-devel-19.21.0.0.0-1.x86_64.rpm
/usr/include/oracle
/usr/include/oracle/19.21
/usr/include/oracle/19.21/client64
/usr/include/oracle/19.21/client64/ldap.h
/usr/include/oracle/19.21/client64/nzerror.h
/usr/include/oracle/19.21/client64/nzt.h
/usr/include/oracle/19.21/client64/occi.h
/usr/include/oracle/19.21/client64/occiAQ.h
/usr/include/oracle/19.21/client64/occiCommon.h
/usr/include/oracle/19.21/client64/occiControl.h
/usr/include/oracle/19.21/client64/occiData.h
/usr/include/oracle/19.21/client64/occiObjects.h
/usr/include/oracle/19.21/client64/oci.h
/usr/include/oracle/19.21/client64/oci1.h
/usr/include/oracle/19.21/client64/oci8dp.h
/usr/include/oracle/19.21/client64/ociap.h
/usr/include/oracle/19.21/client64/ociapr.h
/usr/include/oracle/19.21/client64/ocidef.h
/usr/include/oracle/19.21/client64/ocidem.h
/usr/include/oracle/19.21/client64/ocidfn.h
/usr/include/oracle/19.21/client64/ociextp.h
/usr/include/oracle/19.21/client64/ocikpr.h
/usr/include/oracle/19.21/client64/ociver.h
/usr/include/oracle/19.21/client64/ocixmldb.h
/usr/include/oracle/19.21/client64/ocixstream.h
/usr/include/oracle/19.21/client64/odci.h
/usr/include/oracle/19.21/client64/oratypes.h
/usr/include/oracle/19.21/client64/ori.h
/usr/include/oracle/19.21/client64/orid.h
/usr/include/oracle/19.21/client64/orl.h
/usr/include/oracle/19.21/client64/oro.h
/usr/include/oracle/19.21/client64/ort.h
/usr/include/oracle/19.21/client64/xa.h
/usr/lib/oracle
/usr/lib/oracle/19.21
/usr/lib/oracle/19.21/client64
/usr/lib/oracle/19.21/client64/lib
/usr/lib/oracle/19.21/client64/lib/ottclasses.zip
/usr/share/oracle
/usr/share/oracle/19.21
/usr/share/oracle/19.21/client64
/usr/share/oracle/19.21/client64/admin
/usr/share/oracle/19.21/client64/admin/oraaccess.xsd
/usr/share/oracle/19.21/client64/demo
/usr/share/oracle/19.21/client64/demo/cdemo81.c
/usr/share/oracle/19.21/client64/demo/demo.mk
/usr/share/oracle/19.21/client64/demo/occidemo.sql
/usr/share/oracle/19.21/client64/demo/occidemod.sql
/usr/share/oracle/19.21/client64/demo/occidml.cpp
/usr/share/oracle/19.21/client64/demo/occiobj.cpp
/usr/share/oracle/19.21/client64/demo/occiobj.typ
/usr/share/oracle/19.21/client64/demo/oraaccess.xml
/usr/share/oracle/19.21/client64/demo/ott
/usr/share/oracle/19.21/client64/demo/setuporamysql.sh
/usr/share/oracle/19.21/client64/doc
/usr/share/oracle/19.21/client64/doc/SDK_LICENSE
/usr/share/oracle/19.21/client64/doc/SDK_README
[postgres@localhost:~/odbc]$

接下来编译上述样例:

[postgres@localhost:~/odbc]$ echo $ORACLE_HOME
/usr/lib/oracle/19.21/client64
[postgres@localhost:~/odbc]$ 
[postgres@localhost:~/odbc]$ gcc -o ocitest ocitest.c -I/usr/include/oracle/19.21/client64 -L${ORACLE_HOME}/lib -lclntsh -g -O0
[postgres@localhost:~/odbc]$

执行可执行程序,如下:

[postgres@localhost:~/odbc]$ sqlplus c##oracle/123456@192.168.1.14:1521/orclSQL*Plus: Release 19.0.0.0.0 - Production on Tue Dec 19 01:02:19 2023
Version 19.21.0.0.0Copyright (c) 1982, 2022, Oracle.  All rights reserved.Last Successful login time: Tue Dec 19 2023 01:00:31 -08:00Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0SQL> create table t_oci(id1 int, id2 int);Table created.SQL> Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
[postgres@localhost:~/odbc]$ 
[postgres@localhost:~/odbc]$ ./ocitest
environment create success!init server handle success!init error handle success!init session handle success!init service context handel success!init statement handle success!connect success!prepare SQL statements success!输入ID1,ID2:
1 2  
bind success!bind success!execute SQL statement success![postgres@localhost:~/odbc]$

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/233554.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无人机在融合通信系统中的应用

无人驾驶飞机简称“无人机”&#xff0c;是利用无线电遥控设备和自备的程序控制装置操纵的不载人飞行器&#xff0c;现今无人机在航拍、农业、快递运输、测绘、新闻报道多个领域中都有深度的应用。 在通信行业中&#xff0c;无人机广泛应用于交通&#xff0c;救援&#xff0c;消…

CentOS:Docker 创建及镜像删除

1、安装docker 远程连接服务器&#xff0c;可以直接下载netsarang比较好用 家庭/学校免费 - NetSarang Website 如果有残留docker未删除干净&#xff0c;请使用 sudo yum -y remove docker docker-common docker-selinux docker-engine Step1&#xff1a;安装必要的一些…

【数据结构】栈的使用|模拟实现|应用|栈与虚拟机栈和栈帧的区别

目录 一、栈(Stack) 1.1 概念 1.2 栈的使用 1.3 栈的模拟实现 1.4 栈的应用场景 1. 改变元素的序列 2. 将递归转化为循环 3. 括号匹配 4. 逆波兰表达式求值 5. 出栈入栈次序匹配 6. 最小栈 1.5 概念区分 一、栈(Stack) 1.1 概念 栈&#xff1a;一种特殊的线性表&…

第十七章 爬虫scrapy登录与中间件2

文章目录 数据盘区太快会报错&#xff0c;setting中配置延迟 连接提取器

解决:Android 报错 Failed to transform exifinterface-1.2.0.jar

一、问题说明 Failed to transform exifinterface-1.2.0.jar (androidx.exifinterface:exifinterface:1.2.0) to match attributes {artifactTypeandroid-classes-jar, org.gradle.categorylibrary, org.gradle.libraryelementsjar, org.gradle.statusrelease, org.gradle.usa…

pycharm手动安装ini插件

pycharm中新增pytest.ini文件时发现&#xff0c;文件的图标不是配置文件的图标 原因是没有安装ini插件 安装插件的方式有很多种&#xff0c;今天通过去官网下载插件&#xff0c;再安装的方式 第一步&#xff1a;去官网搜索&#xff0c;地址是&#xff1a;https://plugins.jet…

使用深度学习的微光图像和视频增强:综述

1INTRODUCTION 微光图像增强&#xff08;LLIE&#xff09;旨在提高在光照较差的环境中捕获的图像的感知或可解释性。该领域的最新进展主要是基于深度学习的解决方案&#xff0c;其中采用了许多学习策略、网络结构、损失函数、训练数据等。在本文中&#xff0c;我们提供了一个全…

直流电、交流电和发电机、接地、变压器

直流电 此节内容主要摘录自&#xff1a;图文详解直流电与直流电路基本知识 直流电是指电流方向不随时间作周期性变化&#xff0c;由正极流向负极&#xff0c;但电流的大小可能会变化的电流。直流电可以分为稳定&#xff08;恒定&#xff09;直流和脉动直流两种&#xff0c;如下…

单片机应用实例:LED显示电脑电子钟

本例介绍一种用LED制作的电脑电子钟&#xff08;电脑万年历&#xff09;。其制作完成装潢后的照片如下图&#xff1a; 上图中&#xff0c;年、月、日及时间选用的是1.2寸共阳数码管&#xff0c;星期选用的是2.3寸数码管&#xff0c;温度选用的是0.5寸数码管&#xff0c;也可根据…

饥荒Mod 开发(十七):手动保存和加载,无限重生

饥荒Mod 开发(十六)&#xff1a;五格装备栏 饥荒游戏会自动保存&#xff0c;本来是一个好的机制&#xff0c;但是当角色死亡的时候存档会被删除&#xff0c;又要从头开始&#xff0c;有可能一不小心玩了很久的档就直接给整没了&#xff0c;又或者是打怪没爆好东西&#xff0c; …

LVS最终奥义之DR直接路由模式

1 LVS-DR(直接路由模式) 1.1 LVS-DR模式工作过程 1.客户端通过VIP将访问请求报文&#xff08;源IP为客户端IP&#xff0c;目标IP为VIP&#xff09;发送到调度器 2.调度器通过调度算法选择最适合的节点服务器并重新封装数据报文&#xff08;将源mac地址改为调度器的mac地址&am…

redis基本用法学习(字符串类型基本操作)

字符串类型是redis支持的最简单的数据类型&#xff0c;同时最简单的键值对类型也是key和value都是单个字符串&#xff0c;本质上就是字符串之间的相互映射&#xff0c;redis官网String类型简介页面提到可以用于缓存HTML片段或页面内容。   redis支持设置/获取单个键值对&…

机器学习 | 集成学习

团结就是力量&#xff01; Ensemble Learning 兼听则明&#xff0c;偏信则暗。 集成学习既是一种思想也是一类算法&#xff0c;它是建立在其他机器学习的算法之上&#xff0c;研究怎么让不同的算法之间进行协同。 既可以监督学习&#xff0c;也可以无监督学习。 集成学习用机器…

使用Gensim训练Word2vec模型

1、训练Gensim模型 import gensim # gensim 4.3.2 import jieba import re import warnings import logging warnings.filterwarnings(ignore)with open("dataset/sanguo.txt", r,encodingutf-8)as f: # 读入文本&#xff0c;此处使用的是三国演义&#xff0c;可自…

飞天使-k8s-知识点1-kubernetes架构简述

文章目录 名词功能要点 k8s核心要素CNCF 云原生框架简介k8s组建介绍 名词 CI 持续集成, 自动化构建和测试&#xff1a;通过使用自动化构建工具和自动化测试套件&#xff0c;持续集成可以帮助开发人员自动构建和测试他们的代码。这样可以快速检测到潜在的问题&#xff0c;并及早…

maven仓库导入jar和mvn命令汇总

目录 导入远程仓库 命令结构 命令解释 项目pom 输入执行 本地仓库导入 命令格式 命令解释 Maven命令汇总 mvn 参数 mvn常用命令 web项目相关命令 导入远程仓库 命令结构 mvn deploy:deploy-file -Dfilejar包完整名称 -DgroupIdpom文件中引用的groupId名 -Dartifa…

uniapp-安卓APP开发时使用手机调试

调试 1. 手机打开开发者模式: 华为手机举列-->设置-->关于手机-->版本号&#xff0c;多次连续点击“版本号”&#xff0c;就会提示已打开开发者模式 2. 华为手机举列-->设置-->系统和更新-->开发人员选项-->打开 USB调试&#xff0c;进入调试模式 3. 先…

Next.js 学习笔记(四)——数据获取

数据获取 数据获取、缓存和重新验证 数据获取是任何应用程序的核心部分。本页介绍如何在 React 和 Next.js 中获取、缓存和重新验证数据。 有四种方法可以获取数据&#xff1a; 在服务器上&#xff0c;使用 fetch在服务器上&#xff0c;使用第三方库在客户端上&#xff0c;…

人工智能中不可预测的潜在错误可能是灾难性的——数学解释

一、说明 有没有人研究评估AI的错误产生的后果有多么严重&#xff0c;是否存在AI分险评估机制&#xff1f;更高维度上&#xff0c;人工智能的未来是反乌托邦还是乌托邦&#xff1f;这个问题一直是争论的话题&#xff0c;各大阵营都支持。我相信我们无法准确预测这两种结果。这是…

el-form与el-upload结合上传带附件的表单数据(前端篇)

1.写在之前 本文前端采用Vue element-plus技术栈&#xff0c;前端项目参考yudao-ui-admin-vue3项目与Geeker-Admin项目。 这篇文章是el-form与el-upload结合上传带附件的表单数据&#xff08;后端篇&#xff09;-CSDN博客姐妹篇&#xff0c;后端篇文章主要讲的是后端的实现逻…