我尝试从Oracle数据库连接到PostgreSQL数据库

本文是JPOUG Advent Calendar 2021第16篇文章。昨天ora_gonsuke777先生的文章是「通过CMAN(Oracle连接管理器)和基于角色的服务/NLB将OCI DBCS数据保护配置的Primary连接转变为单一端点(Oracle数据库,Oracle Cloud基础设施)」。明天是tomo先生的文章。

通过Oracle Database Gateway for ODBC的功能,使用ODBC驱动程序创建连接到PostgreSQL数据库的DATABASE LINK。

ODBC 对接 Oracle 数据库的网关

Oracle的ODBC数据库网关是Oracle数据库的标准功能,可以在任何版本中使用。有关许可信息,请参阅”数据库许可信息用户手册”。使用ODBC驱动程序,这个功能可以向除Oracle数据库之外的关系数据库管理系统(RDBMS)发出SQL语句。本文介绍了如何在Red Hat Enterprise Linux环境下连接Oracle Database 19c至PostgreSQL 14。有关详细信息,请参阅”Oracle Database Gateway for ODBC用户指南”提供的手册。

准备安装

PostgreSQL 侧

在安装PostgreSQL时,不需要进行特殊的准备。只需在设置中指定等待外部连接的地址(listen_addresses)和端口号(port),并在pg_hba.conf文件中记录允许来自Oracle数据库服务器的连接。在下面的示例中,允许从Oracle数据库服务器地址192.168.1.100连接到postgres数据库。md5表示使用密码进行身份验证。

$ cat $PGDATA/pg_hba.conf

# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    postgres        all             192.168.1.100/32        md5

Oracle数据库服务器

为了连接Oracle数据库服务器,需要在Linux上安装ODBC Manager包、PostgreSQL ODBC Driver和PostgreSQL Client。在下面的示例中,确认ODBC Manager已安装并安装了PostgreSQL 14的rpm包。

# rpm -qa | grep ODBC
unixODBC-2.3.7-1.el8.x86_64
# rpm -ivh postgresql14-14.1-1PGDG.rhel7.x86_64.rpm postgresql14-libs-14.1-1PGDG.rhel7.x86_64.rpm postgresql14-odbc-13.02.0000-1PGDG.rhel7.x86_64.rpm
warning: postgresql14-14.1-1PGDG.rhel7.x86_64.rpm: Header V4 DSA/SHA1 Signature, key ID 442df0f8: NOKEY
Preparing...                          ################################# [100%]
Updating / installing...
   1:postgresql14-libs-14.1-1PGDG.rhel################################# [ 33%]
   2:postgresql14-14.1-1PGDG.rhel7    ################################# [ 67%]
   3:postgresql14-odbc-13.02.0000-1PGD################################# [100%]

ODBC配置

确认在运行Oracle数据库的Linux上的ODBC Manager配置。

# odbc_config --odbcini --odbcinstini
/etc/odbc.ini
/etc/odbcinst.ini

# odbcinst -j
unixODBC 2.3.7
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
FILE DATA SOURCES..: /etc/ODBCDataSources
USER DATA SOURCES..: /root/.odbc.ini
SQLULEN Size.......: 8
SQLLEN Size........: 8
SQLSETPOSIROW Size.: 8

安装PostgreSQL ODBC驱动程序后,将在/etc/odbcinst.ini文件中追加驱动程序信息。根据需要进行修改。

# cat odbcinst.ini

# Example driver definitions

# Driver from the postgresql-odbc package
# Setup from the unixODBC package
[PostgreSQL]
Description     = ODBC for PostgreSQL
Driver          = /usr/pgsql-14/lib/psqlodbcw.so
Setup           = /usr/pgsql-14/lib/libodbcpsqlS.so
Driver64        = /usr/pgsql-14/lib/psqlodbcw.so
Setup64         = /usr/pgsql-14/lib/libodbcpsqlS.so
FileUsage       = 1

在odbc.ini文件中追加连接到PostgreSQL数据库的属性。您可以在任意名称的部分(例如pgdsn)下添加信息。以下是最低必需的配置选项。

