<?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>Code Analysis Archives - Philipp Salvisberg&#039;s Blog</title>
	<atom:link href="https://www.salvis.com/blog/tag/code-analysis/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.salvis.com/blog/tag/code-analysis/</link>
	<description>Database-centric development</description>
	<lastBuildDate>Wed, 29 Jul 2026 04:07:53 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.2</generator>

<image>
	<url>https://www.salvis.com/blog/wp-content/uploads/2014/04/favicon.png</url>
	<title>Code Analysis Archives - Philipp Salvisberg&#039;s Blog</title>
	<link>https://www.salvis.com/blog/tag/code-analysis/</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/code-analysis/feed/"/>
	<item>
		<title>Detecting Security Vulnerabilities With the APEXlang Parser</title>
		<link>https://www.salvis.com/blog/2026/06/29/detecting-security-vulnerabilities-with-the-apexlang-parser/</link>
					<comments>https://www.salvis.com/blog/2026/06/29/detecting-security-vulnerabilities-with-the-apexlang-parser/#respond</comments>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Mon, 29 Jun 2026 12:12:21 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[ANTLR]]></category>
		<category><![CDATA[APEXlang]]></category>
		<category><![CDATA[Code Analysis]]></category>
		<category><![CDATA[dbLinter]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=19914</guid>

					<description><![CDATA[<p>Introduction A parser for the APEXlang grammar enables the development of tools beyond the scope of the APEXlang compiler included in SQLcl, SQL Developer for VS Code, and ORDS. These tools can perform static code analysis, convert code, generate documentation, and visualise different aspects of an APEX application. A linter, for example,<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2026/06/29/detecting-security-vulnerabilities-with-the-apexlang-parser/">Detecting Security Vulnerabilities With the APEXlang Parser</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">A parser for the APEXlang grammar enables the development of tools beyond the scope of the APEXlang compiler included in SQLcl, SQL Developer for VS Code, and ORDS. These tools can perform static code analysis, convert code, generate documentation, and visualise different aspects of an APEX application.</p>



<p class="wp-block-paragraph">A linter, for example, can check whether an APEXlang file conforms to defined quality standards. These standards may cover project- or company-specific conventions as well as more general concerns, such as detecting potential security vulnerabilities.</p>



<p class="wp-block-paragraph">In this blog post, I explain the elements of an APEXlang file that are the basis of Grisselbav&#8217;s <a href="https://github.com/Grisselbav/APEXlang-Parser" type="link" id="https://github.com/Grisselbav/APEXlang-Parser" target="_blank" rel="noreferrer noopener">APEXlang parser</a>. Then I demonstrate how to use the parser in a simple Java program to detect a security vulnerability.</p>



<h2 id="elements-of-an-apexlang-file" class="wp-block-heading">Elements of an APEXlang File</h2>



<p class="wp-block-paragraph">An APEXlang file consists of three basic building blocks: components, properties, and groups. These elements can also be nested, as shown later.</p>



<p class="wp-block-paragraph">Here&#8217;s an excerpt of Oracle&#8217;s Universal Theme demo application.apx file:</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">1) Excerpt of UT&#8217;s application.apx</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>app UT (
    name: Universal Theme 26.1 Reference
    version: 26.1.0
    group: @universal-theme
    logo {
        type: text
        text: Universal Theme
    }
    // ...removed code...
)</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">app</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">UT</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">    name: </span><span style="color: #569CD6">Universal</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Theme</span><span style="color: #D4D4D4"> 26.1 Reference</span></span>
<span class="line"><span style="color: #D4D4D4">    version: 26.1.0</span></span>
<span class="line"><span style="color: #D4D4D4">    group: @universal-theme</span></span>
<span class="line"><span style="color: #D4D4D4">    logo {</span></span>
<span class="line"><span style="color: #D4D4D4">        type: text</span></span>
<span class="line"><span style="color: #D4D4D4">        text: </span><span style="color: #569CD6">Universal</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Theme</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// ...removed code...</span></span>
<span class="line"><span style="color: #D4D4D4">)</span></span></code></pre></div>



<h5 id="component" class="wp-block-heading">Component</h5>



<p class="wp-block-paragraph">There is one component in this example. It starts on line 1 and ends on line 10. <code>app</code> is the type of the component and <code>UT</code> the component name.</p>



<p class="wp-block-paragraph">A component body starts with a left parenthesis <code>(</code> and ends with a right parenthesis <code>)</code>.</p>



<h5 id="property" class="wp-block-heading">Property</h5>



<p class="wp-block-paragraph">In this example, we have 5 properties. The property keys are <code>name</code>, <code>version</code>, <code>group</code>, <code>type</code> and <code>text</code>. The value of a property follows a colon <code>:</code>. For <code>name</code> The value is <code>Universal Theme 26.1 Reference</code>, for <code>version</code> the value is <code>26.1.0</code> and so on.</p>



<p class="wp-block-paragraph">Please note that a property starts on a new line, and the property value starts after the colon and ends on a new line. This way, no delimiter characters are required for most property values. However, if leading or trailing spaces are significant, you have to pass the property value as a single-line string, which is enclosed in double quotes.</p>



<h5 id="group" class="wp-block-heading">Group (of properties)</h5>



<p class="wp-block-paragraph">The properties <code>type</code> and <code>text</code> are part of a group named <code>logo</code>.  The group in this example covers lines 5 to 8.</p>



<p class="wp-block-paragraph">A group body starts with an open curly bracket <code>{</code> and ends with a close curly bracket <code>}</code>.</p>



<p class="wp-block-paragraph">Properties which are not part of a group are called direct properties. This means they are defined directly in a component. Examples of direct properties are <code>name</code>, <code>version</code> and <code>group</code>.</p>



<h2 id="nesed-elements" class="wp-block-heading">Nested Elements</h2>



<p class="wp-block-paragraph">We have seen that a component may contain properties and groups. But it is also possible to nest elements.</p>



<ul class="wp-block-list">
<li>Components may contain other components besides properties and groups</li>



<li>Property values may contain groups besides simple values</li>
</ul>



<p class="wp-block-paragraph">There is no limit to the number of levels for nested elements.</p>



<p class="wp-block-paragraph">Here&#8217;s an example:</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">2) Nested Component and Group</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>app UT (
    // ...removed code...
    pwaShortcut getting-started (
        name: Getting Started
        sequence: 10
        shortcut {
            target: {
                page: 500
            }
            description: Getting Started Page - Initial Page
        }
        comments {
            comments: -
        }
    )
   // ...removed code...
)</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">app</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">UT</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// ...removed code...</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">pwaShortcut</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">getting</span><span style="color: #D4D4D4">-started (</span></span>
<span class="line"><span style="color: #D4D4D4">        name: </span><span style="color: #569CD6">Getting</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Started</span></span>
<span class="line"><span style="color: #D4D4D4">        sequence: 10</span></span>
<span class="line"><span style="color: #D4D4D4">        shortcut {</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">            target: {</span></span>
<span class="line"><span style="color: #D4D4D4">                page: 500</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">            description: </span><span style="color: #569CD6">Getting</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Started</span><span style="color: #D4D4D4"> Page - </span><span style="color: #569CD6">Initial</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Page</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">        comments {</span></span>
<span class="line"><span style="color: #D4D4D4">            comments: -</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">   </span><span style="color: #6A9955">// ...removed code...</span></span>
<span class="line"><span style="color: #D4D4D4">)</span></span></code></pre></div>



<p class="wp-block-paragraph">A nested component starts on line 3 and a nested group on line 7.</p>



<h2 id="apexlang-grammar" class="wp-block-heading">APEXlang Grammar</h2>



<figure class="wp-block-image size-medium"><a href="https://grisselbav.github.io/APEXlang-Parser/grammar.html" target="_blank" rel=" noreferrer noopener"><img decoding="async" width="300" height="133" src="https://www.salvis.com/blog/wp-content/uploads/2026/06/APEXlang-apxFile-300x133.png" alt="apxFile rule of APEXlang grammar" class="wp-image-19988" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/06/APEXlang-apxFile-300x133.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/06/APEXlang-apxFile-1024x453.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/06/APEXlang-apxFile-768x340.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/06/APEXlang-apxFile-150x66.png 150w, https://www.salvis.com/blog/wp-content/uploads/2026/06/APEXlang-apxFile-480x212.png 480w, https://www.salvis.com/blog/wp-content/uploads/2026/06/APEXlang-apxFile.png 1456w" sizes="(max-width:767px) 300px, 300px" /></a></figure>



<p class="wp-block-paragraph">While the grammar documented in <a href="https://docs.oracle.com/en/database/oracle/apex/26.1/apxln/apexlang.ebnf" target="_blank" rel="noreferrer noopener">apexlang. ebnf</a> of the <a href="https://docs.oracle.com/en/database/oracle/apex/26.1/apxln/" target="_blank" rel="noreferrer noopener">API Reference</a> defines both the language structure and the valid APEXlang elements, the grammar used by Grisselbav&#8217;s APEXlang parser is limited to structural concerns. </p>



<p class="wp-block-paragraph">Because the parser focuses solely on syntax rather than semantic validation, the grammar remains remarkably compact.</p>



<p class="wp-block-paragraph">Click on the image above to view all the syntax diagrams. Alternatively, view the ANTLR4 source files, <a href="https://github.com/Grisselbav/APEXlang-Parser/blob/v0.2.0/src/main/antlr4/com/grisselbav/apexlang/grammar/ApexLangLexer.g4" target="_blank" rel="noreferrer noopener">ApexLangLexer.g4</a> and <a href="https://github.com/Grisselbav/APEXlang-Parser/blob/v0.2.0/src/main/antlr4/com/grisselbav/apexlang/grammar/ApexLangParser.g4" target="_blank" rel="noreferrer noopener">ApexLangParser.g4</a>, which were used to generate the parser available on <a href="https://central.sonatype.com/artifact/com.grisselbav/apexlang-parser" target="_blank" rel="noreferrer noopener">Maven Central</a>.</p>



<h2 id="apex-sert" class="wp-block-heading">APEX-SERT</h2>



<p class="wp-block-paragraph">APEX-SERT is an APEX application that scans a selected APEX application for security vulnerabilities. A vulnerability is detected by querying APEX dictionary views. All rules are defined in the <a href="https://github.com/oracle-samples/apex-sert/blob/v24.2.27.1/product/sert/sert_core/json_data/APEX-SERT%20Rules.json#L978-L1014" type="link" id="https://github.com/oracle-samples/apex-sert/blob/v24.2.27.1/product/sert/sert_core/json_data/APEX-SERT%20Rules.json#L978-L1014" target="_blank" rel="noreferrer noopener">APEX-SERT Rules.json</a> file. </p>



<p class="wp-block-paragraph">To demonstrate a practical use case, let’s look at the security check &#8220;Embed in Frames&#8221; implemented by APEX-SERT.</p>



<p class="wp-block-paragraph">When the property &#8220;Embed in Frames&#8221; is set to <code>Allow</code>, the application may be vulnerable to &#8220;clickjacking&#8221; attacks as explained in the help text of the page designer. See screenshot below.</p>



<figure class="wp-block-image size-large"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow.png"><img fetchpriority="high" decoding="async" width="1024" height="698" src="https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-1024x698.png" alt="" class="wp-image-20001" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-1024x698.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-300x205.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-768x524.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-1536x1047.png 1536w, https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-2048x1396.png 2048w, https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-110x75.png 110w, https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-480x327.png 480w" sizes="(max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">I changed the original value from <code>Allow from same origin</code> to <code>Allow</code> to simulate a security vulnerability.</p>



<p class="wp-block-paragraph">APEX-SERT runs a query similar to the following to find violations of this rule:</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">3) Find Violations with SQL</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 application_id, application_name, browser_frame 
  from apex_applications
 where browser_frame not in ('Deny', 'Allow from same origin');</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"> application_id, application_name, browser_frame </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> apex_applications</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> browser_frame </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> (</span><span style="color: #CE9178">&#39;Deny&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&#39;Allow from same origin&#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;--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>APPLICATION_ID APPLICATION_NAME               BROWSER_FRAME
-------------- ------------------------------ -------------
        101252 Universal Theme 26.1 Reference Allow</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">APPLICATION_ID APPLICATION_NAME               BROWSER_FRAME</span></span>
<span class="line"><span style="color: #D4D4D4">-------------- ------------------------------ -------------</span></span>
<span class="line"><span style="color: #D4D4D4">        101252 Universal Theme 26.1 Reference Allow</span></span></code></pre></div>



<p class="wp-block-paragraph">So, the value of <code>Embed in Frames</code> is provided in the <code>browser_frame</code> column of the APEX dictionary view <code>apex_applications</code>.</p>



<p class="wp-block-paragraph">But where can we find this information in the APEXlang files?</p>



<h2 id="link-page-designer-property-to-apexlang" class="wp-block-heading">Link Page Designer Property to APEXlang</h2>



<p class="wp-block-paragraph">We find the &#8220;Embed in Frames&#8221; property in the page designer by navigating to &#8220;Shared Components&#8221; -&gt; &#8220;Application Definition&#8221; -&gt; &#8220;Security&#8221; -&gt; &#8220;Browser Security&#8221;. </p>



<p class="wp-block-paragraph">According to the <a href="https://docs.oracle.com/en/database/oracle/apex/26.1/apxln/apexlang.ebnf" target="_blank" rel="noreferrer noopener">apexlang. ebnf</a> there is a <code>security</code> group within the <code>app</code> component. Here&#8217;s the relevant excerpt:</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-start:347;--cbp-line-number-width:calc(3 * 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">3) Property embedInFrames within apexlang.ebnf</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>&lt;app-security> ::= &lt;indent> "security" &lt;ws> "{" &lt;line-end> { &lt;app-security-property-line> } &lt;indent> "}" &lt;line-end>
&lt;app-security-property-line> ::= &lt;indent> &lt;app-security-property> &lt;line-end>
&lt;app-security-property> ::= "deepLinking" ":" &lt;ws> ( "true" | "false" ) (* required; type: SELECT LIST *)
  | "enableDictation" ":" &lt;ws> &lt;boolean> (* required; type: YES NO *)
  | "browserCache" ":" &lt;ws> ( "true" | "false" ) (* required; type: SELECT LIST *)
  | "embedInFrames" ":" &lt;ws> ( "deny" | "allowSameOrigin" | "allow" ) (* required; type: SELECT LIST *)
  | "referrerPolicy" ":" &lt;ws> ( "noReferrer" | "noReferrerWhenDowngrade" | "origin" | "originWhenCrossOrigin" | "sameOrigin" | "strictOrigin" | "strictOriginWhenCrossOrigin" | "unsafeUrl" ) (* required; type: SELECT LIST *)
  | "htmlEscapingMode" ":" &lt;ws> ( "basic" | "extended" ) (* required; type: SELECT LIST *)
  | "httpResponseHeaders" ":" &lt;ws> &lt;multiline-string> (* type: TEXT EDITOR *)
  | "runtimeApiUsage" ":" &lt;ws> &lt;array-of-string-like-value> (* type: CHECKBOXES *)</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">&lt;app-security&gt; ::= &lt;indent&gt; &quot;security&quot; &lt;ws&gt; &quot;</span><span style="color: #6A9955">{&quot; &lt;line-end&gt; { &lt;app-security-property-line&gt; }</span><span style="color: #D4D4D4"> &lt;indent&gt; &quot;}&quot; &lt;line-</span><span style="color: #569CD6">end</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;app-security-property-line&gt; ::= &lt;indent&gt; &lt;app-security-property&gt; &lt;line-</span><span style="color: #569CD6">end</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;app-security-property&gt; ::= &quot;deepLinking&quot; &quot;:&quot; &lt;ws&gt; ( &quot;</span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">&quot; | &quot;</span><span style="color: #569CD6">false</span><span style="color: #D4D4D4">&quot; ) </span><span style="color: #6A9955">(* required; type: SELECT LIST *)</span></span>
<span class="line"><span style="color: #D4D4D4">  | &quot;enableDictation&quot; &quot;:&quot; &lt;ws&gt; &lt;</span><span style="color: #569CD6">boolean</span><span style="color: #D4D4D4">&gt; </span><span style="color: #6A9955">(* required; type: YES NO *)</span></span>
<span class="line"><span style="color: #D4D4D4">  | &quot;browserCache&quot; &quot;:&quot; &lt;ws&gt; ( &quot;</span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">&quot; | &quot;</span><span style="color: #569CD6">false</span><span style="color: #D4D4D4">&quot; ) </span><span style="color: #6A9955">(* required; type: SELECT LIST *)</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">  | &quot;embedInFrames&quot; &quot;:&quot; &lt;ws&gt; ( &quot;deny&quot; | &quot;allowSameOrigin&quot; | &quot;allow&quot; ) </span><span style="color: #6A9955">(* required; type: SELECT LIST *)</span></span>
<span class="line"><span style="color: #D4D4D4">  | &quot;referrerPolicy&quot; &quot;:&quot; &lt;ws&gt; ( &quot;noReferrer&quot; | &quot;noReferrerWhenDowngrade&quot; | &quot;origin&quot; | &quot;originWhenCrossOrigin&quot; | &quot;sameOrigin&quot; | &quot;strictOrigin&quot; | &quot;strictOriginWhenCrossOrigin&quot; | &quot;unsafeUrl&quot; ) </span><span style="color: #6A9955">(* required; type: SELECT LIST *)</span></span>
<span class="line"><span style="color: #D4D4D4">  | &quot;htmlEscapingMode&quot; &quot;:&quot; &lt;ws&gt; ( &quot;basic&quot; | &quot;</span><span style="color: #569CD6">extended</span><span style="color: #D4D4D4">&quot; ) </span><span style="color: #6A9955">(* required; type: SELECT LIST *)</span></span>
<span class="line"><span style="color: #D4D4D4">  | &quot;httpResponseHeaders&quot; &quot;:&quot; &lt;ws&gt; &lt;multiline-</span><span style="color: #569CD6">string</span><span style="color: #D4D4D4">&gt; </span><span style="color: #6A9955">(* type: TEXT EDITOR *)</span></span>
<span class="line"><span style="color: #D4D4D4">  | &quot;runtimeApiUsage&quot; &quot;:&quot; &lt;ws&gt; &lt;</span><span style="color: #569CD6">array</span><span style="color: #D4D4D4">-</span><span style="color: #569CD6">of</span><span style="color: #D4D4D4">-</span><span style="color: #569CD6">string</span><span style="color: #D4D4D4">-like-value&gt; </span><span style="color: #6A9955">(* type: CHECKBOXES *)</span></span></code></pre></div>



<p class="wp-block-paragraph">We find on line 352 the definition of the property <code>embedInFrames</code> with a list of valid values. In this case, the property key is unique. This means that no other component or group uses the property key <code>embedInFrames</code>. Therefore, we can search the folder containing the .apx files for the string <code>embedInFrames:</code> to find the position of this property. </p>



<p class="wp-block-paragraph">The matching property is located in the <span style="background-color: initial; font-family: inherit; font-size: inherit; text-align: initial;"><code>application.apx</code> file.</span></p>



<p class="wp-block-paragraph">Here&#8217;s an excerpt.</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-start:46;--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) Property embedInFrames in application.apx</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>    authorization {
        runOnPublicPages: true
    }
    security {
        deepLinking: true
        embedInFrames: allow
        runtimeApiUsage: modifyThisApp
    }
    sessionStateProtection {
        allowUrlsCreatedAfter: 1999-08-04T00:00:00
        checksumSalt: 75BAAC4002F8CA56EF54FD242CCE7719B1AB85BE339E930260B3EC8EA3879365
    }</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">    </span><span style="color: #9CDCFE">authorization</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">runOnPublicPages</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">true</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">security</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">deepLinking</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">true</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">embedInFrames</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">allow</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">runtimeApiUsage</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">modifyThisApp</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">sessionStateProtection</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">allowUrlsCreatedAfter</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">1999-08-04T00:00:00</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">checksumSalt</span><span style="color: #D4D4D4">: 75</span><span style="color: #9CDCFE">BAAC4002F8CA56EF54FD242CCE7719B1AB85BE339E930260B3EC8EA3879365</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span></code></pre></div>



<p class="wp-block-paragraph">Please note that properties with default values are skipped when an APEX application is exported. Therefore, we would not see the <code>embedInFrames</code> property if its value were <code>Deny</code>.</p>



<h2 id="find-vulnerability-with-apexlang-parser" class="wp-block-heading">Find Vulnerability With APEXlang Parser</h2>



<p class="wp-block-paragraph">We now have all the information we need. We can write a small demo program. This program will find this vulnerability in an APEXlang file.</p>



<p class="wp-block-paragraph">The parser exposes the parse tree through ANTLR4-generated context classes. Each parser rule becomes a context class. For example, the class <code>ApexLangParser.PropertyContext</code> represents the <a href="https://github.com/Grisselbav/APEXlang-Parser/blob/v0.2.0/src/main/antlr4/com/grisselbav/apexlang/grammar/ApexLangParser.g4#L66-L68" target="_blank" rel="noreferrer noopener">property</a> parser rule. This makes it easy to traverse the <code>ApexLangDocument</code> using Java streams.</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">5) DemoFindVulnerability.java</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>//DEPS com.grisselbav:apexlang-parser:0.2.0

import com.grisselbav.apexlang.grammar.*;

class DemoFindVulnerability {
    public static void main(String[] args) {
        var apxSource = """
                app UT (
                    name: Universal Theme 26.1 Reference
                    version: 26.1.0
                    // ... removed code ...
                    authorization {
                        runOnPublicPages: true
                    }
                    security {
                        deepLinking: true
                        embedInFrames: allow
                        runtimeApiUsage: modifyThisApp
                    }
                    sessionStateProtection {
                        allowUrlsCreatedAfter: 1999-08-04T00:00:00
                        checksumSalt: 75BAAC4002F8CA56EF54FD242CCE7719B1AB85BE339E930260B3EC8EA3879365
                    }
                    // ... removed code ...
                )
                """;
        var doc = ApexLangDocument.parse(apxSource);
        var violations = doc.getAllContentsOfType(ApexLangParser.PropertyContext.class)
                .stream()
                .filter(p -> p.name.getText().equals("embedInFrames")
                        &amp;&amp; p.value().getText().equals("allow"))
                .toList();
        for (var violation : violations) {
            System.err.println("Found vulnerability: " + violation.getText());
        }
    }
}</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: #6A9955">//DEPS com.grisselbav:apexlang-parser:0.2.0</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">import</span><span style="color: #D4D4D4"> com.grisselbav.apexlang.grammar.*;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">DemoFindVulnerability</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">main</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">String</span><span style="color: #D4D4D4">[] </span><span style="color: #9CDCFE">args</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">apxSource</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;&quot;&quot;</span></span>
<span class="line"><span style="color: #CE9178">                app UT (</span></span>
<span class="line"><span style="color: #CE9178">                    name: Universal Theme 26.1 Reference</span></span>
<span class="line"><span style="color: #CE9178">                    version: 26.1.0</span></span>
<span class="line"><span style="color: #CE9178">                    // ... removed code ...</span></span>
<span class="line"><span style="color: #CE9178">                    authorization {</span></span>
<span class="line"><span style="color: #CE9178">                        runOnPublicPages: true</span></span>
<span class="line"><span style="color: #CE9178">                    }</span></span>
<span class="line"><span style="color: #CE9178">                    security {</span></span>
<span class="line"><span style="color: #CE9178">                        deepLinking: true</span></span>
<span class="line"><span style="color: #CE9178">                        embedInFrames: allow</span></span>
<span class="line"><span style="color: #CE9178">                        runtimeApiUsage: modifyThisApp</span></span>
<span class="line"><span style="color: #CE9178">                    }</span></span>
<span class="line"><span style="color: #CE9178">                    sessionStateProtection {</span></span>
<span class="line"><span style="color: #CE9178">                        allowUrlsCreatedAfter: 1999-08-04T00:00:00</span></span>
<span class="line"><span style="color: #CE9178">                        checksumSalt: 75BAAC4002F8CA56EF54FD242CCE7719B1AB85BE339E930260B3EC8EA3879365</span></span>
<span class="line"><span style="color: #CE9178">                    }</span></span>
<span class="line"><span style="color: #CE9178">                    // ... removed code ...</span></span>
<span class="line"><span style="color: #CE9178">                )</span></span>
<span class="line"><span style="color: #CE9178">                &quot;&quot;&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">ApexLangDocument</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">parse</span><span style="color: #D4D4D4">(apxSource);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">violations</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getAllContentsOfType</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">ApexLangParser</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">PropertyContext</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">                .</span><span style="color: #DCDCAA">stream</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">                .</span><span style="color: #DCDCAA">filter</span><span style="color: #D4D4D4">(p </span><span style="color: #569CD6">-&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">name</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">equals</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;embedInFrames&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">                        &amp;&amp; </span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">value</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">equals</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;allow&quot;</span><span style="color: #D4D4D4">))</span></span>
<span class="line"><span style="color: #D4D4D4">                .</span><span style="color: #DCDCAA">toList</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">violation</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">:</span><span style="color: #D4D4D4"> violations) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">System</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">println</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Found vulnerability: &quot;</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">violation</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">());</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">}</span></span></code></pre></div>



