A Step-by-Step Guide to Setting Up Oracle Database Gateway (DG4ODBC) from Oracle 19c to SQL Server

<p dir="ltr" lang="en">This guide details the step-by-step process of establishing bidirectional communication and executing queries between <strong>Oracle Database 19c</strong> (running on Oracle Linux 9 / RHEL 9) and <strong>Microsoft SQL Server 2022</strong> (running on Windows Server 2022) using <strong>Oracle Database Gateway for ODBC (DG4ODBC)</strong> and <strong>Database Link</strong>.</p>

<h2 dir="ltr" lang="en">1. Architecture and Environment Details</h2>
<ul dir="ltr" lang="en" style="list-style-type: disc; padding-left: 25px;">
  <li><strong>Oracle Server (Oracle Linux 9.x):</strong>
    <ul dir="ltr" style="list-style-type: circle; padding-left: 20px;">
      <li><strong>Hostname:</strong> <span style="font-family: monospace; color: inherit;">dc1.vahiddb.com</span></li>
      <li><strong>IP Address:</strong> <span style="font-family: monospace; color: inherit;">192.168.56.31</span></li>
      <li><strong>Oracle Base:</strong> <span style="font-family: monospace; color: inherit;">/u01/app/oracle</span></li>
      <li><strong>Oracle Home:</strong> <span style="font-family: monospace; color: inherit;">/u01/app/oracle/product/19c/dbhome</span></li>
      <li><strong>Grid Home (if using RAC/GI):</strong> <span style="font-family: monospace; color: inherit;">/u01/app/19c/grid</span></li>
      <li><strong>DB / PDB Name:</strong> <span style="font-family: monospace; color: inherit;">vahiddb</span> / <span style="font-family: monospace; color: inherit;">vahidpdb</span></li>
    </ul>
  </li>
  <li><strong>Target Server (SQL Server 2022 on Windows Server):</strong>
    <ul dir="ltr" style="list-style-type: circle; padding-left: 20px;">
      <li><strong>IP Address:</strong> <span style="font-family: monospace; color: inherit;">192.168.56.19</span></li>
      <li><strong>Port:</strong> <span style="font-family: monospace; color: inherit;">1433</span></li>
      <li><strong>Database Name:</strong> <span style="font-family: monospace; color: inherit;">testdb</span></li>
      <li><strong>SQL User:</strong> <span style="font-family: monospace; color: inherit;">ora_link / OraPassword#123</span></li>
    </ul>
  </li>
</ul>

<h2 dir="ltr" lang="en">2. Microsoft SQL Server Preparation</h2>
<h3 dir="ltr" lang="en">2.1. Enable Mixed Mode Authentication and Open Firewall Port</h3>
<ol dir="ltr" lang="en" style="padding-left: 25px;">
  <li>In <strong>SSMS (SQL Server Management Studio)</strong>, right-click the Instance, navigate to <span style="font-family: monospace; color: inherit;">Properties &gt; Security</span>, and select <strong>SQL Server and Windows Authentication mode</strong>.</li>
  <li>In <strong>SQL Server Configuration Manager</strong>, ensure <span style="font-family: monospace; color: inherit;">TCP/IP</span> is enabled and set the default listening port to <span style="font-family: monospace; color: inherit;">1433</span>.</li>
  <li>Open port <span style="font-family: monospace; color: inherit;">1433</span> in Windows Defender Firewall via PowerShell:</li>
</ol>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">New-NetFirewallRule -DisplayName "SQL Server Port 1433" -Direction Inbound -LocalPort 1433 -Protocol TCP -Action Allow</pre>

<h3 dir="ltr" lang="en">2.2. Create Database, Login, and Test Table</h3>
<p dir="ltr" lang="en">Execute the following script in SSMS:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">-- 1. Create database
CREATE DATABASE testdb;
GO

USE testdb;
GO

