<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Oracle - dbi Blog</title>
	<atom:link href="https://www.dbi-services.com/blog/category/oracle/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.dbi-services.com/blog/category/oracle/</link>
	<description></description>
	<lastBuildDate>Wed, 09 Sep 2026 13:25:21 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/05/cropped-favicon_512x512px-min-32x32.png</url>
	<title>Oracle - dbi Blog</title>
	<link>https://www.dbi-services.com/blog/category/oracle/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Rename a GoldenGate Extract with the REST API</title>
		<link>https://www.dbi-services.com/blog/rename-a-goldengate-extract-with-the-rest-api/</link>
					<comments>https://www.dbi-services.com/blog/rename-a-goldengate-extract-with-the-rest-api/#respond</comments>
		
		<dc:creator><![CDATA[Julien Delattre]]></dc:creator>
		<pubDate>Thu, 10 Sep 2026 06:28:00 +0000</pubDate>
				<category><![CDATA[GoldenGate]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[administration]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[extract]]></category>
		<category><![CDATA[migration]]></category>
		<category><![CDATA[ogg]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Rename]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[restapi]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=46797</guid>

					<description><![CDATA[<p>In a previous blog, I went through the full procedure of renaming a GoldenGate extract from the adminclient. I included all necessary steps to avoid missing transactions. Doing this by hand is completely fine, but if you do it often, or want to remove the risk of a typo on an SCN, I have another [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/rename-a-goldengate-extract-with-the-rest-api/">Rename a GoldenGate Extract with the REST API</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">In a <a href="https://www.dbi-services.com/blog/rename-a-goldengate-extract-without-missing-transactions/" target="_blank" rel="noopener noreferrer">previous blog</a>, I went through the full procedure of renaming a GoldenGate extract from the <code>adminclient</code>. I included all necessary steps to avoid missing transactions. Doing this by hand is completely fine, but if you do it often, or want to remove the risk of a typo on an SCN, I have another solution for you. In this blog, I automate the same procedure with a Python script, <code>rename_extract.py</code>, using GoldenGate REST API (the <a href="https://juliendelattre.com/docs/rename-goldengate-extract-rest-api-script/" target="_blank" rel="noopener noreferrer">full source is in this reference doc</a>).</p>



<p class="wp-block-paragraph">Please read through the previous blog if you have not already done it. I explain there the two SCNs involved (the <strong>start SCN</strong>, the oldest unprocessed transaction, and the <strong>dictionary build SCN</strong>, which must predate it) and why their ordering matters. Here, I only cover how to obtain and pass them through the REST API.</p>



<p class="wp-block-paragraph">As a reminder, these were the steps:</p>



<ul class="wp-block-list">
<li>Build the <strong>LogMiner data dictionary</strong> (if you don’t already build it regularly).</li>



<li>Check for <strong>long running transactions</strong> in the source database.</li>



<li><strong>Stop the extract</strong> that you want to rename.</li>



<li>Get the SCN of the <strong>oldest unprocessed transaction</strong>.</li>



<li>Find the <strong>dictionary build</strong> to register the new extract.</li>



<li><strong>Create the new extract</strong>, registered and started at the correct SCNs, reusing the old extract’s parameter file with only the name and trail changed.</li>
</ul>



<h2 id="building-the-logminer-dictionary" class="wp-block-heading">Building the LogMiner dictionary</h2>



<p class="wp-block-paragraph"><code>DBMS_CAPTURE_ADM.BUILD</code> is a database-side operation, not a GoldenGate one, so the REST API cannot run it directly. The script runs it through the Python <code>oracledb</code> module when available :</p>



<pre class="wp-block-code"><code>import oracledb

def build_dictionary_oracledb(dsn, user, password):
    with oracledb.connect(dsn=dsn, user=user, password=password) as conn:
        with conn.cursor() as cur:
            first_scn = cur.var(int)
            cur.execute("BEGIN DBMS_CAPTURE_ADM.BUILD(first_scn =&gt; :first_scn); END;", first_scn=first_scn)
            return int(first_scn.getvalue())</code></pre>



<pre class="wp-block-code"><code>&gt;&gt;&gt; build_dictionary_oracledb("localhost:1521/CDB01", "c##oggadmin", "ogg")
25261458</code></pre>



<p class="wp-block-paragraph">Or through <code>sqlplus</code> when <code>oracledb</code> is not installed :</p>



<pre class="wp-block-code"><code>import re
import shutil
import subprocess

def build_dictionary_sqlplus(dsn, user, password):
    if not shutil.which("sqlplus"):
        raise RuntimeError("sqlplus is not on PATH")
    script = f"""
        SET SERVEROUTPUT ON
        CONNECT {user}/{password}@{dsn}
        DECLARE
            scn NUMBER;
        BEGIN
            DBMS_CAPTURE_ADM.BUILD(first_scn =&gt; scn);
            DBMS_OUTPUT.PUT_LINE('DICTIONARY_BUILD_SCN:' || scn);
        END;
        /
        EXIT
    """
    proc = subprocess.run(&#091;"sqlplus", "-s", "/nolog"], input=script, capture_output=True, text=True)
    return int(re.search(r"DICTIONARY_BUILD_SCN:(\d+)", proc.stdout).group(1))</code></pre>



<pre class="wp-block-code"><code>&gt;&gt;&gt; build_dictionary_sqlplus("localhost:1521/CDB01", "c##oggadmin", "ogg")
25262183</code></pre>



<p class="wp-block-paragraph">If you already build the dictionary on a regular schedule, <code>rename_extract.py</code> never calls either of these : the lookup further down finds an existing build old enough to reuse and moves straight on. It only builds a fresh one as a fallback, when that lookup comes back empty.</p>



<h2 id="computing-the-start-scn-through-the-api" class="wp-block-heading">Computing the start SCN through the API</h2>



<p class="wp-block-paragraph">Reading the old extract’s recovery checkpoint and the database’s active transactions (exactly what the <a href="https://www.dbi-services.com/blog/checking-long-running-transactions-in-goldengate/" target="_blank" rel="noopener noreferrer">long running transactions blog</a> describes) gives you the oldest unprocessed transaction. <code>get_extract_checkpoint</code> calls <code>GET /services/{version}/extracts/{extract}/info/checkpoints</code> :</p>



<pre class="wp-block-code"><code>&gt;&gt;&gt; extract_checkpoints = ogg_client.get_extract_checkpoint("EXT1")
&gt;&gt;&gt; extract_checkpoints&#091;"current"]&#091;"input"]&#091;0]&#091;"recovery"]
{'timestamp': '2026-09-06T14:03:16.000Z', 'thread': 1, 'sequence': 888, 'offset': 172466704, 'csn': 25167710, 'name': None}
&gt;&gt;&gt; start_scn = extract_checkpoints&#091;"current"]&#091;"input"]&#091;0]&#091;"recovery"]&#091;"csn"]
&gt;&gt;&gt; start_scn
25167710</code></pre>



<p class="wp-block-paragraph"><code>get_active_transactions</code> runs the same check the <a href="https://www.dbi-services.com/blog/checking-long-running-transactions-in-goldengate/" target="_blank" rel="noopener noreferrer">long running transactions blog</a> covers by hand, as a REST call to <code>GET /services/{version}/connections/{connection}/activeTransactions</code> :</p>



<pre class="wp-block-code"><code>&gt;&gt;&gt; ogg_client.get_active_transactions("OracleGoldenGate.source_cdb")
{'activeTransactions': &#091;], 'currentScn': {'csn': 25167998, 'currentDate': '2026-09-06T14:03:30.000Z', 'userName': 'SYS'}, '$schema': 'ogg:activeTransactions'}</code></pre>



<p class="wp-block-paragraph">No open transactions here, so <code>25167710</code> stands as the start SCN. Had there been one, its <code>txnStartScn</code> would have been folded in and the smallest of the two kept, exactly as <code>get_oldest_unprocessed_scn</code> does in the full script <code>rename_extract.py</code> (see below).</p>



<h2 id="computing-the-dictionary-scn" class="wp-block-heading">Computing the dictionary SCN</h2>



<p class="wp-block-paragraph">Building a LogMiner dictionary is a database-side operation (<code>DBMS_CAPTURE_ADM.BUILD</code>). So is finding the right existing build, directly against the source database :</p>



<pre class="wp-block-code"><code>import oracledb

def get_dictionary_scn_oracledb(dsn, user, password, start_scn):
    with oracledb.connect(dsn=dsn, user=user, password=password) as conn:
        with conn.cursor() as cur:
            cur.execute("""
                SELECT first_change#
                FROM v$archived_log
                WHERE dictionary_begin = 'YES'
                AND standby_dest = 'NO'
                AND name IS NOT NULL
                AND status = 'A'
                AND first_change# &lt; :start_scn
                ORDER BY first_change# DESC
                FETCH FIRST 1 ROWS ONLY
            """, start_scn=start_scn)
            row = cur.fetchone()
            return row&#091;0] if row else None</code></pre>



<pre class="wp-block-code"><code>&gt;&gt;&gt; get_dictionary_scn_oracledb("localhost:1521/CDB01", "c##oggadmin", "ogg", 25167710)
25134064</code></pre>



<p class="wp-block-paragraph">If <code>dictionary_scn</code> is <code>None</code>, no existing build predates the start SCN. It happens on a source database where the dictionary is not built on a regular schedule (the same case the <a href="https://www.dbi-services.com/blog/rename-a-goldengate-extract-without-missing-transactions/#find-the-logminer-dictionary-build-to-register-at" target="_blank" rel="noopener noreferrer">adminclient blog</a> covers by hand). <code>rename_extract.py</code> handles it by calling <code>build_dictionary</code> (above) for a fresh build. It then waits for the old extract’s checkpoint to move past that build’s SCN before continuing.</p>



<pre class="wp-block-code"><code>if dictionary_scn is None:
    dictionary_scn = build_dictionary(dsn, user, password, driver)
    start_scn = wait_for_dictionary_scn(ogg_client, "EXT1", "OracleGoldenGate.source_cdb", dictionary_scn)</code></pre>



<p class="wp-block-paragraph"><code>wait_for_dictionary_scn</code> polls <code>get_extract_checkpoint</code> every 30 seconds until the old extract’s start SCN passes the new build’s SCN. It gives up after 10 minutes with an error, rather than hanging forever. Both these delays are configurable. The old extract keeps running throughout, since stopping it would freeze its checkpoint.</p>



<p class="wp-block-paragraph">When <code>oracledb</code> is not installed, the same query runs through <code>sqlplus</code> instead :</p>



<pre class="wp-block-code"><code>import shutil
import subprocess

def get_dictionary_scn_sqlplus(dsn, user, password, start_scn):
    if not shutil.which("sqlplus"):
        raise RuntimeError("sqlplus is not on PATH")
    script = f"""
        SET FEEDBACK OFF HEADING OFF PAGESIZE 0
        CONNECT {user}/{password}@{dsn}
        SELECT first_change# FROM v$archived_log
        WHERE dictionary_begin = 'YES' AND standby_dest = 'NO'
        AND name IS NOT NULL AND status = 'A'
        AND first_change# &lt; {start_scn}
        ORDER BY first_change# DESC FETCH FIRST 1 ROWS ONLY;
        EXIT
    """
    proc = subprocess.run(&#091;"sqlplus", "-s", "/nolog"], input=script, capture_output=True, text=True)
    return int(proc.stdout.strip()) if proc.stdout.strip() else None</code></pre>



<pre class="wp-block-code"><code>&gt;&gt;&gt; get_dictionary_scn_sqlplus("localhost:1521/CDB01", "c##oggadmin", "ogg", 25167710)
25134064</code></pre>



<p class="wp-block-paragraph"><span class="proof-marker">Please note that unlike <code>oracledb</code>, <code>sqlplus</code> needs the statement’s trailing <code>;</code> to execute the query.</span></p>



<h2 id="creating-the-new-extract-at-the-correct-scns" class="wp-block-heading">Creating the new extract at the correct SCNs</h2>



<p class="wp-block-paragraph">Rather than retyping the old extract’s parameter file by hand, <code>get_extract</code> returns its exact <code>config</code> and <code>credentials</code>, which the new extract can reuse as is, only changing the <code>EXTRACT</code> name and the <code>EXTTRAIL</code> line :</p>



<pre class="wp-block-code"><code>&gt;&gt;&gt; old = ogg_client.get_extract("EXT1")
&gt;&gt;&gt; old&#091;"config"]
&#091;'EXTRACT EXT1', 'USERIDALIAS source_cdb DOMAIN OracleGoldenGate', 'EXTTRAIL aa', 'SOURCECATALOG PDB1', 'TABLE SALES.ORDERS;']
&gt;&gt;&gt; old&#091;"credentials"]
{'alias': 'source_cdb', 'domain': 'OracleGoldenGate'}</code></pre>



<pre class="wp-block-code"><code>old_config = old&#091;"config"]
credentials = old&#091;"credentials"]

new_config = &#091;]
for line in old_config:
    if line.startswith("EXTRACT "):
        new_config.append("EXTRACT EXT2")
    elif line.startswith("EXTTRAIL "):
        new_config.append("EXTTRAIL pdb1/bb")
    else:
        new_config.append(line)</code></pre>



<p class="wp-block-paragraph">The <code>create_extract</code> call then accepts both the <strong>begin</strong> position (start SCN) and the <strong>registration</strong> (dictionary build SCN) in a single call, on top of the reused config :</p>



<pre class="wp-block-code"><code>&gt;&gt;&gt; ogg_client.stop_extract("EXT1")
&gt;&gt;&gt; r = ogg_client.create_extract(
...     extract="EXT2",
...     begin={"at": {"csn": start_scn}},
...     registration={"containers": &#091;"PDB1"], "csn": dictionary_scn, "replace": True},
...     source="tranlogs",
...     config=new_config,
...     credentials=credentials,
...     targets=&#091;{"name": "bb", "path": "pdb1"}],
... )
&gt;&gt;&gt; &#091;m&#091;"title"] for m in r&#091;"messages"]]
&#091;'Integrated Extract added.', 'Extract group EXT2 successfully registered with database at SCN 25134064.', 'Parameter file EXT2.prm passed validity check.']
&gt;&gt;&gt; r = ogg_client.start_extract("EXT2")
&gt;&gt;&gt; &#091;m&#091;"title"] for m in r&#091;"messages"]]
&#091;'Extract group EXT2 starting.', 'Extract group EXT2 started.']</code></pre>



<p class="wp-block-paragraph">Running <code>OGGRestAPI</code>’s <code>get_extract_status</code> method right after confirms it, with a real process ID and no lag :</p>



<pre class="wp-block-code"><code>&gt;&gt;&gt; ogg_client.get_extract_status("EXT2")
{'$schema': 'ogg:extractStatus', 'status': 'running', 'processId': 127046, 'lastStarted': None, 'lag': 0, 'sinceLagReported': 5, 'position': '0.25477722'}</code></pre>



<p class="wp-block-paragraph">Notice how <code>begin</code> uses the <code>{"at": {"csn": ...}}</code> form to start the integrated extract at a specific SCN, and how <code>registration</code> carries the dictionary build SCN with its <code>csn</code> field. These are the REST equivalents of the <code>add extract ... scn</code> and <code>register extract ... database scn</code> commands.</p>



<p class="wp-block-paragraph">The <code>targets</code> field is easy to miss and not optional : without it, <code>create_extract</code> writes the <code>EXTTRAIL</code> line into the parameter file but never actually creates the trail on disk, and the new extract abends on start with <code>OGG-02454 Trail ... not found in checkpoint file</code>. <code>targets</code> takes the trail’s two-character <code>name</code> and an optional <code>path</code> value. This also means the new trail must have a different name than the old extract.</p>



<h2 id="complete-script" class="wp-block-heading">Complete script</h2>



<p class="wp-block-paragraph">Assembling everything together into a single script, the only thing left to provide is the connection information and the new trail name. If you already have a dictionary SCN, you can pass it with <code>--dictionary-scn</code>, or let the script look it up by itself with <code>--db-dsn</code>/<code>--db-user</code> (<code>--db-password</code> is prompted if you leave it out) :</p>



<pre class="wp-block-code"><code>python rename_extract.py \
  --url https://vmogg \
  --user ogg \
  --deployment ogg_test_01 \
  --old-extract EXT1 \
  --new-extract EXT2 \
  --connection OracleGoldenGate.source_cdb \
  --db-dsn localhost:1521/CDB01 \
  --db-user c##oggadmin \
  --trail pdb1/bb</code></pre>



<p class="wp-block-paragraph">Here is the same <code>EXT1</code> renaming, but forcing <code>--driver sqlplus</code> explicitly :</p>



<pre class="wp-block-code"><code>$ python rename_extract.py \
    --url http://localhost:7810 \
    --user ogg \
    --old-extract EXT1 \
    --new-extract EXT2 \
    --connection OracleGoldenGate.source_cdb \
    --db-dsn localhost:1521/CDB01 \
    --db-user c##oggadmin \
    --driver sqlplus \
    --trail bb
Password for ogg:
Oldest unprocessed SCN of EXT1...
  start SCN (oldest unprocessed): 25378395
Looking up the dictionary build SCN through sqlplus...
  dictionary SCN: 25342438
Stopping extract EXT1...
  start SCN after stop: 25378395
Creating extract EXT2 (register at 25342438, begin at 25378395)...
Starting extract EXT2...
Done.</code></pre>



<p class="wp-block-paragraph">The script fetches the old extract’s config and credentials, computes the start SCN from its recovery checkpoint, looks up the dictionary SCN (building a fresh one and waiting for the checkpoint to pass it if none was found), stops the old extract, then creates and starts the new one with that config, registered and started at the two SCNs.</p>



<p class="wp-block-paragraph">You can find the full <code>rename_extract.py</code> in this <a href="https://juliendelattre.com/docs/rename-goldengate-extract-rest-api-script/" target="_blank" rel="noopener noreferrer">reference doc</a>. It uses <code>oggrestapi</code>, the GoldenGate REST API Python package you can find <a href="https://www.dbi-services.com/blog/the-goldengate-rest-api-python-client-is-now-on-pip/" target="_blank" rel="noopener noreferrer">here</a> or on <a href="https://github.com/juliendlttr/ogg" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>
<p>L’article <a href="https://www.dbi-services.com/blog/rename-a-goldengate-extract-with-the-rest-api/">Rename a GoldenGate Extract with the REST API</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/rename-a-goldengate-extract-with-the-rest-api/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>The GoldenGate REST API Python client is now on pip</title>
		<link>https://www.dbi-services.com/blog/the-goldengate-rest-api-python-client-is-now-on-pip/</link>
					<comments>https://www.dbi-services.com/blog/the-goldengate-rest-api-python-client-is-now-on-pip/#respond</comments>
		
		<dc:creator><![CDATA[Julien Delattre]]></dc:creator>
		<pubDate>Mon, 07 Sep 2026 06:13:00 +0000</pubDate>
				<category><![CDATA[GoldenGate]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[23ai]]></category>
		<category><![CDATA[26ai]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[Automation]]></category>
		<category><![CDATA[Client]]></category>
		<category><![CDATA[microservices]]></category>
		<category><![CDATA[pip]]></category>
		<category><![CDATA[pypi]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[restapi]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=46781</guid>

					<description><![CDATA[<p>In a previous post, I shared the OGGRestAPI Python client I built for the GoldenGate REST API. Since then, I kept using it on production deployments, fixing it and adding new features along the way. It felt like the right time to stop asking people to copy a .py file into their project, so I [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/the-goldengate-rest-api-python-client-is-now-on-pip/">The GoldenGate REST API Python client is now on pip</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">In a <a href="https://www.dbi-services.com/blog/production-ready-goldengate-rest-client-in-python/" target="_blank" rel="noopener noreferrer">previous post</a>, I shared the <code>OGGRestAPI</code> Python client I built for the GoldenGate REST API. Since then, I kept using it on production deployments, fixing it and adding new features along the way. It felt like the right time to stop asking people to copy a <code>.py</code> file into their project, so I published it to PyPI. You can now install it with a single command.</p>



<pre class="wp-block-code"><code>$ pip install oggrestapi
Collecting oggrestapi
  Using cached oggrestapi-1.0.2-py3-none-any.whl (46 kB)
Collecting urllib3
  Using cached urllib3-2.6.3-py3-none-any.whl (131 kB)
Collecting requests
  Using cached requests-2.32.5-py3-none-any.whl (64 kB)
Collecting charset_normalizer&lt;4,&gt;=2
  Using cached charset_normalizer-3.5.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (262 kB)
Collecting certifi&gt;=2017.4.17
  Using cached certifi-2026.7.22-py3-none-any.whl (136 kB)
Collecting idna&lt;4,&gt;=2.5
  Using cached idna-3.19-py3-none-any.whl (68 kB)
Installing collected packages: urllib3, idna, charset-normalizer, certifi, requests, oggrestapi
Successfully installed certifi-2026.7.22 charset-normalizer-3.5.1 idna-3.19 oggrestapi-1.0.2 requests-2.32.5 urllib3-2.6.3</code></pre>



<h2 id="one-package-for-every-goldengate-version" class="wp-block-heading">One package for every GoldenGate version</h2>



<p class="wp-block-paragraph">The biggest change is not the packaging itself, though. Until now, the repository held one <code>oggrestapi.py</code> per GoldenGate version (19c, 23ai, 26ai), each generated separately from that version’s <code>swagger.json</code>. But after thorough tests, I realized that most of the differences came from typos or inconsistencies in the swaggers with no functional differences in the API. The PyPI package now merges all of that into a single <code>OGGRestAPI</code> class that works against any of these versions. You can import the same class regardless of the GoldenGate release you are working with:</p>



<pre class="wp-block-code"><code>from oggrestapi import OGGRestAPI</code></pre>



<h2 id="what-changed-since-the-last-post" class="wp-block-heading">What changed since the last post</h2>



<p class="wp-block-paragraph">A few things arrived in the client between the previous post and this release:</p>



<ul class="wp-block-list">
<li><strong>Auto-discovery mode</strong> &#8211; A new <code>auto_discovery</code> option lets the client reach every microservice of a deployment (Administration Service, Distribution Service, etc.) from a single connection to the Service Manager, without setting up an NGINX reverse proxy first. The client looks up each service’s own port the first time it is needed.</li>



<li><strong>New methods</strong> &#8211; <code>restart_deployment</code>, <code>restart_extract</code>, <code>restart_replicat</code>, <code>restart_service</code> and <code>restart_all_extracts</code> / <code>restart_all_replicats</code> methods, on top of the existing start/stop ones. <code>kill*</code> methods were also added for extracts and replicats.</li>



<li><strong>Context manager support</strong> &#8211; <code>with OGGRestAPI(...) as ogg_client:</code> now closes the underlying HTTP session for you.</li>



<li><strong>Deployment patching helpers</strong> &#8211; Useful when patching the OGG home of a deployment (or every deployment at once) and optionally restart it, with or without an NGINX reverse proxy.</li>
</ul>



<h2 id="auto-discovery-in-practice" class="wp-block-heading">Auto-discovery in practice</h2>



<p class="wp-block-paragraph">Pointing the client at the Service Manager with <code>auto_discovery=True</code> and a deployment name is enough to access the administration service, for instance, without ever touching a reverse proxy configuration. Of course, this only <strong>works if the credentials are the same</strong>.</p>



<pre class="wp-block-code"><code>&gt;&gt;&gt; ogg_client = OGGRestAPI(
...     url="https://vmogg:7809",  # Port to the Service Manager
...     username="ogg",
...     password="ogg",
...     deployment="ogg_test_01",
...     auto_discovery=True
... )
&gt;&gt;&gt; ogg_client.list_extracts()  # Administration Service endpoint. Would normally fail if queried against the Service Manager's port.
&#091;{'name': 'EPARTV2', 'status': 'running'}, {'name': 'EVTEXT', 'status': 'running'}, {'name': 'EXTC2', 'status': 'stopped'}, {'name': 'EXTCX', 'status': 'stopped'}, {'name': 'EXTCZ', 'status': 'stopped'}, {'name': 'EXTDB04', 'status': 'running'}, {'name': 'EXTI', 'status': 'stopped'}, {'name': 'EXTPL', 'status': 'stopped'}, {'name': 'EXTPP', 'status': 'running'}, {'name': 'EXTPT', 'status': 'running'}]
&gt;&gt;&gt; ogg_client.list_replicats()
&#091;{'name': 'REPC2', 'status': 'running'}, {'name': 'REPCX', 'status': 'running'}, {'name': 'REPCZ', 'status': 'running'}, {'name': 'REPPL', 'status': 'running'}, {'name': 'REPPT', 'status': 'running'}]</code></pre>



<h2 id="where-to-find-it" class="wp-block-heading">Where to find it</h2>



<p class="wp-block-paragraph">The package is on <a href="https://pypi.org/project/oggrestapi/" target="_blank" rel="noopener noreferrer">PyPI</a> and the source is still on <a href="https://github.com/juliendlttr/ogg" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>



<ul class="wp-block-list">
<li><code>pip install oggrestapi</code> is now all it takes to get started, on any GoldenGate version.</li>



<li>Of course, you can still download the <code>oggrestapi.py</code> separately, if you cannot run <code>pip install</code> commands against your environment.</li>
</ul>
<p>L’article <a href="https://www.dbi-services.com/blog/the-goldengate-rest-api-python-client-is-now-on-pip/">The GoldenGate REST API Python client is now on pip</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/the-goldengate-rest-api-python-client-is-now-on-pip/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Rename a GoldenGate Extract Without Missing Transactions</title>
		<link>https://www.dbi-services.com/blog/rename-a-goldengate-extract-without-missing-transactions/</link>
					<comments>https://www.dbi-services.com/blog/rename-a-goldengate-extract-without-missing-transactions/#respond</comments>
		
		<dc:creator><![CDATA[Julien Delattre]]></dc:creator>
		<pubDate>Mon, 31 Aug 2026 06:19:00 +0000</pubDate>
				<category><![CDATA[GoldenGate]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[administration]]></category>
		<category><![CDATA[extract]]></category>
		<category><![CDATA[migration]]></category>
		<category><![CDATA[ogg]]></category>
		<category><![CDATA[Rename]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=46579</guid>

					<description><![CDATA[<p>Throughout my consulting missions, I have often been asked to rename GoldenGate extracts. While this is not a difficult task, it should still be done correctly to avoid missing transactions. In this blog, I will explain how to rename a GoldenGate extract from the adminclient. If you often rename extracts, or want to remove the [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/rename-a-goldengate-extract-without-missing-transactions/">Rename a GoldenGate Extract Without Missing Transactions</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Throughout my consulting missions, I have often been asked to <strong>rename GoldenGate extracts</strong>. While this is not a difficult task, it should still be done correctly to avoid missing transactions. In this blog, I will explain how to rename a GoldenGate extract from the <code>adminclient</code>. If you often rename extracts, or want to remove the risk of a typo on a SCN by automating the process, I will also write a blog on renaming an extract with the REST API later.</p>



<p class="wp-block-paragraph">Please note that these operations are useful not just for renaming an extract. You can also use the same steps to move an extract to another deployment, or to another host.</p>



<h2 id="cant-i-just-directly-rename-the-extract-and-restart-it-" class="wp-block-heading">Can’t I just directly rename the extract and restart it ?</h2>



<p class="wp-block-paragraph">Unfortunately, it is <strong>not possible to just rename the extract and restart it</strong>. Extracts are registered in the database and are associated with a specific SCN. If you stop an extract and try to start it with a new name, you will get an error because the extract is not registered with the new name inside the source database. Moreover, if you try to create a new extract with the new name, you will miss transactions if you do not follow the correct steps described in this blog.</p>



<h2 id="steps-to-rename-a-goldengate-extract" class="wp-block-heading">Steps to rename a GoldenGate extract</h2>



<p class="wp-block-paragraph">The main steps to rename a GoldenGate extract are the following:</p>



<ul class="wp-block-list">
<li>Build the <strong>LogMiner data dictionary</strong> (if you don’t already build it regularly).</li>



<li>Check for <strong>long running transactions</strong> in the source database.</li>



<li><strong>Stop the extract</strong> that you want to rename.</li>



<li>Get the SCN of the <strong>oldest unprocessed transaction</strong>.</li>



<li>Find the <strong>dictionary build</strong> to register the new extract.</li>



<li><strong>Create the new extract</strong>, registered and started at the correct SCNs.</li>



<li>Copy the parameter file and <strong>start the new extract</strong>.</li>
</ul>



<h2 id="build-the-logminer-data-dictionary" class="wp-block-heading">Build the LogMiner data dictionary</h2>



<p class="wp-block-paragraph">To register the new extract, you need a LogMiner data dictionary build that exists <strong>at or before the start SCN</strong>. If your dictionary build SCN is after the start SCN, this will not work. If you don’t already build the dictionary regularly, build one now with <code>DBMS_CAPTURE_ADM.BUILD</code> :</p>



<pre class="wp-block-code"><code>SET SERVEROUTPUT ON
DECLARE
    scn NUMBER;
BEGIN
    DBMS_CAPTURE_ADM.BUILD(first_scn =&gt; scn);
    DBMS_OUTPUT.PUT_LINE('Dictionary build starting SCN: ' || scn);
END;
/

Dictionary build starting SCN: 17218169

PL/SQL procedure successfully completed.</code></pre>



<h2 id="check-for-long-running-transactions-in-the-source-database" class="wp-block-heading">Check for long running transactions in the source database</h2>



<p class="wp-block-paragraph">The recovery checkpoint only moves forward when a transaction <strong>commits</strong>. This means that <strong>an open long running transaction will freeze the start SCN</strong>. It is worth checking for long running transactions here : the start SCN (the oldest unprocessed transaction) must stay <strong>after</strong> the dictionary build SCN, since that build is what you register the new extract with. The further back a long running transaction freezes the start SCN, the more likely it drops before your build, and the more redo the new extract has to re-mine before it catches up. I dedicated a full blog on <a href="https://www.dbi-services.com/blog/checking-long-running-transactions-in-goldengate/" target="_blank" rel="noopener noreferrer">checking long running transactions in GoldenGate</a> both from the <code>adminclient</code> and the REST API, please have a look at it.</p>



<pre class="wp-block-code"><code>OGG (https://vmogg ogg_test_01) 1&gt; send extract ext1 showtrans tabular

Sending showtrans tabular request to Extract group EXT1 ...

No transactions found.</code></pre>



<p class="wp-block-paragraph">Here, the idea is to wait until there are no transactions started before the dictionary build SCN.</p>



<h2 id="stop-the-extract-that-you-want-to-rename" class="wp-block-heading">Stop the extract that you want to rename</h2>



<p class="wp-block-paragraph">Once the dictionary is built and there are no long running transactions, you can stop the extract.</p>



<pre class="wp-block-code"><code>OGG (https://vmogg ogg_test_01) 2&gt; stop extract ext1</code></pre>



<h2 id="get-the-scn-of-the-oldest-unprocessed-transaction" class="wp-block-heading">Get the SCN of the oldest unprocessed transaction</h2>



<p class="wp-block-paragraph">The SCN you are looking for is the one of the <strong>oldest unprocessed transaction</strong>, which corresponds to the <strong>recovery checkpoint</strong> of the extract. In the rest of the blog, I will refer to it as the <strong>start SCN</strong>, because this is the SCN from which the new extract will be started. In this example, the <strong>start SCN</strong> is <code>17219083</code>.</p>



<pre class="wp-block-code"><code>OGG (https://vmogg ogg_test_01) 3&gt; info extract ext1 showch
...
  Recovery Checkpoint (position of oldest unprocessed transaction in the data source):
    Timestamp: 2026-08-12 18:35:47.000000
    SCN: 0.17219083 (17219083)
...</code></pre>



<h2 id="find-the-dictionary-build-to-register-the-new-extract" class="wp-block-heading">Find the dictionary build to register the new extract</h2>



<p class="wp-block-paragraph">If you waited for long running transactions to commit, as mentioned before, the dictionary build that you have will be before the start SCN. However, if you build the dictionary on a regular basis and did not check the long running transactions, you need to retrieve the <strong>most recent build that is still older than the start SCN</strong>:</p>



<pre class="wp-block-code"><code>SELECT first_change#
FROM v$archived_log
WHERE dictionary_begin = 'YES'
AND standby_dest = 'NO'
AND name IS NOT NULL
AND status = 'A'
AND first_change# &lt; 17219083 -- the start SCN retrieved above
ORDER BY first_change# DESC
FETCH FIRST 1 ROWS ONLY;

FIRST_CHANGE#
-------------
   17218169</code></pre>



<p class="wp-block-paragraph">The <code>first_change# &lt; start_scn</code> filter is the important part. Without it, you might pick the most recent dictionary build overall, which is not guaranteed to have happened before the start SCN. In the rest of the blog, I will refer to <code>17218169</code> as the <strong>dictionary build SCN</strong>.</p>



<p class="wp-block-paragraph">If the query returns no rows at all, no build predates the start SCN yet. In that case, you must build the dictionary again, as shown above. Then, you must restart the extract and wait for the oldest unprocessed transaction (recovery checkpoint) to go beyond this SCN.</p>



<h2 id="create-the-new-extract-at-the-correct-scns" class="wp-block-heading">Create the new extract at the correct SCNs</h2>



<p class="wp-block-paragraph">We now have the two SCNs we need :</p>



<ul class="wp-block-list">
<li>The <strong>dictionary build SCN</strong> (<code>17218169</code> in the example), used to <strong>register</strong> the extract.</li>



<li>The <strong>start SCN</strong> (<code>17219083</code> in the example), the oldest unprocessed transaction, used to <strong>add</strong> the extract.</li>
</ul>



<p class="wp-block-paragraph">From the <code>adminclient</code>, log into the database, then create and register the new extract :</p>



<pre class="wp-block-code"><code>OGG (https://vmogg ogg_test_01) 4&gt; dblogin useridalias source_cdb
Successfully logged into database CDB$ROOT.

# Here, we are using the start SCN
OGG (https://vmogg ogg_test_01) 5&gt; add extract ext2, integrated tranlog, scn 17219083
Integrated Extract added.

# Here, we are using the dictionary build SCN
OGG (https://vmogg ogg_test_01) 6&gt; register extract ext2 database scn 17218169 container (pdb1)
Extract group EXT2 successfully registered with database at SCN 17218169.</code></pre>



<h2 id="copy-the-parameter-file-and-start-the-new-extract" class="wp-block-heading">Copy the parameter file and start the new extract</h2>



<p class="wp-block-paragraph">Finally, copy the content of the parameter file from the old extract to the new one, only changing the extract name. Here, you need to make one choice:</p>



<ul class="wp-block-list">
<li>Keep the same trail file name, <code>aa</code> in this case. You will have to delete the original <code>EXT1</code> extract, since two extracts cannot write to the same trail file. <code>EXT2</code> will start from the next trail sequence.</li>



<li>Change to another trail file name. In that case, you would have to reconfigure all replicats or distribution paths consuming the trail file.</li>
</ul>



<pre class="wp-block-code"><code>OGG (https://vmogg ogg_test_01) 7&gt; view params ext1
EXTRACT EXT1
USERIDALIAS source_cdb DOMAIN OracleGoldenGate
EXTTRAIL aa
SOURCECATALOG PDB1
TABLE SALES.ORDERS;

OGG (https://vmogg ogg_test_01) 8&gt; edit params ext2
EXTRACT EXT2
USERIDALIAS source_cdb DOMAIN OracleGoldenGate
EXTTRAIL aa
SOURCECATALOG PDB1
TABLE SALES.ORDERS;</code></pre>



<p class="wp-block-paragraph">In this case, <strong>after deleting <code>EXT1</code></strong> to free the trail, assign the trail to <code>EXT2</code>, then <strong>start the new extract</strong>. It will pick up exactly where the old one left off.</p>



<pre class="wp-block-code"><code>OGG (https://vmogg ogg_test_01) 9&gt; add exttrail aa, extract ext2
EXTTRAIL added.

OGG (https://vmogg ogg_test_01) 10&gt; start extract ext2</code></pre>
<p>L’article <a href="https://www.dbi-services.com/blog/rename-a-goldengate-extract-without-missing-transactions/">Rename a GoldenGate Extract Without Missing Transactions</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/rename-a-goldengate-extract-without-missing-transactions/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>GoldenGate DB2 z/OS Upgrade Checklist</title>
		<link>https://www.dbi-services.com/blog/goldengate-db2-z-os-upgrade-checklist/</link>
					<comments>https://www.dbi-services.com/blog/goldengate-db2-z-os-upgrade-checklist/#respond</comments>
		
		<dc:creator><![CDATA[Julien Delattre]]></dc:creator>
		<pubDate>Thu, 27 Aug 2026 06:17:00 +0000</pubDate>
				<category><![CDATA[GoldenGate]]></category>
		<category><![CDATA[19]]></category>
		<category><![CDATA[19c]]></category>
		<category><![CDATA[21]]></category>
		<category><![CDATA[21c]]></category>
		<category><![CDATA[26]]></category>
		<category><![CDATA[26ai]]></category>
		<category><![CDATA[checklist]]></category>
		<category><![CDATA[clidriver]]></category>
		<category><![CDATA[DB2]]></category>
		<category><![CDATA[IBM]]></category>
		<category><![CDATA[Licensing]]></category>
		<category><![CDATA[migration]]></category>
		<category><![CDATA[ogg]]></category>
		<category><![CDATA[OGG-30057]]></category>
		<category><![CDATA[OGG-30121]]></category>
		<category><![CDATA[sql1598n]]></category>
		<category><![CDATA[upgrade]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=46580</guid>

					<description><![CDATA[<p>Upgrading GoldenGate when the source is DB2 for z/OS is not quite the same exercise as upgrading a GoldenGate installation for Oracle. Most of what I described in my generic blogs about planning a GoldenGate upgrade and migrating from Classic to Microservices Architecture is still valid. However, there is an extra layer to deal with. [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/goldengate-db2-z-os-upgrade-checklist/">GoldenGate DB2 z/OS Upgrade Checklist</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Upgrading GoldenGate when the source is <strong>DB2 for z/OS</strong> is not quite the same exercise as upgrading a GoldenGate installation for Oracle. Most of what I described in my generic blogs about <a href="https://www.dbi-services.com/blog/planning-goldengate-migration-before-premier-support-expires/" target="_blank" rel="noopener noreferrer">planning a GoldenGate upgrade</a> and <a href="https://www.dbi-services.com/blog/upgrade-goldengate-from-classic-to-microservices-architecture-before-its-too-late/" target="_blank" rel="noopener noreferrer">migrating from Classic to Microservices Architecture</a> is still valid. However, there is an extra layer to deal with. It has to do with the <strong>IBM Data Server Driver for ODBC and CLI</strong>, and everything DB2-side depending on it. This blog is a consolidated checklist of everything you should check before, during, and after a GoldenGate for DB2 z/OS upgrade, based on issues I faced.</p>



<h2 id="why-db2-zos-upgrades-are-different" class="wp-block-heading">Why DB2 z/OS upgrades are different</h2>



<p class="wp-block-paragraph">With Oracle, a GoldenGate upgrade does not really involve the databases themselves. You just have to install the new home, and migrate or reconfigure extracts and replicats. Provided that you do not have a complex custom layer on top of it (automation, pipelines, etc.), this is everything you have to do. With DB2 z/OS, GoldenGate talks to the DB2 database through the <strong>CLI driver</strong>. This driver has its own version, its own licensing, and its own DB2-side procedures that need to be updated. If you only upgrade GoldenGate and the CLI driver but forget the DB2 z/OS side, you will hit errors when trying to extract data from DB2. On top of this, a stored procedure is installed in the DB2 database, for GoldenGate to work.</p>



<h2 id="the-sql1598n-licensing-issue" class="wp-block-heading">The <code>SQL1598N</code> licensing issue</h2>



<p class="wp-block-paragraph">The first error you might encounter when upgrading the CLI driver as part of a GoldenGate upgrade is related to the licensing file. I detailed this in a <a href="https://www.dbi-services.com/blog/db2-sql1598n-licensing-error-when-upgrading-goldengate/" target="_blank" rel="noopener noreferrer">previous blog</a>, but the short version is: the IBM Data Server Driver for ODBC and CLI does not ship with a license file to connect to DB2 for z/OS. A separate file, <code>db2consv_zs.lic</code>, has to be placed manually into the <code>clidriver/license/</code> directory. T<strong>his file is tied to the exact driver version</strong> ! Reusing the license from your old driver (<code>11.1</code>) in the new driver’s directory (<code>12.1</code>) will not work, and connections will fail with:</p>



<pre class="wp-block-code"><code>SQLState : 42968
NativeError : -1598
DiagMsg: &#091;IBM]&#091;CLI Driver] SQL1598N An attempt to connect to the database
server failed because of a licensing problem. SQLSTATE=42968</code></pre>



<p class="wp-block-paragraph">Remember to get the new license file and test it way before the cutover. Whoever manages IBM software on your side, or IBM support directly, needs to provide a <strong>new</strong> <code>db2consv_zs.lic</code> matching the target driver version. Since getting a license file from IBM support is rarely instantaneous, plan some time to get this done.</p>



<h2 id="the-db2-side-stored-procedure-step" class="wp-block-heading">The DB2-side stored procedure step</h2>



<p class="wp-block-paragraph">This is the part which is easy to miss because it doesn’t happen on the GoldenGate host at all. However, it is documented by Oracle. A GoldenGate extract for DB2 z/OS relies on an <strong>initialization and utility stored procedure</strong> which is installed directly in DB2 itself. This stored procedure ships with each GoldenGate release and is versioned against it. When you upgrade GoldenGate, the stored procedure sitting in the DB2 subsystem does not upgrade itself. It stays at whatever version was installed during the last GoldenGate install, until it is explicitly reinstalled.</p>



<p class="wp-block-paragraph">When setting up a new GoldenGate home for DB2, a <code>zOSutils.zip</code> file is included under <code>$OGG_HOME/lib</code>. This is what you must use. The new stored procedure will replace the old one in the catalog.</p>



<p class="wp-block-paragraph">Just like the CLI driver issues described above, this should be <strong>managed by DB2 engineers</strong>. Installing or replacing a stored procedure at the DB2 level requires the appropriate privileges, which a Database/GoldenGate/Linux administrator typically does not have. Talk with your <strong>DB2 for z/OS DBA or systems engineer</strong> as part of the upgrade plan, and treat the stored procedure reinstall as a mandatory step of the GoldenGate upgrade itself.</p>



<h3 id="ogg-30121-or-ogg-30057-with-db2-procedure-upgrade" class="wp-block-heading"><code>OGG-30121</code> or <code>OGG-30057</code> with DB2 procedure upgrade</h3>



<p class="wp-block-paragraph">If GoldenGate itself gets upgraded but the stored procedure in the DB2 subsystem is left at its old version, the extract will detect the mismatch at startup and abend with <code>OGG-30121</code>:</p>



<pre class="wp-block-code"><code>OGG-30121  ERROR  The initialization and utility stored procedure major version is 210610 and is not compatible with this Extract. (The minor version is 00).</code></pre>



<p class="wp-block-paragraph">Getting an <code>OGG-30121</code> error during a GoldenGate upgrade means that the DB2-side stored procedure reinstall was missed. There is no need to start debugging the GoldenGate configuration.</p>



<p class="wp-block-paragraph">Also, please note that this stored procedure change needs to happen during the GoldenGate upgrade, not before. What I mean by this is that you cannot ask for the stored procedure to be updated a week before the GoldenGate upgrade. You will need to <strong>allocate time for updating the stored procedure</strong> in your upgrade scenario.</p>



<p class="wp-block-paragraph">The reverse situation also exists. If you update the procedure but not GoldenGate, you will have an <code>OGG-30057</code> error when attempting to restart the extracts.</p>



<pre class="wp-block-code"><code>OGG-30057  ERROR  The log reading user-defined function major version is 231010 and is not supported. (The minor version is 00)</code></pre>



<h2 id="other-things-to-check-during-the-upgrade" class="wp-block-heading">Other things to check during the upgrade</h2>



<p class="wp-block-paragraph">Here are a few other points regarding issues I faced when upgrading GoldenGate for DB2 setups in the past:</p>



<ul class="wp-block-list">
<li>The response file contain an <code>IBMCLIDRIVER</code> variable. It must point to the actual root of the CLI driver installation, not a parent directory. A wrong path produces an <a href="https://www.dbi-services.com/blog/deployment-creation-ins-85037-error-with-goldengate-26ai-for-db2-z-os/" target="_blank" rel="noopener noreferrer">INS-85037 deployment error</a> when using <code>oggca.sh</code>.</li>



<li>Confirm your GoldenGate version is still under <strong>Premier Support</strong> or <strong>Extended Support</strong> before you upgrade. Indeed, 19c and 21c Premier Support came to an end in May 2026, as covered in my <a href="https://www.dbi-services.com/blog/planning-goldengate-migration-before-premier-support-expires/" target="_blank" rel="noopener noreferrer">migration planning blog</a>.</li>
</ul>



<h2 id="using-the-migration-utility-with-db2-zos-sources" class="wp-block-heading">Using the Migration Utility with DB2 z/OS sources</h2>



<p class="wp-block-paragraph">If part of your upgrade also involves moving from <strong>Classic Architecture</strong> to Microservices, the general procedure and its limitations are the same, regardless of source database, and covered in <a href="https://www.dbi-services.com/blog/upgrade-goldengate-from-classic-to-microservices-architecture-before-its-too-late/" target="_blank" rel="noopener noreferrer">Upgrade GoldenGate from Classic to Microservices Architecture</a>. You can use the <strong>migration utility</strong> delivered by Oracle (patch <code>37274898</code> / <code>KB100447</code> in MOS). You will still have to pay attention to the points described above.</p>



<h2 id="checklist-summary" class="wp-block-heading">Checklist summary</h2>



<p class="wp-block-paragraph">Before upgrading GoldenGate for DB2 z/OS:</p>



<ul class="wp-block-list">
<li>Confirm your support status before deciding on a target version. You should upgrade to 26ai.</li>



<li>Identify the current and target CLI driver version and request the matching <code>db2consv_zs.lic</code> from IBM (or your internal license owner) ahead of time, if needed.</li>



<li>Open a change request with your DB2 for z/OS DBA/systems engineer to <strong>reinstall the GoldenGate stored procedure</strong> in every affected DB2 database. This must be done during the upgrade, after stopping and before restarting the new extracts.</li>



<li>After cutover, if an extract abends with the <code>OGG-30121</code> or <code>OGG-30057</code> error, check the stored procedure at the DB2 level.</li>
</ul>



<p class="wp-block-paragraph">With this, I hope you will succeed in your GoldenGate for DB2 z/OS migrations and upgrades.</p>
<p>L’article <a href="https://www.dbi-services.com/blog/goldengate-db2-z-os-upgrade-checklist/">GoldenGate DB2 z/OS Upgrade Checklist</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/goldengate-db2-z-os-upgrade-checklist/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Fixing ORA-00904 on Oracle hidden columns during SSMA data migration</title>
		<link>https://www.dbi-services.com/blog/fixing-ora-00904-on-oracle-hidden-columns-during-ssma-data-migration/</link>
					<comments>https://www.dbi-services.com/blog/fixing-ora-00904-on-oracle-hidden-columns-during-ssma-data-migration/#respond</comments>
		
		<dc:creator><![CDATA[Louis Tochon]]></dc:creator>
		<pubDate>Wed, 26 Aug 2026 08:54:51 +0000</pubDate>
				<category><![CDATA[Database management]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[ssma]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=46636</guid>

					<description><![CDATA[<p>SSMA fails with ORA-00904 on Oracle SET UNUSED columns. Fix it with a custom select aliasing NULL, no source DDL required.</p>
<p>L’article <a href="https://www.dbi-services.com/blog/fixing-ora-00904-on-oracle-hidden-columns-during-ssma-data-migration/">Fixing ORA-00904 on Oracle hidden columns during SSMA data migration</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><a href="https://learn.microsoft.com/en-us/sql/ssma/sql-server-migration-assistant?view=sql-server-ver17">SSMA </a>(SQL Server Migration Assistant) handles the whole Oracle-to-SQL Server move: it reads the source data dictionary, converts the schema, then generates a SELECT per table to pull the rows across. That last step is where this story goes wrong.</p>



<h2 id="h-the-problem" class="wp-block-heading">The problem</h2>



<p class="wp-block-paragraph">Migrating ~5,600 Oracle tables to SQL Server with SSMA. Most load fine; ~100 tables fail <strong>Migrate Data</strong> with the same error:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
ERROR &#x5B;42S22] &#x5B;Oracle]&#x5B;ODBC]&#x5B;Ora]ORA-00904:
&quot;SYS_C00004_21081414:28:22$&quot;: invalid identifier
</pre></div>


<p class="wp-block-paragraph">The named column exists in no DDL anyone wrote. The <code>[Ora]</code> prefix says Oracle itself is rejecting the query: SSMA built an extraction SELECT naming a column Oracle refuses to resolve. Tellingly, <code>SELECT *</code> and <code>COUNT(*)</code> run fine against the same table, whatever this column is, Oracle is happy to ignore it, but not to be asked for it by name.</p>



<h2 id="h-where-the-column-actually-comes-from" class="wp-block-heading">Where the column actually comes from</h2>



<p class="wp-block-paragraph">The name is the giveaway: <code>SYS_C00004_21081414:28:22$</code> is what Oracle calls a column after <code>ALTER TABLE … SET UNUSED COLUMN</code>.</p>



<p class="wp-block-paragraph">Oracle offers two ways to get rid of a column: a logical delete and a physical one. The physical delete (<code>ALTER TABLE … DROP COLUMN</code>) is the honest one, but on a large table it is very time- and resource-consuming. That&#8217;s why people reach for the logical delete instead:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: sql; title: ; notranslate">
ALTER TABLE table_name SET UNUSED (column_name);
</pre></div>


<p class="wp-block-paragraph">That statement is metadata-only and instant. The column immediately stops being visible to users, and the physical removal is deferred to whenever there is time for it (see <a href="https://oracle-base.com/articles/8i/dropping-columns" data-type="link" data-id="https://oracle-base.com/articles/8i/dropping-columns">Oracle Documentation</a>):</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: sql; title: ; notranslate">
ALTER TABLE table_name DROP UNUSED COLUMNS;
-- on large tables, cap undo growth by checkpointing every N rows:
ALTER TABLE table_name DROP UNUSED COLUMNS CHECKPOINT 250;
</pre></div>


<p class="wp-block-paragraph">To free the original name for reuse, Oracle renames the column to <code>SYS_C&lt;internal column number&gt;_&lt;YYMMDDHH24:MI:SS&gt;$</code>, sets <code>USER_GENERATED</code> to NO, <code>HIDDEN_COLUMN</code> to YES and releases its <code>COLUMN_ID</code>. So the timestamp is not when the column was added, it is the second someone ran <code>SET UNUSED</code>. Ours says 14 August 2021, 14:28:22.</p>



<p class="wp-block-paragraph">That also explains the error pattern. The operation is one-way and the column is unreadable by design, so naming it gets you ORA-00904 «invalid identifier». <code>SELECT *</code> and <code>COUNT(*)</code> keep working because the column no longer has a <code>COLUMN_ID</code> and is simply excluded from the star. SSMA, however, lists it and builds an explicit column list Oracle then refuses.</p>



<p class="wp-block-paragraph"><strong>Not to be confused with <code>SYS_NC…$</code>.</strong> Those are a different animal: virtual columns backing a function-based index or extended statistics. </p>



<p class="wp-block-paragraph"><strong>Bottom line:</strong> returning NULL costs you nothing. This is a column its owner already decided to delete, holding data Oracle itself will no longer hand out. There is no information left to lose.</p>



<h2 id="h-what-doesn-t-work-for-the-migration" class="wp-block-heading">What doesn&#8217;t work for the migration</h2>



<ul class="wp-block-list">
<li><strong>SSMA setting </strong><code>Ignore hidden system columns = Yes</code> was not making any effect on this use case</li>



<li><strong>Dropping the column on SQL Server</strong> resolves nothing because the error is on the source SELECT, unaffected.</li>



<li><strong>Dropping it on Oracle</strong> could not be done in our scenario because the source is frozen; DDL not allowed.</li>



<li><strong>Custom select, column removed or bare <code>NULL</code></strong>: SSMA still expects the name in its mapping and fails with &#8220;key not present&#8221; or &#8220;does not match up&#8221; before the query ever reaches Oracle.</li>
</ul>



<h2 id="h-find-them-all-first" class="wp-block-heading">Find them all first</h2>



<p class="wp-block-paragraph">Before editing anything, get the full list. Discovering the affected tables one failed migration at a time is a waste of an afternoon because the data dictionary already knows.</p>



<p class="wp-block-paragraph">The reason the columns are findable at all is an asymmetry between two views: an unused column is gone from <code>ALL_TAB_COLUMNS</code>, but still listed in <code>ALL_TAB_COLS</code> with <code>HIDDEN_COLUMN = 'YES'</code>. That second view is what you query:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: sql; title: ; notranslate">
SELECT owner,
table_name,
column_name,
data_type,
internal_column_id,
TO_DATE(REGEXP_SUBSTR(column_name, &#039;\d{8}:\d{2}:\d{2}&#039;),
&#039;YYMMDDHH24:MI:SS&#039;) AS set_unused_at
FROM dba_tab_cols
WHERE hidden_column = &#039;YES&#039;
AND user_generated = &#039;NO&#039;
AND REGEXP_LIKE(column_name, &#039;^SYS_C\d+_\d{8}:\d{2}:\d{2}\$$&#039;)
-- AND owner = &#039;&lt;SCHEMA_NAME&gt;&#039;
ORDER BY owner, table_name, internal_column_id;
</pre></div>


<p class="wp-block-paragraph">The regex is deliberately strict: it matches only the <code>SET UNUSED</code> naming pattern, so virtual columns and other system-generated names stay out of the result. </p>



<p class="wp-block-paragraph">One more view is worth a look, as a cross-check:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: sql; title: ; notranslate">
SELECT owner, table_name, count AS unused_columns
FROM   dba_unused_col_tabs
--WHERE owner = &#039;&lt;SCHEMA_NAME&gt;&#039;
ORDER  BY count DESC, table_name;
</pre></div>


<p class="wp-block-paragraph"><code>DBA_UNUSED_COL_TABS</code> gives the number of unused columns per table. Sorting by that number puts the dangerous tables first: those with two or three hidden columns are the ones where you&#8217;ll forget a line in the custom select and be back at square one.</p>



<h2 id="h-the-fix" class="wp-block-heading">The fix</h2>



<p class="wp-block-paragraph">Keep the hidden column&#8217;s name as an <strong>alias</strong>, but return a literal NULL instead of reading it. SSMA&#8217;s mapping finds the name (no &#8220;key not present&#8221;); Oracle never resolves the real column (no ORA-00904).</p>



<ul class="wp-block-list">
<li><strong>Tools → Project Settings → General → Migration</strong> → enable <strong>Extended data migration options</strong>.</li>
</ul>



<ul class="wp-block-list">
<li><strong>Data Migration Settings</strong> tab → tick <strong>Use custom select</strong> → replace each hidden-column line with:</li>
</ul>



<ol class="wp-block-list"></ol>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: sql; title: ; notranslate">
 SELECT ...   
    TO_CHAR(&quot;&lt;COLUMN_NAME&gt;&quot;, &#039;TM&#039;, &#039;NLS_NUMERIC_CHARACTERS = &#039;&#039;.,&#039;&#039;&#039;) as &quot;&lt;COLUMN_NAME&gt;&quot;,
    NULL as &quot;SYS_C00004_21081414:28:22$&quot;
from &lt;OWNER&gt;.&lt;TABLE_NAME&gt; t
</pre></div>


<ul class="wp-block-list">
<li><strong>Migrate Data</strong> → 100%. Drop the NULL-filled column(s) on SQL Server in post-migration cleanup.</li>
</ul>



<ol class="wp-block-list"></ol>



<h2 id="h-takeaway" class="wp-block-heading">Takeaway</h2>



<p class="wp-block-paragraph"><code>SYS_C…$</code> is not an exotic Oracle feature, it&#8217;s an ordinary column someone deleted years ago, logically. Oracle keeps the name on file; SSMA finds it, insists on naming it, and Oracle refuses to hand it over. Aliasing a NULL satisfies both, then you drop the column on the target. No source DDL, no external tooling, everything inside SSMA, behind a project setting that&#8217;s hidden by default.</p>
<p>L’article <a href="https://www.dbi-services.com/blog/fixing-ora-00904-on-oracle-hidden-columns-during-ssma-data-migration/">Fixing ORA-00904 on Oracle hidden columns during SSMA data migration</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/fixing-ora-00904-on-oracle-hidden-columns-during-ssma-data-migration/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>NGINX Secured Distribution Path with GoldenGate REST API</title>
		<link>https://www.dbi-services.com/blog/nginx-secured-distribution-path-with-goldengate-rest-api/</link>
					<comments>https://www.dbi-services.com/blog/nginx-secured-distribution-path-with-goldengate-rest-api/#respond</comments>
		
		<dc:creator><![CDATA[Julien Delattre]]></dc:creator>
		<pubDate>Mon, 24 Aug 2026 06:05:32 +0000</pubDate>
				<category><![CDATA[GoldenGate]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[26]]></category>
		<category><![CDATA[26ai]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[Automation]]></category>
		<category><![CDATA[distribution-path]]></category>
		<category><![CDATA[Nginx]]></category>
		<category><![CDATA[ogg]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[restapi]]></category>
		<category><![CDATA[Security]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=46561</guid>

					<description><![CDATA[<p>In a previous blog, I presented how to set up a distribution path between two GoldenGate deployments both secured with NGINX. The method I used there was purely through the Web UI. But GoldenGate also exposes a full REST API, and everything you can do in the UI can be done through the API as [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/nginx-secured-distribution-path-with-goldengate-rest-api/">NGINX Secured Distribution Path with GoldenGate REST API</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">In a <a href="https://www.dbi-services.com/blog/create-distribution-paths-in-nginx-secured-goldengate-26ai/" target="_blank" rel="noopener noreferrer">previous blog</a>, I presented how to set up a distribution path between two GoldenGate deployments both secured with NGINX. The method I used there was purely through the Web UI. But GoldenGate also exposes a full REST API, and everything you can do in the UI can be done through the API as well, which is useful for automation, scripting, or when the UI is not reachable.</p>



<p class="wp-block-paragraph">This blog covers the exact same setup, using the REST API instead. I will show two ways of doing it :</p>



<ul class="wp-block-list">
<li>Using <code>oggrestapi.py</code>, the <a href="https://www.dbi-services.com/blog/production-ready-goldengate-rest-client-in-python/" target="_blank" rel="noopener noreferrer">GoldenGate REST client</a> I released in another blog.</li>



<li>Using the <code>requests</code> library to call the REST API directly.</li>
</ul>



<h2 id="prerequisites" class="wp-block-heading">Prerequisites</h2>



<p class="wp-block-paragraph">The prerequisites are the same as in the previous blog :</p>



<ul class="wp-block-list">
<li>Two GoldenGate Microservices deployments, <code>ogg_test_01</code> (source) on <code>oggvm1</code> and <code>ogg_test_02</code> (target) on <code>oggvm2</code>. I will use the latest 26ai version.</li>



<li>Both OGG setups secured with NGINX acting as a reverse proxy, so everything goes through port <code>443</code>.</li>



<li>A running extract on the source, writing to a trail (<code>aa</code> in my case).</li>
</ul>



<p class="wp-block-paragraph">Just like in the Web UI, there are three steps to get a working distribution path :</p>



<ul class="wp-block-list">
<li><a href="#create-the-path-connection"><strong>Create a path connection</strong></a> on the source, to authenticate against the target.</li>



<li><a href="#register-the-targets-ca-certificate" data-type="internal" data-id="#register-the-targets-ca-certificate"><strong>Register the target’s CA certificate</strong></a> on the source Service Manager.</li>



<li><a href="#create-and-start-the-distribution-path"><strong>Create and start the distribution path</strong></a>.</li>
</ul>



<p class="wp-block-paragraph">A quick note on URLs before we start. Behind an NGINX reverse proxy, each service has its own path prefix :</p>



<ul class="wp-block-list">
<li>Administration Service : <code>/services/&lt;deployment&gt;/adminsrvr/v2/...</code></li>



<li>Distribution Service : <code>/services/&lt;deployment&gt;/distsrvr/v2/...</code></li>



<li>Service Manager : <code>/services/ServiceManager/v2/...</code></li>
</ul>



<p class="wp-block-paragraph">The <code>oggrestapi.py</code> client builds these for you as soon as you pass <code>reverse_proxy=True</code> and the deployment name, so let’s connect once and reuse the client. If you don’t provide the <code>password</code> argument, you will be prompted for it.</p>



<pre class="wp-block-code"><code>from oggrestapi import OGGRestAPI

ogg_source = OGGRestAPI(
    url="https://oggvm1",
    username="ogg",
    deployment="ogg_test_01",
    reverse_proxy=True,
)</code></pre>



<h2 id="create-the-path-connection" class="wp-block-heading">Create the path connection</h2>



<p class="wp-block-paragraph">As explained in <a href="https://www.dbi-services.com/blog/creating-path-connections-with-goldengate-rest-api/" target="_blank" rel="noopener noreferrer">Creating Path Connections with GoldenGate REST API</a>, a <strong>path connection is simply an alias in the <code>Network</code> domain</strong>. It stores the credentials of a user that exists on the target deployment, and its alias is only known on the source side.</p>



<p class="wp-block-paragraph">With the client, just call the <code>create_alias</code> method :</p>



<pre class="wp-block-code"><code>ogg_source.create_alias(
    alias="ogg_target",
    domain="Network",
    data={
        "userid": "ogg_user_on_target",
        "password": "***",
    },
)</code></pre>



<p class="wp-block-paragraph">As mentioned in the introduction, here is the same call with <code>requests</code>, calling the Administration Service of <code>oggvm1</code> through NGINX :</p>



<pre class="wp-block-code"><code>import requests

auth = ("ogg", "ogg_password")

response = requests.post(
    "https://oggvm1/services/ogg_test_01/adminsrvr/v2/credentials/Network/ogg_target",
    auth=auth,
    json={
        "userid": "ogg_user_on_target",
        "password": "***",
    },
)</code></pre>



<p class="wp-block-paragraph">After refreshing the source Web UI, the new path connection is visible under the <em><strong>Path Connections</strong></em> tab :</p>



<figure class="wp-block-image"><img decoding="async" src="https://preview.juliendelattre.pages.dev/images/blog/goldengate-path-connections-rest-api.png" alt="GoldenGate Admin Service Path Connections tab showing the ogg_target alias with user ID ogg_user_on_target and type Password" /></figure>



<p class="wp-block-paragraph">But of course, you can also view the new path connection by calling the REST API:</p>



<pre class="wp-block-code"><code># Since path connections are aliases of the Network domain, we use the get_alias method to retrieve them
&gt;&gt;&gt; ogg_source.get_alias('Network', 'ogg_target')
{'$schema': 'ogg:credentials', 'userid': 'ogg_user_on_target', 'type': 'PASSWORD'}</code></pre>



<h2 id="register-the-targets-ca-certificate" class="wp-block-heading">Register the target’s CA certificate</h2>



<p class="wp-block-paragraph">Because the <strong>deployments are secured with NGINX</strong>, the source has to trust the certificate authority that signed the target’s certificate. This is done <strong>on the source Service Manager</strong>, by registering the target’s <strong>root CA certificate</strong>.</p>



<p class="wp-block-paragraph">With the client, use <code>create_deployment_certificate</code> against the source deployment. The certificate type to use is <code>truststore</code>, and the certificate content goes under <code>trustpointBundle.trustpointPem</code>:</p>



<pre class="wp-block-code"><code>target_ca = open("rootCA_ogg_test_02.pem").read()

ogg_source.create_deployment_certificate(
    deployment="ogg_test_01",
    type="truststore",
    certificate="rootCA_ogg_test_02",
    data={
        "trustpointBundle": {
            "trustpointPem": target_ca,
        }
    },
)</code></pre>



<p class="wp-block-paragraph">The same call with <code>requests</code>, this time on the Service Manager prefix :</p>



<pre class="wp-block-code"><code>target_ca = open("rootCA_ogg_test_02.pem").read()

response = requests.post(
    "https://oggvm1/services/ServiceManager/v2/deployments/ogg_test_01/certificates/truststore/rootCA_ogg_test_02",
    auth=auth,
    json={
        "trustpointBundle": {
            "trustpointPem": target_ca,
        }
    },
)</code></pre>



<p class="wp-block-paragraph">Registering under the specific deployment (<code>ogg_test_01</code>) is the equivalent of the <strong>Local</strong> option in the Web UI. To get the <strong>Shared</strong> behavior instead, register the same certificate under the <code>ServiceManager</code> deployment name, so it becomes available to every deployment on that node.</p>



<p class="wp-block-paragraph">If the certificate file contains a <strong>chain</strong> of certificates, you must register each certificate individually, since GoldenGate does not accept them in one go. I described that issue in detail in a <a href="https://www.dbi-services.com/blog/ogg-30007-how-to-register-certificates-in-goldengate/" target="_blank" rel="noopener noreferrer">blog about the <code>OGG-30007</code> error</a>.</p>



<h2 id="create-and-start-the-distribution-path" class="wp-block-heading">Create and start the distribution path</h2>



<p class="wp-block-paragraph">We can now create the distribution path itself. It has a <strong>source endpoint</strong> (the local trail) and a <strong>target endpoint</strong> (the target’s Receiver Service, reached over <code>wss</code> through NGINX). Because the target is NGINX-secured, the target URI :</p>



<ul class="wp-block-list">
<li>uses the <code>wss</code> protocol on port <code>443</code>,</li>



<li>points at the <strong>Receiver Service</strong> path prefix, <code>recvsrvr</code>, not <code>distsrvr</code> (that prefix is only for the Distribution Service on the source side),</li>



<li>does <strong>not</strong> carry the path connection alias itself. The alias goes in a separate <code>authenticationMethod</code> key.</li>
</ul>



<p class="wp-block-paragraph">With the client :</p>



<pre class="wp-block-code"><code>ogg_source.create_distribution_path(
    distpath="path12",
    name="path12",
    source={
        "uri": "trail://localhost/services/v2/sources?trail=PDB1/aa",
    },
    target={
        "uri": "wss://oggvm2/services/ogg_test_02/recvsrvr/v2/targets?trail=PDB1/bb",
        "authenticationMethod": {
            "domain": "Network",
            "alias": "ogg_target",
        },
    },
    begin="now",
    status="running",
)</code></pre>



<p class="wp-block-paragraph">And the equivalent <code>requests</code> call, <strong>on the Distribution Service prefix</strong> (<code>/services/ogg_test_01/distsrvr/</code>):</p>



<pre class="wp-block-code"><code>response = requests.post(
    "https://oggvm1/services/ogg_test_01/distsrvr/v2/sources/path12",
    auth=auth,
    json={
        "name": "path12",
        "source": {
            "uri": "trail://localhost/services/v2/sources?trail=PDB1/aa",
        },
        "target": {
            "uri": "wss://oggvm2/services/ogg_test_02/recvsrvr/v2/targets?trail=PDB1/bb",
            "authenticationMethod": {
                "domain": "Network",
                "alias": "ogg_target",
            },
        },
        "begin": "now",
        "status": "running",
    },
)</code></pre>



<p class="wp-block-paragraph">The trail value in both URIs also has to match the path the extract actually registers, <code>EXTTRAIL PDB1/aa</code> on the source becomes <code>trail=PDB1/aa</code> in the source URI, and the same logic applies to the target’s <code>bb</code> trail. A bare <code>trail=aa</code> without the PDB path segment matches neither what the extract writes nor what the target’s own directory layout expects.</p>



<p class="wp-block-paragraph">Once the path is created with <code>status: "running"</code>, the trail files start flowing. You can confirm it on the target :</p>



<pre class="wp-block-code"><code>oracle@oggvm2:~/ ll $OGG_DEPLOYMENT_HOME/var/lib/data/PDB1
total 0
-rw-r-----. 1 oracle oinstall 0 Mar 22 07:34 bb000000000</code></pre>



<h2 id="the-remote-peer-submitted-a-certificate-that-failed-validation" class="wp-block-heading">The remote peer submitted a certificate that failed validation</h2>



<p class="wp-block-paragraph">If your distribution path doesn’t start and generates a “<em>certificate that failed validation</em>” error, it means that you incorrectly registered your certificates. Make sure that the <strong>target</strong> deployment’s CA certificate is registered on the <strong>source</strong> Service Manager, and not the other way around.</p>



<p class="wp-block-paragraph">And that’s it. With three REST calls, through <code>oggrestapi.py</code> or using the <code>requests</code> module, you get the exact same NGINX-secured distribution path as the Web UI method, but in a form you can script and repeat.</p>
<p>L’article <a href="https://www.dbi-services.com/blog/nginx-secured-distribution-path-with-goldengate-rest-api/">NGINX Secured Distribution Path with GoldenGate REST API</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/nginx-secured-distribution-path-with-goldengate-rest-api/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>GoldenGate 26ai out-of-place patching with Python</title>
		<link>https://www.dbi-services.com/blog/goldengate-26ai-out-of-place-patching-with-python/</link>
					<comments>https://www.dbi-services.com/blog/goldengate-26ai-out-of-place-patching-with-python/#respond</comments>
		
		<dc:creator><![CDATA[Julien Delattre]]></dc:creator>
		<pubDate>Thu, 20 Aug 2026 06:54:00 +0000</pubDate>
				<category><![CDATA[GoldenGate]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[23ai]]></category>
		<category><![CDATA[26ai]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[Automation]]></category>
		<category><![CDATA[ogg]]></category>
		<category><![CDATA[out of place]]></category>
		<category><![CDATA[patch]]></category>
		<category><![CDATA[patching]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[rest]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=44875</guid>

					<description><![CDATA[<p>I already covered out-of-place patching from the web UI, but patching tasks should be automated, and clicking through the same screens for every deployment can get repetitive. Let’s do the exact same out-of-place patch of a GoldenGate Microservices Architecture deployment, this time entirely with the REST API. Every step below shows two ways to make [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/goldengate-26ai-out-of-place-patching-with-python/">GoldenGate 26ai out-of-place patching with Python</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I already covered <a href="https://www.dbi-services.com/blog/goldengate-26ai-out-of-place-patching-with-the-web-ui/" target="_blank" rel="noopener noreferrer">out-of-place patching from the web UI</a>, but patching tasks should be automated, and clicking through the same screens for every deployment can get repetitive. Let’s do the exact same <strong>out-of-place patch of a GoldenGate Microservices Architecture deployment</strong>, this time entirely with the <strong>REST API</strong>.</p>



<p class="wp-block-paragraph">Every step below shows two ways to make the same call:</p>



<ul class="wp-block-list">
<li>A <strong>standard <code>requests</code> call</strong>, the default Python module to handle REST APIs.</li>



<li>The equivalent call using <strong><code>oggrestapi.py</code></strong>, the <code>OGGRestAPI</code> <a href="https://github.com/juliendlttr/ogg/blob/main/src/oggrestapi/oggrestapi.py" target="_blank" rel="noreferrer noopener">Python client</a> I presented in <a href="https://www.dbi-services.com/blog/production-ready-goldengate-rest-client-in-python/" target="_blank" rel="noopener noreferrer">another blog</a>, which handles everything for you.</li>
</ul>



<h2 id="installing-the-latest-version-of-goldengate" class="wp-block-heading">Installing the latest version of GoldenGate</h2>



<p class="wp-block-paragraph">This part does not change: the REST API cannot install software on the server, so you still need to <strong>unzip the patched installation</strong> to a new <code>OGG_HOME</code> and run <code>runInstaller</code> in silent mode, as described in the web UI blog.</p>



<h2 id="patching-the-service-manager-with-the-rest-api" class="wp-block-heading">Patching the Service Manager with the REST API</h2>



<p class="wp-block-paragraph">As with the web UI, the Service Manager has to be patched first. Assume the following setup:</p>



<ul class="wp-block-list">
<li><code>sm_url</code>: <code>https://vmogg:7809</code></li>



<li><code>new_ogg_home</code>: <code>/u01/app/ogg/product/23.26.2.0.1</code></li>



<li><code>username</code> / <code>password</code>: an administrator on the Service Manager</li>
</ul>



<p class="wp-block-paragraph"><strong>Updating <code>OGG_HOME</code></strong> is a <code>PATCH</code> call on the <code>ServiceManager</code> deployment:</p>



<pre class="wp-block-code"><code>import requests

sm_url = "https://vmogg:7809"
auth = ("oggadmin", "password")

requests.patch(
    f"{sm_url}/services/v2/deployments/ServiceManager",
    json={"oggHome": "/u01/app/ogg/product/23.26.2.0.1"},
    auth=auth,
)</code></pre>



<p class="wp-block-paragraph">With <code>oggrestapi.py</code>:</p>



<pre class="wp-block-code"><code>from oggrestapi import OGGRestAPI

client = OGGRestAPI(url="https://vmogg:7809", username="oggadmin", password="password")
client.update_deployment(deployment="ServiceManager", ogg_home="/u01/app/ogg/product/23.26.2.0.1")</code></pre>



<p class="wp-block-paragraph">Already, you can see that the REST API client simplifies the patching a lot.</p>



<p class="wp-block-paragraph"><strong>Restarting the Service Manager</strong> is the same endpoint, this time setting <code>status</code>:</p>



<pre class="wp-block-code"><code>requests.patch(
    f"{sm_url}/services/v2/deployments/ServiceManager",
    json={"status": "restart"},
    auth=auth,
)</code></pre>



<pre class="wp-block-code"><code>client.restart_deployment(deployment="ServiceManager")</code></pre>



<p class="wp-block-paragraph"><code>restart_deployment</code> is a dedicated method in <code>oggrestapi.py</code>, following the same pattern already used for <code>restart_service</code>, <code>restart_extract</code> and <code>restart_replicat</code>. It makes it easier to use the API, instead of building the <code>{"status": "restart"}</code> payload yourself. It also takes an optional <code>only_if_running</code> argument, so a deployment that was already stopped before the patch is left alone rather than being started by the restart call.</p>



<p class="wp-block-paragraph">As with the web UI, all your deployment processes are still running on the old <code>OGG_HOME</code> at this point. The <code>AIService</code>, introduced in 26ai, does not pick up the new home automatically either. You should then <strong>list the services</strong> attached to the Service Manager and <strong>restart the ones that are not <code>ServiceManager</code> itself</strong>:</p>



<pre class="wp-block-code"><code>services = requests.get(
    f"{sm_url}/services/v2/deployments/ServiceManager/services",
    auth=auth,
).json()&#091;"response"]&#091;"items"]

for service in services:
    if service&#091;"name"] != "ServiceManager":
        requests.patch(
            f"{sm_url}/services/v2/deployments/ServiceManager/services/{service&#091;'name']}",
            json={"status": "restart"},
            auth=auth,
        )</code></pre>



<pre class="wp-block-code"><code>for service in client.list_services("ServiceManager"):
    if service.get("name") != "ServiceManager":
        client.restart_service(deployment="ServiceManager", service=service.get("name"))</code></pre>



<h2 id="patching-each-deployment-with-the-rest-api" class="wp-block-heading">Patching each deployment with the REST API</h2>



<p class="wp-block-paragraph">Once the Service Manager runs on the new home, repeat the same <strong>update, then restart</strong> sequence for each deployment (<code>oggHome</code>, then <code>status: restart</code>):</p>



<pre class="wp-block-code"><code>deployment = "ogg_test_01"

requests.patch(
    f"{sm_url}/services/v2/deployments/{deployment}",
    json={"oggHome": "/u01/app/ogg/product/23.26.2.0.1"},
    auth=auth,
)

requests.patch(
    f"{sm_url}/services/v2/deployments/{deployment}",
    json={"status": "restart"},
    auth=auth,
)</code></pre>



<pre class="wp-block-code"><code>client.update_deployment(deployment="ogg_test_01", ogg_home="/u01/app/ogg/product/23.26.2.0.1")
client.restart_deployment(deployment="ogg_test_01")</code></pre>



<p class="wp-block-paragraph">Once the deployment is back up, restart its extracts and replicats. Since these processes are not accessible through the Service Manager port, you need to change the URL. If you use a reverse proxy setup, or <code>auto_discovery=True</code> (see below), this is also easier with the Python client.</p>



<pre class="wp-block-code"><code>admin_url = "https://vmogg:7810"

extracts = requests.get(f"{admin_url}/services/v2/extracts", auth=auth).json()&#091;"response"]&#091;"items"]
for extract in extracts:
    requests.patch(f"{admin_url}/services/v2/extracts/{extract&#091;'name']}", json={"status": "stopped"}, auth=auth)
    requests.patch(f"{admin_url}/services/v2/extracts/{extract&#091;'name']}", json={"status": "running"}, auth=auth)

replicats = requests.get(f"{admin_url}/services/v2/replicats", auth=auth).json()&#091;"response"]&#091;"items"]
for replicat in replicats:
    requests.patch(f"{admin_url}/services/v2/replicats/{replicat&#091;'name']}", json={"status": "stopped"}, auth=auth)
    requests.patch(f"{admin_url}/services/v2/replicats/{replicat&#091;'name']}", json={"status": "running"}, auth=auth)</code></pre>



<p class="wp-block-paragraph">With <code>oggrestapi.py</code>, <code>restart_all_extracts</code> and <code>restart_all_replicats</code> do the same thing on an <code>OGGRestAPI</code> client already pointed at the deployment (either connected directly to its Administration Service, or through an NGINX reverse proxy with <code>deployment=</code> set):</p>



<pre class="wp-block-code"><code>admin_client = OGGRestAPI(url="https://vmogg:7810", username="oggadmin", password="password")
admin_client.restart_all_extracts(only_if_running=True)
admin_client.restart_all_replicats(only_if_running=True)</code></pre>



<h2 id="automating-the-whole-patching-in-one-call" class="wp-block-heading">Automating the whole patching in one call</h2>



<p class="wp-block-paragraph">The steps listed above (update home, restart deployment, restart processes for every deployment) is exactly what <code>patch_deployment</code> (a single deployment) and <code>patch_deployments</code> (all of them) already do in <code>oggrestapi.py</code>, internally calling <code>restart_deployment</code> for the restart step. They also handle the <code>ServiceManager</code> special case (patch and restart the deployment and its services, but never restart extracts and replicats on it) and the <code>wait_until_deployment_status</code> polling in between:</p>



<pre class="wp-block-code"><code>client = OGGRestAPI(url="https://vmogg:7809", username="oggadmin", password="password", reverse_proxy=True)
client.patch_deployments(new_home="/u01/app/ogg/product/23.26.2.0.1", ask_credentials=False)</code></pre>



<p class="wp-block-paragraph">Both methods take <code>restart_after_patch</code> and <code>restart_processes_after_patch</code> (both default to <code>True</code>) if you need to skip either step, for example to patch every home first and restart everything in a separate maintenance window:</p>



<pre class="wp-block-code"><code>client.patch_deployments(
    new_home="/u01/app/ogg/product/23.26.2.0.1",
    restart_after_patch=False,
    restart_processes_after_patch=False,
    ask_credentials=False,
)</code></pre>



<p class="wp-block-paragraph"><code>restart_processes_after_patch=True</code> needs per-deployment routing: restarting extracts and replicats on <code>ogg_test_01</code> is a different call than on <code>ogg_test_02</code>, and a plain connection to the Service Manager’s own port has no way to reach either one. <code>oggrestapi.py</code> gives you two ways to get that routing from a single client:</p>



<ul class="wp-block-list">
<li><code>reverse_proxy=True</code>, shown above, if you already run NGINX in front of your deployments.</li>



<li><code>auto_discovery=True</code>, with no reverse proxy at all. The client looks up each deployment’s real Administration/Distribution/Performance Metrics Service port through the Service Manager itself (the same <code>GET .../deployments/{deployment}/services/{service}</code> call), the first time each one is actually needed, and reuses that lookup for the rest of the run:</li>
</ul>



<pre class="wp-block-code"><code>client = OGGRestAPI(url="https://vmogg:7809", username="oggadmin", password="password", auto_discovery=True)
client.patch_deployments(new_home="/u01/app/ogg/product/23.26.2.0.1", ask_credentials=False)</code></pre>



<p class="wp-block-paragraph">Without either flag, patch with <code>restart_processes_after_patch=False</code> and restart each deployment’s processes yourself through a separate client pointed at that deployment’s own admin URL.</p>



<h2 id="some-services-are-still-running-on-the-old-ogg_home" class="wp-block-heading">Some services are still running on the old <code>OGG_HOME</code></h2>



<p class="wp-block-paragraph">Same as with the web UI: a <code>restart</code> call on a deployment returns as soon as the Administration Service (<code>adminsrvr</code>) is back up. The Receiver Service (<code>recvsrvr</code>) or the Distribution Service (<code>distsrvr</code>) can take a bit longer to restart. If, after polling for a few minutes, a service is still reporting the old home, restart it individually with the same <code>PATCH .../services/{service}</code> call shown above for the <code>AIService</code>, or with the <code>restart_service</code> method.</p>



<h2 id="other-things-to-consider" class="wp-block-heading">Other things to consider</h2>



<p class="wp-block-paragraph">If you change the name of your home at every release, remember to update <code>OGG_HOME</code> in every script and environment that references it, for example:</p>



<ul class="wp-block-list">
<li>DMK environment files.</li>



<li><code>systemd</code> service files, which might hardcode the <code>OGG_HOME</code> variable.</li>
</ul>
<p>L’article <a href="https://www.dbi-services.com/blog/goldengate-26ai-out-of-place-patching-with-python/">GoldenGate 26ai out-of-place patching with Python</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/goldengate-26ai-out-of-place-patching-with-python/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Checking Long Running Transactions in GoldenGate</title>
		<link>https://www.dbi-services.com/blog/checking-long-running-transactions-in-goldengate/</link>
					<comments>https://www.dbi-services.com/blog/checking-long-running-transactions-in-goldengate/#respond</comments>
		
		<dc:creator><![CDATA[Julien Delattre]]></dc:creator>
		<pubDate>Mon, 17 Aug 2026 06:11:00 +0000</pubDate>
				<category><![CDATA[GoldenGate]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[ogg]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[restapi]]></category>
		<category><![CDATA[transactions]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=45630</guid>

					<description><![CDATA[<p>When doing complex operations with GoldenGate, checking for long running transactions is mandatory if you don’t want to miss transactions. Let’s look at two ways of retrieving such information, first with the adminclient, and then with the REST API. When and why should I worry about long running transactions ? In a standard extract life-cycle, [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/checking-long-running-transactions-in-goldengate/">Checking Long Running Transactions in GoldenGate</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">When doing complex operations with GoldenGate, checking for long running transactions is mandatory if you don’t want to miss transactions. Let’s look at two ways of retrieving such information, first with the <code>adminclient</code>, and then with the REST API.</p>



<h2 id="h-when-and-why-should-i-worry-about-long-running-transactions" class="wp-block-heading">When and why should I worry about long running transactions ?</h2>



<p class="wp-block-paragraph">In a standard extract life-cycle, you should not be worrying about long running transactions. In fact, the only time you should think about these is when you plan an extract migration. By this, I mean moving an ongoing extract to a new GoldenGate environment.</p>



<p class="wp-block-paragraph">This could be the case if you are moving the extract to a new GoldenGate deployment, whether it’s because of a version upgrade, system change or architecture change.</p>



<p class="wp-block-paragraph">Another candidate scenario would be if you wanted to rename an extract.</p>



<h2 id="h-checking-for-long-running-transactions-with-the-adminclient" class="wp-block-heading">Checking for Long Running Transactions with the <code>adminclient</code></h2>



<p class="wp-block-paragraph">To check for long running transactions in the source database, you can use the <code>adminclient</code> and the <code>showtrans tabular</code> option of the <code>send</code> command.</p>



<pre class="wp-block-code"><code>OGG (https://vmogg ogg_test_01) 1&gt; send extract ext showtrans tabular

Sending showtrans tabular request to Extract group EXT ...



XID                     Items    Extract   Redo Thread  Start Time           SCN                               Redo Seq  Redo RBA            Status
------------------------------------------------------------------------------------------------------------------------------------------------------
0.17.18.1700953         0        EXT       1            2026-06-06:08:04:12  629.3084780551 (2704619209735)    48911     156909584           Running</code></pre>



<p class="wp-block-paragraph"><strong>WARNING:</strong> This command will query the database for <strong>ALL</strong> active transactions ! There is absolutely no filter in place to only show transactions that are relevant for the extract you are targeting. To confirm this, let’s look in the database to get more information about this transaction.</p>



<pre class="wp-block-code"><code>-- Query to get the schema associated with a specific transaction, based on the XID column from the OGG output above
SELECT s.username, t.xidusn, t.xidslot, t.xidsqn, t.start_time, t.start_scn
FROM v$transaction t
JOIN v$session s ON t.ses_addr = s.saddr
WHERE t.xidusn = 17
AND t.xidslot = 18
AND t.xidsqn = 1700953;

USERNAME       XIDUSN     XIDSLOT      XIDSQN START_TIME          START_SCN
---------  ----------  ----------  ---------- ------------------- ----------------
DBIBLOG            17          18     1700953 06/06/26 08:04:12   2704619209735</code></pre>



<p class="wp-block-paragraph">But if I look at the extract parameter file, the <code>DBIBLOG</code> schema is not even being extracted.</p>



<pre class="wp-block-code"><code>OGG (https://vmogg ogg_test_01) 1&gt; view params EXT
EXTRACT EXT
USERIDALIAS source_cdb DOMAIN OracleGoldenGate
EXTTRAIL pdb1/aa
SOURCECATALOG PDB1
TABLE APP_SCHEMA.*;</code></pre>



<p class="wp-block-paragraph">Of course, the <code>DBIBLOG</code> user might be editing data in the <code>APP_SCHEMA</code> schema, but there is no way to know for sure just by looking at the output of <code>adminclient</code> command above.</p>



<p class="wp-block-paragraph">When searching for long running transactions, you should retrieve the <code>START_SCN</code> of the transaction. In the example given above, the <code>START_SCN</code> is <code>2704619209735</code>.</p>



<p class="wp-block-paragraph">Now that we have the <code>START_SCN</code>, we can check if the extract has already processed it or not by looking at the checkpoint information. From the <code>adminclient</code>, run the <code>info extract EXT showch</code> command:</p>



<pre class="wp-block-code"><code>OGG (https://vmogg ogg_test_01) 1&gt; info extract EXT showch

Extract    EXT       Last Started 2026-06-06 07:45   Status RUNNING
Description          'Test extract'
Checkpoint Lag       00:01:45 (updated 00:00:32 ago)
Process ID           11711
Log Read Checkpoint  Oracle Integrated Redo Logs
                     2026-06-06:09:01:45
                     SCN 629.3086233843 (2704620663027)
Settings Profile     ogg:managedProcessSettings:dbiDefault


Current Checkpoint Detail:

Read Checkpoint #1

  Oracle Integrated Redo Log

  Startup Checkpoint (starting position in the data source):
    Timestamp: 2026-06-06:07:45:45.000000
    SCN: 0.0 (0)

  Recovery Checkpoint (position of oldest unprocessed transaction in the data source):
    Timestamp: 2026-06-06:08:04:13.000000
    SCN: 629.3084780551 (2704619209735)

  Current Checkpoint (position of last record read in the data source):
    Timestamp: 2026-06-06:09:01:45.000000
    SCN: 629.3086233843 (2704620663027)

  BR Startup Recovery Checkpoint:
    Timestamp: 2026-06-02 10:17:33.403806
    SCN: 0.0 (0)

  BR Begin Recovery Checkpoint:
    Timestamp: 2026-06-06 08:04:13.000000
    SCN: 629.3084780551 (2704619209735)

  BR End Recovery Checkpoint:
    Timestamp: 2026-06-06 08:08:45.000000
    SCN: 629.3084879559 (2704619308743)

Write Checkpoint #1

  GGS Log Trail

  Current Checkpoint (current write position):
    Sequence #: 41
    RBA: 50476
...</code></pre>



<p class="wp-block-paragraph">If we put side to side the <code>START_SCN</code> of the long running transaction and the <code>SCN</code> of the recovery checkpoint, we can see that they are exactly the same (<code>2704619209735</code>). This is expected, and it means that the extract has not yet processed this transaction.</p>



<pre class="wp-block-code"><code># From SQL query on the source database
USERNAME       XIDUSN     XIDSLOT      XIDSQN START_TIME          START_SCN
---------  ----------  ----------  ---------- ------------------- ----------------
DBIBLOG            17          18     1700953 06/06/26 08:04:12   2704619209735

# From adminclient
  Recovery Checkpoint (position of oldest unprocessed transaction in the data source):
    Timestamp: 2026-06-06:08:04:13.000000
    SCN: 629.3084780551 (2704619209735)</code></pre>



<p class="wp-block-paragraph">If you wanted to <strong>move the extract</strong> to another GoldenGate installation or <strong>rename it</strong>, this would be the <code>SCN</code> at which you would need to start the new extract to avoid missing transactions.</p>



<h2 id="h-checking-for-long-running-transactions-from-the-rest-api" class="wp-block-heading">Checking for Long Running Transactions from the REST API</h2>



<p class="wp-block-paragraph">If you are trying to <strong>automate</strong> the process of checking for long running transactions, using the <code>adminclient</code> might not be the best option. In fact, the display of long running transactions in the <code>adminclient</code> is not designed to be easily parsed by scripts.</p>



<p class="wp-block-paragraph">Fortunately, you can also <strong>check for long running transactions</strong> using the official <strong>GoldenGate REST API</strong>. The endpoint that you need to call is <code>GET /services/{version}/connections/{connection}/activeTransactions</code>. It is described in the GoldenGate <a href="https://docs.oracle.com/en/database/goldengate/core/26/oggra/op-services-version-connections-connection-activetransactions-get.html" target="_blank" rel="noreferrer noopener">REST API documentation</a>.</p>



<p class="wp-block-paragraph">The endpoint path parameters explain why the transactions shown in the output are not specific to the endpoint. In GoldenGate, a <code>connection</code> is database specific. Combine the domain name and the alias name with a dot separator to form the <code>connection</code> name. In my case, the <code>connection</code> name is <code>OracleGoldenGate.source_cdb</code>.</p>



<p class="wp-block-paragraph">In Python, let’s see two ways of getting the same information:</p>



<ul class="wp-block-list">
<li>Using the production-ready Python client I presented in <a href="https://www.dbi-services.com/blog/production-ready-goldengate-rest-client-in-python/" target="_blank" rel="noreferrer noopener">another blog</a>.</li>



<li>Using the <code>requests</code> library to call the REST API directly.</li>
</ul>



<p class="wp-block-paragraph">Using the Python client, you can just call the <code>get_active_transactions</code> method as follows:</p>



<pre class="wp-block-code"><code>from oggrestapi import OGGRestAPI

ogg_client = OGGRestAPI(
    url="https://vmogg:7809",
    username="ogg",
)

active_transactions = ogg_client.get_active_transactions('OracleGoldenGate.source_cdb')

&gt;&gt;&gt; active_transactions
{'activeTransactions': &#091;{'txnStartScn': 2704619209735, 'txnStatus': 'ACTIVE', 'txnStartDate': '2026-06-06T08:04:12.000Z', 'sid': 834, 'serialNum': 16450, 'instanceId': 1, 'userName': 'DBIBLOG', 'osUser': 'oracle', 'sessionStatus': 'INACTIVE', 'logonTime': '2026-06-06T08:04:11.456Z'}], 'currentScn': {'csn': 2704620465717, 'currentDate': '2026-06-06T08:27:45.717Z', 'userName': 'SYS'}, '$schema': 'ogg:activeTransactions'}</code></pre>



<p class="wp-block-paragraph">Otherwise, with the <code>requests</code> library, you can call the <code>activeTransactions</code> endpoint as follows:</p>



<pre class="wp-block-code"><code>import requests

connection_name = "OracleGoldenGate.source_cdb"
# Basic configuration
# Direct connection (no reverse proxy)
# url = f"https://vmogg:7809/services/v2/connections/{connection_name}/activeTransactions"
# NGINX reverse proxy
url = f"https://vmogg/services/ogg_test_01/adminsrvr/v2/connections/{connection_name}/activeTransactions"

auth = ("ogg", "ogg_password")
response = requests.get(
    url,
    auth=auth
)</code></pre>



<p class="wp-block-paragraph">Here is an example of the output that you should get when looking at the <code>response.json()</code> value:</p>



<pre class="wp-block-code"><code>&gt;&gt;&gt; active_transactions = response.json()&#091;'response']
&gt;&gt;&gt; active_transactions
{'activeTransactions': &#091;{'txnStartScn': 2704619209735, 'txnStatus': 'ACTIVE', 'txnStartDate': '2026-06-06T08:04:12.000Z', 'sid': 834, 'serialNum': 16450, 'instanceId': 1, 'userName': 'DBIBLOG', 'osUser': 'oracle', 'sessionStatus': 'INACTIVE', 'logonTime': '2026-06-06T08:04:11.456Z'}], 'currentScn': {'csn': 2704620465717, 'currentDate': '2026-06-06T08:27:45.717Z', 'userName': 'SYS'}, '$schema': 'ogg:activeTransactions'}</code></pre>



<p class="wp-block-paragraph">Or using the <code>json.dumps()</code> method to get a more readable output:</p>



<pre class="wp-block-code"><code>&gt;&gt;&gt; import json
&gt;&gt;&gt; print(json.dumps(active_transactions, indent=4))
{
    "activeTransactions": &#091;
        {
            "txnStartScn": 2704619209735,
            "txnStatus": "ACTIVE",
            "txnStartDate": "2026-06-06T08:04:12.000Z",
            "sid": 834,
            "serialNum": 16450,
            "instanceId": 1,
            "userName": "DBIBLOG",
            "osUser": "oracle",
            "sessionStatus": "INACTIVE",
            "logonTime": "2026-06-06T08:04:11.456Z"
        }
    ],
    "currentScn": {
        "csn": 2704620465717,
        "currentDate": "2026-06-06T08:27:45.717Z",
        "userName": "SYS"
    },
    "$schema": "ogg:activeTransactions"
}</code></pre>



<p class="wp-block-paragraph">Using the REST API, the information is more complete and easier to parse. As mentioned before, retrieving the <code>SCN</code> at which the transaction started is sometimes necessary. In that case, you can get it from the following command:</p>



<pre class="wp-block-code"><code>&gt;&gt;&gt; start_scn = active_transactions&#091;'activeTransactions']&#091;0]&#091;'txnStartScn']
&gt;&gt;&gt; start_scn
2704619209735</code></pre>



<p class="wp-block-paragraph">If you have multiple long running transactions, you should retrieve the minimum value for the <code>txnStartScn</code> to be sure to get the <code>SCN</code> of the oldest long running transaction.</p>



<pre class="wp-block-code"><code>&gt;&gt;&gt; start_scns = &#091;txn&#091;'txnStartScn'] for txn in active_transactions&#091;'activeTransactions']]
&gt;&gt;&gt; min(start_scns)
2704619209735</code></pre>



<p class="wp-block-paragraph">Now that we’ve retrieved the <code>START_SCN</code> of the long running transaction, we should check the checkpoint information.</p>



<p class="wp-block-paragraph">Using the Python client, you can call the <code>get_extract_checkpoint</code> method as follows:</p>



<pre class="wp-block-code"><code>&gt;&gt;&gt; extract_checkpoints = ogg_client.get_extract_checkpoint('EXT')
&gt;&gt;&gt; extract_checkpoints
{'$schema': 'ogg:extractCheckpoints', 'current': {'input': &#091;{'starting': {'timestamp': '2026-06-06T07:45:45.000Z', 'thread': 1, 'sequence': 0, 'offset': 0, 'csn': None, 'name': None}, 'recovery': {'timestamp': '2026-06-06T08:04:13.000Z', 'thread': 1, 'sequence': 48911, 'offset': 156909584, 'csn': 2704619209735, 'name': None}, 'current': {'timestamp': '2026-06-06T09:01:45.000Z', 'thread': 1, 'sequence': 0, 'offset': 0, 'csn': 2704620663027, 'name': None}, 'boundedRecoveryPrevious': {'timestamp': '2026-06-02 10:17:33.404Z', 'thread': 0, 'sequence': 0, 'offset': 0, 'csn': None, 'name': None}, 'boundedRecoveryBegin': {'timestamp': '2026-06-06T08:04:13.000Z', 'thread': 0, 'sequence': 48911, 'offset': 156909584, 'csn': 2704619209735, 'name': None}, 'boundedRecoveryEnd': {'timestamp': '2026-06-06T08:08:45.000Z', 'thread': 1, 'sequence': 48912, 'offset': 156918384, 'csn': 2704619308743, 'name': None}}]}</code></pre>



<p class="wp-block-paragraph">Or, using the <code>requests</code> library:</p>



<pre class="wp-block-code"><code>response = requests.get(
    "https://vmogg/services/ogg_test_01/adminsrvr/v2/extracts/EXT/checkpoint",
    auth=auth
)

extract_checkpoints = response.json()&#091;'response']</code></pre>



<p class="wp-block-paragraph">Here is a more readable output from the checkpoint information:</p>



<pre class="wp-block-code"><code>&gt;&gt;&gt; print(json.dumps(extract_checkpoints, indent=4))
{
    "$schema": "ogg:extractCheckpoints",
    "current": {
        "input": &#091;
            {
                "starting": {
                    "timestamp": "2026-06-06T07:45:45.000Z",
                    "thread": 1,
                    "sequence": 0,
                    "offset": 0,
                    "csn": null,
                    "name": null
                },
                "recovery": {
                    "timestamp": "2026-06-06T08:04:13.000Z",
                    "thread": 1,
                    "sequence": 48911,
                    "offset": 156909584,
                    "csn": 2704619209735,
                    "name": null
                },
                "current": {
                    "timestamp": "2026-06-06T09:01:45.000Z",
                    "thread": 1,
                    "sequence": 0,
                    "offset": 0,
                    "csn": 2704620663027,
                    "name": null
                },
                "boundedRecoveryPrevious": {
                    "timestamp": "2026-06-02T10:17:33.404Z",
                    "thread": 0,
                    "sequence": 0,
                    "offset": 0,
                    "csn": null,
                    "name": null
                },
                "boundedRecoveryBegin": {
                    "timestamp": "2026-06-06T08:04:13.000Z",
                    "thread": 0,
                    "sequence": 48911,
                    "offset": 156909584,
                    "csn": 2704619209735,
                    "name": null
                },
                "boundedRecoveryEnd": {
                    "timestamp": "2026-06-06T08:08:45.000Z",
                    "thread": 1,
                    "sequence": 48912,
                    "offset": 156918384,
                    "csn": 2704619308743,
                    "name": null
                }
            }
        ]
    }
}</code></pre>



<p class="wp-block-paragraph">And to finish with, from the json, you can retrieve the <code>SCN</code> of the recovery checkpoint:</p>



<pre class="wp-block-code"><code>&gt;&gt;&gt; recovery_checkpoint_scn = extract_checkpoints&#091;'current']&#091;'input']&#091;0]&#091;'recovery']&#091;'csn']
&gt;&gt;&gt; recovery_checkpoint_scn
2704619209735</code></pre>



<p class="wp-block-paragraph">Whether it’s to rename or move an extract, you now know why you should check long running transactions in GoldenGate, and how to do it from the <code>adminclient</code> and the REST API.</p>
<p>L’article <a href="https://www.dbi-services.com/blog/checking-long-running-transactions-in-goldengate/">Checking Long Running Transactions in GoldenGate</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/checking-long-running-transactions-in-goldengate/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>DB2 SQL1598N Licensing Error When Upgrading GoldenGate</title>
		<link>https://www.dbi-services.com/blog/db2-sql1598n-licensing-error-when-upgrading-goldengate/</link>
					<comments>https://www.dbi-services.com/blog/db2-sql1598n-licensing-error-when-upgrading-goldengate/#respond</comments>
		
		<dc:creator><![CDATA[Julien Delattre]]></dc:creator>
		<pubDate>Thu, 13 Aug 2026 06:18:00 +0000</pubDate>
				<category><![CDATA[GoldenGate]]></category>
		<category><![CDATA[26]]></category>
		<category><![CDATA[26ai]]></category>
		<category><![CDATA[CLI]]></category>
		<category><![CDATA[clidriver]]></category>
		<category><![CDATA[DB2]]></category>
		<category><![CDATA[db2cli]]></category>
		<category><![CDATA[Error]]></category>
		<category><![CDATA[execsql]]></category>
		<category><![CDATA[IBM]]></category>
		<category><![CDATA[Licensing]]></category>
		<category><![CDATA[ogg]]></category>
		<category><![CDATA[sql1598n]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=46175</guid>

					<description><![CDATA[<p>While upgrading GoldenGate to 26ai for a DB2 z/OS source, I had to update the IBM Data Server Driver for ODBC and CLI (CLI Driver, in short) alongside it. Since I realized that DB2 driver know-how was rare in companies, I figured it would be worth writing a blog about the topic. In this GoldenGate [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/db2-sql1598n-licensing-error-when-upgrading-goldengate/">DB2 SQL1598N Licensing Error When Upgrading GoldenGate</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">While upgrading GoldenGate to 26ai for a DB2 z/OS source, I had to update the <em><a href="https://www.ibm.com/support/pages/db2-odbc-cli-driver-download-and-installation-information" target="_blank" rel="noreferrer noopener">IBM Data Server Driver for ODBC and CLI</a></em> (<em><strong>CLI Driver</strong></em>, in short) alongside it. Since I realized that DB2 driver know-how was rare in companies, I figured it would be worth writing a blog about the topic.</p>



<p class="wp-block-paragraph">In this GoldenGate upgrade, the previous driver was version 11.1 and the target version was 12.1. After installing the new driver, <code>db2cli execsql</code> commands that previously worked started failing with the following error:</p>



<pre class="wp-block-code"><code>db2cli execsql -db &lt;database_alias&gt; -user &lt;username&gt; -passwd &lt;password&gt; \
  -inputsql /home/oracle/input.sql</code></pre>



<p class="wp-block-paragraph">Where <code>/home/oracle/input.sql</code> just contains a trivial test query:</p>



<pre class="wp-block-code"><code>select 1 from sysibm.sysdummy1;</code></pre>



<p class="wp-block-paragraph">The <code>sysibm.sysdummy1</code> table is DB2’s equivalent of Oracle’s <code>DUAL</code>, so this is about the simplest query you can run to check connectivity. It failed with the following error:</p>



<pre class="wp-block-code"><code>SQLError: 1 = 0 (SQL_SUCCESS)
SQLGetDiagRec: SQLState : 42968
NativeError : -1598
DiagMsg: &#091;IBM]&#091;CLI Driver] SQL1598N An attempt to connect to the database server failed because of a licensing problem. SQLSTATE=42968</code></pre>



<h2 id="h-what-sql1598n-means" class="wp-block-heading">What SQL1598N means</h2>



<p class="wp-block-paragraph"><code>SQL1598N</code> means the DB2 client does not have a valid license to connect to this database. The CLI driver loaded fine. But when it tried to establish an authenticated connection the server rejected it on licensing grounds.</p>



<p class="wp-block-paragraph">This is distinct from a connection failure or an authentication failure.</p>



<h2 id="h-root-cause" class="wp-block-heading">Root cause</h2>



<p class="wp-block-paragraph">It might not be obvious for Oracle-accustomed DBAs, but the <strong>DB2 CLI Driver does not ship with a license file</strong> for connecting to DB2 for z/OS. A separate license file named <code>db2consv_zs.lic</code> must be placed manually in the <code>clidriver/license/</code> directory of the driver installation.</p>



<p class="wp-block-paragraph">The critical point is that <strong>the license file is version-specific and cannot be reused across driver versions</strong>. The license file that worked with driver 11.1 is not valid for driver 12.1. After upgrading the driver, the new installation directory does not contain the license file in the <code>license/</code> folder, and copying the old license file into it will not resolve the error.</p>



<h2 id="h-observed-behavior" class="wp-block-heading">Observed behavior</h2>



<p class="wp-block-paragraph">The error was reproducible every time the same command was run against the new driver. For reference, a successful run against a properly licensed driver returns:</p>



<pre class="wp-block-code"><code>FetchAll: Columns: 1
1
1
FetchAll: 1 rows fetched.</code></pre>



<h2 id="h-license-file-location" class="wp-block-heading">License file location</h2>



<p class="wp-block-paragraph">It is important to keep in mind that the license file belongs in the <code>license/</code> subdirectory of the CLI driver installation. With CLI driver 11.1, the path looked like:</p>



<pre class="wp-block-code"><code>/opt/ibm/db2_odbc_cli_11_1/clidriver/license/db2consv_zs.lic</code></pre>



<p class="wp-block-paragraph">After upgrading to 12.1, the <strong>new driver</strong> has its own separate installation directory with <strong>its own <code>license/</code> subdirectory</strong>. Placing the old 11.1 license file there will not work &#8211; the file is tied to the driver version.</p>



<h2 id="h-how-to-fix-the-issue" class="wp-block-heading">How to fix the issue ?</h2>



<p class="wp-block-paragraph">Since the old file is unusable, you must obtain a new license file matching the installed driver version from IBM. Essentially, you have two options here:</p>



<ul class="wp-block-list">
<li><strong>Contact your DB2 engineers</strong>: if someone on the team manages IBM software licenses, they should be able to provide the correct <code>db2consv_zs.lic</code> for the version you installed.</li>



<li><strong>Open a case with IBM customer support</strong>: IBM will provide the appropriate license file for the new driver version.</li>
</ul>



<p class="wp-block-paragraph">Once you have the correct file, place it in the <code>clidriver/license/</code> directory of the new driver installation and retry the same <code>db2cli execsql</code> command given above. No restart is required.</p>



<p class="wp-block-paragraph">DB2 CLI drivers are not that complicated to use and to debug. However, there are a few fundamentals that GoldenGate administrators should know before attempting a migration. Renewing the license file is one of them.</p>
<p>L’article <a href="https://www.dbi-services.com/blog/db2-sql1598n-licensing-error-when-upgrading-goldengate/">DB2 SQL1598N Licensing Error When Upgrading GoldenGate</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/db2-sql1598n-licensing-error-when-upgrading-goldengate/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>GoldenGate Extract Abending on NFS Trail: OGG-02897 / OGG-01668 Input/Output Error</title>
		<link>https://www.dbi-services.com/blog/goldengate-extract-abending-on-nfs-trail-ogg-02897-ogg-01668-input-output-error/</link>
					<comments>https://www.dbi-services.com/blog/goldengate-extract-abending-on-nfs-trail-ogg-02897-ogg-01668-input-output-error/#respond</comments>
		
		<dc:creator><![CDATA[Julien Delattre]]></dc:creator>
		<pubDate>Mon, 10 Aug 2026 06:02:00 +0000</pubDate>
				<category><![CDATA[GoldenGate]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[19]]></category>
		<category><![CDATA[19c]]></category>
		<category><![CDATA[26]]></category>
		<category><![CDATA[26ai]]></category>
		<category><![CDATA[Error]]></category>
		<category><![CDATA[extract]]></category>
		<category><![CDATA[NFS]]></category>
		<category><![CDATA[ogg]]></category>
		<category><![CDATA[ogg-01668]]></category>
		<category><![CDATA[ogg-02897]]></category>
		<category><![CDATA[trail]]></category>
		<category><![CDATA[Troubleshooting]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=46068</guid>

					<description><![CDATA[<p>While working on a client’s GoldenGate 26ai environment, I ran into a NFS-related replication issue that could have been serious, had it happened in production. Here is what happened and how the issue was fixed. The client’s GoldenGate extract was running on a dedicated server, capturing changes from an Oracle 19c source database. Trail files [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/goldengate-extract-abending-on-nfs-trail-ogg-02897-ogg-01668-input-output-error/">GoldenGate Extract Abending on NFS Trail: OGG-02897 / OGG-01668 Input/Output Error</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">While working on a client’s GoldenGate 26ai environment, I ran into a NFS-related replication issue that could have been serious, had it happened in production. Here is what happened and how the issue was fixed.</p>



<p class="wp-block-paragraph">The client’s GoldenGate extract was running on a dedicated server, capturing changes from an Oracle 19c source database. Trail files were written on an NFS. Depending on the configuration, this is officially supported by Oracle, and works rather well.</p>



<h2 id="h-ogg-02897-ogg-01668-input-output-error" class="wp-block-heading"><code>OGG-02897</code> / <code>OGG-01668</code> Input/Output Error</h2>



<p class="wp-block-paragraph">On a Monday morning, however, the extract was <code>ABENDED</code>. The extract had been down since Saturday night, with the following error messages:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
2026-06-07T00:19:11.404+0200  ERROR   OGG-02897  Oracle GoldenGate Capture for Oracle, EXT.prm:  Failed to synchronize trail file. Error detail: Could not sync &quot;PDB1/aa000000009&quot; (error 5, Input/output error).
2026-06-07T00:19:11.404+0200  ERROR   OGG-01668  Oracle GoldenGate Capture for Oracle, EXT.prm:  PROCESS ABENDING.
</pre></div>


<p class="wp-block-paragraph">The extract was failing with an <code>OGG-02897</code> error. The OS-level error, <code>errno 5: Input/output error</code>, did not seem to indicate any good news for us. Needless to say that restarting the extract did not fix the issue.</p>



<h2 id="h-root-cause-analysis" class="wp-block-heading">Root Cause Analysis</h2>



<p class="wp-block-paragraph">A firewall upgrade had taken place that Saturday night. The firewall between the GoldenGate server and the NFS server was upgraded, and it briefly went down during the operation.</p>



<p class="wp-block-paragraph">The real problem was what happened after the firewall came back up: some extracts caught up and managed to restart properly, while other were left in this <code>ABENDED</code> state, unable to restart. For these extracts, I/O operations kept failing even though the network path was healthy again.</p>



<h2 id="h-solution-remount-the-nfs" class="wp-block-heading">Solution: Remount the NFS</h2>



<p class="wp-block-paragraph">The solution was to stop all GoldenGate processes whose trail files were generated on the NFS, including all the processes which were running fine, and then unmount and remount the NFS filesystem.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
# Unmount the NFS path
umount /path/to/nfs

# Remount all filesystems defined in /etc/fstab, including the NFS
mount -a
</pre></div>


<p class="wp-block-paragraph">Once that came back up, I restarted the extracts from the <code>adminclient</code> and they all started successfully.</p>



<p class="wp-block-paragraph">In this case, the firewall upgrade happened during the night with no GoldenGate-aware procedure in place. Next time, a scheduled GoldenGate maintenance spanning over the firewall upgrade window will probably avoid crashing multiple replications during the week-end, or worse.</p>
<p>L’article <a href="https://www.dbi-services.com/blog/goldengate-extract-abending-on-nfs-trail-ogg-02897-ogg-01668-input-output-error/">GoldenGate Extract Abending on NFS Trail: OGG-02897 / OGG-01668 Input/Output Error</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/goldengate-extract-abending-on-nfs-trail-ogg-02897-ogg-01668-input-output-error/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 
Lazy Loading (feed)

Served from: www.dbi-services.com @ 2026-09-11 09:07:59 by W3 Total Cache
-->