<p class="wp-block-paragraph">This program embeds the APEXlang source code to scan in the <code>apxSource</code> variable. To run the program, save it as <code>DemoFindVulnerability.java</code>, then run it with <a href="https://www.jbang.dev/" type="link" id="https://www.jbang.dev/" target="_blank" rel="noreferrer noopener">JBang</a>. This will automatically resolve the Maven dependency on the first line.</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>jbang DemoFindVulnerability.java</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">jbang</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">DemoFindVulnerability.java</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;jbang&#93; Resolving dependencies...
&#91;jbang&#93;    com.grisselbav:apexlang-parser:0.2.0
&#91;jbang&#93; Dependencies resolved
&#91;jbang&#93; Building jar for DemoFindVulnerability.java...
Found vulnerability: 
        embedInFrames: allow</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;jbang&#93; Resolving dependencies...</span></span>
<span class="line"><span style="color: #D4D4D4">&#91;jbang&#93;    com.grisselbav:apexlang-parser:0.2.0</span></span>
<span class="line"><span style="color: #D4D4D4">&#91;jbang&#93; Dependencies resolved</span></span>
<span class="line"><span style="color: #D4D4D4">&#91;jbang&#93; Building jar for DemoFindVulnerability.java...</span></span>
<span class="line"><span style="color: #D4D4D4">Found vulnerability: </span></span>
<span class="line"><span style="color: #D4D4D4">        embedInFrames: allow</span></span></code></pre></div>