-- 2. Create dedicated user for Oracle Gateway
CREATE LOGIN ora_link WITH PASSWORD = 'OraPassword#123', CHECK_POLICY = OFF;
CREATE USER ora_link FOR LOGIN ora_link;
ALTER ROLE db_datareader ADD MEMBER ora_link;
ALTER ROLE db_datawriter ADD MEMBER ora_link;
GO

-- 3. Create test table and insert sample records
CREATE TABLE employees (
    emp_id INT PRIMARY KEY,
    emp_name VARCHAR(100),
    department VARCHAR(50),
    salary DECIMAL(10,2)
);

INSERT INTO employees VALUES 
(1, 'Ali Rezaei', 'IT', 75000),
(2, 'Sara Mohammadi', 'HR', 62000),
(3, 'Vahid Karimi', 'Database', 90000);
GO</pre>

<h2 dir="ltr" lang="en">3. Linux Configuration (Oracle Server: dc1)</h2>
<h3 dir="ltr" lang="en">3.1. Install unixODBC and Microsoft ODBC Driver</h3>
<p dir="ltr" lang="en">Run the following commands as the <span style="font-family: monospace; color: inherit;">root</span> user:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">dnf install -y unixODBC</pre>

<p dir="ltr" lang="en">Install the Microsoft ODBC driver RPM package and accept the license terms by entering <span style="font-family: monospace; color: inherit;">yes</span>:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">dnf install -y msodbcsql18-18.4.1.1-1.x86_64.rpm</pre>

<h3 dir="ltr" lang="en">3.2. Configure ODBC Files</h3>
<p dir="ltr" lang="en">Configure the DSN entry in <span style="font-family: monospace; color: inherit;">/etc/odbc.ini</span>:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">cat << "EOF" > /etc/odbc.ini
[MSSQLTEST]
Driver=ODBC Driver 18 for SQL Server
Server=192.168.56.19,1433
Database=testdb
TrustServerCertificate=yes
Encrypt=no
EOF</pre>

<h3 dir="ltr" lang="en">3.3. Test ODBC Connectivity with isql</h3>
<p dir="ltr" lang="en">Switch to the <span style="font-family: monospace; color: inherit;">oracle</span> user and verify the connection using the <span style="font-family: monospace; color: inherit;">isql</span> utility:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">isql -v MSSQLTEST ora_link 'OraPassword#123'</pre>

<p dir="ltr" lang="en">Expected output and query verification:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> SELECT * FROM employees;
+------------+----------------------+--------------------+----------+
| emp_id     | emp_name             | department         | salary   |
+------------+----------------------+--------------------+----------+
| 1          | Ali Rezaei           | IT                 | 75000.00 |
| 2          | Sara Mohammadi       | HR                 | 62000.00 |
| 3          | Vahid Karimi         | Database           | 90000.00 |
+------------+----------------------+--------------------+----------+
SQLRowCount returns 0
3 rows fetched
SQL> quit</pre>

<h2 dir="ltr" lang="en">4. Configure Oracle Database Gateway (DG4ODBC)</h2>
<h3 dir="ltr" lang="en">4.1. Create Gateway Initialization File (<span style="font-family: monospace; color: inherit;">init&lt;SID&gt;.ora</span>)</h3>
<p dir="ltr" lang="en">As the <span style="font-family: monospace; color: inherit;">oracle</span> user, create <span style="font-family: monospace; color: inherit;">$ORACLE_HOME/hs/admin/initMSSQLTEST.ora</span>:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">cat << "EOF" > $ORACLE_HOME/hs/admin/initMSSQLTEST.ora
HS_FDS_CONNECT_INFO = MSSQLTEST
HS_FDS_TRACE_LEVEL = OFF
HS_FDS_SHAREABLE_NAME = /usr/lib64/libodbc.so.2
HS_FDS_SQLLEN_INTERPRETATION = 64
HS_FDS_SUPPORT_STATISTICS = FALSE
HS_KEEP_REMOTE_MM_AND_SEC = TRUE
HS_NLS_NCHAR = UCS2
set ODBCINI=/etc/odbc.ini
set ODBCSYSINI=/etc
HS_LANGUAGE = AMERICAN_AMERICA.AL32UTF8
EOF</pre>

