<?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>PL/SQL Archives - Philipp Salvisberg&#039;s Blog</title>
	<atom:link href="https://www.salvis.com/blog/tag/plsql/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.salvis.com/blog/tag/plsql/</link>
	<description>Database-centric development</description>
	<lastBuildDate>Mon, 12 Oct 2026 18:40:51 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>

<image>
	<url>https://www.salvis.com/blog/wp-content/uploads/2014/04/favicon.png</url>
	<title>PL/SQL Archives - Philipp Salvisberg&#039;s Blog</title>
	<link>https://www.salvis.com/blog/tag/plsql/</link>
	<width>32</width>
	<height>32</height>
</image> 
<atom:link rel="hub" href="https://pubsubhubbub.appspot.com"/>
<atom:link rel="hub" href="https://pubsubhubbub.superfeedr.com"/>
<atom:link rel="hub" href="https://websubhub.com/hub"/>
<atom:link rel="self" href="https://www.salvis.com/blog/tag/plsql/feed/"/>
	<item>
		<title>The Checkbox That Disables TLS</title>
		<link>https://www.salvis.com/blog/2026/08/23/the-checkbox-that-disables-tls/</link>
					<comments>https://www.salvis.com/blog/2026/08/23/the-checkbox-that-disables-tls/#respond</comments>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Sun, 23 Aug 2026 21:20:28 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[APEXlang]]></category>
		<category><![CDATA[Code Analysis]]></category>
		<category><![CDATA[dbLinter]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[SQL]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=23591</guid>

					<description><![CDATA[<p>Introduction The dbLinter clients include a new setting named Allow Insecure TLS. It is disabled by default. As a result, all REST API calls verify the TLS certificate and hostname. The setting allows dbLinter to work in organisations that inspect TLS traffic using tools such as Zscaler. In larger organisations, arranging an<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2026/08/23/the-checkbox-that-disables-tls/">The Checkbox That Disables TLS</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 id="introduction" class="wp-block-heading">Introduction</h2>



<p class="wp-block-paragraph">The dbLinter clients include a new setting named <code>Allow Insecure TLS</code>. It is disabled by default. As a result, all REST API calls verify the TLS certificate and hostname. </p>



<p class="wp-block-paragraph">The setting allows dbLinter to work in organisations that inspect TLS traffic using tools such as <a href="https://help.zscaler.com/zia/understanding-ssltls-inspection" target="_blank" rel="noreferrer noopener">Zscaler</a>.</p>



<p class="wp-block-paragraph">In larger organisations, arranging an inspection bypass can be cumbersome and is often too much effort for an ad-hoc trial of dbLinter. The checkbox provides a temporary workaround and should be enabled only on a trusted network.</p>



<p class="wp-block-paragraph">However, allowing insecure TLS on untrusted networks, such as open Wi-Fi without client isolation, can let an attacker redirect traffic through their own machine using techniques like <a href="https://en.wikipedia.org/wiki/ARP_spoofing" target="_blank" rel="noreferrer noopener">ARP spoofing</a>. The attacker can also operate the access point themselves, for example, by creating a rogue Wi-Fi hotspot.</p>



<p class="wp-block-paragraph">In this blog post, I demonstrate the effect of this checkbox.</p>



<h2 id="allow-insecure-tls" class="wp-block-heading">Allow Insecure TLS</h2>



<p class="wp-block-paragraph">The latest version of dbLinter for VS Code has a checkbox that disables certificate and hostname verification.</p>



<figure class="wp-block-image size-large"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox.png"><img fetchpriority="high" decoding="async" width="1024" height="833" src="https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-1024x833.png" alt="Allow Insecure TLS Checkbox in VS Code" class="wp-image-23595" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-1024x833.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-300x244.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-768x624.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-1536x1249.png 1536w, https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-2048x1665.png 2048w, https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-92x75.png 92w, https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-480x390.png 480w" sizes="(max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">dbLinter&#8217;s <code>allowInsecureTls</code> setting is nothing unusual. Many common tools offer a similar option, including curl (<code>--insecure</code>), wget (<code>--no-check-certificate</code>), and git (<code>--config http.sslVerify false</code>).</p>



<h2 id="installing-and-configuring-a-proxy" class="wp-block-heading">Installing and Configuring a Proxy</h2>



<p class="wp-block-paragraph">I run this demo on macOS 26.6.2.</p>



<p class="wp-block-paragraph">A simple proxy is <a href="https://www.mitmproxy.org/" data-type="link" data-id="https://www.mitmproxy.org/" target="_blank" rel="noreferrer noopener">mitmweb</a>. We can install and configure it as follows:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>brew install mitmproxy
networksetup -setsecurewebproxy "Wi-Fi" 127.0.0.1 8090
mitmweb --listen-port 8090 --web-port 8091 --allow-hosts '^api\.dblinter\.app'</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">brew</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">install</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">mitmproxy</span></span>
<span class="line"><span style="color: #DCDCAA">networksetup</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-setsecurewebproxy</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;Wi-Fi&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">127.0</span><span style="color: #CE9178">.0.1</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">8090</span></span>
<span class="line"><span style="color: #DCDCAA">mitmweb</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--listen-port</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">8090</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--web-port</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">8091</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--allow-hosts</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;^api\.dblinter\.app&#39;</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&#91;20:36:20.907&#93; HTTP(S) proxy listening at *:8090.
&#91;20:36:20.908&#93; Web server listening at http://127.0.0.1:8091/?token=f83b02032aaaccd282ad3925a484fcdb</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&#91;20:36:20.907&#93; HTTP(S) proxy listening at *:8090.</span></span>
<span class="line"><span style="color: #D4D4D4">&#91;20:36:20.908&#93; Web server listening at http://127.0.0.1:8091/?token=f83b02032aaaccd282ad3925a484fcdb</span></span></code></pre></div>



<p class="wp-block-paragraph">The <code>mitmweb</code> command starts the proxy and listens on port 8090 for TLS traffic between localhost and <code>api.dblinter.app</code>. All other traffic is bypassed. </p>



<p class="wp-block-paragraph">The <code>mitmweb</code> proxy also opens the following web page:</p>



<figure class="wp-block-image size-large"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start.png"><img decoding="async" width="1024" height="201" src="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start-1024x201.png" alt="mitmproxy after start up" class="wp-image-23617" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start-1024x201.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start-300x59.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start-768x150.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start-150x29.png 150w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start-480x94.png 480w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start.png 1281w" sizes="(max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<h2 id="intercepting-traffic" class="wp-block-heading">Intercepting Traffic</h2>



<p class="wp-block-paragraph">To generate traffic, we launch VS Code and open a SQL file. This produces the following in the output panel for dbLinter:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>2026-08-23 20:37:43.216 &#91;Info &#93; Starting dbLinter Language Server.
2026-08-23 20:37:43.539 &#91;Info &#93; connect.
2026-08-23 20:37:43.611 &#91;Info &#93; initialize VSCode 1.10.0.
2026-08-23 20:37:43.646 &#91;Info &#93; didOpen file:///.../dbl_client_types.sql.
2026-08-23 20:37:43.651 &#91;Info &#93; AntlrCacheCoordinator initialized with parallel degree 1 and clearCacheThreshold 2048 of 16384 MB.
2026-08-23 20:37:43.671 &#91;Warn &#93; TLS certificate and hostname verification are disabled for dbLinter repository API calls. Use this temporary workaround only when TLS interception cannot be bypassed.
2026-08-23 20:37:45.533 &#91;Info &#93; Configuration dbLinter of tenant Grisselbav loaded with 294 check methods.
2026-08-23 20:37:45.534 &#91;Info &#93; didChangeConfiguration.
2026-08-23 20:37:45.703 &#91;Info &#93; tests returned 43 tests.
2026-08-23 20:37:45.796 &#91;Info &#93; parseAndCheck file:///.../dbl_client_types.sql.
2026-08-23 20:37:45.910 &#91;Info &#93; hasFeature Config returned true.
2026-08-23 20:37:46.286 &#91;Info &#93; parseAndCheck completed in 0.489 sec including 0.052 sec for checks.
2026-08-23 20:37:46.289 &#91;Info &#93; diagnostics for file:///.../dbl_client_types.sql with 2 issues.</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:43.216 &#91;Info &#93; Starting dbLinter Language Server.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:43.539 &#91;Info &#93; connect.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:43.611 &#91;Info &#93; initialize VSCode 1.10.0.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:43.646 &#91;Info &#93; didOpen file:///.../dbl_client_types.sql.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:43.651 &#91;Info &#93; AntlrCacheCoordinator initialized with parallel degree 1 and clearCacheThreshold 2048 of 16384 MB.</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">2026-08-23 20:37:43.671 &#91;Warn &#93; TLS certificate and hostname verification are disabled for dbLinter repository API calls. Use this temporary workaround only when TLS interception cannot be bypassed.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:45.533 &#91;Info &#93; Configuration dbLinter of tenant Grisselbav loaded with 294 check methods.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:45.534 &#91;Info &#93; didChangeConfiguration.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:45.703 &#91;Info &#93; tests returned 43 tests.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:45.796 &#91;Info &#93; parseAndCheck file:///.../dbl_client_types.sql.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:45.910 &#91;Info &#93; hasFeature Config returned true.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:46.286 &#91;Info &#93; parseAndCheck completed in 0.489 sec including 0.052 sec for checks.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:46.289 &#91;Info &#93; diagnostics for file:///.../dbl_client_types.sql with 2 issues.</span></span></code></pre></div>



<p class="wp-block-paragraph">The log contains a warning that TLS certificate and hostname verification are disabled.</p>



<p class="wp-block-paragraph">dbLinter analyses SQL and APEXlang files locally. The captured traffic lets us verify what is sent to the dbLinter API. It contains the API key and session data, but not the contents of the analysed files. The source code therefore remains within the local network.</p>



<figure class="wp-block-image size-large"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-scaled.png"><img decoding="async" width="1024" height="538" src="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-1024x538.png" alt="mitmproxy request message" class="wp-image-23618" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-1024x538.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-300x158.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-768x403.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-1536x807.png 1536w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-2048x1076.png 2048w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-143x75.png 143w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-480x252.png 480w" sizes="(max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">It goes without saying that it is not good to expose the API key in plain text.</p>



<p class="wp-block-paragraph">The proxy also shows the decrypted response:</p>



<figure class="wp-block-image size-large"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-scaled.png"><img loading="lazy" decoding="async" width="1024" height="292" src="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-1024x292.png" alt="mitmproxy response message" class="wp-image-23619" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-1024x292.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-300x85.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-768x219.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-1536x438.png 1536w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-2048x584.png 2048w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-150x43.png 150w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-480x137.png 480w" sizes="auto, (max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">The session object in the response contains a signature. The client can therefore detect changes to the signed content, including the validators. This prevents the proxy from silently modifying the validators or injecting malicious code. However, the signature does not prevent the proxy from reading the request and response.</p>



<h2 id="enforce-tls-verification" class="wp-block-heading">Enforce TLS Verification</h2>



<p class="wp-block-paragraph">Now let&#8217;s uncheck the <code>Allow Insecure TLS</code> checkbox and execute the <code>Reload Window</code> command. </p>



<figure class="wp-block-image size-large"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2.png"><img loading="lazy" decoding="async" width="1024" height="191" src="https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2-1024x191.png" alt="disallow insecure TLS in VS Code" class="wp-image-23613" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2-1024x191.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2-300x56.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2-768x143.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2-150x28.png 150w, https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2-480x89.png 480w, https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2.png 1354w" sizes="auto, (max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">This produces the following in the output panel for dbLinter:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>2026-08-23 20:52:37.281 &#91;Info &#93; Starting dbLinter Language Server.
2026-08-23 20:52:37.550 &#91;Info &#93; connect.
2026-08-23 20:52:37.606 &#91;Info &#93; initialize VSCode 1.10.0.
2026-08-23 20:52:38.047 &#91;Info &#93; didOpen file:///.../dbl_client_types.sql.
2026-08-23 20:52:38.049 &#91;Info &#93; AntlrCacheCoordinator initialized with parallel degree 1 and clearCacheThreshold 2048 of 16384 MB.
2026-08-23 20:52:38.375 &#91;Error&#93; Failed to load configuration.

org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://api.dblinter.app/api/client-session/open": (certificate_unknown) PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">2026-08-23 20:52:37.281 &#91;Info &#93; Starting dbLinter Language Server.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:52:37.550 &#91;Info &#93; connect.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:52:37.606 &#91;Info &#93; initialize VSCode 1.10.0.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:52:38.047 &#91;Info &#93; didOpen file:///.../dbl_client_types.sql.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:52:38.049 &#91;Info &#93; AntlrCacheCoordinator initialized with parallel degree 1 and clearCacheThreshold 2048 of 16384 MB.</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">2026-08-23 20:52:38.375 &#91;Error&#93; Failed to load configuration.</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">org.springframework.web.client.ResourceAccessException: I/O error on POST request for &quot;https://api.dblinter.app/api/client-session/open&quot;: (certificate_unknown) PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target</span></span></code></pre></div>



<p class="wp-block-paragraph">The proxy presented a certificate for <code>api.dblinter.app</code> which was not issued by a trusted certification authority.</p>



<p class="wp-block-paragraph">The proxy console therefore shows the following log entry:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(1 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&#91;20:52:38.217&#93;&#91;127.0.0.1:60439&#93; server connect api.dblinter.app:443 (91.98.90.2:443)
&#91;20:52:38.360&#93;&#91;127.0.0.1:60441&#93; client connect
&#91;20:52:38.375&#93;&#91;127.0.0.1:60439&#93; Client TLS handshake failed. The client does not trust the proxy's certificate for api.dblinter.app (OpenSSL Error(&#91;('SSL routines', '', 'ssl/tls alert certificate unknown')&#93;))
&#91;20:52:38.377&#93;&#91;127.0.0.1:60439&#93; client disconnect
&#91;20:52:38.380&#93;&#91;127.0.0.1:60439&#93; server disconnect api.dblinter.app:443 (91.98.90.2:443)</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&#91;20:52:38.217&#93;&#91;127.0.0.1:60439&#93; server connect api.dblinter.app:443 (91.98.90.2:443)</span></span>
<span class="line"><span style="color: #D4D4D4">&#91;20:52:38.360&#93;&#91;127.0.0.1:60441&#93; client connect</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">&#91;20:52:38.375&#93;&#91;127.0.0.1:60439&#93; Client TLS handshake failed. The client does not trust the proxy&#39;s certificate for api.dblinter.app (OpenSSL Error(&#91;(&#39;SSL routines&#39;, &#39;&#39;, &#39;ssl/tls alert certificate unknown&#39;)&#93;))</span></span>
<span class="line"><span style="color: #D4D4D4">&#91;20:52:38.377&#93;&#91;127.0.0.1:60439&#93; client disconnect</span></span>
<span class="line"><span style="color: #D4D4D4">&#91;20:52:38.380&#93;&#91;127.0.0.1:60439&#93; server disconnect api.dblinter.app:443 (91.98.90.2:443)</span></span></code></pre></div>



<p class="wp-block-paragraph">The REST API call failed before the proxy received the HTTP request. Therefore, the API key and other request data were not exposed.</p>



<h2 id="reset-network-configuration-and-unistall-proxy" class="wp-block-heading">Reset Network Configuration and Uninstall Proxy</h2>



<p class="wp-block-paragraph">Let&#8217;s stop the proxy by pressing Ctrl-C in the terminal window running it. Then run the following:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>networksetup -setsecurewebproxystate "Wi-Fi" off
brew uninstall mitmproxy
rm -rf ~/.mitmproxy</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">networksetup</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-setsecurewebproxystate</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;Wi-Fi&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">off</span></span>
<span class="line"><span style="color: #DCDCAA">brew</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">uninstall</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">mitmproxy</span></span>
<span class="line"><span style="color: #DCDCAA">rm</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-rf</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">~/.mitmproxy</span></span></code></pre></div>



<h2 id="conclusion" class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">The <code>Allow Insecure TLS</code> option solves a practical problem in environments where TLS inspection cannot easily be bypassed. However, it disables certificate and hostname verification. A proxy or an attacker controlling the network can then read requests, including the API key.</p>



<p class="wp-block-paragraph">The captured traffic also confirms that dbLinter analyses SQL and APEXlang files locally. Signed server responses protect the downloaded configuration from manipulation, but they do not protect confidential request data.</p>



<p class="wp-block-paragraph">Therefore, enable this option only as a temporary workaround on a trusted network. The preferred solution is to configure a TLS inspection bypass. Disable the option again as soon as possible.</p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://www.salvis.com/blog/2026/08/23/the-checkbox-that-disables-tls/">The Checkbox That Disables TLS</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.salvis.com/blog/2026/08/23/the-checkbox-that-disables-tls/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Fighting Bad PL/SQL &#038; SQL with VS Code</title>
		<link>https://www.salvis.com/blog/2026/01/02/fighting-bad-pl-sql-sql-with-vs-code/</link>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Fri, 02 Jan 2026 21:05:10 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Code Analysis]]></category>
		<category><![CDATA[dbLinter]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[VSCode]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=14289</guid>

					<description><![CDATA[<p>The success of a project or product depends largely on the quality of the code. But how can I improve security, maintainability or performance? More importantly, how can I prevent code with quality defects from entering production? In addition to testing, code analysis plays a central role. These days, code can be<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2026/01/02/fighting-bad-pl-sql-sql-with-vs-code/">Fighting Bad PL/SQL &amp; SQL with VS Code</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The success of a project or product depends largely on the quality of the code. But how can I improve security, maintainability or performance? More importantly, how can I prevent code with quality defects from entering production? In addition to testing, code analysis plays a central role. These days, code can be checked not only in CI/CD pipelines, but also during development. Modern IDEs, such as Visual Studio Code, can automatically detect quality issues and offer quick fixes. The goal is a fast feedback loop.</p>



<p class="wp-block-paragraph">This blog post is based on my German article with the same title, published in issue 1/2026 of the <a href="https://www.salvis.com/blog/wp-content/uploads/2026/02/01_2026-Red_Stack_Magazin-DTk-WEB-Philipp_Salvisberg_Fighting_Bad_PLSQL__SQL_with_VS_Code.pdf" target="_blank" rel="noreferrer noopener nofollow">Red Stack Magazin</a>.</p>



<h2 class="wp-block-heading" id="measuring-software-quality">Measuring Software Quality</h2>



<p class="wp-block-paragraph">Imagine you are part of a team where code changes to a feature or bug fix branch are only merged into the develop or main branch following a review. Sometimes you are the author and sometimes one of the reviewers. I am currently part of a team that works in this way. In addition to quality assurance, knowledge sharing is also an important aspect. But how can we assess code quality?</p>



<figure class="wp-block-image is-style-default"><a href="https://www.osnews.com/story/19266/wtfsm/" target="_blank" rel=" noreferrer noopener"><img loading="lazy" decoding="async" width="500" height="471" src="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-1-wtfm.jpg" alt="" class="wp-image-14292" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-1-wtfm.jpg 500w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-1-wtfm-300x283.jpg 300w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-1-wtfm-80x75.jpg 80w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-1-wtfm-480x452.jpg 480w" sizes="auto, (max-width:767px) 480px, 500px" /></a><figcaption class="wp-element-caption">Figure 1: WTFs/m</figcaption></figure>



<p class="wp-block-paragraph">This well-known meme by Thom Holwerda says, &#8220;The only valid measurement of code quality is WTFs per minute.&#8221; This seems to be a good metric. However, this metric does have some flaws.</p>



<ul class="wp-block-list">
<li>It is subjective.</li>



<li>It does not provide any information about what is being assessed.</li>



<li>It does not help new team members to adapt quickly.</li>



<li>And it cannot be automated in a meaningful way.</li>
</ul>



<p class="wp-block-paragraph">Sooner or later, a team has no choice but to agree on a set of rules. They can be informal or formal. Typical coding guidelines cover topics such as naming conventions, formatting, code complexity, and language usage rules. The aim is to define and comply with quality standards relating to maintainability, reliability, performance and security. Written coding guidelines also simplify the onboarding of new team members.</p>



<h2 class="wp-block-heading" id="automation">Automation</h2>



<p class="wp-block-paragraph">Manually checking compliance with coding guidelines as part of a review is so time-consuming that no one can afford to do it properly. Therefore, we have to automate as many checks as possible. This is possible for many aspects. The rest still have to be checked manually.</p>



<p class="wp-block-paragraph">In other words, we need a tool suite for automatic rule checking. <a href="https://grisselbav.github.io/dbLinter/" target="_blank" rel="noreferrer noopener nofollow">dbLinter</a> is such a tool suite. It is a new product developed and continuously improved by <a href="https://www.grisselbav.com/" target="_blank" rel="noreferrer noopener nofollow">Grisselbav</a> and <a href="https://www.united-codes.com/" target="_blank" rel="noreferrer noopener nofollow">United Codes</a>. dbLinter uses the <a href="https://github.com/IslandSQL/IslandSQL" target="_blank" rel="noreferrer noopener nofollow">IslandSQL</a> parser, which is updated quarterly with every release update of the Oracle AI Database for SQL, PL/SQL, SQL*Plus and SQLcl.</p>



<p class="wp-block-paragraph">dbLinter is the successor to the decommissioned db* CODECOP suite. dbLinter consists of a central repository, a web GUI and client tools. These include a CLI, a SonarQube plugin and a VS Code extension.</p>



<h2 class="wp-block-heading" id="visual-studio-code-extension">Visual Studio Code Extension</h2>



<p class="wp-block-paragraph">The VS Code extension is compatible with all IDEs that implement the <a href="https://code.visualstudio.com/api" target="_blank" rel="noreferrer noopener nofollow">Visual Studio Code Extension API</a>. Specifically: Visual Studio Code, Theia IDE, VSCodium, Cursor, Windsurf, Void, Kiro and Antigravity.</p>



<p class="wp-block-paragraph">dbLinter for VS Code is available in both the <a href="https://marketplace.visualstudio.com/items?itemName=Grisselbav.dblinter" target="_blank" rel="noreferrer noopener nofollow">Visual Studio Marketplace</a> and the <a href="https://open-vsx.org/extension/Grisselbav/dblinter" target="_blank" rel="noreferrer noopener nofollow">Open VSX Registry</a>. Therefore, it can be conveniently installed directly from the IDE. The extension is free to use as part of the Anonymous and Starter plans (see <a href="https://www.united-codes.com/products/dblinter/#pricing" target="_blank" rel="noreferrer noopener nofollow">dbLinter Pricing Plans</a>).</p>



<p class="wp-block-paragraph">It is important to note that your code is always analysed locally, meaning that it never leaves your network. The configuration is read from the central repository, enabling the client to identify the active rules and parameters. These configurations, along with others, are managed using the <a href="https://dblinter.app/" target="_blank" rel="noreferrer noopener nofollow">Web GUI</a>.</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui.png"><img loading="lazy" decoding="async" width="1228" height="1088" src="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui.png" alt="" class="wp-image-14313" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui.png 1228w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui-300x266.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui-1024x907.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui-768x680.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui-85x75.png 85w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui-480x425.png 480w" sizes="auto, (max-width:767px) 480px, (max-width:1228px) 100vw, 1228px" /></a><figcaption class="wp-element-caption">Figure 2: dbLinter rule configuration in the Web GUI</figcaption></figure>



<p class="wp-block-paragraph">dbLinter currently offers 187 rules. This includes all the rules from the decommissioned Trivadis PL/SQL &amp; SQL Coding Guidelines. Figure 2 shows the configuration of my 14 favourite rules. A violation of one of these rules is a bug. There is almost no room for interpretation here. The following chapters provide two examples.</p>



<h2 class="wp-block-heading top-n-queries-with-rownum">Top-N Queries with ROWNUM</h2>



<p class="wp-block-paragraph">The query in Listing 1 is based on the well-known <code>EMP</code> table owned by the database user <code>SCOTT</code>. It returns two rows.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">Listing 1: Defective pre-12c-style top-n query</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>select ename,
       sal,
       hiredate,
       rownum as rank
  from emp
 where rownum &lt;= 2
 order by sal desc;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> ename,</span></span>
<span class="line"><span style="color: #D4D4D4">       sal,</span></span>
<span class="line"><span style="color: #D4D4D4">       hiredate,</span></span>
<span class="line"><span style="color: #D4D4D4">       </span><span style="color: #569CD6">rownum</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">rank</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> emp</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">rownum</span><span style="color: #D4D4D4"> &lt;= </span><span style="color: #B5CEA8">2</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> sal </span><span style="color: #569CD6">desc</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>ENAME             SAL HIREDATE         RANK
---------- ---------- ---------- ----------
ALLEN            1600 20.02.1981          2
SMITH             800 17.12.1980          1</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">ENAME             SAL HIREDATE         RANK</span></span>
<span class="line"><span style="color: #D4D4D4">---------- ---------- ---------- ----------</span></span>
<span class="line"><span style="color: #D4D4D4">ALLEN            1600 20.02.1981          2</span></span>
<span class="line"><span style="color: #D4D4D4">SMITH             800 17.12.1980          1</span></span></code></pre></div>



<p class="wp-block-paragraph">However, the result barely meets the requirements. I would have expected the two employees with the highest salaries to be returned. Why is this not the case? The query is formulated in such a way that two rows are randomly selected and then sorted in descending order by salary. The result depends on the execution plan and the physical storage of the data.</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-3-g-3185-regelverletzung-in-vs-code.png"><img loading="lazy" decoding="async" width="913" height="448" src="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-3-g-3185-regelverletzung-in-vs-code.png" alt="" class="wp-image-14323" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-3-g-3185-regelverletzung-in-vs-code.png 913w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-3-g-3185-regelverletzung-in-vs-code-300x147.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-3-g-3185-regelverletzung-in-vs-code-768x377.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-3-g-3185-regelverletzung-in-vs-code-150x75.png 150w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-3-g-3185-regelverletzung-in-vs-code-480x236.png 480w" sizes="auto, (max-width:767px) 480px, (max-width:913px) 100vw, 913px" /></a><figcaption class="wp-element-caption">Figure 3: Violation of rule G-3185 in VS Code</figcaption></figure>



<p class="wp-block-paragraph">In VS Code, rule violations are displayed under <code>Problems</code> (see Figure 3). There is also a <a href="https://dblinter.app/ords/r/dblinter/dblinter-console/rules#P1000_SHOW_RULE=core%20g-3185" target="_blank" rel="noreferrer noopener nofollow">Core G-3185</a> link that opens the rule details in the Web GUI.</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2.png"><img loading="lazy" decoding="async" width="982" height="1490" src="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2.png" alt="" class="wp-image-14330" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2.png 982w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2-198x300.png 198w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2-675x1024.png 675w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2-768x1165.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2-49x75.png 49w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2-480x728.png 480w" sizes="auto, (max-width:767px) 480px, (max-width:982px) 100vw, 982px" /></a><figcaption class="wp-element-caption">Figure 4: Rule G-3185 in the dbLinter Web GUI</figcaption></figure>



<p class="wp-block-paragraph">Rule G-3185 in the web GUI is explained based on a similar case in the HR schema (see Figure 4). There are two solutions here. One that can be applied in all Oracle Database versions and one that works from version 12c onwards. Listing 2 shows the traditional solution, which uses an inline view. Of course, nowadays I would always prefer a solution using the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/26/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__BABBADDD" target="_blank" rel="noreferrer noopener nofollow">row_limiting_clause</a>.</p>



<p class="wp-block-paragraph">We can also see that the rule is used in six configurations. Clicking on &#8220;(details)&#8221; opens a pop-up window in which changes can be made. This allows you to configure the rules directly from the IDE.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">Listing 2: Fixed pre-12c-style top-n query</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>select e.*,
       rownum as rank
  from (
          select ename,
                 sal,
                 hiredate
            from emp
           order by sal desc
       ) e
 where rownum &lt;= 2;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> e.*,</span></span>
<span class="line"><span style="color: #D4D4D4">       </span><span style="color: #569CD6">rownum</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">rank</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> ename,</span></span>
<span class="line"><span style="color: #D4D4D4">                 sal,</span></span>
<span class="line"><span style="color: #D4D4D4">                 hiredate</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> emp</span></span>
<span class="line"><span style="color: #D4D4D4">           </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> sal </span><span style="color: #569CD6">desc</span></span>
<span class="line"><span style="color: #D4D4D4">       ) e</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">rownum</span><span style="color: #D4D4D4"> &lt;= </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>ENAME             SAL HIREDATE         RANK
---------- ---------- ---------- ----------
KING             5000 17.11.1981          1
SCOTT            3000 19.04.1987          2</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">ENAME             SAL HIREDATE         RANK</span></span>
<span class="line"><span style="color: #D4D4D4">---------- ---------- ---------- ----------</span></span>
<span class="line"><span style="color: #D4D4D4">KING             5000 17.11.1981          1</span></span>
<span class="line"><span style="color: #D4D4D4">SCOTT            3000 19.04.1987          2</span></span></code></pre></div>



<h2 class="wp-block-heading nvl-vs-coalesce">NVL vs. COALESCE</h2>



<p class="wp-block-paragraph">One often underestimated rule is &#8220;<a href="https://dblinter.app/ords/r/dblinter/dblinter-console/rules#P1000_SHOW_RULE=core%20g-4230" target="_blank" rel="noreferrer noopener nofollow">G-4230</a>: Always use a COALESCE instead of a NVL command, if parameter 2 of the NVL function is a function call or a SELECT statement&#8221;. This rule is about performance, which is relevant to all of us, especially when it is poor. This is why this rule is important.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">Listing 3: Bad performance with NVL</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>with
   function slow_function return integer is
   begin
      sys.dbms_session.sleep(0.2);
      return null;
   end slow_function;
select ename, nvl(mgr, slow_function()) as mgr
  from emp;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">with</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">slow_function</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">integer</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">      sys.</span><span style="color: #DCDCAA">dbms_session.</span><span style="color: #4EC9B0">sleep</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">0.2</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">end</span><span style="color: #D4D4D4"> slow_function;</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> ename, </span><span style="color: #DCDCAA">nvl</span><span style="color: #D4D4D4">(mgr, slow_function()) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> mgr</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> emp;</span></span></code></pre></div>



<p class="wp-block-paragraph">Listing 3 demonstrates a case in which the use of <code>NVL</code> results in an execution time of approximately 2.8 seconds. If <code>COALESCE</code> is used instead of <code>NVL</code>, the execution time is only about 0.2 seconds. The reason is that <code>NVL</code> always evaluates the second parameter, even if the first parameter is not null. <code>COALESCE</code> works differently: the second parameter is only evaluated if the first parameter is null. This performance difference originates from the fact that the <code>EMP</code> table contains 14 rows, but only one of these returns an empty <code>MGR</code>.</p>



<p class="wp-block-paragraph">In this case, using <code>COALESCE</code> is definitely the better solution. So, should <code>NVL</code> always be replaced by <code>COALESCE</code>? No. There are two special cases:</p>



<ol class="wp-block-list">
<li>NVL supports implicit data type conversion.<br /><code>select nvl(mgr, '1') from emp</code> works, but <code>select coalesce(mgr, '1') from emp</code> causes an <a href="https://docs.oracle.com/en/error-help/db/ora-00932/" target="_blank" rel="noreferrer noopener nofollow">ORA-00932</a> error. However, implicit type conversions should be avoided anyway. The code should be adjusted accordingly.<br /></li>



<li>Optimisations of <code>NVL</code> can lead to better execution plans.<br />Such optimisations currently only exist for <code>NVL</code> and not for <code>COALESCE</code>. Therefore, it is better to continue using <code>NVL</code> in these cases. See <a href="https://how2ora-en.blogspot.com/2025/09/the-magical-nvl-function.html" target="_blank" rel="noreferrer noopener nofollow">The Magical NVL Function</a> by Monika Lewandowska for an example. </li>
</ol>



<h5 class="wp-block-heading">Quick Fixes</h5>



<p class="wp-block-paragraph">dbLinter knows these special cases. It offers appropriate alternative solutions. See Figure 5.</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode.png"><img loading="lazy" decoding="async" width="1121" height="717" src="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode.png" alt="" class="wp-image-14346" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode.png 1121w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode-300x192.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode-1024x655.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode-768x491.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode-117x75.png 117w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode-480x307.png 480w" sizes="auto, (max-width:767px) 480px, (max-width:1121px) 100vw, 1121px" /></a><figcaption class="wp-element-caption">Figure 5: Quick fixes for G-4230 violation in VS Code.</figcaption></figure>



<p class="wp-block-paragraph">dbLinter can apply quick fixes to different sections. For example, for a single violation of a rule, for all violations of a rule, or for all violations of all rules in the editor window.</p>



<p class="wp-block-paragraph">The &#8220;@dbLinter ignore markers&#8221; are special comments used to ignore rule violations. There are various legitimate reasons for doing this. For example, in the case of false positives (dbLinter bugs) or exceptions to the rule. A comment such as <code>-- @dbLinter ignore(G-4230): NVL forever</code> can have the following scopes: line, statement or file, depending on where the comment is positioned.</p>



<h2 class="wp-block-heading" id="code-analysis-and-ai">Code Analysis and AI</h2>



<p class="wp-block-paragraph">The solution proposals in Figure 5, indicated by the yellow lamp symbol, are quick fixes from dbLinter. However, the last two menu options come from GitHub Copilot.</p>



<p class="wp-block-paragraph">When Copilot suggests a solution to a rule violation, dbLinter provides the necessary context, including the file and the exact location of the violation, as well as the name of the violated rule. This gives Copilot access to the rule definition online, enabling it to suggest a reasonable solution in many cases. In other words, dbLinter enhances the support offered by tools such as Copilot, Cline and Windsurf.</p>



<p class="wp-block-paragraph">Rules are useful for AI tools. They provide a framework that leads to better results. However, there is no guarantee that all rules will be followed. Ultimately, code generated or expanded by AI becomes part of our code base. This is why it is important to check AI-generated code according to the same rules as manually created code.</p>



<p class="wp-block-paragraph">In other words, AI does not enforce standards. But dbLinter can do that.</p>



<h2 class="wp-block-heading" id="conclusion">Conclusion</h2>



<p class="wp-block-paragraph">Software quality is a matter of definition. dbLinter offers many rules. Not all of them are useful and applicable to every project. The dbLinter rules can therefore be seen as a large buffet. You choose what you like and what is healthy. But not too much at once. Nevertheless, there are some rules that, in my opinion, should be followed in every project. I have presented two of them in this blog post.</p>



<p class="wp-block-paragraph">Install dbLinter for VS Code to identify the rules that will be most helpful for your projects. The rules in Figure 2 are certainly a good starting point.</p>



<p class="wp-block-paragraph">If you have any questions, please feel free to contact me. Alternatively, you can create issues directly in the <a href="https://github.com/Grisselbav/dbLinter" target="_blank" rel="noreferrer noopener nofollow">dbLinter GitHub repository</a>.</p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://www.salvis.com/blog/2026/01/02/fighting-bad-pl-sql-sql-with-vs-code/">Fighting Bad PL/SQL &amp; SQL with VS Code</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Is SYSDATE Deterministic? #JoelKallmanDay</title>
		<link>https://www.salvis.com/blog/2025/10/15/is-sysdate-deterministic-joelkallmanday/</link>
					<comments>https://www.salvis.com/blog/2025/10/15/is-sysdate-deterministic-joelkallmanday/#comments</comments>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Tue, 14 Oct 2025 22:00:00 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[JoelKallmanDay]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[SQL]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=14035</guid>

					<description><![CDATA[<p>TL;DR No, SYSDATE is not deterministic. However, it behaves very similarly to a deterministic function within an Oracle Database SQL statement. Background On a customer site, we used faketime on the OS to change the date and time for testing purposes. As long as you only travel forward in time, the Oracle<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2025/10/15/is-sysdate-deterministic-joelkallmanday/">Is SYSDATE Deterministic? #JoelKallmanDay</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="tldr">TL;DR</h2>



<p class="wp-block-paragraph">No, <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/SYSDATE.html">SYSDATE</a> is not deterministic. However, it behaves very similarly to a deterministic function within an Oracle Database SQL statement.</p>



<h2 class="wp-block-heading" id="background">Background</h2>



<p class="wp-block-paragraph">On a customer site, we used <a href="https://github.com/wolfcw/libfaketime">faketime</a> on the OS to change the date and time for testing purposes. As long as you only travel forward in time, the Oracle Database behaves fine. The solution worked well for the last 8 years. However, this approach had some drawbacks, such as the need for a full-blown VM (we cannot change the time in an isolated manner within a Docker container), disabling time synchronisation processes and issues with third-party software due to failed sanity/license checks. This approach prevented us from simplifying the architecture of the testing environment.</p>



<p class="wp-block-paragraph">We were exploring alternatives to travel in time only within the Oracle Database. One option was to set <a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/refrn/FIXED_DATE.html">FIXED_DATE</a>, and another to replace calls to <code>SYSDATE</code>, <code>SYSTIMESTAMP</code>, <code>CURRENT_DATE</code>, <code>CURRENT_TIMESTAMP</code> and <code>LOCALTIMESTAMP</code> with custom functions that added an offset to the current date/time. For the latter, I&#8217;d like to share some simplified test results.</p>



<p class="wp-block-paragraph">But before that, let&#8217;s look at some definitions.</p>



<h2 class="wp-block-heading" id="definitions">Definitions</h2>



<p class="wp-block-paragraph"><a href="https://en.wikipedia.org/wiki/Deterministic_algorithm">Wikipedia</a> defines a deterministic algorithm in computer science as follows:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">In&nbsp;computer science, a&nbsp;deterministic algorithm&nbsp;is an<strong>&nbsp;algorithm&nbsp;that, given a particular input, will always produce the same output</strong>, with the underlying machine always passing through the same sequence of states. Deterministic algorithms are by far the most studied and familiar kind of algorithm, as well as one of the most practical, since they can be run on real machines efficiently.</p>
</blockquote>



<p class="wp-block-paragraph">The Oracle Database PL/SQL Language Reference defines deterministic for the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/lnpls/DETERMINISTIC-clause.html#GUID-6AECC957-27CC-4334-9F43-0FBE88F92654__GUID-4E715AAA-9A87-4AB0-8F53-DE82D802AD21">deterministic_clause</a> as follows:</p>



<ul class="wp-block-list">
<li>A function is deterministic if the&nbsp;<code>DETERMINISTIC</code>&nbsp;clause appears in either a declaration or the definition of the function.</li>



<li>The&nbsp;<code>DETERMINISTIC</code>&nbsp;clause may appear at most once in a function declaration and at most once in a function definition.</li>



<li>A deterministic function must <strong>return the same value on two distinct invocations if the arguments provided to the two invocations are the same</strong>.</li>



<li>A&nbsp;<code>DETERMINISTIC</code>&nbsp;function may not have <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/lnpls/subprogram-side-effects.html">side effects</a>.</li>



<li>A&nbsp;<code>DETERMINISTIC</code>&nbsp;function may not raise an unhandled exception.</li>



<li>If a function with a&nbsp;<code>DETERMINISTIC</code>&nbsp;clause violates any of these semantic rules, the results of its invocation, its value, and the effect on its invoker are all undefined.</li>
</ul>



<h2 class="wp-block-heading" id="how-to-check">How to Check?</h2>



<p class="wp-block-paragraph">There are two ways to check if a function is deterministic. Firstly, you can query the data dictionary like this:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">1) Query Data Dictionary</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>select deterministic 
  from dba_procedures
 where procedure_name = 'SYSDATE';</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">deterministic</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dba_procedures</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> procedure_name = </span><span style="color: #CE9178">&#39;SYSDATE&#39;</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>DETERMINISTIC
-------------
NO</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">DETERMINISTIC</span></span>
<span class="line"><span style="color: #D4D4D4">-------------</span></span>
<span class="line"><span style="color: #D4D4D4">NO</span></span></code></pre></div>



<blockquote class="wp-block-quote is-style-plain is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"></p>
</blockquote>



<p class="wp-block-paragraph">Secondly, you can check the source code to see if it contains a deterministic_clause. <code>SYSDATE</code> is defined in the <code>STANDARD</code> package as a wrapper to the kernel function <code>pessdt</code> and has no deterministic_clause.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">2) STANDARD specification excerpt</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>create or replace package STANDARD AUTHID CURRENT_USER is …
  function SYSDATE return DATE;
    pragma FIPSFLAG('SYSDATE', 1452); …
end;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">package</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">STANDARD</span><span style="color: #D4D4D4"> AUTHID CURRENT_USER </span><span style="color: #569CD6">is</span><span style="color: #D4D4D4"> …</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">SYSDATE</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">DATE</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    pragma FIPSFLAG(</span><span style="color: #CE9178">&#39;SYSDATE&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1452</span><span style="color: #D4D4D4">); …</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">3) STANDARD body excerpt</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>create or replace package body STANDARD is …
  -- Bug 1287775: back to calling ICD.
  -- Special: if the ICD raises ICD_UNABLE_TO_COMPUTE, that means we should do
  -- the old 'SELECT SYSDATE FROM DUAL;' thing.  This allows us to do the
  -- SELECT from PL/SQL rather than having to do it from C (within the ICD.)
  function sysdate return date is
    d date;
  begin
    d := pessdt;
    return d;
  exception
    when ICD_UNABLE_TO_COMPUTE then
      select sysdate into d from sys.dual;
      return d;
  end; …
end;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">package body</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">STANDARD</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span><span style="color: #D4D4D4"> …</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955">-- Bug 1287775: back to calling ICD.</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955">-- Special: if the ICD raises ICD_UNABLE_TO_COMPUTE, that means we should do</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955">-- the old &#39;SELECT SYSDATE FROM DUAL;&#39; thing.  This allows us to do the</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955">-- SELECT from PL/SQL rather than having to do it from C (within the ICD.)</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sysdate</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span></span>
<span class="line"><span style="color: #D4D4D4">    d </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">    d := pessdt;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> d;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">exception</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">when</span><span style="color: #D4D4D4"> ICD_UNABLE_TO_COMPUTE </span><span style="color: #569CD6">then</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sysdate</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">into</span><span style="color: #D4D4D4"> d </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> sys.dual;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> d;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">end</span><span style="color: #D4D4D4">; …</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<p class="wp-block-paragraph">So, <code>SYSDATE</code> is clearly non-deterministic. </p>



<p class="wp-block-paragraph">Interesting are the comments regarding bug 1287775 (APPSST:PERF: SERVER SIDE PL/SQL SHOULD NOT USE SQL TO OBTAIN SYSDATE). It does not seem to be entirely about performance. The last update of the bug was in mid-2021. I was unable to find out why a <code>pessdt</code> call may fail, and why getting <code>SYSDATE</code> via a query from dual should solve the problem. Anyway, it&#8217;s not essential for this blog post.</p>



<h2 class="wp-block-heading" id="comparing-sysdate-to-a-non-deterministic-function">Comparing SYSDATE to a Non-Deterministic Function</h2>



<p class="wp-block-paragraph">Let&#8217;s create a non-deterministic function <code>APPDATE</code> that returns <code>SYSDATE</code>. Then, we compare the <code>SYSDATE</code> and <code>APPDATE</code> results in a PL/SQL cursor.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">4) Non-deterministic APPDATE</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>create or replace function appdate return date is
begin
  return sysdate;
end;
/

set serveroutput on size unlimited
set arraysize 1
declare
   cursor c is 
        select rownum,
               to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS') as the_sysdate, 
               to_char(appdate, 'YYYY-MM-DD HH24:MI:SS') as the_appdate
          from user_objects
         where rownum &lt;= 5;
   r c%rowtype;     
begin
    open c;
    sys.dbms_output.put_line('# THE_SYSDATE         THE_APPDATE');
    sys.dbms_output.put_line('- ------------------- -------------------');
    loop
        fetch c into r;
        exit when c%notfound;
        sys.dbms_output.put_line(r.rownum || ' ' || r.the_sysdate || ' ' || r.the_appdate);
        sys.dbms_session.sleep(1);
    end loop;
    close c;
end;
/</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> function appdate </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sysdate</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> serveroutput </span><span style="color: #569CD6">on</span><span style="color: #D4D4D4"> size unlimited</span></span>
<span class="line cbp-line-highlight"><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> arraysize </span><span style="color: #B5CEA8">1</span></span>
<span class="line"><span style="color: #569CD6">declare</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">cursor</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">c</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">rownum</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">               </span><span style="color: #DCDCAA">to_char</span><span style="color: #D4D4D4">(</span><span style="color: #DCDCAA">sysdate</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&#39;YYYY-MM-DD HH24:MI:SS&#39;</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> the_sysdate, </span></span>
<span class="line"><span style="color: #D4D4D4">               </span><span style="color: #DCDCAA">to_char</span><span style="color: #D4D4D4">(appdate, </span><span style="color: #CE9178">&#39;YYYY-MM-DD HH24:MI:SS&#39;</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> the_appdate</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> user_objects</span></span>
<span class="line"><span style="color: #D4D4D4">         </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">rownum</span><span style="color: #D4D4D4"> &lt;= </span><span style="color: #B5CEA8">5</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">   r </span><span style="color: #569CD6">c</span><span style="color: #D4D4D4">%</span><span style="color: #569CD6">rowtype</span><span style="color: #D4D4D4">;     </span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">open</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">c</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    sys.</span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;# THE_SYSDATE         THE_APPDATE&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    sys.</span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;- ------------------- -------------------&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">loop</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">fetch</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">c</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">into</span><span style="color: #D4D4D4"> r;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">exit</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">when</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">c</span><span style="color: #DCDCAA">%notfound</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        sys.</span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">(r.</span><span style="color: #569CD6">rownum</span><span style="color: #D4D4D4"> || </span><span style="color: #CE9178">&#39; &#39;</span><span style="color: #D4D4D4"> || r.the_sysdate || </span><span style="color: #CE9178">&#39; &#39;</span><span style="color: #D4D4D4"> || r.the_appdate);</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        sys.</span><span style="color: #DCDCAA">dbms_session.</span><span style="color: #4EC9B0">sleep</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">end loop</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">close</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">c</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>Function APPDATE compiled

# THE_SYSDATE         THE_APPDATE
- ------------------- -------------------
1 2025-10-13 08:28:29 2025-10-13 08:28:29
2 2025-10-13 08:28:29 2025-10-13 08:28:30
3 2025-10-13 08:28:29 2025-10-13 08:28:31
4 2025-10-13 08:28:29 2025-10-13 08:28:32
5 2025-10-13 08:28:29 2025-10-13 08:28:33


PL/SQL procedure successfully completed.</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">Function APPDATE compiled</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4"># THE_SYSDATE         THE_APPDATE</span></span>
<span class="line"><span style="color: #D4D4D4">- ------------------- -------------------</span></span>
<span class="line"><span style="color: #D4D4D4">1 2025-10-13 08:28:29 2025-10-13 08:28:29</span></span>
<span class="line"><span style="color: #D4D4D4">2 2025-10-13 08:28:29 2025-10-13 08:28:30</span></span>
<span class="line"><span style="color: #D4D4D4">3 2025-10-13 08:28:29 2025-10-13 08:28:31</span></span>
<span class="line"><span style="color: #D4D4D4">4 2025-10-13 08:28:29 2025-10-13 08:28:32</span></span>
<span class="line"><span style="color: #D4D4D4">5 2025-10-13 08:28:29 2025-10-13 08:28:33</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4">PL/SQL procedure successfully completed.</span></span></code></pre></div>



<p class="wp-block-paragraph">You see, the results are different except for the first row. We had to set the fetch array size to one to ensure the sleep call on line 25 affects each fetched record. Otherwise, you would see the effect between the batch of records defined by the default fetch size.</p>



<h2 class="wp-block-heading" id="comparing-sysdate-to-a-deterministic-function">Comparing SYSDATE to a Deterministic Function</h2>



<p class="wp-block-paragraph">Let&#8217;s make the <code>APPDATE</code> function deterministic and rerun the script.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">5) Deterministic APPDATE</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>create or replace function appdate return date deterministic is
begin
  return sysdate;
end;
/

set serveroutput on size unlimited
set arraysize 1
declare
   cursor c is 
        select rownum,
               to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS') as the_sysdate, 
               to_char(appdate, 'YYYY-MM-DD HH24:MI:SS') as the_appdate
          from user_objects
         where rownum &lt;= 5;
   r c%rowtype;     
begin
    open c;
    sys.dbms_output.put_line('# THE_SYSDATE         THE_APPDATE');
    sys.dbms_output.put_line('- ------------------- -------------------');
    loop
        fetch c into r;
        exit when c%notfound;
        sys.dbms_output.put_line(r.rownum || ' ' || r.the_sysdate || ' ' || r.the_appdate);
        sys.dbms_session.sleep(1);
    end loop;
    close c;
end;
/</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line cbp-line-highlight"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> function appdate </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">deterministic</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sysdate</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> serveroutput </span><span style="color: #569CD6">on</span><span style="color: #D4D4D4"> size unlimited</span></span>
<span class="line"><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> arraysize </span><span style="color: #B5CEA8">1</span></span>
<span class="line"><span style="color: #569CD6">declare</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">cursor</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">c</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">rownum</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">               </span><span style="color: #DCDCAA">to_char</span><span style="color: #D4D4D4">(</span><span style="color: #DCDCAA">sysdate</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&#39;YYYY-MM-DD HH24:MI:SS&#39;</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> the_sysdate, </span></span>
<span class="line"><span style="color: #D4D4D4">               </span><span style="color: #DCDCAA">to_char</span><span style="color: #D4D4D4">(appdate, </span><span style="color: #CE9178">&#39;YYYY-MM-DD HH24:MI:SS&#39;</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> the_appdate</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> user_objects</span></span>
<span class="line"><span style="color: #D4D4D4">         </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">rownum</span><span style="color: #D4D4D4"> &lt;= </span><span style="color: #B5CEA8">5</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">   r </span><span style="color: #569CD6">c</span><span style="color: #D4D4D4">%</span><span style="color: #569CD6">rowtype</span><span style="color: #D4D4D4">;     </span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">open</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">c</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    sys.</span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;# THE_SYSDATE         THE_APPDATE&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    sys.</span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;- ------------------- -------------------&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">loop</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">fetch</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">c</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">into</span><span style="color: #D4D4D4"> r;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">exit</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">when</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">c</span><span style="color: #DCDCAA">%notfound</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        sys.</span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">(r.</span><span style="color: #569CD6">rownum</span><span style="color: #D4D4D4"> || </span><span style="color: #CE9178">&#39; &#39;</span><span style="color: #D4D4D4"> || r.the_sysdate || </span><span style="color: #CE9178">&#39; &#39;</span><span style="color: #D4D4D4"> || r.the_appdate);</span></span>
<span class="line"><span style="color: #D4D4D4">        sys.</span><span style="color: #DCDCAA">dbms_session.</span><span style="color: #4EC9B0">sleep</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">end loop</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">close</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">c</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>Function APPDATE compiled

# THE_SYSDATE         THE_APPDATE
- ------------------- -------------------
1 2025-10-13 08:29:00 2025-10-13 08:29:00
2 2025-10-13 08:29:00 2025-10-13 08:29:00
3 2025-10-13 08:29:00 2025-10-13 08:29:00
4 2025-10-13 08:29:00 2025-10-13 08:29:00
5 2025-10-13 08:29:00 2025-10-13 08:29:00


PL/SQL procedure successfully completed.</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">Function APPDATE compiled</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4"># THE_SYSDATE         THE_APPDATE</span></span>
<span class="line"><span style="color: #D4D4D4">- ------------------- -------------------</span></span>
<span class="line"><span style="color: #D4D4D4">1 2025-10-13 08:29:00 2025-10-13 08:29:00</span></span>
<span class="line"><span style="color: #D4D4D4">2 2025-10-13 08:29:00 2025-10-13 08:29:00</span></span>
<span class="line"><span style="color: #D4D4D4">3 2025-10-13 08:29:00 2025-10-13 08:29:00</span></span>
<span class="line"><span style="color: #D4D4D4">4 2025-10-13 08:29:00 2025-10-13 08:29:00</span></span>
<span class="line"><span style="color: #D4D4D4">5 2025-10-13 08:29:00 2025-10-13 08:29:00</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4">PL/SQL procedure successfully completed.</span></span></code></pre></div>



<p class="wp-block-paragraph">Now we have the same result. <code>SYSDATE</code> is evaluated once for the whole query as the deterministic function <code>APPDATE</code>. There is obviously some special treatment of <code>SYSDATE</code> in the Oracle Database code for SQL statements. It handles it similarly to a deterministic function or a bind variable. That&#8217;s good. This matches the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/cncpt/data-concurrency-and-consistency.html#GUID-6A252EAE-7900-47DC-BD6A-D5376A6B7608">read consistency concepts</a>. We do not want to get different results of SYSDATE in a single query.</p>



<p class="wp-block-paragraph">But how does it behave in PL/SQL?</p>



<h2 class="wp-block-heading" id="sysdate-in-plsql">SYSDATE in PL/SQL</h2>



<p class="wp-block-paragraph">24 years ago, someone posted a puzzle in the forum of <a href="https://www.dbasupport.com/forums/showthread.php?15390-PUZZLE">dbasupport.com</a> that covered the same topic. I snitched the code from there and adapted it slightly.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">6) SYSDATE endless-Loop?</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>set serveroutput on size unlimited
declare
   i binary_integer := 0;
begin
   while sysdate = sysdate loop
      i := i + 1;
   end loop;
   dbms_output.put_line('Left the loop after ' || i || ' iterations');
end;
/</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> serveroutput </span><span style="color: #569CD6">on</span><span style="color: #D4D4D4"> size unlimited</span></span>
<span class="line"><span style="color: #569CD6">declare</span></span>
<span class="line"><span style="color: #D4D4D4">   i </span><span style="color: #569CD6">binary_integer</span><span style="color: #D4D4D4"> := </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #C586C0">while</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sysdate</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">sysdate</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">loop</span></span>
<span class="line"><span style="color: #D4D4D4">      i := i + </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #C586C0">end loop</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Left the loop after &#39;</span><span style="color: #D4D4D4"> || i || </span><span style="color: #CE9178">&#39; iterations&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>Left the loop after 2957099 iterations


PL/SQL procedure successfully completed.</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">Left the loop after 2957099 iterations</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4">PL/SQL procedure successfully completed.</span></span></code></pre></div>



<p class="wp-block-paragraph">It appears to be an endless loop, but it is not. The two <code>SYSDATE</code> calls are evaluated independently, and eventually they return different results. Of course, the number of iterations varies. Therefore, the algorithm could be used as a kind of random number generator.</p>



<h2 class="wp-block-heading" id="appdate-in-plsql">APPDATE in PL/SQL</h2>



<p class="wp-block-paragraph">Let&#8217;s use the deterministic variant of the <code>APPDATE</code> function in the same script.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">7) APPDATE endless-Loop?</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>create or replace function appdate return date deterministic is
begin
  return sysdate;
end;
/

set serveroutput on size unlimited
declare 
   i binary_integer := 0;
begin
   while appdate = appdate loop
      i := i + 1;
   end loop;
   dbms_output.put_line('Left the loop after ' || i || ' iterations');
end;
/</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> function appdate </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">deterministic</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sysdate</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> serveroutput </span><span style="color: #569CD6">on</span><span style="color: #D4D4D4"> size unlimited</span></span>
<span class="line"><span style="color: #569CD6">declare</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">   i </span><span style="color: #569CD6">binary_integer</span><span style="color: #D4D4D4"> := </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">   </span><span style="color: #C586C0">while</span><span style="color: #D4D4D4"> appdate = appdate </span><span style="color: #C586C0">loop</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">      i := i + </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #C586C0">end loop</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Left the loop after &#39;</span><span style="color: #D4D4D4"> || i || </span><span style="color: #CE9178">&#39; iterations&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>Function APPDATE compiled

declare 
*
ERROR at line 1:
ORA-01426: numeric overflow
ORA-06512: at line 5

https://docs.oracle.com/error-help/db/ora-01426/


More Details :
https://docs.oracle.com/error-help/db/ora-01426/
https://docs.oracle.com/error-help/db/ora-06512/</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">Function APPDATE compiled</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4">declare </span></span>
<span class="line"><span style="color: #D4D4D4">*</span></span>
<span class="line"><span style="color: #D4D4D4">ERROR at line 1:</span></span>
<span class="line"><span style="color: #D4D4D4">ORA-01426: numeric overflow</span></span>
<span class="line"><span style="color: #D4D4D4">ORA-06512: at line 5</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4">https://docs.oracle.com/error-help/db/ora-01426/</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4">More Details :</span></span>
<span class="line"><span style="color: #D4D4D4">https://docs.oracle.com/error-help/db/ora-01426/</span></span>
<span class="line"><span style="color: #D4D4D4">https://docs.oracle.com/error-help/db/ora-06512/</span></span></code></pre></div>



<p class="wp-block-paragraph">Luckily, the maximum value of a binary integer is 2,147,483,647. With a <code>NULL</code> statement on line 12, the script would run endlessly. It looks like the <code>APPDATE</code> function is evaluated only once within the <code>WHILE</code> statement.</p>



<p class="wp-block-paragraph">We told the PL/SQL compiler that the <code>APPDATE</code> function is deterministic. So the same input (none in this case) always produces the same output. This is a lie. However, the compiler is a nice component and trusts us. So it can come up with some optimisations to improve the runtime of our code and produce a solution that calls <code>APPDATE</code> only once. And boom, we have an endless loop.</p>



<p class="wp-block-paragraph">Let&#8217;s verify this.</p>



<h2 class="wp-block-heading" id="plsql-optimize-level">PLSQL_OPTIMIZE_LEVEL</h2>



<p class="wp-block-paragraph">The PL/SQL compiler knows the following four optimisation <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/refrn/PLSQL_OPTIMIZE_LEVEL.html">levels</a>:</p>



<ul class="wp-block-list">
<li>0 = Oracle Database 9i style with some minor improvements</li>



<li>1 = Various optimisations, does not move code, therefore required when debugging PL/SQL</li>



<li>2 = More optimisations, including moving code around, this is the default in 19c/23ai</li>



<li>3 = Even more optimisations</li>
</ul>



<p class="wp-block-paragraph">The documentation leaves us in the dark about what each level does exactly. However, one thing is sure. The higher the level, the more aggressive the optimisation.</p>



<p class="wp-block-paragraph">So let&#8217;s try the previous code with level 0.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">8) APPDATE endless-Loop with plsql_optimize_level 0?</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>alter session set plsql_optimize_level = 0;
create or replace function appdate return date deterministic is
begin
  return sysdate;
end;
/

set serveroutput on size unlimited
declare 
   i binary_integer := 0;
begin
   while appdate = appdate loop
      i := i + 1;
   end loop;
   dbms_output.put_line('Left the loop after ' || i || ' iterations');
end;
/</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line cbp-line-highlight"><span style="color: #DCDCAA">alter session</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> plsql_optimize_level = </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> function appdate </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">deterministic</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sysdate</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> serveroutput </span><span style="color: #569CD6">on</span><span style="color: #D4D4D4"> size unlimited</span></span>
<span class="line"><span style="color: #569CD6">declare</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">   i </span><span style="color: #569CD6">binary_integer</span><span style="color: #D4D4D4"> := </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #C586C0">while</span><span style="color: #D4D4D4"> appdate = appdate </span><span style="color: #C586C0">loop</span></span>
<span class="line"><span style="color: #D4D4D4">      i := i + </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #C586C0">end loop</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Left the loop after &#39;</span><span style="color: #D4D4D4"> || i || </span><span style="color: #CE9178">&#39; iterations&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>Session altered.


Function APPDATE compiled

Left the loop after 3224661 iterations


PL/SQL procedure successfully completed.</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">Session altered.</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4">Function APPDATE compiled</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4">Left the loop after 3224661 iterations</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4">PL/SQL procedure successfully completed.</span></span></code></pre></div>



<p class="wp-block-paragraph">Ha, this worked. No endless loop. We get a similar result with level 1. However, levels 2 and 3 lead to an endless loop.</p>



<p class="wp-block-paragraph">This example should illustrate that we should not lie to the compiler. Sooner or later, another optimisation in a newer version could break our code.</p>



<h2 class="wp-block-heading" id="conclusion">Conclusion</h2>



<p class="wp-block-paragraph">In fact, the previous paragraph could be a good conclusion. However, at the beginning of this post, I mentioned a real use case where we were evaluating an alternative to the <a href="https://github.com/wolfcw/libfaketime">faketime</a> library. We opted for <a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/refrn/FIXED_DATE.html">FIXED_DATE</a> because it is simple to apply and worked for the application under test. The application uses <code>SYSDATE</code> exclusively for business-relevant dates and times. <code>SYSTIMESTAMP</code>, <code>CURRENT_DATE</code>, <code>CURRENT_TIMESTAMP</code> and <code>LOCALTIMESTAMP</code>, which are unaffected by <code>FIXED_DATE</code>, are used only for logging purposes.</p>



<p class="wp-block-paragraph">The idea of providing a custom function that returns <code>SYSDATE</code> with a centrally defined offset might have worked in our case. But providing a solution that behaves like <code>SYSDATE</code> is much more challenging than I thought. We would need something that is evaluated once in a SQL statement and per call in other cases. Passing <code>SYSDATE</code> as a default parameter to a deterministic function does the trick. Either way, I&#8217;m glad we opted for the simpler solution, which meant there was no need to change the code base.</p>
<p>The post <a href="https://www.salvis.com/blog/2025/10/15/is-sysdate-deterministic-joelkallmanday/">Is SYSDATE Deterministic? #JoelKallmanDay</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.salvis.com/blog/2025/10/15/is-sysdate-deterministic-joelkallmanday/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
	</channel>
</rss>