<h2 id="are-regular-expressions-an-alternative" class="wp-block-heading">Are Regular Expressions An Alternative?</h2>



<p class="wp-block-paragraph">In this case, we could have used a regular expression to identify the violation. </p>



<p class="wp-block-paragraph">However, as soon as the rules become more complicated, e.g. if we want to ensure that the property is part of the <code>security</code> group and the <code>security</code> group is part of the <code>app</code> component, regular expressions are no longer suited. But a parser is. Because we can navigate the parse tree and adjust the filter settings 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(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">6) DemoFindVulnerability2.java with extended filter</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>//DEPS com.grisselbav:apexlang-parser:0.2.0

import com.grisselbav.apexlang.grammar.*;

class DemoFindVulnerability2 {
    public static void main(String[] args) {
        var apxSource = """
                app UT (
                    name: Universal Theme 26.1 Reference
                    version: 26.1.0
                    // ... removed code ...
                    authorization {
                        runOnPublicPages: true
                    }
                    security {
                        deepLinking: true
                        embedInFrames: allow
                        runtimeApiUsage: modifyThisApp
                    }
                    sessionStateProtection {
                        allowUrlsCreatedAfter: 1999-08-04T00:00:00
                        checksumSalt: 75BAAC4002F8CA56EF54FD242CCE7719B1AB85BE339E930260B3EC8EA3879365
                    }
                    // ... removed code ...
                )
                """;
        var doc = ApexLangDocument.parse(apxSource);
        var violations = doc.getAllContentsOfType(ApexLangParser.PropertyContext.class)
                .stream()
                .filter(p -> p.name.getText().equals("embedInFrames")
                        &amp;&amp; p.value().getText().equals("allow")
                        &amp;&amp; p.parent.parent instanceof ApexLangParser.GroupContext g
                        &amp;&amp; g.name.getText().equals("security")
                        &amp;&amp; g.parent.parent.parent instanceof ApexLangParser.ComponentContext c
                        &amp;&amp; c.type.getText().equals("app"))
                .toList();
        for (var violation : violations) {
            System.err.println("Found vulnerability: " + violation.getText());
        }
    }
}</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: #6A9955">//DEPS com.grisselbav:apexlang-parser:0.2.0</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">import</span><span style="color: #D4D4D4"> com.grisselbav.apexlang.grammar.*;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">DemoFindVulnerability2</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">main</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">String</span><span style="color: #D4D4D4">[] </span><span style="color: #9CDCFE">args</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">apxSource</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;&quot;&quot;</span></span>
<span class="line"><span style="color: #CE9178">                app UT (</span></span>
<span class="line"><span style="color: #CE9178">                    name: Universal Theme 26.1 Reference</span></span>
<span class="line"><span style="color: #CE9178">                    version: 26.1.0</span></span>
<span class="line"><span style="color: #CE9178">                    // ... removed code ...</span></span>
<span class="line"><span style="color: #CE9178">                    authorization {</span></span>
<span class="line"><span style="color: #CE9178">                        runOnPublicPages: true</span></span>
<span class="line"><span style="color: #CE9178">                    }</span></span>
<span class="line"><span style="color: #CE9178">                    security {</span></span>
<span class="line"><span style="color: #CE9178">                        deepLinking: true</span></span>
<span class="line"><span style="color: #CE9178">                        embedInFrames: allow</span></span>
<span class="line"><span style="color: #CE9178">                        runtimeApiUsage: modifyThisApp</span></span>
<span class="line"><span style="color: #CE9178">                    }</span></span>
<span class="line"><span style="color: #CE9178">                    sessionStateProtection {</span></span>
<span class="line"><span style="color: #CE9178">                        allowUrlsCreatedAfter: 1999-08-04T00:00:00</span></span>
<span class="line"><span style="color: #CE9178">                        checksumSalt: 75BAAC4002F8CA56EF54FD242CCE7719B1AB85BE339E930260B3EC8EA3879365</span></span>
<span class="line"><span style="color: #CE9178">                    }</span></span>
<span class="line"><span style="color: #CE9178">                    // ... removed code ...</span></span>
<span class="line"><span style="color: #CE9178">                )</span></span>
<span class="line"><span style="color: #CE9178">                &quot;&quot;&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">ApexLangDocument</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">parse</span><span style="color: #D4D4D4">(apxSource);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">violations</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getAllContentsOfType</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">ApexLangParser</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">PropertyContext</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">                .</span><span style="color: #DCDCAA">stream</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">                .</span><span style="color: #DCDCAA">filter</span><span style="color: #D4D4D4">(p </span><span style="color: #569CD6">-&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">name</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">equals</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;embedInFrames&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                        &amp;&amp; </span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">value</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">equals</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;allow&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                        &amp;&amp; </span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">parent</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">parent</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">instanceof</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ApexLangParser</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">GroupContext</span><span style="color: #D4D4D4"> g</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                        &amp;&amp; </span><span style="color: #9CDCFE">g</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">name</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">equals</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;security&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                        &amp;&amp; </span><span style="color: #9CDCFE">g</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">parent</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">parent</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">parent</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">instanceof</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ApexLangParser</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">ComponentContext</span><span style="color: #D4D4D4"> c</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                        &amp;&amp; </span><span style="color: #9CDCFE">c</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">type</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">equals</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;app&quot;</span><span style="color: #D4D4D4">))</span></span>
<span class="line"><span style="color: #D4D4D4">                .</span><span style="color: #DCDCAA">toList</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">violation</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">:</span><span style="color: #D4D4D4"> violations) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">System</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">println</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Found vulnerability: &quot;</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">violation</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">());</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">}</span></span></code></pre></div>