<h3 dir="ltr" lang="en">4.2. Configure listener.ora</h3>
<p dir="ltr" lang="en">Edit <span style="font-family: monospace; color: inherit;">listener.ora</span> (located at <span style="font-family: monospace; color: inherit;">$GRID_HOME/network/admin/listener.ora</span> for Grid/ASM environments, or <span style="font-family: monospace; color: inherit;">$ORACLE_HOME/network/admin/listener.ora</span> for Standalone) and append the <span style="font-family: monospace; color: inherit;">SID_DESC</span> entry for <span style="font-family: monospace; color: inherit;">dg4odbc</span>:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (GLOBAL_DBNAME = vahiddb)
      (ORACLE_HOME = /u01/app/oracle/product/19c/dbhome)
      (SID_NAME = vahiddb)
    )
    (SID_DESC =
      (PROGRAM = dg4odbc)
      (SID_NAME = MSSQLTEST)
      (ORACLE_HOME = /u01/app/oracle/product/19c/dbhome)
      (ENVS = "LD_LIBRARY_PATH=/usr/lib64:/opt/microsoft/msodbcsql18/lib64:/u01/app/oracle/product/19c/dbhome/lib,ODBCINI=/etc/odbc.ini,ODBCSYSINI=/etc")
    )
  )</pre>

<p dir="ltr" lang="en">Reload the listener to apply the changes:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">lsnrctl reload
lsnrctl status</pre>

<h3 dir="ltr" lang="en">4.3. Configure tnsnames.ora</h3>
<p dir="ltr" lang="en">Edit <span style="font-family: monospace; color: inherit;">$ORACLE_HOME/network/admin/tnsnames.ora</span> and append the following entry:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">MSSQLTEST =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = dc1.vahiddb.com)(PORT = 1521))
    (CONNECT_DATA =
      (SID = MSSQLTEST)
    )
    (HS = OK)
  )</pre>

<p dir="ltr" lang="en">Verify TNS resolution:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">tnsping MSSQLTEST</pre>

<h2 dir="ltr" lang="en">5. Create Database Link and Verify in Oracle</h2>
<p dir="ltr" lang="en">Log in to SQL*Plus as SYSDBA:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">sqlplus / as sysdba</pre>

<p dir="ltr" lang="en">Create the Database Link and execute a SELECT query:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">-- Switch to the target PDB (if using Multitenant)
ALTER SESSION SET CONTAINER = vahidpdb;

-- Create Database Link pointing to SQL Server
CREATE PUBLIC DATABASE LINK mssql_link
CONNECT TO "ora_link" IDENTIFIED BY "OraPassword#123"
USING 'MSSQLTEST';

-- Test SELECT query
SELECT * FROM "employees"@mssql_link;</pre>

<p dir="ltr" lang="en">Successful query output:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">    emp_id emp_name             department     salary
---------- -------------------- ------------ --------
         1 Ali Rezaei           IT              75000
         2 Sara Mohammadi       HR              62000
         3 Vahid Karimi         Database        90000</pre>

<h3 dir="ltr" lang="en">DML Testing (INSERT) and Synonym Creation:</h3>
<p dir="ltr" lang="en">To allow DML operations, ensure write permissions are granted in SQL Server:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">USE testdb;
GO
ALTER ROLE db_datawriter ADD MEMBER ora_link;
GO</pre>

<p dir="ltr" lang="en">Next, create a synonym in Oracle, insert a new record, and commit:</p>

<pre dir="ltr" style="text-align: left; background-color: #f6f8fa; color: #24292e; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">-- Create Synonym for cleaner SQL syntax
CREATE OR REPLACE SYNONYM mssql_emp FOR "employees"@mssql_link;

-- Insert new record
INSERT INTO mssql_emp ("emp_id", "emp_name", "department", "salary")
VALUES (4, 'Reza Ahmadi', 'DevOps', 88000);

COMMIT;

-- Verify final data
SELECT * FROM mssql_emp;</pre>