項目説明[セクション名]任意の名前Driverドライバー名 odbcinst.ini ファイルから転記Description任意の説明Database接続先 PostgreSQL データベース名Servername接続先ホスト名または TCP/IP アドレスPort接続先 PostgreSQL の接続ポート番号
# cat /etc/odbc.ini

[pgdsn]
Driver = PostgreSQL
Description = PostgreSQL ODBC Driver
Database = postgres
Servername = 192.168.1.223
Port = 5432
UseDeclareFetch = 1
Debug = 1
LowerCaseIdentifier = 1
ShowOidColumn = 0

设定初始参数

在中国,只需要一个选项。
准备异机种间接(HS)続专用的初始化参数。文件需要在 $ORACLE_HOME/hs/admin 目录下以 init{接口名}.ora 的名称创建。以下示例使用 pgdsn 作为连接名进行初始化参数设置。

$ pwd
/u01/app/oracle/homes/OraDB19Home1/hs/admin
$
$ ls
initpgdsn.ora
$
$ cat initpgdsn.ora
HS_FDS_CONNECT_INFO = pgdsn
HS_FDS_TRACE_LEVEL = DEBUG
HS_FDS_SHAREABLE_NAME = /usr/lib64/libodbc.so
HS_LANGUAGE=AMERICAN_AMERICA.WE8ISO8859P1
set ODBCINI=/etc/odbc.ini
項目説明HS_FDS_CONNECT_INFO接続名称HS_FDS_TRACE_LEVELトレース・ファイルに出力するレベルHS_FDS_SHAREABLE_NAMEODBC Driver ManagerへのパスHS_LANGUAGE言語設定HS_FDS_FETCH_ROWSフェッチサイズset ODBCINIODBC 設定ファイルへのパス

网络设置

然后,我们将进行听众设置。当Oracle Database Gateway连接到不同的数据库时,它将通过监听器启动dg4odbc进程。我们需要在监听器设置文件(listener.ora)中添加用于外部连接的SID_LIST。同时,我们还需设置环境变量LD_LIBRARY_PATH以及启动进程的PROGRAM=dg4odbc设置。

$ pwd
/u01/app/oracle/homes/OraDB21Home1/network/admin
$
$ cat listener.ora
# listener.ora Network Configuration File: /u01/app/oracle/homes/OraDB21Home1/network/admin/listener.ora
# Generated by Oracle configuration tools.

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.200)(PORT = 1521))
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
    )
  )

SID_LIST_LISTENER =
(SID_LIST =
  (SID_DESC=
    (SID_NAME = pgdsn)
    (ORACLE_HOME = /u01/app/oracle/product/19.0.0/dbhome_1)
    (ENVS="LD_LIBRARY_PATH=/usr/local/lib:/usr/lib64:/u01/app/oracle/product/19.0.0/dbhome_1/lib")
    (PROGRAM=dg4odbc)
  )
)

将连接数据库的入口添加到 tnsnames.ora 文件中。连接到本地主机的监听器,并添加 HS=OK 的设置。

$ cat tnsnames.ora

pgdsn  =
(DESCRIPTION=
    (ADDRESS=(PROTOCOL=tcp)(HOST = localhost)(PORT = 1521))
    (CONNECT_DATA=(SID=pgdsn))
    (HS=OK)
)

创建数据库链接

我会创建一个引用PostgreSQL实例的DATABASE LINK。我会提供PostgreSQL数据库的用户名和密码。为了注意大小写,我会用双引号括起用户名和密码。我会在USING子句中指定在tnsnames.ora文件中添加的连接器。在下面的示例中,我将创建一个DATABASE LINK,并引用pg_am目录的定义。如果能够成功地引用查看定义而不输出错误,则表示成功。

SQL> CREATE DATABASE LINK pglink CONNECT TO "demo" identified by "<<PASSWORD>>"
  2  USING 'pgdsn';

データベース・リンクが作成されました。

SQL> DESCRIBE "pg_am"@pglink
 名前                                    NULL?    
 ----------------------------------------- -------- ----------------------------
 oid                                       NOT NULL NUMBER(10)
 amname                                    NOT NULL VARCHAR2(189)
 amhandler                                 NOT NULL VARCHAR2(765)
 amtype                                    NOT NULL CHAR(3)

执行 SQL 语句