<h2 id="integration-into-dblinter" class="wp-block-heading">Integration Into dbLinter</h2>



<p class="wp-block-paragraph">The APEX-SERT &#8220;Embed in Frames&#8221; rule has been added to the dbLinter repository as rule <a href="https://dblinter.app/ords/r/dblinter/dblinter-console/rules#P1000_SHOW_RULE=core%20a-0770" target="_blank" rel="noreferrer noopener">A-0770: Never allow application pages within an HTML frame</a>. The VS Code extension, the CLI and the SonarQube plugin now support checks implemented for APEXlang.</p>



<p class="wp-block-paragraph">Here&#8217;s a short silent video that demonstrates how this security vulnerability is detected and quickly fixed.</p>



<figure class="wp-block-video"><video height="720" style="aspect-ratio: 1280 / 720;" width="1280" controls src="https://www.salvis.com/blog/wp-content/uploads/2026/06/dblinter-a1010.mp4"></video></figure>



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



<p class="wp-block-paragraph">The APEXlang grammar is intentionally simple through focusing on structural elements, leaving semantic validation, such as valid property values, to the APEXlang compiler in SQLcl, SQL Developer and VS Code.</p>



<p class="wp-block-paragraph">Integrating the APEXlang parser into dbLinter was straightforward, as was implementing the first APEXlang-based dbLinter rule.</p>



