<?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>ANTLR Archives - Philipp Salvisberg&#039;s Blog</title>
	<atom:link href="https://www.salvis.com/blog/tag/antlr/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.salvis.com/blog/tag/antlr/</link>
	<description>Database-centric development</description>
	<lastBuildDate>Wed, 01 Jul 2026 22:57:34 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://www.salvis.com/blog/wp-content/uploads/2014/04/favicon.png</url>
	<title>ANTLR Archives - Philipp Salvisberg&#039;s Blog</title>
	<link>https://www.salvis.com/blog/tag/antlr/</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/antlr/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-1010" target="_blank" rel="noreferrer noopener">A-1010: 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"></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>IslandSQL Final Episode 10: Parsing PL/pgSQL</title>
		<link>https://www.salvis.com/blog/2024/07/29/islandsql-final-episode-10-parsing-pl-pgsql/</link>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Mon, 29 Jul 2024 14:00:55 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[ANTLR]]></category>
		<category><![CDATA[Code Analysis]]></category>
		<category><![CDATA[IslandSQL]]></category>
		<category><![CDATA[Oracle 26ai]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[SQL]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=13526</guid>

					<description><![CDATA[<p>Introduction IslandSQL is a parser for SQL files targeting OracleDB or PostgreSQL. The parser is available on Maven Central and can process SQL*Plus, SQLcl or psql statements besides SQL statements. However, the focus is on statements with static DML statements and code in PL/SQL and PL/pgSQL. For static code analysis, for example.<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2024/07/29/islandsql-final-episode-10-parsing-pl-pgsql/">IslandSQL Final Episode 10: Parsing PL/pgSQL</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="introduction">Introduction</h2>



<p class="wp-block-paragraph">IslandSQL is a parser for SQL files targeting OracleDB or PostgreSQL. The parser is available on <a href="https://central.sonatype.com/artifact/ch.islandsql/islandsql">Maven Central</a> and can process SQL*Plus, SQLcl or psql statements besides SQL statements. However, the focus is on statements with static DML statements and code in PL/SQL and PL/pgSQL. For static code analysis, for example.</p>



<p class="wp-block-paragraph">In PostgreSQL <code>create function</code>, <code>create procedure</code> and <code>do</code> accept code as a string. This simplifies parsing and the implementation of additional languages. As a result, you can write functions and procedures in SQL, PL/pgSQL, PL/Tcl, PL/Perl and PL/Python in any standard PostgreSQL distribution.</p>



<p class="wp-block-paragraph">Starting with IslandSQL version 0.10 it&#8217;s possible to parse SQL and PL/pgSQL in strings and extend the parse tree accordingly. In this blog post, I will explain how this works.</p>



<p class="wp-block-paragraph">This <a href="https://marketplace.visualstudio.com/items?itemName=phsalvisberg.islandsql">VS Code extension</a> uses IslandSQL in a language server to report syntax errors and to produce parse trees as shown in this blog post.</p>



<h2 class="wp-block-heading" id="plpgsql_as_string">PL/pgSQL as String</h2>



<p class="wp-block-paragraph">Let&#8217;s look at a <code>do</code> statement executing a PL/pgSQL block provided as a string.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">1) hello_world.sql</span><span role="button" tabindex="0" data-code="do '
begin
   raise notice $$Hello World!$$;
end
';" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">do </span><span style="color: #CE9178">&#39;</span></span>
<span class="line"><span style="color: #CE9178">begin</span></span>
<span class="line"><span style="color: #CE9178">   raise notice $$Hello World!$$;</span></span>
<span class="line"><span style="color: #CE9178">end</span></span>
<span class="line"><span style="color: #CE9178">&#39;</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="NOTICE:  Hello World!
DO" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">NOTICE:  Hello World!</span></span>
<span class="line"><span style="color: #D4D4D4">DO</span></span></code></pre></div>



<p class="wp-block-paragraph">The parse tree in IslandSQL version 0.9 looks as follows:</p>



<figure class="wp-block-image size-full is-resized is-style-default"><a href="https://www.salvis.com/blog/wp-content/uploads/2024/07/1-plpgsql-string-only.svg"><img decoding="async" src="https://www.salvis.com/blog/wp-content/uploads/2024/07/1-plpgsql-string-only.svg" alt="Parse tree with PL/pgSQL as string" class="wp-image-13529" style="width:310px"/></a></figure>



<p class="wp-block-paragraph">Look at the parse tree. It is quite simple. Interesting is the PL/pgSQL block. The content in single quotes is represented as a single token. The big rectangle at the bottom. It&#8217;s a single token regardless of the code size.</p>



<h2 class="wp-block-heading" id="plpgsql_as_subtree">PL/pgSQL as Subtree</h2>



<p class="wp-block-paragraph">Parsing PL/pgSQL as a string is easy. The lexer produces the token for the string containing the PL/pgSQL code. The parser does not need to understand the PL/pgSQL at all.</p>



<p class="wp-block-paragraph">But this does not help analyse the PL/pgSQL code. We need a parser that </p>



<ul class="wp-block-list">
<li>understands PL/pgSQL </li>



<li>parses PL/pgSQL code provided as a string</li>



<li>extends the main parse tree by sub-parse trees with PL/pgSQL code</li>
</ul>



<p class="wp-block-paragraph">The IslandSQL parser in version 0.10 does exactly that. It produces this parse tree by default:</p>



<figure class="wp-block-image size-full is-resized"><a href="https://www.salvis.com/blog/wp-content/uploads/2024/07/2-plpgsql-string-and-subtree.svg"><img decoding="async" src="https://www.salvis.com/blog/wp-content/uploads/2024/07/2-plpgsql-string-and-subtree.svg" alt="Parse tree with PL/pgSQL as string and as subtree" class="wp-image-13540" style="width:550px"/></a></figure>



<p class="wp-block-paragraph">The PL/pgSQL code is represented twice in this parse tree. Once as a single token. And once as a node named <code>postgresqlPlpgsqlCode</code>.</p>



<h2 class="wp-block-heading" id="plpgsql_as_subtree_only">PL/pgSQL as Subtree Only</h2>



<p class="wp-block-paragraph">Maybe you do not like it when PL/pgSQL code is represented twice in the parse tree. In this case, you can override the default options when creating an IslandSQL document.</p>



<p class="wp-block-paragraph">The IslandSQL library requires Java 8 or newer. In the next example, we use Java 22 to reduce boilerplate code. <a href="https://docs.oracle.com/en/java/javase/22/language/implicitly-declared-classes-and-instance-main-methods.html">Implicitly declared classes</a> are still in preview. Hence we have to pass the parameters <code>--enable-preview --source 22</code> when running the <code>HelloWorld.java</code> program. </p>



<h5 class="wp-block-heading">Explaining HelloWorld.java</h5>



<p class="wp-block-paragraph">In line 13 we create the IslandSQL document with a series of parameters. One of them is <code>removeCode(true)</code> in line 19 which oversteers the default behaviour and removes the code as a string from the parse tree.</p>



<p class="wp-block-paragraph">In line 21 we print a profile. Thanks to Cary Millsap, I can&#8217;t deal with performance issues without thinking about a bicycle, a Ferrari and kissing&#8230; The profile helps to understand where the parser has spent its time.</p>



<p class="wp-block-paragraph">Finally, in lines 22 and 23 we print the parse tree. Once as a simple textual hierarchy and once as a <a href="https://www.graphviz.org/doc/info/lang.html">DOT</a> graph. You can visualise the result in <a href="https://edotor.net/?engine=dot#digraph%20islandSQL%20%7B%0A%20%20bgcolor%3D%22transparent%22%0A%20%20%221155757579%22%20%5Bshape%3Dellipse%20label%3D%22file%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%221155757579%22%20-%3E%20%221785111044%22%0A%20%20%221155757579%22%20-%3E%20%221482748887%22%0A%20%20%221785111044%22%20%5Bshape%3Dellipse%20label%3D%22statement%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%221785111044%22%20-%3E%20%22494894055%22%0A%20%20%22494894055%22%20%5Bshape%3Dellipse%20label%3D%22doStatement%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22494894055%22%20-%3E%20%221123226989%22%0A%20%20%22494894055%22%20-%3E%20%22500885941%22%0A%20%20%221123226989%22%20%5Bshape%3Dellipse%20label%3D%22postgresqlDo%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%221123226989%22%20-%3E%20%221115381650%22%0A%20%20%221123226989%22%20-%3E%20%22616412281%22%0A%20%20%221115381650%22%20%5Bshape%3Dbox%20label%3D%22do%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22616412281%22%20%5Bshape%3Dellipse%20label%3D%22postgresqlPlpgsqlCode%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22616412281%22%20-%3E%20%222118096382%22%0A%20%20%22616412281%22%20-%3E%20%22878861517%22%0A%20%20%22616412281%22%20-%3E%20%22746394140%22%0A%20%20%222118096382%22%20%5Bshape%3Dbox%20label%3D%22begin%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22878861517%22%20%5Bshape%3Dellipse%20label%3D%22plsqlStatement%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22878861517%22%20-%3E%20%221705665942%22%0A%20%20%221705665942%22%20%5Bshape%3Dellipse%20label%3D%22postgresqlRaiseStatement%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%221705665942%22%20-%3E%20%221731763384%22%0A%20%20%221705665942%22%20-%3E%20%221100619942%22%0A%20%20%221705665942%22%20-%3E%20%2287242619%22%0A%20%20%221705665942%22%20-%3E%20%22864248990%22%0A%20%20%221731763384%22%20%5Bshape%3Dbox%20label%3D%22raise%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%221100619942%22%20%5Bshape%3Dellipse%20label%3D%22raiseLevel%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%221100619942%22%20-%3E%20%22285074186%22%0A%20%20%22285074186%22%20%5Bshape%3Dbox%20label%3D%22notice%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%2287242619%22%20%5Bshape%3Dellipse%20label%3D%22dollarString%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%2287242619%22%20-%3E%20%2215892131%22%0A%20%20%2215892131%22%20%5Bshape%3Dbox%20label%3D%22%24%24Hello%20World!%24%24%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22864248990%22%20%5Bshape%3Dbox%20label%3D%22%3B%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22746394140%22%20%5Bshape%3Dbox%20label%3D%22end%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22500885941%22%20%5Bshape%3Dellipse%20label%3D%22sqlEnd%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22500885941%22%20-%3E%20%22484841769%22%0A%20%20%22484841769%22%20%5Bshape%3Dbox%20label%3D%22%3B%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%221482748887%22%20%5Bshape%3Dbox%20label%3D%22%3CEOF%3E%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%7D%0A">Edotor.net</a>, for 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) HelloWorld.java</span><span role="button" tabindex="0" data-code="import ch.islandsql.grammar.IslandSqlDialect;
import ch.islandsql.grammar.IslandSqlDocument;
import ch.islandsql.grammar.util.ParseTreeUtil;

void main() {
    var source = &quot;&quot;&quot;
            do '
            begin
               raise notice $$Hello World!$$;
            end
            ';
            &quot;&quot;&quot;;
    var doc = new IslandSqlDocument.Builder()
            .sql(source)
            .hideOutOfScopeTokens(false)
            .dialect(IslandSqlDialect.POSTGRESQL)
            .profile(true)
            .subtrees(true)
            .removeCode(true)
            .build();
    System.out.println(doc.getParserMetrics().printProfile());
    System.out.println(ParseTreeUtil.printParseTree(doc.getFile()));
    System.out.println(ParseTreeUtil.dotParseTree(doc.getFile()));
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">import</span><span style="color: #D4D4D4"> ch.islandsql.grammar.IslandSqlDialect;</span></span>
<span class="line"><span style="color: #569CD6">import</span><span style="color: #D4D4D4"> ch.islandsql.grammar.IslandSqlDocument;</span></span>
<span class="line"><span style="color: #569CD6">import</span><span style="color: #D4D4D4"> ch.islandsql.grammar.util.ParseTreeUtil;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4EC9B0">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">main</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">source</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;&quot;&quot;</span></span>
<span class="line"><span style="color: #CE9178">            do &#39;</span></span>
<span class="line"><span style="color: #CE9178">            begin</span></span>
<span class="line"><span style="color: #CE9178">               raise notice $$Hello World!$$;</span></span>
<span class="line"><span style="color: #CE9178">            end</span></span>
<span class="line"><span style="color: #CE9178">            &#39;;</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: #C586C0">new</span><span style="color: #D4D4D4"> IslandSqlDocument.</span><span style="color: #DCDCAA">Builder</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">            .</span><span style="color: #DCDCAA">sql</span><span style="color: #D4D4D4">(source)</span></span>
<span class="line"><span style="color: #D4D4D4">            .</span><span style="color: #DCDCAA">hideOutOfScopeTokens</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">false</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">            .</span><span style="color: #DCDCAA">dialect</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">IslandSqlDialect</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">POSTGRESQL</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">            .</span><span style="color: #DCDCAA">profile</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">            .</span><span style="color: #DCDCAA">subtrees</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">)</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">            .</span><span style="color: #DCDCAA">removeCode</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">            .</span><span style="color: #DCDCAA">build</span><span style="color: #D4D4D4">();</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">out</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">println</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getParserMetrics</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">printProfile</span><span style="color: #D4D4D4">());</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">out</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">println</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">ParseTreeUtil</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">printParseTree</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getFile</span><span style="color: #D4D4D4">()));</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">out</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">println</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">ParseTreeUtil</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">dotParseTree</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getFile</span><span style="color: #D4D4D4">()));</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="java --enable-preview --source 22 -cp .:islandsql-0.10.0.jar:antlr4-runtime-4.13.1.jar HelloWorld.java" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">java</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--enable-preview</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--source</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">22</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-cp</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">.:islandsql-0.10.0.jar:antlr4-runtime-4.13.1.jar</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">HelloWorld.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;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="Profile
=======

Total memory used by parser    : 5’164 KB
Total time spent in parser     : 27.918 ms
Total time recorded by profiler: 14.167 ms (100%)

Rule Name (Decision)                          Time (ms) Percent Invocations Lookahead Max Lookahead Ambiguities Errors
---------------------------------------- -------------- ------- ----------- --------- ------------- ----------- ------
string (1887)                                    10.302   72.72           2         0             0           0      0
plsqlStatement (1129)                             1.337    9.44           1         0             0           0      0
postgresqlDo (576)                                0.750    5.30           1         0             0           0      0
postgresqlPlpgsqlCode (6)                         0.735    5.19           2         0             0           0      0
statement (11)                                    0.566    3.99           1         0             0           0      0
sqlEnd (1888)                                     0.314    2.21           1         0             0           0      0
postgresqlRaiseStatement (1260)                   0.134    0.95           1         0             0           0      0
postgresqlRaiseStatement (1269)                   0.030    0.21           1         0             0           0      0

file
  statement
    doStatement
      postgresqlDo
        K_DO:do
        postgresqlPlpgsqlCode
          K_BEGIN:begin
          plsqlStatement
            postgresqlRaiseStatement
              K_RAISE:raise
              raiseLevel
                K_NOTICE:notice
              string:dollarString
                DOLLAR_STRING:$$Hello World!$$
              SEMI:;
          K_END:end
      sqlEnd
        SEMI:;
  &lt;EOF&gt;

digraph islandSQL {
  bgcolor=&quot;transparent&quot;
  &quot;1155757579&quot; [shape=ellipse label=&quot;file&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]
  &quot;1155757579&quot; -&gt; &quot;1785111044&quot;
  &quot;1155757579&quot; -&gt; &quot;1482748887&quot;
  &quot;1785111044&quot; [shape=ellipse label=&quot;statement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]
  &quot;1785111044&quot; -&gt; &quot;494894055&quot;
  &quot;494894055&quot; [shape=ellipse label=&quot;doStatement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]
  &quot;494894055&quot; -&gt; &quot;1123226989&quot;
  &quot;494894055&quot; -&gt; &quot;500885941&quot;
  &quot;1123226989&quot; [shape=ellipse label=&quot;postgresqlDo&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]
  &quot;1123226989&quot; -&gt; &quot;1115381650&quot;
  &quot;1123226989&quot; -&gt; &quot;616412281&quot;
  &quot;1115381650&quot; [shape=box label=&quot;do&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]
  &quot;616412281&quot; [shape=ellipse label=&quot;postgresqlPlpgsqlCode&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]
  &quot;616412281&quot; -&gt; &quot;2118096382&quot;
  &quot;616412281&quot; -&gt; &quot;878861517&quot;
  &quot;616412281&quot; -&gt; &quot;746394140&quot;
  &quot;2118096382&quot; [shape=box label=&quot;begin&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]
  &quot;878861517&quot; [shape=ellipse label=&quot;plsqlStatement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]
  &quot;878861517&quot; -&gt; &quot;1705665942&quot;
  &quot;1705665942&quot; [shape=ellipse label=&quot;postgresqlRaiseStatement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]
  &quot;1705665942&quot; -&gt; &quot;1731763384&quot;
  &quot;1705665942&quot; -&gt; &quot;1100619942&quot;
  &quot;1705665942&quot; -&gt; &quot;87242619&quot;
  &quot;1705665942&quot; -&gt; &quot;864248990&quot;
  &quot;1731763384&quot; [shape=box label=&quot;raise&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]
  &quot;1100619942&quot; [shape=ellipse label=&quot;raiseLevel&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]
  &quot;1100619942&quot; -&gt; &quot;285074186&quot;
  &quot;285074186&quot; [shape=box label=&quot;notice&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]
  &quot;87242619&quot; [shape=ellipse label=&quot;dollarString&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]
  &quot;87242619&quot; -&gt; &quot;15892131&quot;
  &quot;15892131&quot; [shape=box label=&quot;$$Hello World!$$&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]
  &quot;864248990&quot; [shape=box label=&quot;;&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]
  &quot;746394140&quot; [shape=box label=&quot;end&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]
  &quot;500885941&quot; [shape=ellipse label=&quot;sqlEnd&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]
  &quot;500885941&quot; -&gt; &quot;484841769&quot;
  &quot;484841769&quot; [shape=box label=&quot;;&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]
  &quot;1482748887&quot; [shape=box label=&quot;&lt;EOF&gt;&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">Profile</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">Total memory used by parser    : 5’164 KB</span></span>
<span class="line"><span style="color: #D4D4D4">Total time spent in parser     : 27.918 ms</span></span>
<span class="line"><span style="color: #D4D4D4">Total time recorded by profiler: 14.167 ms (100%)</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4">Rule Name (Decision)                          Time (ms) Percent Invocations Lookahead Max Lookahead Ambiguities Errors</span></span>
<span class="line"><span style="color: #D4D4D4">---------------------------------------- -------------- ------- ----------- --------- ------------- ----------- ------</span></span>
<span class="line"><span style="color: #D4D4D4">string (1887)                                    10.302   72.72           2         0             0           0      0</span></span>
<span class="line"><span style="color: #D4D4D4">plsqlStatement (1129)                             1.337    9.44           1         0             0           0      0</span></span>
<span class="line"><span style="color: #D4D4D4">postgresqlDo (576)                                0.750    5.30           1         0             0           0      0</span></span>
<span class="line"><span style="color: #D4D4D4">postgresqlPlpgsqlCode (6)                         0.735    5.19           2         0             0           0      0</span></span>
<span class="line"><span style="color: #D4D4D4">statement (11)                                    0.566    3.99           1         0             0           0      0</span></span>
<span class="line"><span style="color: #D4D4D4">sqlEnd (1888)                                     0.314    2.21           1         0             0           0      0</span></span>
<span class="line"><span style="color: #D4D4D4">postgresqlRaiseStatement (1260)                   0.134    0.95           1         0             0           0      0</span></span>
<span class="line"><span style="color: #D4D4D4">postgresqlRaiseStatement (1269)                   0.030    0.21           1         0             0           0      0</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4">file</span></span>
<span class="line"><span style="color: #D4D4D4">  statement</span></span>
<span class="line"><span style="color: #D4D4D4">    doStatement</span></span>
<span class="line"><span style="color: #D4D4D4">      postgresqlDo</span></span>
<span class="line"><span style="color: #D4D4D4">        K_DO:do</span></span>
<span class="line"><span style="color: #D4D4D4">        postgresqlPlpgsqlCode</span></span>
<span class="line"><span style="color: #D4D4D4">          K_BEGIN:begin</span></span>
<span class="line"><span style="color: #D4D4D4">          plsqlStatement</span></span>
<span class="line"><span style="color: #D4D4D4">            postgresqlRaiseStatement</span></span>
<span class="line"><span style="color: #D4D4D4">              K_RAISE:raise</span></span>
<span class="line"><span style="color: #D4D4D4">              raiseLevel</span></span>
<span class="line"><span style="color: #D4D4D4">                K_NOTICE:notice</span></span>
<span class="line"><span style="color: #D4D4D4">              string:dollarString</span></span>
<span class="line"><span style="color: #D4D4D4">                DOLLAR_STRING:$$Hello World!$$</span></span>
<span class="line"><span style="color: #D4D4D4">              SEMI:;</span></span>
<span class="line"><span style="color: #D4D4D4">          K_END:end</span></span>
<span class="line"><span style="color: #D4D4D4">      sqlEnd</span></span>
<span class="line"><span style="color: #D4D4D4">        SEMI:;</span></span>
<span class="line"><span style="color: #D4D4D4">  &lt;EOF&gt;</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4">digraph islandSQL {</span></span>
<span class="line"><span style="color: #D4D4D4">  bgcolor=&quot;transparent&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1155757579&quot; [shape=ellipse label=&quot;file&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1155757579&quot; -&gt; &quot;1785111044&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1155757579&quot; -&gt; &quot;1482748887&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1785111044&quot; [shape=ellipse label=&quot;statement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1785111044&quot; -&gt; &quot;494894055&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;494894055&quot; [shape=ellipse label=&quot;doStatement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;494894055&quot; -&gt; &quot;1123226989&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;494894055&quot; -&gt; &quot;500885941&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1123226989&quot; [shape=ellipse label=&quot;postgresqlDo&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1123226989&quot; -&gt; &quot;1115381650&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1123226989&quot; -&gt; &quot;616412281&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1115381650&quot; [shape=box label=&quot;do&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;616412281&quot; [shape=ellipse label=&quot;postgresqlPlpgsqlCode&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;616412281&quot; -&gt; &quot;2118096382&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;616412281&quot; -&gt; &quot;878861517&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;616412281&quot; -&gt; &quot;746394140&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;2118096382&quot; [shape=box label=&quot;begin&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;878861517&quot; [shape=ellipse label=&quot;plsqlStatement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;878861517&quot; -&gt; &quot;1705665942&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1705665942&quot; [shape=ellipse label=&quot;postgresqlRaiseStatement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1705665942&quot; -&gt; &quot;1731763384&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1705665942&quot; -&gt; &quot;1100619942&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1705665942&quot; -&gt; &quot;87242619&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1705665942&quot; -&gt; &quot;864248990&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1731763384&quot; [shape=box label=&quot;raise&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1100619942&quot; [shape=ellipse label=&quot;raiseLevel&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1100619942&quot; -&gt; &quot;285074186&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;285074186&quot; [shape=box label=&quot;notice&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;87242619&quot; [shape=ellipse label=&quot;dollarString&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;87242619&quot; -&gt; &quot;15892131&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;15892131&quot; [shape=box label=&quot;$$Hello World!$$&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;864248990&quot; [shape=box label=&quot;;&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;746394140&quot; [shape=box label=&quot;end&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;500885941&quot; [shape=ellipse label=&quot;sqlEnd&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;500885941&quot; -&gt; &quot;484841769&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;484841769&quot; [shape=box label=&quot;;&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;1482748887&quot; [shape=box label=&quot;&lt;EOF&gt;&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">The parse tree looks now like this:</p>



<figure class="wp-block-image size-full is-resized"><a href="https://www.salvis.com/blog/wp-content/uploads/2024/07/3-plpgsql-subtree-only.svg"><img decoding="async" src="https://www.salvis.com/blog/wp-content/uploads/2024/07/3-plpgsql-subtree-only.svg" alt="Parse tree with PL/pgSQL as subtree only" class="wp-image-13539" style="width:380px"/></a></figure>



<h2 class="wp-block-heading" id="sql_dialect">SQL Dialect</h2>



<p class="wp-block-paragraph">In line 16 of the previous <code>HelloWorld.java</code> program we set the dialect to <code>POSTGRESQL</code>.  Is that required? &#8211; No, it&#8217;s not. But when do we need to set the SQL dialect in IslandSQL? &#8211; When the lexical incompatibility between OracleDB and PostgreSQL leads to syntax errors in the code to be parsed. </p>



<p class="wp-block-paragraph">What? &#8211; Let me explain.</p>



<h2 class="wp-block-heading" id="identifiers">Identifiers</h2>



<p class="wp-block-paragraph">OracleDB and PostgreSQL use different characters to build an identifier. The following table shows the differences. The allowed characters are listed in square brackets. Read <code>\p{Alpha}</code> as any alphabetic letter in the character set of the database.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>DBMS</th><th>Allowed as First Character</th><th>Allowed in Subsequent Characters</th></tr></thead><tbody><tr><td>OracleDB</td><td><code>[\p{Alpha}]</code></td><td>[_$#0-9\p{Alpha}]</td></tr><tr><td>PostgreSQL</td><td><code>[_\p{Alpha}]</code></td><td>[_$0-9\p{Alpha}]</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">PostgreSQL allows identifiers that start with an underscore. That&#8217;s not a problem. However, OracleDB allows the hash sign (<code>#</code>) to be used in an identifier. That leads to unexpected results when the PostgreSQL code uses the <a href="https://www.postgresql.org/docs/current/functions-bitstring.html">bitwise XOR operator</a> without spaces around it. 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(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) One or two identifiers in select_list?</span><span role="button" tabindex="0" data-code="select a#b from t;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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"> a#b </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> t;</span></span></code></pre></div>



<p class="wp-block-paragraph">PostgreSQL expects that the columns <code>a</code> and <code>b</code> exists in table <code>t</code>.</p>



<p class="wp-block-paragraph">OracleDB expects that the column <code>a#b</code> exists in table <code>t</code>.</p>



<p class="wp-block-paragraph">In this case, IslandSQL can parse the code without errors. However, the parse tree might not look as expected. That&#8217;s a documented limitation and cannot be influenced by setting the dialect. At least not in version 0.10 of IslandSQL. Nevertheless, it shows the impact of a lexical incompatibility.</p>



<h2 class="wp-block-heading" id="inquiry_directives">Inquiry Directives</h2>



<p class="wp-block-paragraph">PL/SQL supports predefined and custom <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/lnpls/plsql-language-fundamentals.html#GUID-E918087C-D5A8-4CEE-841B-5333DE6D4C15">Inquiry Directives</a>. These directives are lexically incompatible with PostgreSQL <a href="https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING">dollar-quoted string constants</a>.</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(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">4) Using custom inquiry directives</span><span role="button" tabindex="0" data-code="alter session set plsql_ccflags = 'custom1:41, custom2:42';
begin
   dbms_output.put_line($$custom1);
   dbms_output.put_line($$custom2 || '(2)');
end;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">alter session</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> plsql_ccflags = </span><span style="color: #CE9178">&#39;custom1:41, custom2:42&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">($$custom1);</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">($$custom2 || </span><span style="color: #CE9178">&#39;(2)&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<p class="wp-block-paragraph">By default, this causes a parse error, because <code>$$custom1);\n dbms_output.put_line($$</code> is identified as a dollar-quoted string constant by the lexer. As a result, the code is interpreted like this:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">5) Visualising how two custom inquiry directives  are treated as a string</span><span role="button" tabindex="0" data-code="alter session set plsql_ccflags = 'custom1:41, custom2:42';
begin
   dbms_output.put_line('custom1);
   dbms_output.put_line('custom2 || '(2)');
end;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">alter session</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> plsql_ccflags = </span><span style="color: #CE9178">&#39;custom1:41, custom2:42&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;custom1);</span></span>
<span class="line"><span style="color: #CE9178">   dbms_output.put_line(&#39;</span><span style="color: #D4D4D4">custom2 || </span><span style="color: #CE9178">&#39;(2)&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<p class="wp-block-paragraph">This makes it clearer, why we get a syntax error in line 4 at <code>custom2</code>.</p>



<p class="wp-block-paragraph">In this case, we have to set the SQL dialect to <code>ORACLEDB</code> to parse <code>custom_inquiry_directives.sql</code> without errors. </p>



<h2 class="wp-block-heading" id="predefined_inquiry_directives">Predefined Inquiry Directives</h2>



<p class="wp-block-paragraph">To simplify the use, we want to avoid specifying the SQL dialect. One way to achieve that is to handle predefined inquiry directives in the <code>GENERIC</code> SQL dialect.</p>



<p class="wp-block-paragraph">Here&#8217;s an example, that does not report syntax errors:</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">6) Using predefined inquiry directives</span><span role="button" tabindex="0" data-code="begin
   dbms_output.put_line($$plsql_line);
   dbms_output.put_line($$plsql_line || '(2)');
end;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">begin</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">($$plsql_line);</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">($$plsql_line || </span><span style="color: #CE9178">&#39;(2)&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<p class="wp-block-paragraph">We know the predefined inquiry directives and can deal with them in the lexer.</p>



<p class="wp-block-paragraph">However, this special treatment can cause problems in corner cases like this one:</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">7) Using the name of a predefined inquiry directive at the start of a dollar-quoted string constant</span><span role="button" tabindex="0" data-code="do '
begin
   raise notice $$plsql_line is a predefined inquiry directive$$;
end
';" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">do </span><span style="color: #CE9178">&#39;</span></span>
<span class="line"><span style="color: #CE9178">begin</span></span>
<span class="line"><span style="color: #CE9178">   raise notice $$plsql_line is a predefined inquiry directive$$;</span></span>
<span class="line"><span style="color: #CE9178">end</span></span>
<span class="line"><span style="color: #CE9178">&#39;</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<p class="wp-block-paragraph">In such cases, we should use the <code>POSTGRESQL</code> dialect to avoid parse errors.</p>



<h2 class="wp-block-heading" id="detect_sql_dialect">Detect SQL Dialect</h2>



<p class="wp-block-paragraph">Is there a way to detect the SQL dialect of an SQL input automatically? Sure. Several. I&#8217;m sure there is a way to use an LLM to get a reasonable result. I&#8217;m more of a rule-based guy. So we could parse the code with one dialect and on parse errors try other dialects. If all dialects produce errors, we could choose the one with the fewest errors.</p>



<p class="wp-block-paragraph">This sounds costly, right? Therefore I decided to start with a simple SQL dialect detection mechanism. The current implementation looks like this:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">8) Excerpt of IslandSqlDocument.java in version 0.10.0</span><span role="button" tabindex="0" data-code="private static IslandSqlDialect guessDialect(String sql) {
    return sql.contains(&quot;\n/\n&quot;) ? IslandSqlDialect.ORACLEDB : IslandSqlDialect.GENERIC;
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">private</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">IslandSqlDialect</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">guessDialect</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">String</span><span style="color: #D4D4D4"> sql) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sql</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">contains</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;</span><span style="color: #D7BA7D">\n</span><span style="color: #CE9178">/</span><span style="color: #D7BA7D">\n</span><span style="color: #CE9178">&quot;</span><span style="color: #D4D4D4">) </span><span style="color: #C586C0">?</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IslandSqlDialect</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">ORACLEDB</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IslandSqlDialect</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">GENERIC</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">In other words, if the code contains a slash followed by a newline character in the first column of a line, then we go with the <code>ORACLEDB</code> dialect. In all other cases, we go with the <code>GENERIC</code> SQL dialect.</p>



<p class="wp-block-paragraph">My first version was even simpler. However, I had to add a final <code>\n</code> to the search string to ensure that SQL code containing multiline comments is not recognized as <code>ORACLEDB</code> dialect. Files with Windows newline characters are always recognized as GENERIC. That&#8217;s the price when trying to keep things simple and fast.</p>



<p class="wp-block-paragraph">Now, the ORACLEDB SQL dialect is correctly detected in the next example. As a result, no syntax errors are reported.</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">9) Using custom inquiry directives in a PL/SQL Block ending on slash</span><span role="button" tabindex="0" data-code="alter session set plsql_ccflags = 'custom1:41, custom2:42';
begin
   dbms_output.put_line($$custom1);
   dbms_output.put_line($$custom2 || '(2)');
end;
/
" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">alter session</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> plsql_ccflags = </span><span style="color: #CE9178">&#39;custom1:41, custom2:42&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">($$custom1);</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #DCDCAA">dbms_output.</span><span style="color: #4EC9B0">put_line</span><span style="color: #D4D4D4">($$custom2 || </span><span style="color: #CE9178">&#39;(2)&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">The SQL dialect detection mechanism kicks in when no SQL dialect is specified (<code>null</code>). </p>



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



<p class="wp-block-paragraph">Developing a single grammar for OracleDB and PostgreSQL was an interesting work. I learned a lot about the underlying DBMS. I often looked at the grammar documentation and did not understand it fully. So I had to run the provided examples or create some myself. The typical test cases are based on working examples, extended by tests based on the cartesian product of a subset of clauses that verified if I had defined the order, the optionality, and the cardinality according to the documentation.</p>



<p class="wp-block-paragraph">A challenge is the undocumented stuff. There are various reasons why something is not documented. In the end, it does not matter why something is missing. The parser fails when processing code that works but should not according to the docs. This cannot be covered by tests based on the official documentation. I found some bugs while processing real-life code. And I expect to find more.</p>



<p class="wp-block-paragraph">This is the season finale of IslandSQL. There won&#8217;t be a second season. However, there might be some spin-offs since I plan to build products based on IslandSQL. Therefore I plan to keep the parser compatible with the latest versions of OracleDB and PostgreSQL.</p>



<p class="wp-block-paragraph">Feedback is welcome. Please leave your comments on this blog post or open an issue in the <a href="https://github.com/IslandSQL/IslandSQL">IslandSQL GitHub repository</a> for questions, bugs or feature requests.</p>



<p class="wp-block-paragraph">Thank you.</p>
<p>The post <a href="https://www.salvis.com/blog/2024/07/29/islandsql-final-episode-10-parsing-pl-pgsql/">IslandSQL Final Episode 10: Parsing PL/pgSQL</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>IslandSQL Episode 9: GraphQL, JSON and Flexible Schemas With Duality Views</title>
		<link>https://www.salvis.com/blog/2024/06/27/islandsql-episode-9-graphql-json-and-flexible-schemas-with-duality-views/</link>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Thu, 27 Jun 2024 11:31:12 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[ANTLR]]></category>
		<category><![CDATA[Code Analysis]]></category>
		<category><![CDATA[IslandSQL]]></category>
		<category><![CDATA[Oracle 26ai]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[SQL]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=13430</guid>

					<description><![CDATA[<p>Introduction In the last episode, we looked at some new features in Oracle Database 23.4. The IslandSQL grammar now covers all statements that can contain static DML statements and code in PL/SQL and PL/pgSQL. While implementing the ANTLR grammar for the create JSON relational duality view statement I stumbled over GraphQL in<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2024/06/27/islandsql-episode-9-graphql-json-and-flexible-schemas-with-duality-views/">IslandSQL Episode 9: GraphQL, JSON and Flexible Schemas With Duality Views</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">In the <a href="https://www.salvis.com/blog/2024/06/15/islandsql-episode-8-whats-new-in-oracle-database-23-4/">last episode</a>, we looked at some new features in Oracle Database 23.4. The <a href="https://github.com/IslandSQL/IslandSQL">IslandSQL</a> grammar now covers all statements that can contain static DML statements and code in PL/SQL and PL/pgSQL. </p>



<p class="wp-block-paragraph">While implementing the ANTLR grammar for the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/create-json-relational-duality-view.html">create JSON relational duality view</a> statement I stumbled over GraphQL in this syntax diagram:</p>



<figure class="wp-block-image size-large is-resized"><a href="https://www.salvis.com/blog/wp-content/uploads/2024/06/image.png"><img decoding="async" width="1024" height="469" src="https://www.salvis.com/blog/wp-content/uploads/2024/06/image-1024x469.png" alt="create_json_relational_duality_view railroad diagram" class="wp-image-13431" style="width:541px" srcset="https://www.salvis.com/blog/wp-content/uploads/2024/06/image-1024x469.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2024/06/image-300x138.png 300w, https://www.salvis.com/blog/wp-content/uploads/2024/06/image-768x352.png 768w, https://www.salvis.com/blog/wp-content/uploads/2024/06/image-150x69.png 150w, https://www.salvis.com/blog/wp-content/uploads/2024/06/image-480x220.png 480w, https://www.salvis.com/blog/wp-content/uploads/2024/06/image.png 1082w" sizes="(max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">You can use <a href="https://graphql.org/learn/">GraphQL</a> as an alternative to a subquery to describe the source of your JSON relational duality view. This feature was already part of 23.3. Usually, I don&#8217;t like it when there are several ways to do the same thing. However, in this case, GraphQL helped me to understand the variant of the <code>select statement</code> in the duality view better. GraphQL might even be better suited to describe the content of a duality view.</p>



<p class="wp-block-paragraph">The funny thing is that JSON is about schema flexibility and GraphQL needs a schema to work. That sounds contradictory. However, if we reduce the scope of schema flexibility to a JSON object within existing entities, this can work quite well.</p>



<p class="wp-block-paragraph">In this blog post, I explore some features related to the schema flexibility of JSON relational duality views.</p>



<ol class="wp-block-list">
<li><a href="#setup">Setup</a></li>



<li><a href="#read-only-view">Read-only View à la 19c</a></li>



<li><a href="#read-only-duality-view">Read-only Duality View</a></li>



<li><a href="#updateable-duality-view-using-select">Updateable Duality View Using SELECT</a></li>



<li><a href="#updateable-duality-view-using-graphql">Updateable Duality View Using GraphQL</a></li>



<li><a href="#graphql-vs-select">GraphQL vs. SELECT</a></li>



<li><a href="#insert-into-duality-view">Insert Into Duality View</a></li>



<li><a href="#update-duality-view">Update Duality View</a></li>



<li><a href="#delete-from-duality-view">Delete From Duality View</a></li>
</ol>



<h2 class="wp-block-heading" id="setup">1. Setup</h2>



<p class="wp-block-paragraph">The examples in this blog post require an Oracle Database 23.4 (yes, 23.3 is not enough). In a schema of your choice you can run the following setup script:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">1) Setup for extended dept and emp table</span><span role="button" tabindex="0" data-code="set linesize 200
set pagesize 1000  
set long 32767
column ext format a72
column data format a130
alter session set nls_date_format = 'YYYY-MM-DD';

drop table if exists emp;
drop table if exists dept;

create table dept (
   deptno number(2, 0)      not null constraint dept_pk primary key,
   dname  varchar2(14 char) not null,
   loc    varchar2(13 char) not null,
   ext    json(object)
);

create table emp (
   empno    number(4, 0)      not null  constraint emp_pk primary key,
   ename    varchar2(10 char) not null,
   job      varchar2(9 char)  not null,
   mgr      number(4, 0)                constraint emp_mgr_fk references emp,
   hiredate date              not null,
   sal      number(7, 2)      not null,
   comm     number(7, 2),
   deptno   number(2, 0)      not null  constraint emp_deptno_fk references dept,
   ext      json(object)
);

insert into dept (deptno, dname, loc)
values (10, 'ACCOUNTING', 'NEW YORK'),
       (20, 'RESEARCH',   'DALLAS'),
       (30, 'SALES',      'CHICAGO'),
       (40, 'OPERATIONS', 'BOSTON');
commit;
       
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (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),
       (7839, 'KING',   'PRESIDENT', null, date '1981-11-17', 5000, null, 10),
       (7876, 'ADAMS',  'CLERK',     7788, date '1987-05-23', 1100, null, 20);
commit;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> linesize </span><span style="color: #B5CEA8">200</span></span>
<span class="line"><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> pagesize </span><span style="color: #B5CEA8">1000</span><span style="color: #D4D4D4">  </span></span>
<span class="line"><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">long</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">32767</span></span>
<span class="line"><span style="color: #569CD6">column</span><span style="color: #D4D4D4"> ext format a72</span></span>
<span class="line"><span style="color: #569CD6">column</span><span style="color: #D4D4D4"> data format a130</span></span>
<span class="line"><span style="color: #DCDCAA">alter session</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> nls_date_format = </span><span style="color: #CE9178">&#39;YYYY-MM-DD&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">drop</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">table</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">exists</span><span style="color: #D4D4D4"> emp;</span></span>
<span class="line"><span style="color: #569CD6">drop</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">table</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">exists</span><span style="color: #D4D4D4"> dept;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">create</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">table</span><span style="color: #D4D4D4"> dept (</span></span>
<span class="line"><span style="color: #D4D4D4">   deptno </span><span style="color: #569CD6">number</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">)      </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">constraint</span><span style="color: #D4D4D4"> dept_pk </span><span style="color: #569CD6">primary key</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">   dname  </span><span style="color: #569CD6">varchar2</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">14</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">char</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">not</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">   loc    </span><span style="color: #569CD6">varchar2</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">13</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">char</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">   ext    json(object)</span></span>
<span class="line"><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">create</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">table</span><span style="color: #D4D4D4"> emp (</span></span>
<span class="line"><span style="color: #D4D4D4">   empno    </span><span style="color: #569CD6">number</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">4</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">)      </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">  </span><span style="color: #569CD6">constraint</span><span style="color: #D4D4D4"> emp_pk </span><span style="color: #569CD6">primary key</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">   ename    </span><span style="color: #569CD6">varchar2</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">char</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">not</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">   job      </span><span style="color: #569CD6">varchar2</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">9</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">char</span><span style="color: #D4D4D4">)  </span><span style="color: #569CD6">not</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">   mgr      </span><span style="color: #569CD6">number</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">4</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">)                </span><span style="color: #569CD6">constraint</span><span style="color: #D4D4D4"> emp_mgr_fk </span><span style="color: #569CD6">references</span><span style="color: #D4D4D4"> emp,</span></span>
<span class="line"><span style="color: #D4D4D4">   hiredate </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4">              </span><span style="color: #569CD6">not</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">   sal      </span><span style="color: #569CD6">number</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">7</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">)      </span><span style="color: #569CD6">not</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">   comm     </span><span style="color: #569CD6">number</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">7</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">   deptno   </span><span style="color: #569CD6">number</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">)      </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">  </span><span style="color: #569CD6">constraint</span><span style="color: #D4D4D4"> emp_deptno_fk </span><span style="color: #569CD6">references</span><span style="color: #D4D4D4"> dept,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">   ext      json(object)</span></span>
<span class="line"><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">insert</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">into</span><span style="color: #D4D4D4"> dept (deptno, dname, loc)</span></span>
<span class="line"><span style="color: #569CD6">values</span><span style="color: #D4D4D4"> (</span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4">, </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">       (</span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">, </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">       (</span><span style="color: #B5CEA8">30</span><span style="color: #D4D4D4">, </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">       (</span><span style="color: #B5CEA8">40</span><span style="color: #D4D4D4">, </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: #DCDCAA">commit</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">       </span></span>
<span class="line"><span style="color: #569CD6">insert</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">into</span><span style="color: #D4D4D4"> emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)</span></span>
<span class="line"><span style="color: #569CD6">values</span><span style="color: #D4D4D4"> (</span><span style="color: #B5CEA8">7566</span><span style="color: #D4D4D4">, </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">,   </span><span style="color: #B5CEA8">7839</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-04-02&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">2975</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">       (</span><span style="color: #B5CEA8">7698</span><span style="color: #D4D4D4">, </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">,   </span><span style="color: #B5CEA8">7839</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-05-01&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">2850</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">30</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">       (</span><span style="color: #B5CEA8">7782</span><span style="color: #D4D4D4">, </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">,   </span><span style="color: #B5CEA8">7839</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-06-09&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">2450</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">       (</span><span style="color: #B5CEA8">7788</span><span style="color: #D4D4D4">, </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">,   </span><span style="color: #B5CEA8">7566</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1987-04-19&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">3000</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">       (</span><span style="color: #B5CEA8">7902</span><span style="color: #D4D4D4">, </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">,   </span><span style="color: #B5CEA8">7566</span><span style="color: #D4D4D4">, </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: #B5CEA8">3000</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">       (</span><span style="color: #B5CEA8">7499</span><span style="color: #D4D4D4">, </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">,  </span><span style="color: #B5CEA8">7698</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-02-20&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1600</span><span style="color: #D4D4D4">,  </span><span style="color: #B5CEA8">300</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">30</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">       (</span><span style="color: #B5CEA8">7521</span><span style="color: #D4D4D4">, </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">,  </span><span style="color: #B5CEA8">7698</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-02-22&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1250</span><span style="color: #D4D4D4">,  </span><span style="color: #B5CEA8">500</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">30</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">       (</span><span style="color: #B5CEA8">7654</span><span style="color: #D4D4D4">, </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">,  </span><span style="color: #B5CEA8">7698</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-09-28&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1250</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1400</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">30</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">       (</span><span style="color: #B5CEA8">7844</span><span style="color: #D4D4D4">, </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">,  </span><span style="color: #B5CEA8">7698</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-09-08&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1500</span><span style="color: #D4D4D4">,    </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">30</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">       (</span><span style="color: #B5CEA8">7900</span><span style="color: #D4D4D4">, </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">,     </span><span style="color: #B5CEA8">7698</span><span style="color: #D4D4D4">, </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: #B5CEA8">950</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">30</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">       (</span><span style="color: #B5CEA8">7934</span><span style="color: #D4D4D4">, </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">,     </span><span style="color: #B5CEA8">7782</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1982-01-23&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1300</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">       (</span><span style="color: #B5CEA8">7369</span><span style="color: #D4D4D4">, </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">,     </span><span style="color: #B5CEA8">7902</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1980-12-17&#39;</span><span style="color: #D4D4D4">,  </span><span style="color: #B5CEA8">800</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">       (</span><span style="color: #B5CEA8">7839</span><span style="color: #D4D4D4">, </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: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1981-11-17&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">5000</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">       (</span><span style="color: #B5CEA8">7876</span><span style="color: #D4D4D4">, </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">,     </span><span style="color: #B5CEA8">7788</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">date</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1987-05-23&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1100</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #DCDCAA">commit</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" data-code="
Session altered.


Table EMP dropped.


Table DEPT dropped.


Table DEPT created.


Table EMP created.


4 rows inserted.


Commit complete.


14 rows inserted.


Commit complete." style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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>
<span class="line"><span style="color: #D4D4D4">Session altered.</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line"><span style="color: #D4D4D4">Table EMP dropped.</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">Table DEPT dropped.</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">Table DEPT created.</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">Table EMP created.</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">4 rows inserted.</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">Commit complete.</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">14 rows inserted.</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">Commit complete.</span></span></code></pre></div>



<p class="wp-block-paragraph">There are a few changes to the well-known <code>dept</code> and <code>emp</code> tables I&#8217;d like to highlight:</p>



<ul class="wp-block-list">
<li>Firstly, primary keys and foreign keys. They are required for the duality views, however, they do not need to be enabled.</li>



<li>Secondly, both tables got an additional <code>ext</code> column. The data type is <code>json(object)</code>. Before 23.4 there was just a generic <code>json</code> data type. With 23.4 it&#8217;s possible to add <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/SQL-JSON-Conditions.html#GUID-99B9493D-2929-4A09-BA39-A56F8E7319DA__SECTION_AFR_B3S_KBC">modifiers</a>. The modifier <code>object</code> is required for <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/jsnvu/json-data-stored-json-relational-duality-views.html#GUID-8D09B4D6-2853-40ED-8E7A-A921C197D5A8">flex columns</a> in duality views.</li>
</ul>



<h2 class="wp-block-heading" id="read-only-view">2. Read-Only View à la 19c</h2>



<p class="wp-block-paragraph">Let&#8217;s step back and create a view that returns a single JSON column, as in Oracle Database 19c (to make it work in 19c you have to use for example <code>ext clob check (ext is json)</code> instead of <code>ext json(object)</code> in the tables <code>dept</code> and <code>emp</code>).</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">2) Read-only view à la 19c</span><span role="button" tabindex="0" data-code="create or replace view dept_v as
select json_object(
          deptno,
          dname,
          loc,
          ext,
          'sal': (select sum(sal) from emp where emp.deptno = dept.deptno)
          absent on null
       ) as data
  from dept;

select * from dept_v;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">view</span><span style="color: #D4D4D4"> dept_v </span><span style="color: #569CD6">as</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> json_object(</span></span>
<span class="line"><span style="color: #D4D4D4">          deptno,</span></span>
<span class="line"><span style="color: #D4D4D4">          dname,</span></span>
<span class="line"><span style="color: #D4D4D4">          loc,</span></span>
<span class="line"><span style="color: #D4D4D4">          ext,</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #CE9178">&#39;sal&#39;</span><span style="color: #D4D4D4">: (</span><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sum</span><span style="color: #D4D4D4">(sal) </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> emp </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> emp.deptno = dept.deptno)</span></span>
<span class="line"><span style="color: #D4D4D4">          absent </span><span style="color: #569CD6">on</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">null</span></span>
<span class="line"><span style="color: #D4D4D4">       ) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> data</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>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> * </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept_v;</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" data-code="View DEPT_V created.


DATA
--------------------------------------------------------------
{&quot;deptno&quot;:10,&quot;dname&quot;:&quot;ACCOUNTING&quot;,&quot;loc&quot;:&quot;NEW YORK&quot;,&quot;sal&quot;:8750}
{&quot;deptno&quot;:20,&quot;dname&quot;:&quot;RESEARCH&quot;,&quot;loc&quot;:&quot;DALLAS&quot;,&quot;sal&quot;:10875}
{&quot;deptno&quot;:30,&quot;dname&quot;:&quot;SALES&quot;,&quot;loc&quot;:&quot;CHICAGO&quot;,&quot;sal&quot;:9400}
{&quot;deptno&quot;:40,&quot;dname&quot;:&quot;OPERATIONS&quot;,&quot;loc&quot;:&quot;BOSTON&quot;}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">View DEPT_V created.</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">DATA</span></span>
<span class="line"><span style="color: #D4D4D4">--------------------------------------------------------------</span></span>
<span class="line"><span style="color: #D4D4D4">{&quot;deptno&quot;:10,&quot;dname&quot;:&quot;ACCOUNTING&quot;,&quot;loc&quot;:&quot;NEW YORK&quot;,&quot;sal&quot;:8750}</span></span>
<span class="line"><span style="color: #D4D4D4">{&quot;deptno&quot;:20,&quot;dname&quot;:&quot;RESEARCH&quot;,&quot;loc&quot;:&quot;DALLAS&quot;,&quot;sal&quot;:10875}</span></span>
<span class="line"><span style="color: #D4D4D4">{&quot;deptno&quot;:30,&quot;dname&quot;:&quot;SALES&quot;,&quot;loc&quot;:&quot;CHICAGO&quot;,&quot;sal&quot;:9400}</span></span>
<span class="line"><span style="color: #D4D4D4">{&quot;deptno&quot;:40,&quot;dname&quot;:&quot;OPERATIONS&quot;,&quot;loc&quot;:&quot;BOSTON&quot;}</span></span></code></pre></div>



<h2 class="wp-block-heading" id="read-only-duality-view">3. Read-Only Duality View</h2>



<p class="wp-block-paragraph">And now let&#8217;s try to use the previous subquery in a duality view.</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">3a) Read-only duality view (ORA-40616)</span><span role="button" tabindex="0" data-code="create or replace json duality view dept_dv as
select json_object(
          deptno,
          dname,
          loc,
          ext,
          'sal': (select sum(sal) from emp where emp.deptno = dept.deptno)
          absent on null
       ) as data
  from dept;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> json duality </span><span style="color: #569CD6">view</span><span style="color: #D4D4D4"> dept_dv </span><span style="color: #569CD6">as</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> json_object(</span></span>
<span class="line"><span style="color: #D4D4D4">          deptno,</span></span>
<span class="line"><span style="color: #D4D4D4">          dname,</span></span>
<span class="line"><span style="color: #D4D4D4">          loc,</span></span>
<span class="line"><span style="color: #D4D4D4">          ext,</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #CE9178">&#39;sal&#39;</span><span style="color: #D4D4D4">: (</span><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sum</span><span style="color: #D4D4D4">(sal) </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> emp </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">          absent </span><span style="color: #569CD6">on</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">null</span></span>
<span class="line"><span style="color: #D4D4D4">       ) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> data</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept;</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" data-code="ORA-40616: Cannot create JSON Relational Duality View 'DEPT_DV': using ABSENT ON NULL in JSON_OBJECT() is not permitted." style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">ORA-40616: Cannot create JSON Relational Duality View &#39;DEPT_DV&#39;: using ABSENT ON NULL in JSON_OBJECT() is not permitted.</span></span></code></pre></div>



<p class="wp-block-paragraph">This does not work. The <code>absent on null</code> clause on line 8 is not supported in a duality view. Let&#8217;s remove this line and try again.</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">3b) Read-only duality view (ORA-40895)</span><span role="button" tabindex="0" data-code="create or replace json duality view dept_dv as
select json_object(
          deptno,
          dname,
          loc,
          ext,
          'sal': (select sum(sal) from emp where emp.deptno = dept.deptno)
       ) as data
  from dept;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> json duality </span><span style="color: #569CD6">view</span><span style="color: #D4D4D4"> dept_dv </span><span style="color: #569CD6">as</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> json_object(</span></span>
<span class="line"><span style="color: #D4D4D4">          deptno,</span></span>
<span class="line"><span style="color: #D4D4D4">          dname,</span></span>
<span class="line"><span style="color: #D4D4D4">          loc,</span></span>
<span class="line"><span style="color: #D4D4D4">          ext,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">          </span><span style="color: #CE9178">&#39;sal&#39;</span><span style="color: #D4D4D4">: (</span><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sum</span><span style="color: #D4D4D4">(sal) </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> emp </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">as</span><span style="color: #D4D4D4"> data</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept;</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" data-code="ORA-40895: invalid SQL expression in JSON relational duality view (operators except JSON_OBJECT or JSON_ARRAYAGG not allowed)" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">ORA-40895: invalid SQL expression in JSON relational duality view (operators except JSON_OBJECT or JSON_ARRAYAGG not allowed)</span></span></code></pre></div>



<p class="wp-block-paragraph">This still does not work. It&#8217;s not allowed to include an aggregate as in line 7. Let&#8217;s also remove this line and try again.</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">3c) Read-only duality view (ORA-40941)</span><span role="button" tabindex="0" data-code="create or replace json duality view dept_dv as
select json_object(
          deptno,
          dname,
          loc,
          ext
       ) as data
  from dept;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> json duality </span><span style="color: #569CD6">view</span><span style="color: #D4D4D4"> dept_dv </span><span style="color: #569CD6">as</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> json_object(</span></span>
<span class="line"><span style="color: #D4D4D4">          deptno,</span></span>
<span class="line"><span style="color: #D4D4D4">          dname,</span></span>
<span class="line"><span style="color: #D4D4D4">          loc,</span></span>
<span class="line"><span style="color: #D4D4D4">          ext</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">       ) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> data</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept;</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" data-code="ORA-40941: cannot specify a column name or subquery alias for JSON relational duality view" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">ORA-40941: cannot specify a column name or subquery alias for JSON relational duality view</span></span></code></pre></div>



<p class="wp-block-paragraph">Argh. We cannot use the column alias <code>data</code> on line 7. Let&#8217;s remove the alias and try again.</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">3d) Read-only duality view (ORA-42647)</span><span role="button" tabindex="0" data-code="create or replace json duality view dept_dv as
select json_object(
          deptno,
          dname,
          loc,
          ext
       )
  from dept;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> json duality </span><span style="color: #569CD6">view</span><span style="color: #D4D4D4"> dept_dv </span><span style="color: #569CD6">as</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> json_object(</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">          deptno,</span></span>
<span class="line"><span style="color: #D4D4D4">          dname,</span></span>
<span class="line"><span style="color: #D4D4D4">          loc,</span></span>
<span class="line"><span style="color: #D4D4D4">          ext</span></span>
<span class="line"><span style="color: #D4D4D4">       )</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept;</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" data-code="ORA-42647: Missing '_id' field at the root level for JSON-relational duality view 'DEPT_DV'." style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">ORA-42647: Missing &#39;_id&#39; field at the root level for JSON-relational duality view &#39;DEPT_DV&#39;.</span></span></code></pre></div>



<p class="wp-block-paragraph">Okay, an <code>_id</code> field is required to identify a document. Composite keys can be passed as a JSON array. In this case, we do not need that. We can use <code>deptno</code>. Let&#8217;s amend the query and try again.</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">3e) Read-only duality view</span><span role="button" tabindex="0" data-code="create or replace json duality view dept_dv as
select json_object(
          '_id': deptno,
          dname,
          loc,
          ext
       )
  from dept;

select * from dept_dv;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> json duality </span><span style="color: #569CD6">view</span><span style="color: #D4D4D4"> dept_dv </span><span style="color: #569CD6">as</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> json_object(</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #CE9178">&#39;_id&#39;</span><span style="color: #D4D4D4">: deptno,</span></span>
<span class="line"><span style="color: #D4D4D4">          dname,</span></span>
<span class="line"><span style="color: #D4D4D4">          loc,</span></span>
<span class="line"><span style="color: #D4D4D4">          ext</span></span>
<span class="line"><span style="color: #D4D4D4">       )</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>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> * </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept_dv;</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" data-code="Json DUALITY created.


DATA
----------------------------------------------------------------------------------------------------------------------------------
{&quot;_id&quot;:10,&quot;dname&quot;:&quot;ACCOUNTING&quot;,&quot;loc&quot;:&quot;NEW YORK&quot;,&quot;_metadata&quot;:{&quot;etag&quot;:&quot;38CBB37294BEE09C6D9867B5B1871FE2&quot;,&quot;asof&quot;:&quot;000025652FBC556F&quot;}}
{&quot;_id&quot;:20,&quot;dname&quot;:&quot;RESEARCH&quot;,&quot;loc&quot;:&quot;DALLAS&quot;,&quot;_metadata&quot;:{&quot;etag&quot;:&quot;1D1973E9B068183129F7DA59F6A9C283&quot;,&quot;asof&quot;:&quot;000025652FBC556F&quot;}}
{&quot;_id&quot;:30,&quot;dname&quot;:&quot;SALES&quot;,&quot;loc&quot;:&quot;CHICAGO&quot;,&quot;_metadata&quot;:{&quot;etag&quot;:&quot;11CC2AE352D52FFDAE0B7A3DFC99F836&quot;,&quot;asof&quot;:&quot;000025652FBC556F&quot;}}
{&quot;_id&quot;:40,&quot;dname&quot;:&quot;OPERATIONS&quot;,&quot;loc&quot;:&quot;BOSTON&quot;,&quot;_metadata&quot;:{&quot;etag&quot;:&quot;B33BBA9A74C046813C59BA0763AD81C9&quot;,&quot;asof&quot;:&quot;000025652FBC556F&quot;}}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">Json DUALITY created.</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">DATA</span></span>
<span class="line"><span style="color: #D4D4D4">----------------------------------------------------------------------------------------------------------------------------------</span></span>
<span class="line"><span style="color: #D4D4D4">{&quot;_id&quot;:10,&quot;dname&quot;:&quot;ACCOUNTING&quot;,&quot;loc&quot;:&quot;NEW YORK&quot;,&quot;_metadata&quot;:{&quot;etag&quot;:&quot;38CBB37294BEE09C6D9867B5B1871FE2&quot;,&quot;asof&quot;:&quot;000025652FBC556F&quot;}}</span></span>
<span class="line"><span style="color: #D4D4D4">{&quot;_id&quot;:20,&quot;dname&quot;:&quot;RESEARCH&quot;,&quot;loc&quot;:&quot;DALLAS&quot;,&quot;_metadata&quot;:{&quot;etag&quot;:&quot;1D1973E9B068183129F7DA59F6A9C283&quot;,&quot;asof&quot;:&quot;000025652FBC556F&quot;}}</span></span>
<span class="line"><span style="color: #D4D4D4">{&quot;_id&quot;:30,&quot;dname&quot;:&quot;SALES&quot;,&quot;loc&quot;:&quot;CHICAGO&quot;,&quot;_metadata&quot;:{&quot;etag&quot;:&quot;11CC2AE352D52FFDAE0B7A3DFC99F836&quot;,&quot;asof&quot;:&quot;000025652FBC556F&quot;}}</span></span>
<span class="line"><span style="color: #D4D4D4">{&quot;_id&quot;:40,&quot;dname&quot;:&quot;OPERATIONS&quot;,&quot;loc&quot;:&quot;BOSTON&quot;,&quot;_metadata&quot;:{&quot;etag&quot;:&quot;B33BBA9A74C046813C59BA0763AD81C9&quot;,&quot;asof&quot;:&quot;000025652FBC556F&quot;}}</span></span></code></pre></div>



<p class="wp-block-paragraph">Finally, we have a working read-only duality view. </p>



<p class="wp-block-paragraph">Please note that each document contains a <code>_metadata</code> object. The <code>etag</code> field is a hash value based on all document fields by default. It can be used for optimistic locking. The <code>asof</code> field represents the SCN (system change number). It&#8217;s useful for read consistency, this means querying related data in subsequent queries using the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__GUID-9CA8AB48-7DE6-4601-A798-42B2038CA3A6">flashback_query_clause</a>.</p>



<h2 class="wp-block-heading" id="updateable-duality-view-using-select">4. Updateable Duality View Using SELECT</h2>



<p class="wp-block-paragraph">Let&#8217;s create an updateable duality view that represents all data in our model and uses all relationships. </p>



<p class="wp-block-paragraph">The highlighted lines contain clauses that work only in a duality view. In other words, the &#8220;select&#8221; part does not work as a standalone statement as in common relational views.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">4) Updateable duality view using select</span><span role="button" tabindex="0" data-code="create or replace json duality view dept_dv as
select json {
          '_id': deptno,
          dname,
          loc,
          ext as flex,
          'emps':
             (
                select json_arrayagg(
                          JSON {
                             emp.empno,
                             emp.ename,
                             emp.job,
                             unnest
                                (
                                   select json {
                                             'mgr'    : mgr.empno with nocheck,
                                             'mgrname': mgr.ename with nocheck
                                          }
                                     from emp mgr
                                    where mgr.empno = emp.mgr
                                ),
                             emp.hiredate,
                             emp.sal,
                             emp.comm,
                             ext as flex
                          }
                       )
                  from emp with insert update delete
                 where emp.deptno = dept.deptno
             )
       }
  from dept with insert update delete;

select json_serialize(data returning clob pretty) as data
  from dept_dv dv
 where dv.data.&quot;_id&quot;.numberOnly() in (20, 40);" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> json duality </span><span style="color: #569CD6">view</span><span style="color: #D4D4D4"> dept_dv </span><span style="color: #569CD6">as</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> json {</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #CE9178">&#39;_id&#39;</span><span style="color: #D4D4D4">: deptno,</span></span>
<span class="line"><span style="color: #D4D4D4">          dname,</span></span>
<span class="line"><span style="color: #D4D4D4">          loc,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">          ext </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> flex,</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #CE9178">&#39;emps&#39;</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 style="color: #569CD6">select</span><span style="color: #D4D4D4"> json_arrayagg(</span></span>
<span class="line"><span style="color: #D4D4D4">                          JSON {</span></span>
<span class="line"><span style="color: #D4D4D4">                             emp.empno,</span></span>
<span class="line"><span style="color: #D4D4D4">                             emp.ename,</span></span>
<span class="line"><span style="color: #D4D4D4">                             emp.job,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                             unnest</span></span>
<span class="line"><span style="color: #D4D4D4">                                (</span></span>
<span class="line"><span style="color: #D4D4D4">                                   </span><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> json {</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                                             </span><span style="color: #CE9178">&#39;mgr&#39;</span><span style="color: #D4D4D4">    : mgr.empno </span><span style="color: #569CD6">with</span><span style="color: #D4D4D4"> nocheck,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                                             </span><span style="color: #CE9178">&#39;mgrname&#39;</span><span style="color: #D4D4D4">: mgr.ename </span><span style="color: #569CD6">with</span><span style="color: #D4D4D4"> nocheck</span></span>
<span class="line"><span style="color: #D4D4D4">                                          }</span></span>
<span class="line"><span style="color: #D4D4D4">                                     </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> emp mgr</span></span>
<span class="line"><span style="color: #D4D4D4">                                    </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> mgr.empno = emp.mgr</span></span>
<span class="line"><span style="color: #D4D4D4">                                ),</span></span>
<span class="line"><span style="color: #D4D4D4">                             emp.hiredate,</span></span>
<span class="line"><span style="color: #D4D4D4">                             emp.sal,</span></span>
<span class="line"><span style="color: #D4D4D4">                             emp.comm,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                             ext </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> flex</span></span>
<span class="line"><span style="color: #D4D4D4">                          }</span></span>
<span class="line"><span style="color: #D4D4D4">                       )</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> emp </span><span style="color: #569CD6">with</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">insert</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">update</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">delete</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>
<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">with</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">insert</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">update</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">delete</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> json_serialize(data </span><span style="color: #569CD6">returning</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">clob</span><span style="color: #D4D4D4"> pretty) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> data</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept_dv dv</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> dv.data.</span><span style="color: #CE9178">&quot;_id&quot;</span><span style="color: #D4D4D4">.numberOnly() </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> (</span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">40</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" data-code="Json DUALITY created.


DATA
------------------------------------------------
{
  &quot;_id&quot; : 20,
  &quot;_metadata&quot; :
  {
    &quot;etag&quot; : &quot;88A4A9648C2CA1752E477545DCA85FD3&quot;,
    &quot;asof&quot; : &quot;00002565300350E5&quot;
  },
  &quot;dname&quot; : &quot;RESEARCH&quot;,
  &quot;loc&quot; : &quot;DALLAS&quot;,
  &quot;emps&quot; :
  [
    {
      &quot;empno&quot; : 7369,
      &quot;ename&quot; : &quot;SMITH&quot;,
      &quot;job&quot; : &quot;CLERK&quot;,
      &quot;mgr&quot; : 7902,
      &quot;mgrname&quot; : &quot;FORD&quot;,
      &quot;hiredate&quot; : &quot;1980-12-17T00:00:00&quot;,
      &quot;sal&quot; : 800,
      &quot;comm&quot; : null
    },
    {
      &quot;empno&quot; : 7566,
      &quot;ename&quot; : &quot;JONES&quot;,
      &quot;job&quot; : &quot;MANAGER&quot;,
      &quot;mgr&quot; : 7839,
      &quot;mgrname&quot; : &quot;KING&quot;,
      &quot;hiredate&quot; : &quot;1981-04-02T00:00:00&quot;,
      &quot;sal&quot; : 2975,
      &quot;comm&quot; : null
    },
    {
      &quot;empno&quot; : 7788,
      &quot;ename&quot; : &quot;SCOTT&quot;,
      &quot;job&quot; : &quot;ANALYST&quot;,
      &quot;mgr&quot; : 7566,
      &quot;mgrname&quot; : &quot;JONES&quot;,
      &quot;hiredate&quot; : &quot;1987-04-19T00:00:00&quot;,
      &quot;sal&quot; : 3000,
      &quot;comm&quot; : null
    },
    {
      &quot;empno&quot; : 7876,
      &quot;ename&quot; : &quot;ADAMS&quot;,
      &quot;job&quot; : &quot;CLERK&quot;,
      &quot;mgr&quot; : 7788,
      &quot;mgrname&quot; : &quot;SCOTT&quot;,
      &quot;hiredate&quot; : &quot;1987-05-23T00:00:00&quot;,
      &quot;sal&quot; : 1100,
      &quot;comm&quot; : null
    },
    {
      &quot;empno&quot; : 7902,
      &quot;ename&quot; : &quot;FORD&quot;,
      &quot;job&quot; : &quot;ANALYST&quot;,
      &quot;mgr&quot; : 7566,
      &quot;mgrname&quot; : &quot;JONES&quot;,
      &quot;hiredate&quot; : &quot;1981-12-03T00:00:00&quot;,
      &quot;sal&quot; : 3000,
      &quot;comm&quot; : null
    }
  ]
}

{
  &quot;_id&quot; : 40,
  &quot;_metadata&quot; :
  {
    &quot;etag&quot; : &quot;28E9C49240CD26A29FDED7B253A38ED7&quot;,
    &quot;asof&quot; : &quot;00002565300350E5&quot;
  },
  &quot;dname&quot; : &quot;OPERATIONS&quot;,
  &quot;loc&quot; : &quot;BOSTON&quot;,
  &quot;emps&quot; :
  [
  ]
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">Json DUALITY created.</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">DATA</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">  &quot;_id&quot; : 20,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;_metadata&quot; :</span></span>
<span class="line"><span style="color: #D4D4D4">  {</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;etag&quot; : &quot;88A4A9648C2CA1752E477545DCA85FD3&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;asof&quot; : &quot;00002565300350E5&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  },</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;dname&quot; : &quot;RESEARCH&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;loc&quot; : &quot;DALLAS&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;emps&quot; :</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">      &quot;empno&quot; : 7369,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;ename&quot; : &quot;SMITH&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;job&quot; : &quot;CLERK&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgr&quot; : 7902,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgrname&quot; : &quot;FORD&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;hiredate&quot; : &quot;1980-12-17T00:00:00&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;sal&quot; : 800,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;comm&quot; : null</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">      &quot;empno&quot; : 7566,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;ename&quot; : &quot;JONES&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;job&quot; : &quot;MANAGER&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgr&quot; : 7839,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgrname&quot; : &quot;KING&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;hiredate&quot; : &quot;1981-04-02T00:00:00&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;sal&quot; : 2975,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;comm&quot; : null</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">      &quot;empno&quot; : 7788,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;ename&quot; : &quot;SCOTT&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;job&quot; : &quot;ANALYST&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgr&quot; : 7566,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgrname&quot; : &quot;JONES&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;hiredate&quot; : &quot;1987-04-19T00:00:00&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;sal&quot; : 3000,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;comm&quot; : null</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">      &quot;empno&quot; : 7876,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;ename&quot; : &quot;ADAMS&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;job&quot; : &quot;CLERK&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgr&quot; : 7788,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgrname&quot; : &quot;SCOTT&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;hiredate&quot; : &quot;1987-05-23T00:00:00&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;sal&quot; : 1100,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;comm&quot; : null</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">      &quot;empno&quot; : 7902,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;ename&quot; : &quot;FORD&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;job&quot; : &quot;ANALYST&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgr&quot; : 7566,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgrname&quot; : &quot;JONES&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;hiredate&quot; : &quot;1981-12-03T00:00:00&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;sal&quot; : 3000,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;comm&quot; : null</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>
<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">  &quot;_id&quot; : 40,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;_metadata&quot; :</span></span>
<span class="line"><span style="color: #D4D4D4">  {</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;etag&quot; : &quot;28E9C49240CD26A29FDED7B253A38ED7&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;asof&quot; : &quot;00002565300350E5&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  },</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;dname&quot; : &quot;OPERATIONS&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;loc&quot; : &quot;BOSTON&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;emps&quot; :</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">Since the <code>ext</code> column in the <code>dept</code> and <code>emp</code> table is empty for all rows, we do not see any additional fields in the two JSON documents. </p>



<p class="wp-block-paragraph">Due to the <code>unest</code> clause in line 14, the fields <code>mgr</code> and <code>mgrname</code> appear on the same level as all other fields of the table <code>emp</code>.</p>



<h2 class="wp-block-heading" id="updateable-duality-view-using-graphql">5. Updateable Duality View Using GraphQL</h2>



<p class="wp-block-paragraph">The next duality view is equivalent to the one in the previous chapter.</p>



<p class="wp-block-paragraph">The highlighted lines with annotations match the highlighted clauses in the previous statement.</p>



<p class="wp-block-paragraph">GraphQL requires a model for a query. The Oracle implementation uses tables, primary, and foreign keys to build the underlying model.</p>



<h5 class="wp-block-heading">Some explanations</h5>



<ul class="wp-block-list">
<li>In line 2, we use the <code>dept</code> table as root. For select, insert, update and delete. This means we get a JSON document per department.</li>



<li>In line 8, we use the <code>emp</code> table for the field <code>emps</code>. We expect an array of objects. However, we do not have to tell that explicitly. The Oracle Database will figure that out. There is just one relationship between <code>dept</code> and <code>emp</code>. Therefore it is clear how to join the tables and access the data. For select, insert, update and delete.</li>



<li>In line 13, we use the <code>emp</code> table for the fields <code>mgr</code> and <code>mgrname</code>. The access is possible via the foreign keys <code>emp_mgr_fk</code> and <code>emp_deptno_fk</code>. We know that it is <code>emp_mgr_fk</code> but the Oracle Database does not. We have to tell it. We do that with the <code>@link(from: [mgr])</code> annotation, to use the <code>mgr</code> field for the recursive join. An update of <code>mgrname</code> is not allowed (it is read-only by default). An update of <code>mgr</code> is allowed (it will update the foreign key column in <code>emp</code>).</li>
</ul>



<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) Updateable duality view using GraphQL</span><span role="button" tabindex="0" data-code="create or replace json duality view dept_dv as
dept @insert @update @delete
{
   _id: deptno
   dname
   loc
   ext @flex
   emps: emp @insert @update @delete
      {
         empno
         ename
         job
         emp @unnest @link(from: [mgr])
            {
               mgr    : empno @nocheck
               mgrname: ename @nocheck
            }
         hiredate
         sal
         comm
         ext @flex
      }
};

select json_serialize(data returning clob pretty) as data
  from dept_dv dv
 where dv.data.&quot;_id&quot;.numberOnly() in (20, 40);" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> json duality </span><span style="color: #569CD6">view</span><span style="color: #D4D4D4"> dept_dv </span><span style="color: #569CD6">as</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">dept @</span><span style="color: #569CD6">insert</span><span style="color: #D4D4D4"> @</span><span style="color: #569CD6">update</span><span style="color: #D4D4D4"> @</span><span style="color: #569CD6">delete</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">   _id: deptno</span></span>
<span class="line"><span style="color: #D4D4D4">   dname</span></span>
<span class="line"><span style="color: #D4D4D4">   loc</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">   ext @flex</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">   emps: emp @</span><span style="color: #569CD6">insert</span><span style="color: #D4D4D4"> @</span><span style="color: #569CD6">update</span><span style="color: #D4D4D4"> @</span><span style="color: #569CD6">delete</span></span>
<span class="line"><span style="color: #D4D4D4">      {</span></span>
<span class="line"><span style="color: #D4D4D4">         empno</span></span>
<span class="line"><span style="color: #D4D4D4">         ename</span></span>
<span class="line"><span style="color: #D4D4D4">         job</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">         emp @unnest @link(</span><span style="color: #569CD6">from</span><span style="color: #D4D4D4">: [mgr])</span></span>
<span class="line"><span style="color: #D4D4D4">            {</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">               mgr    : empno @nocheck</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">               mgrname: ename @nocheck</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">         hiredate</span></span>
<span class="line"><span style="color: #D4D4D4">         sal</span></span>
<span class="line"><span style="color: #D4D4D4">         comm</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">         ext @flex</span></span>
<span class="line"><span style="color: #D4D4D4">      }</span></span>
<span class="line"><span style="color: #D4D4D4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> json_serialize(data </span><span style="color: #569CD6">returning</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">clob</span><span style="color: #D4D4D4"> pretty) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> data</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept_dv dv</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> dv.data.</span><span style="color: #CE9178">&quot;_id&quot;</span><span style="color: #D4D4D4">.numberOnly() </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> (</span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">40</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" data-code="Json DUALITY created.


DATA
------------------------------------------------
{
  &quot;_id&quot; : 20,
  &quot;_metadata&quot; :
  {
    &quot;etag&quot; : &quot;88A4A9648C2CA1752E477545DCA85FD3&quot;,
    &quot;asof&quot; : &quot;00002565301D6D5C&quot;
  },
  &quot;dname&quot; : &quot;RESEARCH&quot;,
  &quot;loc&quot; : &quot;DALLAS&quot;,
  &quot;emps&quot; :
  [
    {
      &quot;empno&quot; : 7369,
      &quot;ename&quot; : &quot;SMITH&quot;,
      &quot;job&quot; : &quot;CLERK&quot;,
      &quot;mgr&quot; : 7902,
      &quot;mgrname&quot; : &quot;FORD&quot;,
      &quot;hiredate&quot; : &quot;1980-12-17T00:00:00&quot;,
      &quot;sal&quot; : 800,
      &quot;comm&quot; : null
    },
    {
      &quot;empno&quot; : 7566,
      &quot;ename&quot; : &quot;JONES&quot;,
      &quot;job&quot; : &quot;MANAGER&quot;,
      &quot;mgr&quot; : 7839,
      &quot;mgrname&quot; : &quot;KING&quot;,
      &quot;hiredate&quot; : &quot;1981-04-02T00:00:00&quot;,
      &quot;sal&quot; : 2975,
      &quot;comm&quot; : null
    },
    {
      &quot;empno&quot; : 7788,
      &quot;ename&quot; : &quot;SCOTT&quot;,
      &quot;job&quot; : &quot;ANALYST&quot;,
      &quot;mgr&quot; : 7566,
      &quot;mgrname&quot; : &quot;JONES&quot;,
      &quot;hiredate&quot; : &quot;1987-04-19T00:00:00&quot;,
      &quot;sal&quot; : 3000,
      &quot;comm&quot; : null
    },
    {
      &quot;empno&quot; : 7876,
      &quot;ename&quot; : &quot;ADAMS&quot;,
      &quot;job&quot; : &quot;CLERK&quot;,
      &quot;mgr&quot; : 7788,
      &quot;mgrname&quot; : &quot;SCOTT&quot;,
      &quot;hiredate&quot; : &quot;1987-05-23T00:00:00&quot;,
      &quot;sal&quot; : 1100,
      &quot;comm&quot; : null
    },
    {
      &quot;empno&quot; : 7902,
      &quot;ename&quot; : &quot;FORD&quot;,
      &quot;job&quot; : &quot;ANALYST&quot;,
      &quot;mgr&quot; : 7566,
      &quot;mgrname&quot; : &quot;JONES&quot;,
      &quot;hiredate&quot; : &quot;1981-12-03T00:00:00&quot;,
      &quot;sal&quot; : 3000,
      &quot;comm&quot; : null
    }
  ]
}

{
  &quot;_id&quot; : 40,
  &quot;_metadata&quot; :
  {
    &quot;etag&quot; : &quot;28E9C49240CD26A29FDED7B253A38ED7&quot;,
    &quot;asof&quot; : &quot;00002565301D6D5C&quot;
  },
  &quot;dname&quot; : &quot;OPERATIONS&quot;,
  &quot;loc&quot; : &quot;BOSTON&quot;,
  &quot;emps&quot; :
  [
  ]
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">Json DUALITY created.</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">DATA</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">  &quot;_id&quot; : 20,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;_metadata&quot; :</span></span>
<span class="line"><span style="color: #D4D4D4">  {</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;etag&quot; : &quot;88A4A9648C2CA1752E477545DCA85FD3&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;asof&quot; : &quot;00002565301D6D5C&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  },</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;dname&quot; : &quot;RESEARCH&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;loc&quot; : &quot;DALLAS&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;emps&quot; :</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">      &quot;empno&quot; : 7369,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;ename&quot; : &quot;SMITH&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;job&quot; : &quot;CLERK&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgr&quot; : 7902,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgrname&quot; : &quot;FORD&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;hiredate&quot; : &quot;1980-12-17T00:00:00&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;sal&quot; : 800,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;comm&quot; : null</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">      &quot;empno&quot; : 7566,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;ename&quot; : &quot;JONES&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;job&quot; : &quot;MANAGER&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgr&quot; : 7839,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgrname&quot; : &quot;KING&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;hiredate&quot; : &quot;1981-04-02T00:00:00&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;sal&quot; : 2975,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;comm&quot; : null</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">      &quot;empno&quot; : 7788,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;ename&quot; : &quot;SCOTT&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;job&quot; : &quot;ANALYST&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgr&quot; : 7566,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgrname&quot; : &quot;JONES&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;hiredate&quot; : &quot;1987-04-19T00:00:00&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;sal&quot; : 3000,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;comm&quot; : null</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">      &quot;empno&quot; : 7876,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;ename&quot; : &quot;ADAMS&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;job&quot; : &quot;CLERK&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgr&quot; : 7788,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgrname&quot; : &quot;SCOTT&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;hiredate&quot; : &quot;1987-05-23T00:00:00&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;sal&quot; : 1100,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;comm&quot; : null</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">      &quot;empno&quot; : 7902,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;ename&quot; : &quot;FORD&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;job&quot; : &quot;ANALYST&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgr&quot; : 7566,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgrname&quot; : &quot;JONES&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;hiredate&quot; : &quot;1981-12-03T00:00:00&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;sal&quot; : 3000,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;comm&quot; : null</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>
<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">  &quot;_id&quot; : 40,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;_metadata&quot; :</span></span>
<span class="line"><span style="color: #D4D4D4">  {</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;etag&quot; : &quot;28E9C49240CD26A29FDED7B253A38ED7&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;asof&quot; : &quot;00002565301D6D5C&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  },</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;dname&quot; : &quot;OPERATIONS&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;loc&quot; : &quot;BOSTON&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;emps&quot; :</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">The result is the same as for the variant based on <code>select</code>. The only difference is the <code>asof</code> fields, which is expected.</p>



<h2 class="wp-block-heading" id="graphql-vs-select">6. GraphQL vs. SELECT</h2>



<p class="wp-block-paragraph">What I like about the GraphQL variant is that the syntax is simple. It looks similar to the result document and is easy to read. No compromises due to feature parity. I run less risk of trying SQL expressions that are not applicable in a duality view.  The downside is that the definition might become ambiguous when extending the model with additional foreign key relationships. You might need to add <code>@link</code> annotations to your existing duality views to successfully recreate them. The variant using <code>select</code> cannot become ambiguous. There is no default join logic in SQL yet.</p>



<p class="wp-block-paragraph">However, writing complex duality views might be easier with the variant using <code>select</code>. I can temporarily comment out all duality-view-specific clauses to make the <code>select</code> part work as a standalone statement until I&#8217;m happy with the result.</p>



<p class="wp-block-paragraph">From a performance point of view, it should theoretically not matter which syntax variant you use. Any duality view can be built on GraphQL or <code>select</code>. The optimizer has all the information it needs to produce an optimal execution plan for both variants. I see no reason why the internal representation should differ.</p>



<p class="wp-block-paragraph">Maybe a future version of the Oracle Database will offer options to generate the preferred syntax variant independently of the originally deployed variant. By extending <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/arpls/DBMS_METADATA.html#GUID-A4683EEE-6F54-4081-B7BF-1496096675FA">dbms_metadata.get_ddl</a>, for example.</p>



<h2 class="wp-block-heading" id="insert-into-duality-view">7. Insert Into Duality View</h2>



<p class="wp-block-paragraph">Here&#8217;s an example of inserting a JSON document with one department and two employees into the previously created duality view. </p>



<h5 class="wp-block-heading">Some explanations</h5>



<ul class="wp-block-list">
<li>In line 6, we populate a department field named <code>secret</code> with the boolean value <code>true</code>. This field does not exist in the model. Therefore it will be stored in the <code>ext</code> column of the <code>dept</code> table.</li>



<li>In line 13, we set the <code>mgr</code> field to <code>1</code>. That&#8217;s the foreign key column in the <code>emp</code> table.</li>



<li>In line 16 we populate an employee field named <code>tools</code> with an array. The field does not exist in the model. Therefore it will be stored in the <code>ext</code> column of the <code>emp</code> table.   </li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">7) Insert into duality view (extending the schema)</span><span role="button" tabindex="0" data-code="insert into dept_dv values ('
{
  &quot;_id&quot; : 50,
  &quot;dname&quot; : &quot;MI6&quot;,
  &quot;loc&quot; : &quot;LONDON&quot;,
  &quot;secret&quot; : true,
  &quot;emps&quot; :
  [
    {
      &quot;empno&quot; : 7,
      &quot;ename&quot; : &quot;BOND&quot;,
      &quot;job&quot; : &quot;AGENT&quot;,
      &quot;mgr&quot; : 1,
      &quot;hiredate&quot; : &quot;1950-01-01T00:00:00&quot;,
      &quot;sal&quot; : 500,
      &quot;tools&quot; : [&quot;Knife&quot;, &quot;Garrote Watch&quot;, &quot;Walther PPK&quot;]
    },
    {
      &quot;empno&quot; : 1,
      &quot;ename&quot; : &quot;M&quot;,
      &quot;job&quot; : &quot;MANAGER&quot;,
      &quot;hiredate&quot; : &quot;1940-01-01T00:00:00&quot;,
      &quot;sal&quot; : 1000,
      &quot;comm&quot; : 8000
    }
  ]
}
');
commit;

select * from dept where deptno = 50;
select * from emp where deptno = 50;
select json_serialize(data returning clob pretty) as data 
  from dept_dv dv
 where dv.data.secret.booleanOnly();" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">insert</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">into</span><span style="color: #D4D4D4"> dept_dv </span><span style="color: #569CD6">values</span><span style="color: #D4D4D4"> (</span><span style="color: #CE9178">&#39;</span></span>
<span class="line"><span style="color: #CE9178">{</span></span>
<span class="line"><span style="color: #CE9178">  &quot;_id&quot; : 50,</span></span>
<span class="line"><span style="color: #CE9178">  &quot;dname&quot; : &quot;MI6&quot;,</span></span>
<span class="line"><span style="color: #CE9178">  &quot;loc&quot; : &quot;LONDON&quot;,</span></span>
<span class="line cbp-line-highlight"><span style="color: #CE9178">  &quot;secret&quot; : true,</span></span>
<span class="line"><span style="color: #CE9178">  &quot;emps&quot; :</span></span>
<span class="line"><span style="color: #CE9178">  [</span></span>
<span class="line"><span style="color: #CE9178">    {</span></span>
<span class="line"><span style="color: #CE9178">      &quot;empno&quot; : 7,</span></span>
<span class="line"><span style="color: #CE9178">      &quot;ename&quot; : &quot;BOND&quot;,</span></span>
<span class="line"><span style="color: #CE9178">      &quot;job&quot; : &quot;AGENT&quot;,</span></span>
<span class="line cbp-line-highlight"><span style="color: #CE9178">      &quot;mgr&quot; : 1,</span></span>
<span class="line"><span style="color: #CE9178">      &quot;hiredate&quot; : &quot;1950-01-01T00:00:00&quot;,</span></span>
<span class="line"><span style="color: #CE9178">      &quot;sal&quot; : 500,</span></span>
<span class="line cbp-line-highlight"><span style="color: #CE9178">      &quot;tools&quot; : [&quot;Knife&quot;, &quot;Garrote Watch&quot;, &quot;Walther PPK&quot;]</span></span>
<span class="line"><span style="color: #CE9178">    },</span></span>
<span class="line"><span style="color: #CE9178">    {</span></span>
<span class="line"><span style="color: #CE9178">      &quot;empno&quot; : 1,</span></span>
<span class="line"><span style="color: #CE9178">      &quot;ename&quot; : &quot;M&quot;,</span></span>
<span class="line"><span style="color: #CE9178">      &quot;job&quot; : &quot;MANAGER&quot;,</span></span>
<span class="line"><span style="color: #CE9178">      &quot;hiredate&quot; : &quot;1940-01-01T00:00:00&quot;,</span></span>
<span class="line"><span style="color: #CE9178">      &quot;sal&quot; : 1000,</span></span>
<span class="line"><span style="color: #CE9178">      &quot;comm&quot; : 8000</span></span>
<span class="line"><span style="color: #CE9178">    }</span></span>
<span class="line"><span style="color: #CE9178">  ]</span></span>
<span class="line"><span style="color: #CE9178">}</span></span>
<span class="line"><span style="color: #CE9178">&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #DCDCAA">commit</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> * </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> deptno = </span><span style="color: #B5CEA8">50</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> * </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> emp </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> deptno = </span><span style="color: #B5CEA8">50</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> json_serialize(data </span><span style="color: #569CD6">returning</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">clob</span><span style="color: #D4D4D4"> pretty) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> data </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept_dv dv</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> dv.data.secret.booleanOnly();</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);--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" data-code="1 row inserted.


Commit complete.


    DEPTNO DNAME          LOC           EXT
---------- -------------- ------------- --------------------
        50 MI6            LONDON        {&quot;secret&quot;:true}


     EMPNO ENAME      JOB              MGR HIREDATE          SAL       COMM     DEPTNO EXT
---------- ---------- --------- ---------- ---------- ---------- ---------- ---------- ---------------------------------------------------
         1 M          MANAGER              1940-01-01       1000       8000         50
         7 BOND       AGENT              1 1950-01-01        500                    50 {&quot;tools&quot;:[&quot;Knife&quot;,&quot;Garrote Watch&quot;,&quot;Walther PPK&quot;]}


DATA
------------------------------------------------
{
  &quot;_id&quot; : 50,
  &quot;_metadata&quot; :
  {
    &quot;etag&quot; : &quot;486256AA33D638F4D339FFE534EC910F&quot;,
    &quot;asof&quot; : &quot;0000256530950ADB&quot;
  },
  &quot;dname&quot; : &quot;MI6&quot;,
  &quot;loc&quot; : &quot;LONDON&quot;,
  &quot;emps&quot; :
  [
    {
      &quot;empno&quot; : 1,
      &quot;ename&quot; : &quot;M&quot;,
      &quot;job&quot; : &quot;MANAGER&quot;,
      &quot;hiredate&quot; : &quot;1940-01-01T00:00:00&quot;,
      &quot;sal&quot; : 1000,
      &quot;comm&quot; : 8000
    },
    {
      &quot;empno&quot; : 7,
      &quot;ename&quot; : &quot;BOND&quot;,
      &quot;job&quot; : &quot;AGENT&quot;,
      &quot;mgr&quot; : 1,
      &quot;mgrname&quot; : &quot;M&quot;,
      &quot;hiredate&quot; : &quot;1950-01-01T00:00:00&quot;,
      &quot;sal&quot; : 500,
      &quot;comm&quot; : null,
      &quot;tools&quot; :
      [
        &quot;Knife&quot;,
        &quot;Garrote Watch&quot;,
        &quot;Walther PPK&quot;
      ]
    }
  ],
  &quot;secret&quot; : true
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">1 row inserted.</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">Commit complete.</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">    DEPTNO DNAME          LOC           EXT</span></span>
<span class="line"><span style="color: #D4D4D4">---------- -------------- ------------- --------------------</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        50 MI6            LONDON        {&quot;secret&quot;:true}</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">     EMPNO ENAME      JOB              MGR HIREDATE          SAL       COMM     DEPTNO EXT</span></span>
<span class="line"><span style="color: #D4D4D4">---------- ---------- --------- ---------- ---------- ---------- ---------- ---------- ---------------------------------------------------</span></span>
<span class="line"><span style="color: #D4D4D4">         1 M          MANAGER              1940-01-01       1000       8000         50</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">         7 BOND       AGENT              1 1950-01-01        500                    50 {&quot;tools&quot;:[&quot;Knife&quot;,&quot;Garrote Watch&quot;,&quot;Walther PPK&quot;]}</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">DATA</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">  &quot;_id&quot; : 50,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;_metadata&quot; :</span></span>
<span class="line"><span style="color: #D4D4D4">  {</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;etag&quot; : &quot;486256AA33D638F4D339FFE534EC910F&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;asof&quot; : &quot;0000256530950ADB&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  },</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;dname&quot; : &quot;MI6&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;loc&quot; : &quot;LONDON&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;emps&quot; :</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">      &quot;empno&quot; : 1,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;ename&quot; : &quot;M&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;job&quot; : &quot;MANAGER&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;hiredate&quot; : &quot;1940-01-01T00:00:00&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;sal&quot; : 1000,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;comm&quot; : 8000</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">      &quot;empno&quot; : 7,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;ename&quot; : &quot;BOND&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;job&quot; : &quot;AGENT&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgr&quot; : 1,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgrname&quot; : &quot;M&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;hiredate&quot; : &quot;1950-01-01T00:00:00&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;sal&quot; : 500,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;comm&quot; : null,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">      &quot;tools&quot; :</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">      [</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        &quot;Knife&quot;,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        &quot;Garrote Watch&quot;,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        &quot;Walther PPK&quot;</span></span>
<span class="line cbp-line-highlight"><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 cbp-line-highlight"><span style="color: #D4D4D4">  &quot;secret&quot; : true</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">One insert statement leads to three new rows in two tables. Before 23ai, a view and an instead-of trigger would have been required for this.</p>



<p class="wp-block-paragraph">The fields <code>secret</code> and <code>tools</code> are automatically stored in the flex columns <code>ext</code>. This shows how easy it is to extend the data model on the fly with an <code>insert</code> statement. Without DDL statements. Without PL/SQL code.</p>



<h2 class="wp-block-heading" id="update-duality-view">8. Update Duality View</h2>



<p class="wp-block-paragraph">Let&#8217;s update the previously created document.</p>



<h5 class="wp-block-heading">Some explanations</h5>



<ul class="wp-block-list">
<li>In line 4, we add a new field named <code>street</code> for the department <code>50</code>.</li>



<li>In line 6, we change the salary for all employees in the department <code>50</code> by the factor of <code>42</code>.</li>



<li>In line 9, we increase the salary of <code>BOND</code> by <code>1</code>. Please note that this is the second change of the salary for this employee in this <code>update</code> statement.</li>



<li>In line 10, we append the <code>Aston Martin DB5</code> to the list of <code>BOND</code>&#8216;s tools.</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">8) Update duality view (extending the schema again)</span><span role="button" tabindex="0" data-code="update dept_dv v
   set v.data = json_transform(
                   v.data, 
                   set '$.street' = '85 Albert Embankment',
                   nested '$.emps[*]' (
                      set '@.sal' = path '@.sal * 42'
                   ),
                   nested '$.emps[*]?(@.ename == &quot;BOND&quot;)' (
                      set '@.sal' = path '@.sal + 1',
                      append '@.tools' = 'Aston Martin DB5'
                   )
                )
 where v.data.&quot;_id&quot;.numberOnly() = 50;
commit;

select * from dept where deptno = 50;
select * from emp where deptno = 50;
select json_serialize(data returning clob pretty) as data 
  from dept_dv v
 where v.data.&quot;_id&quot;.numberOnly() = 50;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">update</span><span style="color: #D4D4D4"> dept_dv v</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> v.data = json_transform(</span></span>
<span class="line"><span style="color: #D4D4D4">                   v.data, </span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                   </span><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;$.street&#39;</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&#39;85 Albert Embankment&#39;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                   nested </span><span style="color: #CE9178">&#39;$.emps[*]&#39;</span><span style="color: #D4D4D4"> (</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                      </span><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;@.sal&#39;</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">path</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;@.sal * 42&#39;</span></span>
<span class="line"><span style="color: #D4D4D4">                   ),</span></span>
<span class="line"><span style="color: #D4D4D4">                   nested </span><span style="color: #CE9178">&#39;$.emps[*]?(@.ename == &quot;BOND&quot;)&#39;</span><span style="color: #D4D4D4"> (</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                      </span><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;@.sal&#39;</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">path</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;@.sal + 1&#39;</span><span style="color: #D4D4D4">,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                      append </span><span style="color: #CE9178">&#39;@.tools&#39;</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&#39;Aston Martin DB5&#39;</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: #569CD6">where</span><span style="color: #D4D4D4"> v.data.</span><span style="color: #CE9178">&quot;_id&quot;</span><span style="color: #D4D4D4">.numberOnly() = </span><span style="color: #B5CEA8">50</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #DCDCAA">commit</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> * </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> deptno = </span><span style="color: #B5CEA8">50</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> * </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> emp </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> deptno = </span><span style="color: #B5CEA8">50</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> json_serialize(data </span><span style="color: #569CD6">returning</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">clob</span><span style="color: #D4D4D4"> pretty) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> data </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept_dv v</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> v.data.</span><span style="color: #CE9178">&quot;_id&quot;</span><span style="color: #D4D4D4">.numberOnly() = </span><span style="color: #B5CEA8">50</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(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 role="button" tabindex="0" data-code="1 row updated.


Commit complete.


    DEPTNO DNAME          LOC           EXT
---------- -------------- ------------- -----------------------------------------------
        50 MI6            LONDON        {&quot;secret&quot;:true,&quot;street&quot;:&quot;85 Albert Embankment&quot;}


     EMPNO ENAME      JOB              MGR HIREDATE          SAL       COMM     DEPTNO EXT
---------- ---------- --------- ---------- ---------- ---------- ---------- ---------- ----------------------------------------------------------------------
         1 M          MANAGER              1940-01-01      42000       8000         50
         7 BOND       AGENT              1 1950-01-01      21001                    50 {&quot;tools&quot;:[&quot;Knife&quot;,&quot;Garrote Watch&quot;,&quot;Walther PPK&quot;,&quot;Aston Martin DB5&quot;]}


DATA
------------------------------------------------
{
  &quot;_id&quot; : 50,
  &quot;_metadata&quot; :
  {
    &quot;etag&quot; : &quot;1591A6C3A20C4BC85C0498F7B1F4031F&quot;,
    &quot;asof&quot; : &quot;000025653374F0C7&quot;
  },
  &quot;dname&quot; : &quot;MI6&quot;,
  &quot;loc&quot; : &quot;LONDON&quot;,
  &quot;emps&quot; :
  [
    {
      &quot;empno&quot; : 1,
      &quot;ename&quot; : &quot;M&quot;,
      &quot;job&quot; : &quot;MANAGER&quot;,
      &quot;hiredate&quot; : &quot;1940-01-01T00:00:00&quot;,
      &quot;sal&quot; : 42000,
      &quot;comm&quot; : 8000
    },
    {
      &quot;empno&quot; : 7,
      &quot;ename&quot; : &quot;BOND&quot;,
      &quot;job&quot; : &quot;AGENT&quot;,
      &quot;mgr&quot; : 1,
      &quot;mgrname&quot; : &quot;M&quot;,
      &quot;hiredate&quot; : &quot;1950-01-01T00:00:00&quot;,
      &quot;sal&quot; : 21001,
      &quot;comm&quot; : null,
      &quot;tools&quot; :
      [
        &quot;Knife&quot;,
        &quot;Garrote Watch&quot;,
        &quot;Walther PPK&quot;,
        &quot;Aston Martin DB5&quot;
      ]
    }
  ],
  &quot;secret&quot; : true,
  &quot;street&quot; : &quot;85 Albert Embankment&quot;
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">1 row updated.</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">Commit complete.</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">    DEPTNO DNAME          LOC           EXT</span></span>
<span class="line"><span style="color: #D4D4D4">---------- -------------- ------------- -----------------------------------------------</span></span>
<span class="line"><span style="color: #D4D4D4">        50 MI6            LONDON        {&quot;secret&quot;:true,&quot;street&quot;:&quot;85 Albert Embankment&quot;}</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">     EMPNO ENAME      JOB              MGR HIREDATE          SAL       COMM     DEPTNO EXT</span></span>
<span class="line"><span style="color: #D4D4D4">---------- ---------- --------- ---------- ---------- ---------- ---------- ---------- ----------------------------------------------------------------------</span></span>
<span class="line"><span style="color: #D4D4D4">         1 M          MANAGER              1940-01-01      42000       8000         50</span></span>
<span class="line"><span style="color: #D4D4D4">         7 BOND       AGENT              1 1950-01-01      21001                    50 {&quot;tools&quot;:[&quot;Knife&quot;,&quot;Garrote Watch&quot;,&quot;Walther PPK&quot;,&quot;Aston Martin DB5&quot;]}</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">DATA</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">  &quot;_id&quot; : 50,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;_metadata&quot; :</span></span>
<span class="line"><span style="color: #D4D4D4">  {</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;etag&quot; : &quot;1591A6C3A20C4BC85C0498F7B1F4031F&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;asof&quot; : &quot;000025653374F0C7&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  },</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;dname&quot; : &quot;MI6&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;loc&quot; : &quot;LONDON&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">  &quot;emps&quot; :</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">      &quot;empno&quot; : 1,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;ename&quot; : &quot;M&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;job&quot; : &quot;MANAGER&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;hiredate&quot; : &quot;1940-01-01T00:00:00&quot;,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">      &quot;sal&quot; : 42000,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;comm&quot; : 8000</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">      &quot;empno&quot; : 7,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;ename&quot; : &quot;BOND&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;job&quot; : &quot;AGENT&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgr&quot; : 1,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;mgrname&quot; : &quot;M&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;hiredate&quot; : &quot;1950-01-01T00:00:00&quot;,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">      &quot;sal&quot; : 21001,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;comm&quot; : null,</span></span>
<span class="line"><span style="color: #D4D4D4">      &quot;tools&quot; :</span></span>
<span class="line"><span style="color: #D4D4D4">      [</span></span>
<span class="line"><span style="color: #D4D4D4">        &quot;Knife&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">        &quot;Garrote Watch&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">        &quot;Walther PPK&quot;,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        &quot;Aston Martin DB5&quot;</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>
<span class="line"><span style="color: #D4D4D4">  &quot;secret&quot; : true,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">  &quot;street&quot; : &quot;85 Albert Embankment&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h2 class="wp-block-heading" id="delete-from-duality-view">9. Delete From Duality View</h2>



<p class="wp-block-paragraph">And now, let&#8217;s delete department 50 with all its employees to restore the original content of the <code>dept</code> and <code>emp</code> tables.</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">9) Delete from duality view</span><span role="button" tabindex="0" data-code="delete dept_dv v
 where v.data.&quot;_id&quot;.numberOnly() = 50;
commit;

select * from dept order by deptno;
select * from emp order by deptno, empno;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">delete</span><span style="color: #D4D4D4"> dept_dv v</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> v.data.</span><span style="color: #CE9178">&quot;_id&quot;</span><span style="color: #D4D4D4">.numberOnly() = </span><span style="color: #B5CEA8">50</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #DCDCAA">commit</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> * </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> deptno;</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> * </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> emp </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> deptno, empno;</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);--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" data-code="1 row deleted.


Commit complete.


    DEPTNO DNAME          LOC           EXT
---------- -------------- ------------- --------------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON


     EMPNO ENAME      JOB              MGR HIREDATE          SAL       COMM     DEPTNO EXT
---------- ---------- --------- ---------- ---------- ---------- ---------- ---------- --------------------
      7782 CLARK      MANAGER         7839 1981-06-09       2450                    10
      7839 KING       PRESIDENT            1981-11-17       5000                    10
      7934 MILLER     CLERK           7782 1982-01-23       1300                    10
      7369 SMITH      CLERK           7902 1980-12-17        800                    20
      7566 JONES      MANAGER         7839 1981-04-02       2975                    20
      7788 SCOTT      ANALYST         7566 1987-04-19       3000                    20
      7876 ADAMS      CLERK           7788 1987-05-23       1100                    20
      7902 FORD       ANALYST         7566 1981-12-03       3000                    20
      7499 ALLEN      SALESMAN        7698 1981-02-20       1600        300         30
      7521 WARD       SALESMAN        7698 1981-02-22       1250        500         30
      7654 MARTIN     SALESMAN        7698 1981-09-28       1250       1400         30
      7698 BLAKE      MANAGER         7839 1981-05-01       2850                    30
      7844 TURNER     SALESMAN        7698 1981-09-08       1500          0         30
      7900 JAMES      CLERK           7698 1981-12-03        950                    30

14 rows selected." style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">1 row deleted.</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">Commit complete.</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">    DEPTNO DNAME          LOC           EXT</span></span>
<span class="line"><span style="color: #D4D4D4">---------- -------------- ------------- --------------------</span></span>
<span class="line"><span style="color: #D4D4D4">        10 ACCOUNTING     NEW YORK</span></span>
<span class="line"><span style="color: #D4D4D4">        20 RESEARCH       DALLAS</span></span>
<span class="line"><span style="color: #D4D4D4">        30 SALES          CHICAGO</span></span>
<span class="line"><span style="color: #D4D4D4">        40 OPERATIONS     BOSTON</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">     EMPNO ENAME      JOB              MGR HIREDATE          SAL       COMM     DEPTNO EXT</span></span>
<span class="line"><span style="color: #D4D4D4">---------- ---------- --------- ---------- ---------- ---------- ---------- ---------- --------------------</span></span>
<span class="line"><span style="color: #D4D4D4">      7782 CLARK      MANAGER         7839 1981-06-09       2450                    10</span></span>
<span class="line"><span style="color: #D4D4D4">      7839 KING       PRESIDENT            1981-11-17       5000                    10</span></span>
<span class="line"><span style="color: #D4D4D4">      7934 MILLER     CLERK           7782 1982-01-23       1300                    10</span></span>
<span class="line"><span style="color: #D4D4D4">      7369 SMITH      CLERK           7902 1980-12-17        800                    20</span></span>
<span class="line"><span style="color: #D4D4D4">      7566 JONES      MANAGER         7839 1981-04-02       2975                    20</span></span>
<span class="line"><span style="color: #D4D4D4">      7788 SCOTT      ANALYST         7566 1987-04-19       3000                    20</span></span>
<span class="line"><span style="color: #D4D4D4">      7876 ADAMS      CLERK           7788 1987-05-23       1100                    20</span></span>
<span class="line"><span style="color: #D4D4D4">      7902 FORD       ANALYST         7566 1981-12-03       3000                    20</span></span>
<span class="line"><span style="color: #D4D4D4">      7499 ALLEN      SALESMAN        7698 1981-02-20       1600        300         30</span></span>
<span class="line"><span style="color: #D4D4D4">      7521 WARD       SALESMAN        7698 1981-02-22       1250        500         30</span></span>
<span class="line"><span style="color: #D4D4D4">      7654 MARTIN     SALESMAN        7698 1981-09-28       1250       1400         30</span></span>
<span class="line"><span style="color: #D4D4D4">      7698 BLAKE      MANAGER         7839 1981-05-01       2850                    30</span></span>
<span class="line"><span style="color: #D4D4D4">      7844 TURNER     SALESMAN        7698 1981-09-08       1500          0         30</span></span>
<span class="line"><span style="color: #D4D4D4">      7900 JAMES      CLERK           7698 1981-12-03        950                    30</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>



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



<p class="wp-block-paragraph">One thing is missing in version 0.9 of IslandSQL grammar. The support of PL/pgSQL in PostgreSQL statements <code>create function</code>, <code>create procedure</code>, <code>create trigger</code> and <code>do</code>. These statements can already be parsed but the PL/pgSQL code passed as string is not further analyzed. This will change in the next and final episode of this season.</p>
<p>The post <a href="https://www.salvis.com/blog/2024/06/27/islandsql-episode-9-graphql-json-and-flexible-schemas-with-duality-views/">IslandSQL Episode 9: GraphQL, JSON and Flexible Schemas With Duality Views</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