由于可以创建 DATABASE LINK,因此可以对 PostgreSQL 上的表执行 SQL 语句。需要注意的是,PostgreSQL 数据库的对象名基本上以小写存储,因此在指定对象名时需要使用双引号。

SQL> SELECT COUNT(*) FROM pg_am@pglink;
SELECT COUNT(*) FROM pg_am@pglink
                     *
1でエラーが発生しました。:
ORA-28500:
OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:  ERROR: relation "PG_AM" does
not exist;
No query has been executed with that handle {42P01,NativeErr = 1}
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(PGLINK)

SQL> SELECT COUNT(*) FROM "pg_am"@pglink;

  COUNT(*)
----------
         7

故障排除

最初的验证使用了Red Hat Enterprise 7和Red Hat Enterprise 8附带的PostgreSQL 9或PostgreSQL 10的ODBC驱动程序。然而,由于无法连接到PostgreSQL 14或在搜索oid列(在PostgreSQL 12中已弃用)时出现错误等问题,我们决定安装适用于PostgreSQL 14的新驱动程序。以下是PostgreSQL 10 ODBC驱动程序在进行表存在检查时出现错误的日志。

2021-10-19 00:37:20.221 JST [4142] ERROR:  column c.relhasoids does not exist at character 245
2021-10-19 00:37:20.221 JST [4142] STATEMENT:  select n.nspname, c.relname, a.attname, a.atttypid, t.typname, a.attnum, a.attlen, a.atttypmod, a.attnotnull, c.relhasrules, c.relkind, c.oid, pg_get_expr(d.adbin, d.adrelid), case t.typtype when 'd' then t.typbasetype else 0 end, t.typtypmod, c.relhasoids, attidentity, c.relhassubclass from (((pg_catalog.pg_class c inner join pg_catalog.pg_namespace n on n.oid = c.relnamespace and c.oid = 16984) inner join pg_catalog.pg_attribute a on (not a.attisdropped) and a.attnum > 0 and a.attrelid = c.oid) inner join pg_catalog.pg_type t on t.oid = a.atttypid) left outer join pg_attrdef d on a.atthasdef and d.adrelid = a.attrelid and d.adnum = a.attnum order by n.nspname, c.relname, attnum
2021-10-19 00:37:20.222 JST [4142] ERROR:  current transaction is aborted, commands ignored until end of transaction block

当发生错误时,需要检查的日志文件将被创建在 $ORACLE_HOME/hs/log 目录中。

$ pwd
/u01/app/oracle/homes/OraDB19Home1/hs/log

$ ls
37951.log            pgdsn_agt_38220.trc  pgdsn_agt_6608.trc
38059.log            pgdsn_agt_38282.trc  pgdsn_agt_6811.trc
38174.log            pgdsn_agt_38728.trc  pgdsn_agt_7245.trc
38220.log            pgdsn_agt_39133.trc  pgdsn_agt_7432.trc
38282.log            pgdsn_agt_39282.trc  pgdsn_agt_7970.trc
pgdsn_agt_10390.trc  pgdsn_agt_39390.trc  pgdsn_agt_8004.trc
pgdsn_agt_37657.trc  pgdsn_agt_5867.trc   pgdsn_agt_8021.trc
pgdsn_agt_37721.trc  pgdsn_agt_5954.trc   pgdsn_agt_8081.trc
pgdsn_agt_37951.trc  pgdsn_agt_5994.trc   pgdsn_agt_8451.trc
pgdsn_agt_38059.trc  pgdsn_agt_6143.trc   pgdsn_agt_8526.trc
pgdsn_agt_38174.trc  pgdsn_agt_6328.trc

如果在初始化参数HS_LANGUAGE中设置除AMERICAN_AMERICA.WE8ISO8859P1以外的值,那么SQL语句的执行将会失败,因此无法完成汉字编码转换。

SQL> INSERT INTO "data1"@pglink VALUES (0, '漢字');
INSERT INTO "data1"@pglink VALUES (0, '漢字')
*
1でエラーが発生しました。:
ORA-28500:
OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:  ERROR: invalid byte sequence
for encoding "UTF8": 0xbf;
Error while preparing parameters {22021,NativeErr = 1}
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(PGLINK)
广告
将在 10 秒后关闭
bannerAds