<p class="wp-block-paragraph">The next step is to identify which additional rules would be beneficial to bring to dbLinter. If you have any suggestions, please let me know. Even better, open a GitHub issue in the <a href="https://github.com/Grisselbav/dbLinter" target="_blank" rel="noreferrer noopener">dbLinter GitHub repository</a>. </p>



<p class="wp-block-paragraph">Thank you.</p>



<p class="wp-block-paragraph"><em>Updated on 2026-07-29, fixed link to rule &#8220;Never allow application pages within an HTML frame&#8221; (A-1010 → A-0770).</em></p>
<p>The post <a href="https://www.salvis.com/blog/2026/06/29/detecting-security-vulnerabilities-with-the-apexlang-parser/">Detecting Security Vulnerabilities With the APEXlang Parser</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/06/29/detecting-security-vulnerabilities-with-the-apexlang-parser/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://www.salvis.com/blog/wp-content/uploads/2026/06/dblinter-a1010.mp4" length="2752429" type="video/mp4" />

			</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 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="(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>Outer Joining With ANSI SQL-89 and SQL-92</title>
		<link>https://www.salvis.com/blog/2025/07/12/outer-joining-with-ansi-sql-89-and-sql-92/</link>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Sat, 12 Jul 2025 15:20:05 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Code Analysis]]></category>
		<category><![CDATA[dbLinter]]></category>
		<category><![CDATA[SQL]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=13988</guid>

					<description><![CDATA[<p>Introduction I recently implemented a quick fix for the rule G-3130 to transform queries to ANSI SQL-92 syntax. One of the challenges was to handle Oracle&#8217;s outer-join syntax (+). In ANSI SQL-89, join and filter criteria are part of the WHERE clause. It&#8217;s not easy to distinguish them. In this blog post,<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2025/07/12/outer-joining-with-ansi-sql-89-and-sql-92/">Outer Joining With ANSI SQL-89 and SQL-92</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">Introduction</h2>



<p class="wp-block-paragraph">I recently implemented a quick fix for the rule <a href="https://dblinter-rules.united-codes.com/rules/G-3130/">G-3130</a> to transform queries to ANSI SQL-92 syntax. One of the challenges was to handle Oracle&#8217;s outer-join syntax <code>(+)</code>. In ANSI SQL-89, join and filter criteria are part of the WHERE clause.  It&#8217;s not easy to distinguish them. In this blog post, I explain why it is important to do that when using outer joins, regardless of which join syntax you prefer.</p>



<h2 class="wp-block-heading">Data Setup</h2>



<p class="wp-block-paragraph">All examples in this blog post are based on the tables <code>DEPT</code> and <code>EMP</code>, that were originally present in every Oracle Database instance as part of the <code>SCOTT</code> schema. Here&#8217;s a script to create these tables. The script requires an Oracle Database 23ai. </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">1) Create table DEPT and EMP</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 table if not exists dept as select * from (values
          (10, 'ACCOUNTING', 'NEW YORK'),
          (20, 'RESEARCH',   'DALLAS'),
          (30, 'SALES',      'CHICAGO'),
          (40, 'OPERATIONS', 'BOSTON')
       ) s (deptno, dname, loc);

create table if not exists emp as select * from (values
          (7839, 'KING',   'PRESIDENT', null, date '1981-11-17', 5000, null, 10),
          (7566, 'JONES',  'MANAGER',   7839, date '1981-04-02', 2975, null, 20),
          (7698, 'BLAKE',  'MANAGER',   7839, date '1981-05-01', 2850, null, 30),
          (7782, 'CLARK',  'MANAGER',   7839, date '1981-06-09', 2450, null, 10),
          (7788, 'SCOTT',  'ANALYST',   7566, date '1987-04-19', 3000, null, 20),
          (7902, 'FORD',   'ANALYST',   7566, date '1981-12-03', 3000, null, 20),
          (7499, 'ALLEN',  'SALESMAN',  7698, date '1981-02-20', 1600,  300, 30),
          (7521, 'WARD',   'SALESMAN',  7698, date '1981-02-22', 1250,  500, 30),
          (7654, 'MARTIN', 'SALESMAN',  7698, date '1981-09-28', 1250, 1400, 30),
          (7844, 'TURNER', 'SALESMAN',  7698, date '1981-09-08', 1500,    0, 30),
          (7900, 'JAMES',  'CLERK',     7698, date '1981-12-03',  950, null, 30),
          (7934, 'MILLER', 'CLERK',     7782, date '1982-01-23', 1300, null, 10),
          (7369, 'SMITH',  'CLERK',     7902, date '1980-12-17',  800, null, 20),
          (7876, 'ADAMS',  'CLERK',     7788, date '1987-05-23', 1100, null, 20)
       ) s (empno, ename, job, mgr, hiredate, sal, comm, deptno);</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: #9CDCFE">create</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">table</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">not</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">exists</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">dept</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">as</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">select</span><span style="color: #D4D4D4"> * </span><span style="color: #4EC9B0">from</span><span style="color: #D4D4D4"> (</span><span style="color: #4EC9B0">values</span></span>
<span class="line"><span style="color: #D4D4D4">          (10, </span><span style="color: #CE9178">&#39;ACCOUNTING&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&#39;NEW YORK&#39;</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">          (20, </span><span style="color: #CE9178">&#39;RESEARCH&#39;</span><span style="color: #D4D4D4">,   </span><span style="color: #CE9178">&#39;DALLAS&#39;</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">          (30, </span><span style="color: #CE9178">&#39;SALES&#39;</span><span style="color: #D4D4D4">,      </span><span style="color: #CE9178">&#39;CHICAGO&#39;</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">          (40, </span><span style="color: #CE9178">&#39;OPERATIONS&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&#39;BOSTON&#39;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">       ) </span><span style="color: #4EC9B0">s</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">deptno</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">dname</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">loc</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">create</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">table</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">not</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">exists</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">emp</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">as</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">select</span><span style="color: #D4D4D4"> * </span><span style="color: #4EC9B0">from</span><span style="color: #D4D4D4"> (</span><span style="color: #4EC9B0">values</span></span>
<span class="line"><span style="color: #D4D4D4">          (7839, </span><span style="color: #CE9178">&#39;KING&#39;</span><span style="color: #D4D4D4">,   </span><span style="color: #CE9178">&#39;PRESIDENT&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">null</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-11-17&#39;</span><span style="color: #D4D4D4">, 5000, </span><span style="color: #9CDCFE">null</span><span style="color: #D4D4D4">, 10),</span></span>
<span class="line"><span style="color: #D4D4D4">          (7566, </span><span style="color: #CE9178">&#39;JONES&#39;</span><span style="color: #D4D4D4">,  </span><span style="color: #CE9178">&#39;MANAGER&#39;</span><span style="color: #D4D4D4">,   7839, </span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-04-02&#39;</span><span style="color: #D4D4D4">, 2975, </span><span style="color: #9CDCFE">null</span><span style="color: #D4D4D4">, 20),</span></span>
<span class="line"><span style="color: #D4D4D4">          (7698, </span><span style="color: #CE9178">&#39;BLAKE&#39;</span><span style="color: #D4D4D4">,  </span><span style="color: #CE9178">&#39;MANAGER&#39;</span><span style="color: #D4D4D4">,   7839, </span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-05-01&#39;</span><span style="color: #D4D4D4">, 2850, </span><span style="color: #9CDCFE">null</span><span style="color: #D4D4D4">, 30),</span></span>
<span class="line"><span style="color: #D4D4D4">          (7782, </span><span style="color: #CE9178">&#39;CLARK&#39;</span><span style="color: #D4D4D4">,  </span><span style="color: #CE9178">&#39;MANAGER&#39;</span><span style="color: #D4D4D4">,   7839, </span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-06-09&#39;</span><span style="color: #D4D4D4">, 2450, </span><span style="color: #9CDCFE">null</span><span style="color: #D4D4D4">, 10),</span></span>
<span class="line"><span style="color: #D4D4D4">          (7788, </span><span style="color: #CE9178">&#39;SCOTT&#39;</span><span style="color: #D4D4D4">,  </span><span style="color: #CE9178">&#39;ANALYST&#39;</span><span style="color: #D4D4D4">,   7566, </span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1987-04-19&#39;</span><span style="color: #D4D4D4">, 3000, </span><span style="color: #9CDCFE">null</span><span style="color: #D4D4D4">, 20),</span></span>
<span class="line"><span style="color: #D4D4D4">          (7902, </span><span style="color: #CE9178">&#39;FORD&#39;</span><span style="color: #D4D4D4">,   </span><span style="color: #CE9178">&#39;ANALYST&#39;</span><span style="color: #D4D4D4">,   7566, </span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-12-03&#39;</span><span style="color: #D4D4D4">, 3000, </span><span style="color: #9CDCFE">null</span><span style="color: #D4D4D4">, 20),</span></span>
<span class="line"><span style="color: #D4D4D4">          (7499, </span><span style="color: #CE9178">&#39;ALLEN&#39;</span><span style="color: #D4D4D4">,  </span><span style="color: #CE9178">&#39;SALESMAN&#39;</span><span style="color: #D4D4D4">,  7698, </span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-02-20&#39;</span><span style="color: #D4D4D4">, 1600,  300, 30),</span></span>
<span class="line"><span style="color: #D4D4D4">          (7521, </span><span style="color: #CE9178">&#39;WARD&#39;</span><span style="color: #D4D4D4">,   </span><span style="color: #CE9178">&#39;SALESMAN&#39;</span><span style="color: #D4D4D4">,  7698, </span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-02-22&#39;</span><span style="color: #D4D4D4">, 1250,  500, 30),</span></span>
<span class="line"><span style="color: #D4D4D4">          (7654, </span><span style="color: #CE9178">&#39;MARTIN&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&#39;SALESMAN&#39;</span><span style="color: #D4D4D4">,  7698, </span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-09-28&#39;</span><span style="color: #D4D4D4">, 1250, 1400, 30),</span></span>
<span class="line"><span style="color: #D4D4D4">          (7844, </span><span style="color: #CE9178">&#39;TURNER&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&#39;SALESMAN&#39;</span><span style="color: #D4D4D4">,  7698, </span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-09-08&#39;</span><span style="color: #D4D4D4">, 1500,    0, 30),</span></span>
<span class="line"><span style="color: #D4D4D4">          (7900, </span><span style="color: #CE9178">&#39;JAMES&#39;</span><span style="color: #D4D4D4">,  </span><span style="color: #CE9178">&#39;CLERK&#39;</span><span style="color: #D4D4D4">,     7698, </span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-12-03&#39;</span><span style="color: #D4D4D4">,  950, </span><span style="color: #9CDCFE">null</span><span style="color: #D4D4D4">, 30),</span></span>
<span class="line"><span style="color: #D4D4D4">          (7934, </span><span style="color: #CE9178">&#39;MILLER&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&#39;CLERK&#39;</span><span style="color: #D4D4D4">,     7782, </span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1982-01-23&#39;</span><span style="color: #D4D4D4">, 1300, </span><span style="color: #9CDCFE">null</span><span style="color: #D4D4D4">, 10),</span></span>
<span class="line"><span style="color: #D4D4D4">          (7369, </span><span style="color: #CE9178">&#39;SMITH&#39;</span><span style="color: #D4D4D4">,  </span><span style="color: #CE9178">&#39;CLERK&#39;</span><span style="color: #D4D4D4">,     7902, </span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1980-12-17&#39;</span><span style="color: #D4D4D4">,  800, </span><span style="color: #9CDCFE">null</span><span style="color: #D4D4D4">, 20),</span></span>
<span class="line"><span style="color: #D4D4D4">          (7876, </span><span style="color: #CE9178">&#39;ADAMS&#39;</span><span style="color: #D4D4D4">,  </span><span style="color: #CE9178">&#39;CLERK&#39;</span><span style="color: #D4D4D4">,     7788, </span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1987-05-23&#39;</span><span style="color: #D4D4D4">, 1100, </span><span style="color: #9CDCFE">null</span><span style="color: #D4D4D4">, 20)</span></span>
<span class="line"><span style="color: #D4D4D4">       ) </span><span style="color: #4EC9B0">s</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">empno</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">ename</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">job</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">mgr</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">hiredate</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">sal</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">comm</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">deptno</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<h2 class="wp-block-heading">Joins</h2>



<p class="wp-block-paragraph">The predecessor of the ANSI SQL-92 standard is the ANSI SQL-89 standard. Based on that standard, you could write joins only 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);--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">2) ANSI SQL-89 Join</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 dept.deptno, emp.ename
  from dept, emp
 where emp.deptno = dept.deptno
 order by dept.deptno, emp.ename;</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"> dept.deptno, emp.ename</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept, emp</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> emp.deptno = dept.deptno</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> dept.deptno, emp.ename;</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(2 * 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>    DEPTNO ENAME 
---------- ------
        10 CLARK 
        10 KING  
        10 MILLER
        20 ADAMS 
        20 FORD  
        20 JONES 
        20 SCOTT 
        20 SMITH 
        30 ALLEN 
        30 BLAKE 
        30 JAMES 
        30 MARTIN
        30 TURNER
        30 WARD  

14 rows selected. </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">    DEPTNO ENAME </span></span>
<span class="line"><span style="color: #D4D4D4">---------- ------</span></span>
<span class="line"><span style="color: #D4D4D4">        10 CLARK </span></span>
<span class="line"><span style="color: #D4D4D4">        10 KING  </span></span>
<span class="line"><span style="color: #D4D4D4">        10 MILLER</span></span>
<span class="line"><span style="color: #D4D4D4">        20 ADAMS </span></span>
<span class="line"><span style="color: #D4D4D4">        20 FORD  </span></span>
<span class="line"><span style="color: #D4D4D4">        20 JONES </span></span>
<span class="line"><span style="color: #D4D4D4">        20 SCOTT </span></span>
<span class="line"><span style="color: #D4D4D4">        20 SMITH </span></span>
<span class="line"><span style="color: #D4D4D4">        30 ALLEN </span></span>
<span class="line"><span style="color: #D4D4D4">        30 BLAKE </span></span>
<span class="line"><span style="color: #D4D4D4">        30 JAMES </span></span>
<span class="line"><span style="color: #D4D4D4">        30 MARTIN</span></span>
<span class="line"><span style="color: #D4D4D4">        30 TURNER</span></span>
<span class="line"><span style="color: #D4D4D4">        30 WARD  </span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4">14 rows selected. </span></span></code></pre></div>



<p class="wp-block-paragraph">In the FROM clause, we list the tables to be joined, and in the WHERE clause, we define the JOIN criteria. There are no filter criteria in this case.</p>



<p class="wp-block-paragraph">There are several ways to transform this query to ANSI SQL-92. One rather silly way, but very similar to the original ANSI SQL-89 syntax, is the use of an explicit CROSS JOIN.</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);--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">3) ANSI SQL-92 Cross Join </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 dept.deptno, emp.ename
  from dept cross join emp
 where emp.deptno = dept.deptno
 order by dept.deptno, emp.ename;</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"> dept.deptno, emp.ename</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept </span><span style="color: #569CD6">cross join</span><span style="color: #D4D4D4"> emp</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> emp.deptno = dept.deptno</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> dept.deptno, emp.ename;</span></span></code></pre></div>



<p class="wp-block-paragraph">While this is technically an ANSI SQL-92 compliant query, it&#8217;s not a good option. Why? &#8211; ANSI SQL-92 allows us to define the join criteria for each join. Using a CROSS JOIN implies that there is no join criterion between these tables, which is wrong.</p>



<p class="wp-block-paragraph">A better option is to use an INNER JOIN, like in the next example.</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);--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) ANSI SQL-92 Inner Join</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 dept.deptno, emp.ename
  from dept join emp on emp.deptno = dept.deptno
 order by dept.deptno, emp.ename;</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"> dept.deptno, emp.ename</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept </span><span style="color: #569CD6">join</span><span style="color: #D4D4D4"> emp </span><span style="color: #569CD6">on</span><span style="color: #D4D4D4"> emp.deptno = dept.deptno</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> dept.deptno, emp.ename;</span></span></code></pre></div>



<p class="wp-block-paragraph">We see that the WHERE clause is gone. Why? &#8211;  Because we do not have filter criteria in this query. No WHERE clause, no filter. As simple as that.</p>



<h2 class="wp-block-heading">Outer Joins</h2>



<p class="wp-block-paragraph">Now let&#8217;s write an outer join with ANSI SQL-89. As I mentioned before, the standard back then only defined INNER JOINs. So, we need to work around it. One way is something 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(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) ANSI SQL-89 Outer Join</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 dept.deptno, emp.ename
  from dept, emp
 where emp.deptno = dept.deptno
union all
select dept.deptno, null
  from dept
 where not exists (
          select 1
            from emp
           where emp.deptno = dept.deptno
       )
 order by deptno, ename;</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"> dept.deptno, emp.ename</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept, emp</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> emp.deptno = dept.deptno</span></span>
<span class="line cbp-line-highlight"><span style="color: #569CD6">union</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">all</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> dept.deptno, </span><span style="color: #569CD6">null</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">exists</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: #B5CEA8">1</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"> emp.deptno = dept.deptno</span></span>
<span class="line"><span style="color: #D4D4D4">       )</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> deptno, ename;</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(2 * 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>    DEPTNO ENAME 
---------- ------
        10 CLARK 
        10 KING  
        10 MILLER
        20 ADAMS 
        20 FORD  
        20 JONES 
        20 SCOTT 
        20 SMITH 
        30 ALLEN 
        30 BLAKE 
        30 JAMES 
        30 MARTIN
        30 TURNER
        30 WARD  
        40       

15 rows selected. </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">    DEPTNO ENAME </span></span>
<span class="line"><span style="color: #D4D4D4">---------- ------</span></span>
<span class="line"><span style="color: #D4D4D4">        10 CLARK </span></span>
<span class="line"><span style="color: #D4D4D4">        10 KING  </span></span>
<span class="line"><span style="color: #D4D4D4">        10 MILLER</span></span>
<span class="line"><span style="color: #D4D4D4">        20 ADAMS </span></span>
<span class="line"><span style="color: #D4D4D4">        20 FORD  </span></span>
<span class="line"><span style="color: #D4D4D4">        20 JONES </span></span>
<span class="line"><span style="color: #D4D4D4">        20 SCOTT </span></span>
<span class="line"><span style="color: #D4D4D4">        20 SMITH </span></span>
<span class="line"><span style="color: #D4D4D4">        30 ALLEN </span></span>
<span class="line"><span style="color: #D4D4D4">        30 BLAKE </span></span>
<span class="line"><span style="color: #D4D4D4">        30 JAMES </span></span>
<span class="line"><span style="color: #D4D4D4">        30 MARTIN</span></span>
<span class="line"><span style="color: #D4D4D4">        30 TURNER</span></span>
<span class="line"><span style="color: #D4D4D4">        30 WARD  </span></span>
<span class="line"><span style="color: #D4D4D4">        40       </span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4">15 rows selected. </span></span></code></pre></div>



<p class="wp-block-paragraph">Phew, that&#8217;s a lot of work. It&#8217;s no surprise that database vendors came up with proprietary solutions for outer joins. For example:</p>



<ul class="wp-block-list">
<li><code>*=</code> and <code>=*</code> operators in Sybase/SQL Server</li>



<li><code>(+)</code> operator in Db2 and the Oracle Database</li>
</ul>



<p class="wp-block-paragraph">Let&#8217;s use the Oracle join syntax.</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);--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">6) Oracle-style Outer Join</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 dept.deptno, emp.ename
  from dept, emp
 where emp.deptno (+) = dept.deptno
 order by dept.deptno, emp.ename;</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"> dept.deptno, emp.ename</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept, emp</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> emp.deptno (+) = dept.deptno</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> dept.deptno, emp.ename;</span></span></code></pre></div>



<p class="wp-block-paragraph">Much simpler. <code>EMP</code> is outer joined due to the <code>(+)</code> operator.</p>



<p class="wp-block-paragraph">And here is an ANSI SQL-92 compliant variant:</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);--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) ANSI SQL-92 Outer Join</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 dept.deptno, emp.ename
  from dept left join emp on emp.deptno = dept.deptno
 order by dept.deptno, emp.ename;</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"> dept.deptno, emp.ename</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept </span><span style="color: #569CD6">left join</span><span style="color: #D4D4D4"> emp </span><span style="color: #569CD6">on</span><span style="color: #D4D4D4"> emp.deptno = dept.deptno</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> dept.deptno, emp.ename;</span></span></code></pre></div>



<p class="wp-block-paragraph">No WHERE clause, no filter. So far, so good.</p>



<h2 class="wp-block-heading">Outer Joins With Additional Filters</h2>



<p class="wp-block-paragraph">The problem starts as soon as you use outer join queries with filter predicates. Here&#8217;s an example.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<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);--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">8a) Outer Join With Filter &#8211; Oracle-style</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 dept.deptno, emp.ename, emp.hiredate
  from dept, emp
 where emp.deptno (+) = dept.deptno
   and emp.hiredate (+) > date '1981-12-03'
 order by deptno, ename;</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"> dept.deptno, emp.ename, emp.hiredate</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept, emp</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> emp.deptno (+) = dept.deptno</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">and</span><span style="color: #D4D4D4"> emp.hiredate (+) &gt; </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-12-03&#39;</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> deptno, ename;</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-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>    DEPTNO ENAME  HIREDATE  
---------- ------ ----------
        10 MILLER 23.01.1982
        20 ADAMS  23.05.1987
        20 SCOTT  19.04.1987
        30                  
        40                  </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">    DEPTNO ENAME  HIREDATE  </span></span>
<span class="line"><span style="color: #D4D4D4">---------- ------ ----------</span></span>
<span class="line"><span style="color: #D4D4D4">        10 MILLER 23.01.1982</span></span>
<span class="line"><span style="color: #D4D4D4">        20 ADAMS  23.05.1987</span></span>
<span class="line"><span style="color: #D4D4D4">        20 SCOTT  19.04.1987</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        30                  </span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        40                  </span></span></code></pre></div>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<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);--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">8b) Outer Join With Filter &#8211; ANSI SQL-92</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 dept.deptno, emp.ename, emp.hiredate
  from dept
  left join emp on emp.deptno = dept.deptno
   and emp.hiredate > date '1981-12-03'
 order by deptno, ename;</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"> dept.deptno, emp.ename, emp.hiredate</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">left join</span><span style="color: #D4D4D4"> emp </span><span style="color: #569CD6">on</span><span style="color: #D4D4D4"> emp.deptno = dept.deptno</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">and</span><span style="color: #D4D4D4"> emp.hiredate &gt; </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-12-03&#39;</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> deptno, ename;</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-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>    DEPTNO ENAME  HIREDATE  
---------- ------ ----------
        10 MILLER 23.01.1982
        20 ADAMS  23.05.1987
        20 SCOTT  19.04.1987
        30                  
        40                  </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">    DEPTNO ENAME  HIREDATE  </span></span>
<span class="line"><span style="color: #D4D4D4">---------- ------ ----------</span></span>
<span class="line"><span style="color: #D4D4D4">        10 MILLER 23.01.1982</span></span>
<span class="line"><span style="color: #D4D4D4">        20 ADAMS  23.05.1987</span></span>
<span class="line"><span style="color: #D4D4D4">        20 SCOTT  19.04.1987</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        30                  </span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        40                  </span></span></code></pre></div>
</div>
</div>



<p class="wp-block-paragraph">Both query variants use the predicate <code>emp.hiredate &gt; date '1981-12-03'</code> as part of the outer join criteria. As a result, the DEPT rows 30 and 40 are shown with empty EMP columns. </p>



<p class="wp-block-paragraph">The result is correct. But is this the result we want?</p>



<p class="wp-block-paragraph">I don&#8217;t think so. One option is that we don&#8217;t want an outer join at all. Something like this:</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<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);--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">9a) Inner Join With Filter &#8211; ANSI SQL-89</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 dept.deptno, emp.ename, emp.hiredate
  from dept, emp
 where emp.deptno = dept.deptno
   and emp.hiredate > date '1981-12-03'
 order by deptno, ename;</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"> dept.deptno, emp.ename, emp.hiredate</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept, emp</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> emp.deptno = dept.deptno</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">and</span><span style="color: #D4D4D4"> emp.hiredate &gt; </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-12-03&#39;</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> deptno, ename;</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>    DEPTNO ENAME  HIREDATE  
---------- ------ ----------
        10 MILLER 23.01.1982
        20 ADAMS  23.05.1987
        20 SCOTT  19.04.1987</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">    DEPTNO ENAME  HIREDATE  </span></span>
<span class="line"><span style="color: #D4D4D4">---------- ------ ----------</span></span>
<span class="line"><span style="color: #D4D4D4">        10 MILLER 23.01.1982</span></span>
<span class="line"><span style="color: #D4D4D4">        20 ADAMS  23.05.1987</span></span>
<span class="line"><span style="color: #D4D4D4">        20 SCOTT  19.04.1987</span></span></code></pre></div>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<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);--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">9b) Inner Join With Filter &#8211; ANSI SQL-92</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 dept.deptno, emp.ename, emp.hiredate
  from dept
  join emp on emp.deptno = dept.deptno
 where emp.hiredate > date '1981-12-03'
 order by deptno, ename;</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"> dept.deptno, emp.ename, emp.hiredate</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">join</span><span style="color: #D4D4D4"> emp </span><span style="color: #569CD6">on</span><span style="color: #D4D4D4"> emp.deptno = dept.deptno</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> emp.hiredate &gt; </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-12-03&#39;</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> deptno, ename;</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>    DEPTNO ENAME  HIREDATE  
---------- ------ ----------
        10 MILLER 23.01.1982
        20 ADAMS  23.05.1987
        20 SCOTT  19.04.1987</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">    DEPTNO ENAME  HIREDATE  </span></span>
<span class="line"><span style="color: #D4D4D4">---------- ------ ----------</span></span>
<span class="line"><span style="color: #D4D4D4">        10 MILLER 23.01.1982</span></span>
<span class="line"><span style="color: #D4D4D4">        20 ADAMS  23.05.1987</span></span>
<span class="line"><span style="color: #D4D4D4">        20 SCOTT  19.04.1987</span></span></code></pre></div>
</div>
</div>



<p class="wp-block-paragraph">Now we use the predicate <code>emp.hiredate &gt; date '1981-12-03'</code> as a filter criterion. It&#8217;s applied after the join. The result would be the same if we used a LEFT JOIN in 9b).</p>



<p class="wp-block-paragraph">In most cases, join criteria are based only on the foreign key-primary key relationships. If I see something else, I typically need to dig deeper to understand what the requirements of the query are.</p>



<p class="wp-block-paragraph">So, maybe we want to see only the employees that match the filter, including departments that have no employees. For that, we could rewrite the query as follows:</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<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);--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">10a) Outer Join With Filter &#8211; Oracle-style</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 dept.deptno, emp.ename, emp.hiredate
  from dept, emp
 where emp.deptno (+) = dept.deptno
   and (emp.hiredate > date '1981-12-03' or emp.deptno is null)
 order by deptno, ename;</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"> dept.deptno, emp.ename, emp.hiredate</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept, emp</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> emp.deptno (+) = dept.deptno</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">and</span><span style="color: #D4D4D4"> (emp.hiredate &gt; </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-12-03&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> emp.deptno </span><span style="color: #569CD6">is null</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> deptno, ename;</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>    DEPTNO ENAME  HIREDATE  
---------- ------ ----------
        10 MILLER 23.01.1982
        20 ADAMS  23.05.1987
        20 SCOTT  19.04.1987
        40                  </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">    DEPTNO ENAME  HIREDATE  </span></span>
<span class="line"><span style="color: #D4D4D4">---------- ------ ----------</span></span>
<span class="line"><span style="color: #D4D4D4">        10 MILLER 23.01.1982</span></span>
<span class="line"><span style="color: #D4D4D4">        20 ADAMS  23.05.1987</span></span>
<span class="line"><span style="color: #D4D4D4">        20 SCOTT  19.04.1987</span></span>
<span class="line"><span style="color: #D4D4D4">        40                  </span></span></code></pre></div>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<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);--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">10b) Outer Join With Filter &#8211; ANSI SQL-92</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 dept.deptno, emp.ename, emp.hiredate
  from dept left join emp
    on emp.deptno = dept.deptno
 where (emp.hiredate > date '1981-12-03' or emp.deptno is null)
 order by deptno, ename;</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"> dept.deptno, emp.ename, emp.hiredate</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept </span><span style="color: #569CD6">left join</span><span style="color: #D4D4D4"> emp</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">on</span><span style="color: #D4D4D4"> emp.deptno = dept.deptno</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> (emp.hiredate &gt; </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-12-03&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> emp.deptno </span><span style="color: #569CD6">is null</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> deptno, ename;</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>    DEPTNO ENAME  HIREDATE  
---------- ------ ----------
        10 MILLER 23.01.1982
        20 ADAMS  23.05.1987
        20 SCOTT  19.04.1987
        40                  </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">    DEPTNO ENAME  HIREDATE  </span></span>
<span class="line"><span style="color: #D4D4D4">---------- ------ ----------</span></span>
<span class="line"><span style="color: #D4D4D4">        10 MILLER 23.01.1982</span></span>
<span class="line"><span style="color: #D4D4D4">        20 ADAMS  23.05.1987</span></span>
<span class="line"><span style="color: #D4D4D4">        20 SCOTT  19.04.1987</span></span>
<span class="line"><span style="color: #D4D4D4">        40                  </span></span></code></pre></div>
</div>
</div>



<p class="wp-block-paragraph">This example shows why it&#8217;s important to distinguish between join criteria and filter criteria. The ANSI SQL-92 syntax makes this easier. Unfortunately, there are still a few bugs and limitations when using ANSI-92 syntax in every Oracle Database version. But there are fewer and fewer of these problems with each new version. </p>



<p class="wp-block-paragraph">Therefore, I use the ANSI SQL-92 join syntax whenever possible and try to document the reason when I cannot. </p>



<h2 class="wp-block-heading">Use dbLinter to Change Queries to ANSI SQL-92 Join Syntax</h2>



<p class="wp-block-paragraph"><a href="https://marketplace.visualstudio.com/items?itemName=Grisselbav.dblinter">dbLinter</a> can find queries that do not use ANSI SQL-92 join syntax. Simply put, it searches for multiple items in the FROM clause. It also provides a quick fix to convert ANSI SQL-89 and Oracle-style joins to ANSI SQL-92 syntax. Here&#8217;s a screenshot with the previously discussed queries:</p>



<figure class="wp-block-image size-large is-resized"><a href="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-10.png"><img loading="lazy" decoding="async" width="1024" height="845" src="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-10-1024x845.png" alt="dbLinter for VS Code showing G-3130 violations and the pop-up window to apply quick fixes" class="wp-image-13999" style="width:820px" srcset="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-10-1024x845.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-10-300x248.png 300w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-10-768x634.png 768w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-10-1536x1268.png 1536w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-10-91x75.png 91w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-10-480x396.png 480w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-10.png 1640w" sizes="auto, (max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">After applying the quick fix to all <a href="https://dblinter-rules.united-codes.com/rules/G-3130/">G-3130</a> violations in the file, the result looks like this:</p>



<figure class="wp-block-image size-large is-resized"><a href="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-9.png"><img loading="lazy" decoding="async" width="1024" height="768" src="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-9-1024x768.png" alt="dbLinter for VS Code after applying the quick fix for all G-3130 violations" class="wp-image-13998" style="width:640px" srcset="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-9-1024x768.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-9-300x225.png 300w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-9-768x576.png 768w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-9-100x75.png 100w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-9-480x360.png 480w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-9.png 1280w" sizes="auto, (max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">The result looks quite good, except that the predicate in the 8a) example is not moved to the join condition (see red arrow in the screenshot above). Why is that the case? &#8211; The quick fix only moves equality predicates and predicates that are not part of a Boolean OR condition to the join condition. If there are leftover outer join operators <code>(+)</code> in the WHERE clause, they are surrounded by a TODO comment.</p>



<p class="wp-block-paragraph">To get started with <a href="https://marketplace.visualstudio.com/items?itemName=Grisselbav.dblinter">dbLinter</a>, I recommend <a href="https://youtu.be/V-ePBfUFhhk">watching Philipp Harenfeller&#8217;s video</a>. United Codes and Grisselbav are collaborating on this product.</p>



<p class="wp-block-paragraph">Feedback is very much appreciated. Comment on this blog post or raise an issue on the <a href="https://github.com/Grisselbav/dbLinter">dbLinter GitHub repository</a>.</p>



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



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://www.salvis.com/blog/2025/07/12/outer-joining-with-ansi-sql-89-and-sql-92/">Outer Joining With ANSI SQL-89 and SQL-92</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
