

# 通过使用 oracle\$1fdw 扩展来使用 Oracle 数据库
<a name="postgresql-oracle-fdw"></a>

要从 RDS for PostgreSQL 数据库实例访问 Oracle 数据库，您可以安装并使用 `oracle_fdw` 扩展。此扩展是 Oracle 数据库的外部数据包装器。要了解有关此扩展的更多信息，请参阅 [oracle\$1fdw](https://github.com/laurenz/oracle_fdw) 文档。

RDS for PostgreSQL 12.7、13.3 及更高版本支持 `oracle_fdw` 扩展。

**Topics**
+ [启用 oracle\$1fdw 扩展](#postgresql-oracle-fdw.enabling)
+ [示例：使用链接到 Amazon RDS for Oracle Database 的外部服务器](#postgresql-oracle-fdw.example)
+ [在传输过程中使用加密](#postgresql-oracle-fdw.encryption)
+ [了解 pg\$1user\$1mappings 视图和权限](#postgresql-oracle-fdw.permissions)

## 启用 oracle\$1fdw 扩展
<a name="postgresql-oracle-fdw.enabling"></a>

要使用 oracle\$1fdw 扩展，请执行以下步骤。

**启用 oracle\$1fdw 扩展**
+ 使用具有 `rds_superuser` 权限的账户运行以下命令。

  ```
  CREATE EXTENSION oracle_fdw;
  ```

## 示例：使用链接到 Amazon RDS for Oracle Database 的外部服务器
<a name="postgresql-oracle-fdw.example"></a>

以下示例展示如何使用链接到 Amazon RDS for Oracle Database 的外部服务器。

**创建链接到 RDS for Oracle 数据库的外部服务器**

1. 请注意 RDS for Oracle 数据库实例上的以下内容：
   + Endpoint
   + 端口
   + 数据库名称

1. 创建外部服务器。

   ```
   test=> CREATE SERVER oradb FOREIGN DATA WRAPPER oracle_fdw OPTIONS (dbserver '//endpoint:port/DB_name');
   CREATE SERVER
   ```

1. 将使用权授予没有 `rds_superuser` 权限的用户，例如 `user1`。

   ```
   test=> GRANT USAGE ON FOREIGN SERVER oradb TO user1;
   GRANT
   ```

1. 作为 `user1` 连接并创建到 Oracle 用户的映射。

   ```
   test=> CREATE USER MAPPING FOR user1 SERVER oradb OPTIONS (user 'oracleuser', password 'mypassword');
   CREATE USER MAPPING
   ```

1. 创建链接到 Oracle 表的外部表。

   ```
   test=> CREATE FOREIGN TABLE mytab (a int) SERVER oradb OPTIONS (table 'MYTABLE');
   CREATE FOREIGN TABLE
   ```

1. 查询外部表。

   ```
   test=>  SELECT * FROM mytab;
   a
   ---
   1
   (1 row)
   ```

如果查询报告以下错误，请检查您的安全组和访问控制列表（ACL）以确保两个实例可以通信。

```
ERROR: connection for foreign table "mytab" cannot be established
DETAIL: ORA-12170: TNS:Connect timeout occurred
```

## 在传输过程中使用加密
<a name="postgresql-oracle-fdw.encryption"></a>

PostgreSQL-to-Oracle 传输中加密基于客户端和服务器配置参数的组合。有关使用 Oracle 21c 的示例，请参阅 Oracle 文档中的[关于协商加密和完整性的值](https://docs.oracle.com/en/database/oracle/oracle-database/21/dbseg/configuring-network-data-encryption-and-integrity.html#GUID-3A2AF4AA-AE3E-446B-8F64-31C48F27A2B5)。用于 Amazon RDS 上 oracle\$1fdw 的客户端配置有 `ACCEPTED`，这意味着加密取决于 Oracle 数据库服务器配置，并且使用 Oracle 安全库（libnnz）进行加密。

如果您的数据库位于 RDS for Oracle 上，请参阅 [Oracle 本机网络加密](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.Oracle.Options.NetworkEncryption.html)来配置加密。

## 了解 pg\$1user\$1mappings 视图和权限
<a name="postgresql-oracle-fdw.permissions"></a>

PostgreSQL 目录 `pg_user_mapping` 存储 RDS for PostgreSQL 用户到外部数据（远程）服务器上用户的映射。虽然对目录的访问受到限制，但是您可以使用 `pg_user_mappings` 视图来查看映射。在下面，您可以找到一个示例，该示例演示如何将权限应用于示例 Oracle 数据库，但此信息更普遍地适用于任何外部数据包装器。

在以下输出中，您可以找到映射到三个不同示例用户的角色和权限。用户 `rdssu1` 和 `rdssu2` 是 `rds_superuser` 角色的成员，而 `user1` 不是。此示例使用 `psql` 元命令 `\du` 列出现有角色。

```
test=>  \du
                                                               List of roles
    Role name    |                         Attributes                         |                          Member of
-----------------+------------------------------------------------------------+-------------------------------------------------------------
 rdssu1          |                                                            | {rds_superuser}
 rdssu2          |                                                            | {rds_superuser}
 user1           |                                                            | {}
```

所有用户，包括具有 `rds_superuser` 权限的用户，都可以查看 `pg_user_mappings` 表中他们自己的用户映射 (`umoptions`)。如以下示例所示，当 `rdssu1` 尝试获取所有用户映射时，即使存在 `rdssu1``rds_superuser` 权限，也会出现错误：

```
test=> SELECT * FROM pg_user_mapping;
ERROR: permission denied for table pg_user_mapping
```

下面是一些示例。

```
test=> SET SESSION AUTHORIZATION rdssu1;
SET
test=> SELECT * FROM pg_user_mappings;
 umid  | srvid | srvname | umuser | usename    |            umoptions
-------+-------+---------+--------+------------+----------------------------------
 16414 | 16411 | oradb   |  16412 | user1      |
 16423 | 16411 | oradb   |  16421 | rdssu1     | {user=oracleuser,password=mypwd}
 16424 | 16411 | oradb   |  16422 | rdssu2     |
 (3 rows)

test=> SET SESSION AUTHORIZATION rdssu2;
SET
test=> SELECT * FROM pg_user_mappings;
 umid  | srvid | srvname | umuser | usename    |            umoptions
-------+-------+---------+--------+------------+----------------------------------
 16414 | 16411 | oradb   |  16412 | user1      |
 16423 | 16411 | oradb   |  16421 | rdssu1     |
 16424 | 16411 | oradb   |  16422 | rdssu2     | {user=oracleuser,password=mypwd}
 (3 rows)

test=> SET SESSION AUTHORIZATION user1;
SET
test=> SELECT * FROM pg_user_mappings;
 umid  | srvid | srvname | umuser | usename    |           umoptions
-------+-------+---------+--------+------------+--------------------------------
 16414 | 16411 | oradb   |  16412 | user1      | {user=oracleuser,password=mypwd}
 16423 | 16411 | oradb   |  16421 | rdssu1     |
 16424 | 16411 | oradb   |  16422 | rdssu2     |
 (3 rows)
```

由于 `information_schema._pg_user_mappings` 和 `pg_catalog.pg_user_mappings` 的实施差异，手动创建的 `rds_superuser` 需要额外的权限才能在 `pg_catalog.pg_user_mappings` 中查看密码。

`rds_superuser` 无需额外权限即可在 `information_schema._pg_user_mappings` 中查看密码。

没有 `rds_superuser` 角色的用户只能在以下条件下在 `pg_user_mappings` 中查看密码：
+ 当前用户是被映射的用户，拥有服务器或对其具有 `USAGE` 权限。
+ 当前用户是服务器所有者，此映射用于 `PUBLIC`。