<?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>Java Archives - Philipp Salvisberg&#039;s Blog</title>
	<atom:link href="https://www.salvis.com/blog/tag/java/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.salvis.com/blog/tag/java/</link>
	<description>Database-centric development</description>
	<lastBuildDate>Sat, 13 Jan 2024 15:02:41 +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>Java Archives - Philipp Salvisberg&#039;s Blog</title>
	<link>https://www.salvis.com/blog/tag/java/</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/java/feed/"/>
	<item>
		<title>IslandSQL Episode 3: Lock Table</title>
		<link>https://www.salvis.com/blog/2023/02/19/islandsql-episode-3-lock-table/</link>
					<comments>https://www.salvis.com/blog/2023/02/19/islandsql-episode-3-lock-table/#comments</comments>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Sun, 19 Feb 2023 16:27:05 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[ANTLR]]></category>
		<category><![CDATA[Code Analysis]]></category>
		<category><![CDATA[IslandSQL]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[VSCode]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=12127</guid>

					<description><![CDATA[<p>Introduction In the&#160;last episode, we extended the IslandSQL grammar to cover all DML statements as a single lexer token. Now it&#8217;s time to handle the complete grammar for one DML statement. The simplest one is lock table. A good reason to start with it and lay the foundation for the other DML<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2023/02/19/islandsql-episode-3-lock-table/">IslandSQL Episode 3: Lock Table</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&nbsp;<a href="https://www.salvis.com/blog/2023/02/07/islandsql-episode-2-all-dml-statements/">last episode</a>, we extended the IslandSQL grammar to cover all DML statements as a single lexer token. Now it&#8217;s time to handle the complete grammar for one DML statement. The simplest one is <code>lock table</code>. A good reason to start with it and lay the foundation for the other DML commands.</p>



<p class="wp-block-paragraph">The full source code is available on&nbsp;<a href="https://github.com/IslandSQL/IslandSQL/tree/v0.3.1">GitHub</a>&nbsp;and the binaries on&nbsp;<a href="https://central.sonatype.com/artifact/ch.islandsql/islandsql/0.3.1">Maven Central</a>.</p>



<h2 class="wp-block-heading">Grammars in SQL Scripts</h2>



<p class="wp-block-paragraph">When using SQL scripts, we work with several grammars. There is always more than one grammar involved. It depends on your use case how much more.</p>



<p class="wp-block-paragraph">The candidates when working with an Oracle Database 21c are:</p>



<ul class="wp-block-list">
<li>SQL*Plus</li>



<li>SQLcl</li>



<li>PGQL</li>



<li>SQL</li>



<li>PL/SQL</li>



<li>Java</li>



<li>more hidden in strings and LOBs such as XML, XSLT, JSON, &#8230;</li>
</ul>



<p class="wp-block-paragraph">The number of grammars is growing. For example, we expect JavaScript stored procedures in Oracle Database 23c.</p>



<p class="wp-block-paragraph">In the previous episodes, we have primarily dealt with SQL*Plus and SQL as a whole. Before we deal with a specific SQL statement such as <code>lock table</code>, we need to know where a SQL statement starts and where it ends. The start seems obvious, but the end? Is the fragment <code>SQL_END</code> correctly describing the end of a SQL statement?</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) ANTLR fragment SQL_END</span><span role="button" tabindex="0" data-code="fragment SQL_END:
      EOF
    | (';' [ \t]* SINGLE_NL?)
    | SLASH_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: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #C8C8C8">SQL_END</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #4FC1FF">EOF</span></span>
<span class="line"><span style="color: #D4D4D4">    | (</span><span style="color: #CE9178">&#39;;&#39;</span><span style="color: #D4D4D4"> [ \</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">]* </span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">?)</span></span>
<span class="line"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">SLASH_END</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span></code></pre></div>



<h2 class="wp-block-heading">Where Does a SQL Statement End?</h2>



<p class="wp-block-paragraph">A common misconception is, that a SQL statement ends with a semicolon. This seems to be true when you only look at the syntax per statement in the Oracle Database documentation, but it is not. 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">2) Lock table in dynamic SQL</span><span role="button" tabindex="0" data-code="begin
   execute immediate '
      lock table dept in exclusive mode
   ';
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">execute immediate</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;</span></span>
<span class="line"><span style="color: #CE9178">      lock table dept in exclusive mode</span></span>
<span class="line"><span style="color: #CE9178">   &#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span></code></pre></div>



<p class="wp-block-paragraph">The anonymous PL/SQL block executes a dynamic <code>lock table</code> statement on line 3. Please note that the <code>lock table</code> statement starts with whitespace and ends with whitespace. We do not pass a semicolon as part of the <code>execute immediate</code> statement. This anonymous PL/SQL block completes successfully when the connected user can lock <code>emp</code>.</p>



<p class="wp-block-paragraph">However, when we add a semicolon at the end of the <code>lock table</code> statement we get the following error:</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">3) Error when using semicolon in dynamic SQL</span><span role="button" tabindex="0" data-code="Error starting at line : 1 in command -
begin
   execute immediate '
      lock table dept in exclusive mode;
   ';
end;
Error report -
ORA-00933: SQL command not properly ended
ORA-06512: at line 2
00933. 00000 -  &quot;SQL command not properly ended&quot;
*Cause:    
*Action:" 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">Error starting at line : 1 in command -</span></span>
<span class="line"><span style="color: #D4D4D4">begin</span></span>
<span class="line"><span style="color: #D4D4D4">   execute immediate &#39;</span></span>
<span class="line"><span style="color: #D4D4D4">      lock table dept in exclusive mode;</span></span>
<span class="line"><span style="color: #D4D4D4">   &#39;;</span></span>
<span class="line"><span style="color: #D4D4D4">end;</span></span>
<span class="line"><span style="color: #D4D4D4">Error report -</span></span>
<span class="line"><span style="color: #D4D4D4">ORA-00933: SQL command not properly ended</span></span>
<span class="line"><span style="color: #D4D4D4">ORA-06512: at line 2</span></span>
<span class="line"><span style="color: #D4D4D4">00933. 00000 -  &quot;SQL command not properly ended&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">*Cause:    </span></span>
<span class="line"><span style="color: #D4D4D4">*Action:</span></span></code></pre></div>



<p class="wp-block-paragraph">It&#8217;s not allowed to terminate a SQL statement with a semicolon in dynamic SQL and therefore also when executing SQL via JDBC or ODBC.</p>



<p class="wp-block-paragraph">But what is the semicolon for? Well, it terminates a SQL statement within a SQL*Plus or SQLcl script. In SQL*Plus you can change the behaviour using the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/21/sqpug/SET-system-variable-summary.html#GUID-5D91A9A9-13A2-4F62-B02A-AD2F3AFF8BB7">set sqlterminator</a> command.</p>



<p class="wp-block-paragraph">The following script works in SQL*Plus (but not in SQLcl, it&#8217;s a <a href="https://docs.oracle.com/en/database/oracle/sql-developer-command-line/22.4/sqcug/list-unsupported-commands-and-features-sqlplus.html">documented limitation</a>):</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 dollar sign instead of semicolon to terminate SQL statement</span><span role="button" tabindex="0" data-code="set sqlterminator $
lock table dept in exclusive mode$" 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"> sqlterminator $</span></span>
<span class="line"><span style="color: #D4D4D4">lock </span><span style="color: #569CD6">table</span><span style="color: #D4D4D4"> dept </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> exclusive mode$</span></span></code></pre></div>



<p class="wp-block-paragraph">The semicolon is the default terminator of SQL statements in SQL scripts. The semicolon is part of the SQL*Plus grammar but not part of the SQL grammar. However, it is more. It is also the only supported statement terminator in PL/SQL as the following SQL*Plus script shows.</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) Statement terminator in PL/SQL</span><span role="button" tabindex="0" data-code="set sqlterminator $
begin
   lock table dept in exclusive mode;
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">set</span><span style="color: #D4D4D4"> sqlterminator $</span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">lock</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">table</span><span style="color: #D4D4D4"> dept </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">exclusive</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">mode</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span></code></pre></div>



<p class="wp-block-paragraph">The semicolon on line 4 terminates the anonymous PL/SQL block. It&#8217;s part of the PL/SQL grammar. The final slash is not part of the anonymous PL/SQL block. It is an alternative to the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/21/sqpug/RUN.html#GUID-C0504161-EFF9-4AF0-9F59-074F17B0CB85">SQL*Plus run</a> command. It sends the buffer (the anonymous PL/SQL block) to the database server.</p>



<p class="wp-block-paragraph">By the way, the Oracle Database documentation explains why it uses a semicolon in its grammar. Here is the corresponding quote:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Note: SQL statements are terminated differently in different programming environments. This documentation set uses the default SQL*Plus character, the semicolon (;).<br />&#8212; <a href="https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Lexical-Conventions.html">Lexical Conventions, SQL Language Reference. Oracle Datase 21c</a></p>
</blockquote>



<p class="wp-block-paragraph">Yes, the semicolon is part of the SQL*Plus grammar. There is no common sequence of characters for identifying the end of an SQL statement.</p>



<h2 class="wp-block-heading">What Are We Going to Do Now?</h2>



<p class="wp-block-paragraph">I initially wanted to use <a href="https://github.com/antlr/antlr4/blob/master/doc/lexer-rules.md#lexical-modes">ANTLR modes</a> to handle the complete grammar of chosen statements. However, ANTLR modes require that you can identify the start and the end of a mode. For the <code>lock mode</code> statement, the start is the <code>lock</code> keyword and the end is the <code>SQL_END</code> fragment as we used before. We could also use just the semicolon to determine the end. While this works for the <code>lock table</code> statement, it will cause some problems when trying to integrate the PL/SQL grammar.</p>



<p class="wp-block-paragraph">How do we find out whether a semicolon belongs to a PL/SQL statement or to an SQL statement? Is this possible in the lexer? Well, I think it&#8217;s possible by doing some semantic predicate acrobatics, but I don&#8217;t think it&#8217;s sensible.</p>



<p class="wp-block-paragraph">Another approach is to use two lexers. The first one, extracting the relevant statement in the scope of the IslandSQL grammar. And the second lexer processes only the extracted statements. The parser uses the token stream from the second lexer. Perfect. However, we want to keep the original positions (line/column) of the tokens in scope. They are important for navigating to the right place in the code. How do we do that?</p>



<h2 class="wp-block-heading">Keep Hidden Tokens as Whitespace</h2>



<p class="wp-block-paragraph">The idea is to replace all non-whitespace characters in hidden tokens with a space. This way the number of lines and the position in the line of all relevant tokens stay the same. The total number of characters is also the same (the number of bytes might change when multibyte characters are replaced).</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">6) Original SQL script</span><span role="button" tabindex="0" data-code="/* ===========================================
 * ignore multiline comment
 * =========================================== */
select * from dual;

rem ignore remark: select * from dual;

-- ignore single line comment
lock table dept in exclusive mode;" 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: #6A9955">/* ===========================================</span></span>
<span class="line"><span style="color: #6A9955"> * ignore multiline comment</span></span>
<span class="line"><span style="color: #6A9955"> * =========================================== */</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"> dual;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">rem </span><span style="color: #569CD6">ignore</span><span style="color: #D4D4D4"> remark: </span><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> * </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dual;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">-- ignore single line comment</span></span>
<span class="line"><span style="color: #D4D4D4">lock </span><span style="color: #569CD6">table</span><span style="color: #D4D4D4"> dept </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> exclusive mode;</span></span></code></pre></div>



<p class="wp-block-paragraph">After the transformation, the script should look 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">7) Transformed SQL script</span><span role="button" tabindex="0" data-code="..............................................
...........................
.................................................
select * from dual;

......................................

.............................
lock table dept in exclusive mode;" 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">...........................</span></span>
<span class="line"><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"> dual;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">......................................</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">.............................</span></span>
<span class="line"><span style="color: #D4D4D4">lock </span><span style="color: #569CD6">table</span><span style="color: #D4D4D4"> dept </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> exclusive mode;</span></span></code></pre></div>



<p class="wp-block-paragraph">Please note that a dot(<code>.</code>) represents a replaced character. Read a dot as a space.</p>



<p class="wp-block-paragraph">We can use this converted script as input for the second lexer.</p>



<p class="wp-block-paragraph">The implementation is relatively easy.&nbsp;I renamed the original lexer to <code>IslandSqlScopeLexer</code> und used this code for the transformation:</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">8) getScopeText() method</span><span role="button" tabindex="0" data-code="static public String getScopeText(CommonTokenStream tokenStream) {
    TokenStreamRewriter rewriter = new TokenStreamRewriter(tokenStream);
    tokenStream.fill();
    tokenStream.getTokens().stream()
            .filter(token -&gt; token.getChannel() == Token.HIDDEN_CHANNEL
                    &amp;&amp; token.getType() != IslandSqlScopeLexer.WS)
            .forEach(token -&gt; {
                        StringBuilder sb = new StringBuilder();
                        token.getText().codePoints().mapToObj(c -&gt; (char) c)
                                .forEach(c -&gt; sb.append(c == '\t' || c == '\r' || c == '\n' ? c : ' '));
                        rewriter.replace(token, sb.toString());
                    }
            );
    return rewriter.getText();
}" 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">static</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">String</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">getScopeText</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">CommonTokenStream</span><span style="color: #D4D4D4"> tokenStream) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #4EC9B0">TokenStreamRewriter</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">rewriter</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">new</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">TokenStreamRewriter</span><span style="color: #D4D4D4">(tokenStream);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">tokenStream</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">fill</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">tokenStream</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getTokens</span><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">(token </span><span style="color: #569CD6">-&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">token</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getChannel</span><span style="color: #D4D4D4">() == </span><span style="color: #9CDCFE">Token</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">HIDDEN_CHANNEL</span></span>
<span class="line"><span style="color: #D4D4D4">                    &amp;&amp; </span><span style="color: #9CDCFE">token</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getType</span><span style="color: #D4D4D4">() != </span><span style="color: #9CDCFE">IslandSqlScopeLexer</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">WS</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">            .</span><span style="color: #DCDCAA">forEach</span><span style="color: #D4D4D4">(token </span><span style="color: #569CD6">-&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #4EC9B0">StringBuilder</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sb</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">new</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">StringBuilder</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">token</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">codePoints</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">mapToObj</span><span style="color: #D4D4D4">(c </span><span style="color: #569CD6">-&gt;</span><span style="color: #D4D4D4"> (</span><span style="color: #4EC9B0">char</span><span style="color: #D4D4D4">) c)</span></span>
<span class="line"><span style="color: #D4D4D4">                                .</span><span style="color: #DCDCAA">forEach</span><span style="color: #D4D4D4">(c </span><span style="color: #569CD6">-&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sb</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">append</span><span style="color: #D4D4D4">(c == </span><span style="color: #CE9178">&#39;</span><span style="color: #D7BA7D">\t</span><span style="color: #CE9178">&#39;</span><span style="color: #D4D4D4"> || c == </span><span style="color: #CE9178">&#39;</span><span style="color: #D7BA7D">\r</span><span style="color: #CE9178">&#39;</span><span style="color: #D4D4D4"> || c == </span><span style="color: #CE9178">&#39;</span><span style="color: #D7BA7D">\n</span><span style="color: #CE9178">&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">?</span><span style="color: #D4D4D4"> c </span><span style="color: #C586C0">:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39; &#39;</span><span style="color: #D4D4D4">));</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">rewriter</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">replace</span><span style="color: #D4D4D4">(token, </span><span style="color: #9CDCFE">sb</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">toString</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 style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">rewriter</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></code></pre></div>



<p class="wp-block-paragraph">The method gets a token stream as input and returns the transformed text (SQL script).</p>



<p class="wp-block-paragraph">The ANTLR runtime comes with a <a href="https://www.antlr.org/api/Java/org/antlr/v4/runtime/TokenStreamRewriter.html">TokenStreamRewriter</a> that helps adding, deleting or changing tokens. We are only changing hidden tokens that are not of type whitespace. Tabs, carriage returns and line feeds are kept. Other characters are replaced by a space.</p>



<h2 class="wp-block-heading">The New Lexer</h2>



<p class="wp-block-paragraph">After the preprocessing of the original input, we can concentrate on the islands. The sea is represented as a whitespace. This simplifies the logic of the lexer.</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(3 * 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) IslandSqlLexer.g4: based on https://github.com/IslandSQL/IslandSQL/tree/v0.3.1/</span><span role="button" tabindex="0" data-code="lexer grammar IslandSqlLexer;

options {
    superClass=IslandSqlLexerBase;
    caseInsensitive = true;
}

/*----------------------------------------------------------------------------*/
// Fragments to name expressions and reduce code duplication
/*----------------------------------------------------------------------------*/

fragment SINGLE_NL: '\r'? '\n';
fragment COMMENT_OR_WS: ML_COMMENT|SL_COMMENT|WS;
fragment SQL_TEXT: (ML_COMMENT|SL_COMMENT|STRING|.);
fragment SLASH_END: SINGLE_NL WS* '/' [ \t]* (EOF|SINGLE_NL);
fragment PLSQL_DECLARATION_END: ';'? [ \t]* (EOF|SLASH_END);
fragment SQL_END:
      EOF
    | (';' [ \t]* SINGLE_NL?)
    | SLASH_END
;

/*----------------------------------------------------------------------------*/
// Hidden tokens
/*----------------------------------------------------------------------------*/

WS: [ \t\r\n]+ -&gt; channel(HIDDEN);
ML_COMMENT: '/*' .*? '*/' -&gt; channel(HIDDEN);
SL_COMMENT: '--' .*? (EOF|SINGLE_NL) -&gt; channel(HIDDEN);
CONDITIONAL_COMPILATION_DIRECTIVE: '$if' .*? '$end' -&gt; channel(HIDDEN);

/*----------------------------------------------------------------------------*/
// Keywords
/*----------------------------------------------------------------------------*/

K_EXCLUSIVE: 'exclusive';
K_FOR: 'for';
K_IN: 'in';
K_LOCK: 'lock';
K_MODE: 'mode';
K_NOWAIT: 'nowait';
K_PARTITION: 'partition';
K_ROW: 'row';
K_SHARE: 'share';
K_SUBPARTITION: 'subpartition';
K_TABLE: 'table';
K_UPDATE: 'update';
K_WAIT: 'wait';

/*----------------------------------------------------------------------------*/
// Special characters
/*----------------------------------------------------------------------------*/

AT_SIGN: '@';
CLOSE_PAREN: ')';
COMMA: ',';
DOT: '.';
OPEN_PAREN: '(';
SEMI: ';';
SLASH: '/';

/*----------------------------------------------------------------------------*/
// Data types
/*----------------------------------------------------------------------------*/

STRING:
    'n'?
    (
          (['] .*? ['])+
        | ('q' ['] '[' .*? ']' ['])
        | ('q' ['] '(' .*? ')' ['])
        | ('q' ['] '{' .*? '}' ['])
        | ('q' ['] '<' .*? '&gt;' ['])
        | ('q' ['] . {saveQuoteDelimiter1()}? .+? . ['] {checkQuoteDelimiter2()}?)
    )
;

INT: [0-9]+;

/*----------------------------------------------------------------------------*/
// Identifier
/*----------------------------------------------------------------------------*/

QUOTED_ID: '&quot;' .*? '&quot;' ('&quot;' .*? '&quot;')*;
ID: [\p{Alpha}] [_$#0-9\p{Alpha}]*;

/*----------------------------------------------------------------------------*/
// Islands of interest as single tokens
/*----------------------------------------------------------------------------*/

CALL:
    'call' COMMENT_OR_WS+ SQL_TEXT+? SQL_END
;

DELETE:
    'delete' COMMENT_OR_WS+ SQL_TEXT+? SQL_END
;

EXPLAIN_PLAN:
    'explain' COMMENT_OR_WS+ 'plan' COMMENT_OR_WS+ SQL_TEXT+? SQL_END
;

INSERT:
    'insert' COMMENT_OR_WS+ SQL_TEXT+? SQL_END
;

MERGE:
    'merge' COMMENT_OR_WS+ SQL_TEXT+? SQL_END
;

UPDATE:
    'update' COMMENT_OR_WS+ SQL_TEXT+? 'set' COMMENT_OR_WS+ SQL_TEXT+? SQL_END
;

SELECT:
    (
          ('with' COMMENT_OR_WS+ ('function'|'procedure') SQL_TEXT+? PLSQL_DECLARATION_END)
        | ('with' COMMENT_OR_WS+ SQL_TEXT+? SQL_END)
        | (('(' COMMENT_OR_WS*)* 'select' COMMENT_OR_WS SQL_TEXT+? SQL_END)
    )
;

/*----------------------------------------------------------------------------*/
// Any other token
/*----------------------------------------------------------------------------*/

ANY_OTHER: . -&gt; channel(HIDDEN);" 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: #9CDCFE">lexer</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">grammar</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IslandSqlLexer</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">options</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">superClass</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">IslandSqlLexerBase</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">caseInsensitive</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>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Fragments to name expressions and reduce code duplication</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #C8C8C8">SINGLE_NL</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;</span><span style="color: #D7BA7D">\r</span><span style="color: #CE9178">&#39;</span><span style="color: #D4D4D4">? </span><span style="color: #CE9178">&#39;</span><span style="color: #D7BA7D">\n</span><span style="color: #CE9178">&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">ML_COMMENT</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SL_COMMENT</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">WS</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #C8C8C8">SQL_TEXT</span><span style="color: #D4D4D4">: (</span><span style="color: #4FC1FF">ML_COMMENT</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SL_COMMENT</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">STRING</span><span style="color: #D4D4D4">|.);</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #C8C8C8">SLASH_END</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">WS</span><span style="color: #D4D4D4">* </span><span style="color: #CE9178">&#39;/&#39;</span><span style="color: #D4D4D4"> [ \</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">]* (</span><span style="color: #4FC1FF">EOF</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #C8C8C8">PLSQL_DECLARATION_END</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;;&#39;</span><span style="color: #D4D4D4">? [ \</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">]* (</span><span style="color: #4FC1FF">EOF</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SLASH_END</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SQL_END</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #4FC1FF">EOF</span></span>
<span class="line"><span style="color: #D4D4D4">    | (</span><span style="color: #CE9178">&#39;;&#39;</span><span style="color: #D4D4D4"> [ \</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">]* </span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">?)</span></span>
<span class="line"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">SLASH_END</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Hidden tokens</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">WS</span><span style="color: #D4D4D4">: [ \</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">\</span><span style="color: #9CDCFE">r</span><span style="color: #D4D4D4">\</span><span style="color: #9CDCFE">n</span><span style="color: #D4D4D4">]+ -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #4FC1FF">ML_COMMENT</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;/*&#39;</span><span style="color: #D4D4D4"> .*? </span><span style="color: #CE9178">&#39;*/&#39;</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #4FC1FF">SL_COMMENT</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;--&#39;</span><span style="color: #D4D4D4"> .*? (</span><span style="color: #4FC1FF">EOF</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">) -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #4FC1FF">CONDITIONAL_COMPILATION_DIRECTIVE</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;$if&#39;</span><span style="color: #D4D4D4"> .*? </span><span style="color: #CE9178">&#39;$end&#39;</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Keywords</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">K_EXCLUSIVE</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;exclusive&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">K_FOR</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;for&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">K_IN</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;in&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">K_LOCK</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;lock&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">K_MODE</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;mode&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">K_NOWAIT</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;nowait&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">K_PARTITION</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;partition&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">K_ROW</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;row&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">K_SHARE</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;share&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">K_SUBPARTITION</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;subpartition&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">K_TABLE</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;table&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">K_UPDATE</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;update&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">K_WAIT</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;wait&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Special characters</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">AT_SIGN</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;@&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">CLOSE_PAREN</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;)&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">COMMA</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;,&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">DOT</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;.&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">OPEN_PAREN</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;(&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">SEMI</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;;&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">SLASH</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;/&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Data types</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">STRING</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&#39;n&#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: #CE9178">&#39;] .*? [&#39;</span><span style="color: #D4D4D4">])+</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;q&#39;</span><span style="color: #D4D4D4"> [</span><span style="color: #CE9178">&#39;] &#39;</span><span style="color: #D4D4D4">[</span><span style="color: #CE9178">&#39; .*? &#39;</span><span style="color: #D4D4D4">]</span><span style="color: #CE9178">&#39; [&#39;</span><span style="color: #D4D4D4">])</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;q&#39;</span><span style="color: #D4D4D4"> [</span><span style="color: #CE9178">&#39;] &#39;</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39; .*? &#39;</span><span style="color: #D4D4D4">)</span><span style="color: #CE9178">&#39; [&#39;</span><span style="color: #D4D4D4">])</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;q&#39;</span><span style="color: #D4D4D4"> [</span><span style="color: #CE9178">&#39;] &#39;</span><span style="color: #D4D4D4">{</span><span style="color: #CE9178">&#39; .*? &#39;</span><span style="color: #D4D4D4">}</span><span style="color: #CE9178">&#39; [&#39;</span><span style="color: #D4D4D4">])</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;q&#39;</span><span style="color: #D4D4D4"> [</span><span style="color: #CE9178">&#39;] &#39;</span><span style="color: #D4D4D4">&lt;</span><span style="color: #CE9178">&#39; .*? &#39;</span><span style="color: #D4D4D4">&gt;</span><span style="color: #CE9178">&#39; [&#39;</span><span style="color: #D4D4D4">])</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;q&#39;</span><span style="color: #D4D4D4"> [</span><span style="color: #CE9178">&#39;] . {saveQuoteDelimiter1()}? .+? . [&#39;</span><span style="color: #D4D4D4">] {</span><span style="color: #DCDCAA">checkQuoteDelimiter2</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>
<span class="line"><span style="color: #4FC1FF">INT</span><span style="color: #D4D4D4">: [</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">-</span><span style="color: #B5CEA8">9</span><span style="color: #D4D4D4">]+;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Identifier</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">QUOTED_ID</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;&quot;&#39;</span><span style="color: #D4D4D4"> .*? </span><span style="color: #CE9178">&#39;&quot;&#39;</span><span style="color: #D4D4D4"> (</span><span style="color: #CE9178">&#39;&quot;&#39;</span><span style="color: #D4D4D4"> .*? </span><span style="color: #CE9178">&#39;&quot;&#39;</span><span style="color: #D4D4D4">)*;</span></span>
<span class="line"><span style="color: #4FC1FF">ID</span><span style="color: #D4D4D4">: [\</span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">{</span><span style="color: #9CDCFE">Alpha</span><span style="color: #D4D4D4">}] [</span><span style="color: #9CDCFE">_$</span><span style="color: #D4D4D4">#</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">-</span><span style="color: #B5CEA8">9</span><span style="color: #D4D4D4">\</span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">{</span><span style="color: #9CDCFE">Alpha</span><span style="color: #D4D4D4">}]*;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Islands of interest as single tokens</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">CALL</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&#39;call&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">DELETE</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&#39;delete&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">EXPLAIN_PLAN</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&#39;explain&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #CE9178">&#39;plan&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">INSERT</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&#39;insert&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">MERGE</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&#39;merge&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">UPDATE</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&#39;update&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #CE9178">&#39;set&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">SELECT</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: #CE9178">&#39;with&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ (</span><span style="color: #CE9178">&#39;function&#39;</span><span style="color: #D4D4D4">|</span><span style="color: #CE9178">&#39;procedure&#39;</span><span style="color: #D4D4D4">) </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">PLSQL_DECLARATION_END</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;with&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">        | ((</span><span style="color: #CE9178">&#39;(&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">*)* </span><span style="color: #CE9178">&#39;select&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</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>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Any other token</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">ANY_OTHER</span><span style="color: #D4D4D4">: . -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<h3 class="wp-block-heading">Options</h3>



<p class="wp-block-paragraph">The options are the same as in <code>IslandSqlScopeLexer</code>. We need the superclass <code>IslandSqlLexerBase</code> only in the <code>STRING</code> rule to handle all quote identifiers supported by the Oracle Database.</p>



<h3 class="wp-block-heading">Fragments</h3>



<p class="wp-block-paragraph">We moved the fragments section to the top. The fragments <code>CONTINUE_LINE</code>, <code>SQLPLUS_TEXT</code> and <code> SQLPLUS_END</code> are not required in this lexer. They are used in <code>IslandSqlLexerBase</code> to identify SQL*Plus commands as hidden tokens.</p>



<p class="wp-block-paragraph">Since we replaced all SQL*Plus commands with whitespace there is no need to handle SQL*Plus commands in this lexer.</p>



<h3 class="wp-block-heading">Hidden Tokens</h3>



<p class="wp-block-paragraph">In this section, we define the tokens that we do not need in the parser. Therefore we place them on the hidden channel.</p>



<p class="wp-block-paragraph">Wait, weren&#8217;t the hidden tokens replaced by whitespace? Yes, but only those that were not part of other tokens. However, the statements in scope (represented as a single token in <code>IslandSqlScopeLexer</code>) contain whitespace characters and maybe also comments or even conditional compilation directives (e.g. in plsql_declarations of a <code>select statement</code>). At the current stage of the grammar, the <code>CONDITIONAL_COMPILATION_DIRECTIVE</code> is de facto unused. We will need it (or some adequate replacement) once we are going to implement the <code>select</code> statement or other statements containing PL/SQL code.</p>



<h3 class="wp-block-heading">Keywords</h3>



<p class="wp-block-paragraph">It&#8217;s a good practice to define a rule for each token. This way we can control the names of the constants generated by ANTLR. We prefix the keywords with a <code>K_</code> to distinguish them from other rules/tokens. These keywords can also be used as identifiers in various contexts. At the current stage of the grammar, this section contains only the keywords used in the <code>lock table</code> statement of the Oracle Database 21c.</p>



<h3 class="wp-block-heading">Special Characters</h3>



<p class="wp-block-paragraph">The <code>lock table</code> statement uses these special characters.</p>



<h3 class="wp-block-heading">Data Types</h3>



<p class="wp-block-paragraph">The <code>STRING</code> rule is the same as in <code>IslandSqlScopeLexer</code>. It is a complete definition of a <a href="https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Literals.html#GUID-1824CBAA-6E16-4921-B2A6-112FB02248DA">text literal</a>. The <code>INT</code> rule is new. It defines an unsigned integer.</p>



<p class="wp-block-paragraph">In a future version of the grammar, we will need to support all <a href="https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Literals.html#GUID-F521FBA0-FFED-4079-ABC4-9052218B3FD5">numeric literals</a>. And of course also <a href="https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Literals.html#GUID-8F4B3F82-8821-4071-84D6-FBBA21C05AC1">date literals</a> and <a href="https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Literals.html#GUID-DC8D1DAD-7D04-45EA-9546-82810CD09A1B">interval literals</a>. We will split the implementation between the lexer and the parser. That will be a bit tricky. For now, let&#8217;s keep it simple. &#8211; An unsigned integer works in most cases.</p>



<h3 class="wp-block-heading">Identifier</h3>



<p class="wp-block-paragraph">In the lexer, we define two types of identifiers. Quoted and nonquoted Identifiers. See also <a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Database-Object-Names-and-Qualifiers.html#GUID-75337742-67FD-4EC0-985F-741C93D918DA">Database Object Naming Rules</a>. See also my blog post regarding unnecessary <a href="https://www.salvis.com/blog/2022/10/11/quoted-identifiers-joelkallmanday/">quoted identifiers</a>.</p>



<h3 class="wp-block-heading">Islands of Interest as Single Token</h3>



<p class="wp-block-paragraph">This is the same list of rules as in <code>IslandSqlScopeLexer</code>. The only rule that is missing is <code>LOCK_TABLE</code> since we are tokenizing this SQL statement completely.</p>



<p class="wp-block-paragraph">Please note that the <code>UPDATE</code> rule includes a <code>set</code> keyword. This is necessary because the keyword <code>update</code>&nbsp; is also part of the <code>lock table</code> statement. Without this change, a lock table emp in share update mode nowait; statement would be partly identified as <code>update</code> statement (<code>update mode nowait;</code>).</p>



<p class="wp-block-paragraph">The final version of the lexer will not contain statements as single tokens.</p>



<h3 class="wp-block-heading">Any Other Token</h3>



<p class="wp-block-paragraph">As in <code>IslandSqlScopeLexer</code> we put any other character on the hidden channel. This suppresses some errors in the parser. For example, we can insert a euro sign (<code>€</code>) or a pound sign (<code>£</code>) almost anywhere in the code without causing an error.</p>



<p class="wp-block-paragraph">In future versions of the lexer, we will put the <code>ANY_OTHER</code> token on the <code>DEFAULT_CHANNEL</code> to avoid this kind of error suppression.</p>



<h2 class="wp-block-heading">Parser Changes</h2>



<p class="wp-block-paragraph">The changes to the previous version of the parser are highlighted.</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(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">10) IslandSqlParser.g4: based on https://github.com/IslandSQL/IslandSQL/tree/v0.3.1/</span><span role="button" tabindex="0" data-code="parser grammar IslandSqlParser;

options {
    tokenVocab=IslandSqlLexer;
}

/*----------------------------------------------------------------------------*/
// Start rule
/*----------------------------------------------------------------------------*/

file: dmlStatement* EOF;

/*----------------------------------------------------------------------------*/
// Data Manipulation Language
/*----------------------------------------------------------------------------*/

dmlStatement:
      callStatement
    | deleteStatement
    | explainPlanStatement
    | insertStatement
    | lockTableStatement
    | mergeStatement
    | selectStatement
    | updateStatement
;

callStatement: CALL;
deleteStatement: DELETE;
explainPlanStatement: EXPLAIN_PLAN;
insertStatement: INSERT;
mergeStatement: MERGE;
updateStatement: UPDATE;
selectStatement: SELECT;

/*----------------------------------------------------------------------------*/
// Lock table
/*----------------------------------------------------------------------------*/

lockTableStatement:
    stmt=lockTableStatementUnterminated sqlEnd
;

lockTableStatementUnterminated:
    K_LOCK K_TABLE objects+=lockTableObject (COMMA objects+=lockTableObject)*
        K_IN lockmode=lockMode K_MODE waitOption=lockTableWaitOption?
;

lockTableObject:
    (schema=sqlName DOT)? table=sqlName
        (
              partitionExtensionClause
            | (AT_SIGN dblink=qualifiedName)
        )?
;

partitionExtensionClause:
      (K_PARTITION OPEN_PAREN name=sqlName CLOSE_PAREN)             # partition
    | (K_PARTITION K_FOR OPEN_PAREN
        (keys+=expression (COMMA keys+=expression)*) CLOSE_PAREN)   # partitionKeys
    | (K_SUBPARTITION OPEN_PAREN name=sqlName CLOSE_PAREN)          # subpartition
    | (K_SUBPARTITION K_FOR OPEN_PAREN
        (keys+=expression (COMMA keys+=expression)*) CLOSE_PAREN)   # subpartitionKeys
;

// TODO: complete according https://github.com/IslandSQL/IslandSQL/issues/11
expression:
      STRING        # stringLiteral
    | INT           # integerLiteral
    | sqlName       # sqlNameExpression
;

lockMode:
      (K_ROW K_SHARE)               # rowShare
    | (K_ROW K_EXCLUSIVE)           # rowExclusive
    | (K_SHARE K_UPDATE)            # shareUpdate
    | (K_SHARE)                     # share
    | (K_SHARE K_ROW K_EXCLUSIVE)   # shareRowExclusive
    | (K_EXCLUSIVE)                 # exclusive
;

lockTableWaitOption:
      K_NOWAIT                  # nowait
    | K_WAIT waitSeconds=INT    # wait
;

/*----------------------------------------------------------------------------*/
// Identifiers
/*----------------------------------------------------------------------------*/

keywordAsId:
      K_EXCLUSIVE
    | K_FOR
    | K_IN
    | K_LOCK
    | K_MODE
    | K_NOWAIT
    | K_PARTITION
    | K_ROW
    | K_SHARE
    | K_SUBPARTITION
    | K_TABLE
    | K_UPDATE
    | K_WAIT
;

unquotedId:
      ID
    | keywordAsId
;

sqlName:
      unquotedId
    | QUOTED_ID
;

qualifiedName:
	sqlName (DOT sqlName)*
;

/*----------------------------------------------------------------------------*/
// SQL statement end, slash accepted without preceeding newline
/*----------------------------------------------------------------------------*/

sqlEnd: EOF | SEMI | SLASH;" 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: #9CDCFE">parser</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">grammar</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IslandSqlParser</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">options</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">tokenVocab</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">IslandSqlLexer</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Start rule</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C8C8C8">file</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">dmlStatement</span><span style="color: #D4D4D4">* </span><span style="color: #4FC1FF">EOF</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line cbp-line-highlight"><span style="color: #6A9955">// Data Manipulation Language</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C8C8C8">dmlStatement</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #9CDCFE">callStatement</span></span>
<span class="line"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">deleteStatement</span></span>
<span class="line"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">explainPlanStatement</span></span>
<span class="line"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">insertStatement</span></span>
<span class="line"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">lockTableStatement</span></span>
<span class="line"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">mergeStatement</span></span>
<span class="line"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">selectStatement</span></span>
<span class="line"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">updateStatement</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C8C8C8">callStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">CALL</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C8C8C8">deleteStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">DELETE</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C8C8C8">explainPlanStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">EXPLAIN_PLAN</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C8C8C8">insertStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">INSERT</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C8C8C8">mergeStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">MERGE</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C8C8C8">updateStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">UPDATE</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C8C8C8">selectStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">SELECT</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line cbp-line-highlight"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line cbp-line-highlight"><span style="color: #6A9955">// Lock table</span></span>
<span class="line cbp-line-highlight"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">lockTableStatement</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">stmt</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">lockTableStatementUnterminated</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sqlEnd</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">lockTableStatementUnterminated</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    </span><span style="color: #4FC1FF">K_LOCK</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">K_TABLE</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">objects</span><span style="color: #D4D4D4">+=</span><span style="color: #DCDCAA">lockTableObject</span><span style="color: #D4D4D4"> (</span><span style="color: #4FC1FF">COMMA</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">objects</span><span style="color: #D4D4D4">+=</span><span style="color: #9CDCFE">lockTableObject</span><span style="color: #D4D4D4">)*</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        </span><span style="color: #4FC1FF">K_IN</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">lockmode</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">lockMode</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">K_MODE</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">waitOption</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">lockTableWaitOption</span><span style="color: #D4D4D4">?</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #9CDCFE">lockTableObject</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    (</span><span style="color: #9CDCFE">schema</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">sqlName</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">DOT</span><span style="color: #D4D4D4">)? </span><span style="color: #9CDCFE">table</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">sqlName</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        (</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">              </span><span style="color: #9CDCFE">partitionExtensionClause</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">            | (</span><span style="color: #4FC1FF">AT_SIGN</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">dblink</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">qualifiedName</span><span style="color: #D4D4D4">)</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        )?</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #9CDCFE">partitionExtensionClause</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">      (</span><span style="color: #4FC1FF">K_PARTITION</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">OPEN_PAREN</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">name</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">sqlName</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">CLOSE_PAREN</span><span style="color: #D4D4D4">)             # </span><span style="color: #9CDCFE">partition</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | (</span><span style="color: #4FC1FF">K_PARTITION</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">K_FOR</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">OPEN_PAREN</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        (</span><span style="color: #9CDCFE">keys</span><span style="color: #D4D4D4">+=</span><span style="color: #DCDCAA">expression</span><span style="color: #D4D4D4"> (</span><span style="color: #4FC1FF">COMMA</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">keys</span><span style="color: #D4D4D4">+=</span><span style="color: #9CDCFE">expression</span><span style="color: #D4D4D4">)*) </span><span style="color: #4FC1FF">CLOSE_PAREN</span><span style="color: #D4D4D4">)   # </span><span style="color: #9CDCFE">partitionKeys</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | (</span><span style="color: #4FC1FF">K_SUBPARTITION</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">OPEN_PAREN</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">name</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">sqlName</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">CLOSE_PAREN</span><span style="color: #D4D4D4">)          # </span><span style="color: #9CDCFE">subpartition</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | (</span><span style="color: #4FC1FF">K_SUBPARTITION</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">K_FOR</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">OPEN_PAREN</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        (</span><span style="color: #9CDCFE">keys</span><span style="color: #D4D4D4">+=</span><span style="color: #DCDCAA">expression</span><span style="color: #D4D4D4"> (</span><span style="color: #4FC1FF">COMMA</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">keys</span><span style="color: #D4D4D4">+=</span><span style="color: #9CDCFE">expression</span><span style="color: #D4D4D4">)*) </span><span style="color: #4FC1FF">CLOSE_PAREN</span><span style="color: #D4D4D4">)   # </span><span style="color: #9CDCFE">subpartitionKeys</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #6A9955">// TODO: complete according https://github.com/IslandSQL/IslandSQL/issues/11</span></span>
<span class="line cbp-line-highlight"><span style="color: #9CDCFE">expression</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">      </span><span style="color: #4FC1FF">STRING</span><span style="color: #D4D4D4">        # </span><span style="color: #9CDCFE">stringLiteral</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">INT</span><span style="color: #D4D4D4">           # </span><span style="color: #9CDCFE">integerLiteral</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">sqlName</span><span style="color: #D4D4D4">       # </span><span style="color: #9CDCFE">sqlNameExpression</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">lockMode</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">      (</span><span style="color: #4FC1FF">K_ROW</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">K_SHARE</span><span style="color: #D4D4D4">)               # </span><span style="color: #9CDCFE">rowShare</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | (</span><span style="color: #4FC1FF">K_ROW</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">K_EXCLUSIVE</span><span style="color: #D4D4D4">)           # </span><span style="color: #9CDCFE">rowExclusive</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | (</span><span style="color: #4FC1FF">K_SHARE</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">K_UPDATE</span><span style="color: #D4D4D4">)            # </span><span style="color: #9CDCFE">shareUpdate</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | (</span><span style="color: #4FC1FF">K_SHARE</span><span style="color: #D4D4D4">)                     # </span><span style="color: #9CDCFE">share</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | (</span><span style="color: #4FC1FF">K_SHARE</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">K_ROW</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">K_EXCLUSIVE</span><span style="color: #D4D4D4">)   # </span><span style="color: #9CDCFE">shareRowExclusive</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | (</span><span style="color: #4FC1FF">K_EXCLUSIVE</span><span style="color: #D4D4D4">)                 # </span><span style="color: #9CDCFE">exclusive</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">lockTableWaitOption</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">      </span><span style="color: #4FC1FF">K_NOWAIT</span><span style="color: #D4D4D4">                  # </span><span style="color: #9CDCFE">nowait</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">K_WAIT</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">waitSeconds</span><span style="color: #D4D4D4">=</span><span style="color: #4FC1FF">INT</span><span style="color: #D4D4D4">    # </span><span style="color: #9CDCFE">wait</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line cbp-line-highlight"><span style="color: #6A9955">// Identifiers</span></span>
<span class="line cbp-line-highlight"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">keywordAsId</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">      </span><span style="color: #4FC1FF">K_EXCLUSIVE</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">K_FOR</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">K_IN</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">K_LOCK</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">K_MODE</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">K_NOWAIT</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">K_PARTITION</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">K_ROW</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">K_SHARE</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">K_SUBPARTITION</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">K_TABLE</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">K_UPDATE</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">K_WAIT</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">unquotedId</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">      </span><span style="color: #4FC1FF">ID</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">keywordAsId</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">sqlName</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">      </span><span style="color: #9CDCFE">unquotedId</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">QUOTED_ID</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">qualifiedName</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">	</span><span style="color: #DCDCAA">sqlName</span><span style="color: #D4D4D4"> (</span><span style="color: #4FC1FF">DOT</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sqlName</span><span style="color: #D4D4D4">)*</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line cbp-line-highlight"><span style="color: #6A9955">// SQL statement end, slash accepted without preceeding newline</span></span>
<span class="line cbp-line-highlight"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">sqlEnd</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">EOF</span><span style="color: #D4D4D4"> | </span><span style="color: #4FC1FF">SEMI</span><span style="color: #D4D4D4"> | </span><span style="color: #4FC1FF">SLASH</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<h3 class="wp-block-heading">Data Manipulation Language</h3>



<p class="wp-block-paragraph">The only visible change in this section is the title. However, there is an important change regarding <code>lockTableStatement</code>.&nbsp; It&#8217;s not a simple rule referring to a lexer token anymore.</p>



<h3 class="wp-block-heading">Lock Table</h3>



<h4 class="wp-block-heading">lockTableStatement</h4>



<p class="wp-block-paragraph">On lines 40-42 we define the lockTableStatement. It starts with a lockTableStatementUnterminated and ends on sqlEnd. It contains the same number of characters as in the previous parser version. As a result, the <a href="https://marketplace.visualstudio.com/items?itemName=phsalvisberg.islandsql">extension for Visual Studio Code</a> finds the same <code>lock table</code> statements as before.</p>



<h4 class="wp-block-heading">lockTableStatementUnterminated</h4>



<p class="wp-block-paragraph">On lines 44-47 we define the <code>lockTableStatementUnterminated</code> according to the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/LOCK-TABLE.html">Oracle Database SQL Language Reference 21c</a> with the following three fields:</p>



<ul class="wp-block-list">
<li><code>objects</code> as an array of <code>lockTableObjects</code> with at least one entry</li>



<li><code>lockMode</code> that refers to a mandatory instance of <code>lockMode</code></li>



<li>&nbsp;<code>waitOption</code> that refers to an optional instance of <code>lockTableWaitOption</code></li>
</ul>



<p class="wp-block-paragraph">Based on that ANTLR generates a <code>IslandSqlParser</code> class with a nested class <code>LockTableStatementUnterminatedContext</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">11) Excerpt of IslandSqlParser.java generated by ANTLR</span><span role="button" tabindex="0" data-code="public class IslandSqlParser extends Parser {
    ...
    public static class LockTableStatementUnterminatedContext extends ParserRuleContext {
        public LockTableObjectContext lockTableObject;
        public List<LockTableObjectContext&gt; objects = new ArrayList<LockTableObjectContext&gt;();
        public LockModeContext lockmode;
        public LockTableWaitOptionContext waitOption;
        ...
    }
    ...
}" 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">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">IslandSqlParser</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Parser</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">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">LockTableStatementUnterminatedContext</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ParserRuleContext</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: #4EC9B0">LockTableObjectContext</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">lockTableObject</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: #4EC9B0">List</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">LockTableObjectContext</span><span style="color: #D4D4D4">&gt; </span><span style="color: #9CDCFE">objects</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ArrayList</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">LockTableObjectContext</span><span style="color: #D4D4D4">&gt;();</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">LockModeContext</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">lockmode</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: #4EC9B0">LockTableWaitOptionContext</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">waitOption</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>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">The parser populates an instance of <code>LockTableStatementUnterminatedContext</code> according to the input. Interesting is, that there is a redundancy between <code>objects</code> and <code>lockTableObject</code>. The former contains all objects to be locked and the latter just the last one.</p>



<p class="wp-block-paragraph">Please note that the <code>lock table</code> statement ends on <code>mode</code> keyword or on <code>lockTableWaitOption</code> which can end on <code>wait</code> keyword or on an integer value.</p>



<h4 class="wp-block-heading">lockTableObject</h4>



<p class="wp-block-paragraph">The <code>lockTableObject</code> on lines 49-55 defines the following fields:</p>



<ul class="wp-block-list">
<li><code>schema</code>, optional refers to a <code>sqlName</code>identifier</li>



<li><code>table</code>, mandatory refers to a <code>sqlName</code> identifier</li>



<li><code>dblink</code>, optional refers to a <code>qualifiedName</code> identifier</li>
</ul>



<p class="wp-block-paragraph">For the optional <code>partitionExtensionClause</code> no field is defined. I think this is wrong and should be fixed in a future version. Nonetheless, it&#8217;s possible to find it in the generic <code>children</code> field.</p>



<h4 class="wp-block-heading">partitionExtensionClause</h4>



<p class="wp-block-paragraph">The <code>partitionExtensionClause</code> on lines 57-64 defines four partition variants. Each variant has a label &#8211; the token after the hash sign (<code>#</code>). Based on these labels ANTLR generates the following subclasses of the class <code>PartitionExtensionClauseContext</code>:</p>



<ul class="wp-block-list">
<li><code>PartitionContext</code></li>



<li><code>SubpartitionKeysContext</code></li>



<li><code>SubpartitionContext</code></li>



<li><code>SubpartitionKeysContext</code></li>
</ul>



<p class="wp-block-paragraph">It&#8217;s another good practice to define a label for an alternative. It simplifies finding classes in the parse tree using listeners or visitors and makes the parse tree more expressive. The next screenshots highlight the partition alternative in the ANTLR IntelliJ plugin. The ANTLR interpreter does not generate classes. Instead, it shows the alternative after a colon. Either the ordinal number or the label, if available. However, it&#8217;s still a good representation of what you can expect at runtime of the parser generated by ANTLR.</p>



<figure class="wp-block-image"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/02/antr-preview-lock-table-sales-partition.png"><img fetchpriority="high" decoding="async" width="701" height="642" src="https://www.salvis.com/blog/wp-content/uploads/2023/02/antr-preview-lock-table-sales-partition.png" alt="" class="wp-image-12207" srcset="https://www.salvis.com/blog/wp-content/uploads/2023/02/antr-preview-lock-table-sales-partition.png 701w, https://www.salvis.com/blog/wp-content/uploads/2023/02/antr-preview-lock-table-sales-partition-300x275.png 300w, https://www.salvis.com/blog/wp-content/uploads/2023/02/antr-preview-lock-table-sales-partition-159x146.png 159w, https://www.salvis.com/blog/wp-content/uploads/2023/02/antr-preview-lock-table-sales-partition-50x46.png 50w, https://www.salvis.com/blog/wp-content/uploads/2023/02/antr-preview-lock-table-sales-partition-82x75.png 82w, https://www.salvis.com/blog/wp-content/uploads/2023/02/antr-preview-lock-table-sales-partition-1x1.png 1w" sizes="(max-width:767px) 480px, 701px" /></a></figure>



<p class="wp-block-paragraph">The alternatives for <code>partitionKeys</code> and <code>subpartitionKeys</code> define a field named <code>keys</code> with an array of <code>expression</code>.</p>



<h4 class="wp-block-heading">expression</h4>



<p class="wp-block-paragraph">When working on a grammar you feel more than once like <a href="https://www.youtube.com/watch?v=AbSehcT19u0">Hal fixing a light bulb</a>. An expression is probably the most extensive part of the SQL grammar. It&#8217;s huge. It contains subqueries and a subquery is basically a <code>select</code> statement and a select statement uses conditions&#8230; Once we&#8217;ve done that, implementing the rest of the IslandSQL grammar is a piece of cake.</p>



<p class="wp-block-paragraph">Therefore I decided to postpone the complete implementation and define just the bare minimum on lines 66-71. Making the <code>lock table</code> statement work for partition keys based on integers, strings and variable names. &#8211; No datetime expressions yet.</p>



<h4 class="wp-block-heading">lockMode</h4>



<p class="wp-block-paragraph">The Oracle Database allows 6 different lock modes. You find the valid alternatives on lines 74-79.</p>



<h4 class="wp-block-heading">lockTableWaitOption</h4>



<p class="wp-block-paragraph">By default, the Oracle Database waits indefinitely for the lock. You can override this behaviour by one of the alternatives defined on lines 83-84.</p>



<p class="wp-block-paragraph">The grammar defines <code>waitSeconds</code> as an <code>INT</code>. That matches the definition in the SQL Language Reference of the Oracle Database 21c.</p>



<figure class="wp-block-image"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/02/lock_table.gif"><img decoding="async" width="631" height="235" src="https://www.salvis.com/blog/wp-content/uploads/2023/02/lock_table.gif" alt="" class="wp-image-12194"/></a></figure>



<p class="wp-block-paragraph">However, what is the meaning of <code>integer</code> in this case? Can we use an integer variable in PL/SQL? Can we use a decimal literal that can be converted to an integer such as <code>10.</code>? Or can we use scientific notations such as <code>1e2</code> or even <code>1e2d</code>? To know that, we have to try it out.</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">12) Integer tests in SQL*Plus</span><span role="button" tabindex="0" data-code="SQL&gt; declare
  2     co_wait_in_seconds constant integer := 10;
  3  begin
  4     lock table emp in exclusive mode wait co_wait_in_seconds;
  5  end;
  6  /
   lock table emp in exclusive mode wait co_wait_in_seconds;
                                         *
ERROR at line 4:
ORA-06550: line 4, column 42:
PL/SQL: ORA-30005: missing or invalid WAIT interval
ORA-06550: line 4, column 4:
PL/SQL: SQL Statement ignored

SQL&gt; lock table emp in exclusive mode wait 10.;

Table(s) Locked.

SQL&gt; lock table emp in exclusive mode wait 1e2;

Table(s) Locked.

SQL&gt; lock table emp in exclusive mode wait 1e2d;
lock table emp in exclusive mode wait 1e2d
                                      *
ERROR at line 1:
ORA-30005: missing or invalid WAIT interval" 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">SQL</span><span style="color: #D4D4D4">&gt; </span><span style="color: #569CD6">declare</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">     co_wait_in_seconds constant </span><span style="color: #569CD6">integer</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">3</span><span style="color: #D4D4D4">  </span><span style="color: #569CD6">begin</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">  </span><span style="color: #B5CEA8">4</span><span style="color: #D4D4D4">     lock </span><span style="color: #569CD6">table</span><span style="color: #D4D4D4"> emp </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> exclusive mode wait co_wait_in_seconds;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #B5CEA8">5</span><span style="color: #D4D4D4">  </span><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #B5CEA8">6</span><span style="color: #D4D4D4">  /</span></span>
<span class="line"><span style="color: #D4D4D4">   lock </span><span style="color: #569CD6">table</span><span style="color: #D4D4D4"> emp </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> exclusive mode wait co_wait_in_seconds;</span></span>
<span class="line"><span style="color: #D4D4D4">                                         *</span></span>
<span class="line"><span style="color: #D4D4D4">ERROR </span><span style="color: #569CD6">at</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">line</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">4</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">ORA-</span><span style="color: #B5CEA8">06550</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">line</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">4</span><span style="color: #D4D4D4">, column </span><span style="color: #B5CEA8">42</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">PL/</span><span style="color: #569CD6">SQL</span><span style="color: #D4D4D4">: ORA-</span><span style="color: #B5CEA8">30005</span><span style="color: #D4D4D4">: missing </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> invalid WAIT interval</span></span>
<span class="line"><span style="color: #D4D4D4">ORA-</span><span style="color: #B5CEA8">06550</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">line</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">4</span><span style="color: #D4D4D4">, column </span><span style="color: #B5CEA8">4</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">PL/</span><span style="color: #569CD6">SQL</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">SQL</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">Statement</span><span style="color: #D4D4D4"> ignored</span></span>
<span class="line"></span>
<span class="line cbp-line-highlight"><span style="color: #569CD6">SQL</span><span style="color: #D4D4D4">&gt; lock </span><span style="color: #569CD6">table</span><span style="color: #D4D4D4"> emp </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> exclusive mode wait </span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4">.;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">Table</span><span style="color: #D4D4D4">(s) Locked.</span></span>
<span class="line"></span>
<span class="line cbp-line-highlight"><span style="color: #569CD6">SQL</span><span style="color: #D4D4D4">&gt; lock </span><span style="color: #569CD6">table</span><span style="color: #D4D4D4"> emp </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> exclusive mode wait 1e2;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">Table</span><span style="color: #D4D4D4">(s) Locked.</span></span>
<span class="line"></span>
<span class="line cbp-line-highlight"><span style="color: #569CD6">SQL</span><span style="color: #D4D4D4">&gt; lock </span><span style="color: #569CD6">table</span><span style="color: #D4D4D4"> emp </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> exclusive mode wait 1e2d;</span></span>
<span class="line"><span style="color: #D4D4D4">lock </span><span style="color: #569CD6">table</span><span style="color: #D4D4D4"> emp </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> exclusive mode wait 1e2d</span></span>
<span class="line"><span style="color: #D4D4D4">                                      *</span></span>
<span class="line"><span style="color: #D4D4D4">ERROR </span><span style="color: #569CD6">at</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">line</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">ORA-</span><span style="color: #B5CEA8">30005</span><span style="color: #D4D4D4">: missing </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> invalid WAIT interval</span></span></code></pre></div>



<p class="wp-block-paragraph">So, we cannot use a variable/constant. But the scientific notation works and a decimal literal can be converted to an integer as long as we do not use the scientific notation.</p>



<p class="wp-block-paragraph">I consider it a bug that we cannot use a variable/constant for the time to wait in PL/SQL. Especially since we can use <a href="https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/plsql-language-fundamentals.html#GUID-6CDF1EB6-913D-48E7-AFDA-DB4DE45209CE">static expressions</a> in PL/SQL in various places, e.g. to define the size of <code>varchar2</code> variable (since 12.2). It does not make sense to enforce the use of dynamic SQL to handle dynamic wait times in PL/SQL.</p>



<p class="wp-block-paragraph">I can imagine that a future version of the Oracle Database will lift this restriction in the <code>lock table</code> statement. It would be a small change. Maybe not even documented. Therefore it might be a good idea to change this part of the grammar and support a bit more.</p>



<h3 class="wp-block-heading">Identifiers</h3>



<p class="wp-block-paragraph">The Oracle Database allows the use of keywords as identifiers in a lot of places. Therefore we should allow the use of keywords such as <code>lock</code> in the <code>lock table</code> statement&#8217;s the identifiers <code>schema</code>, <code>table</code> and <code>dblink</code>.&nbsp; For that, we created a rule named <code>keywordAsId</code> on lines 91-105 that covers all keywords.</p>



<p class="wp-block-paragraph">We defined <code>ID</code> in the lexer. It covers all identifiers. However, keywords have a higher priority in the lexer. Therefore we defined a new rule <code>unquotedId</code> that combines <code>ID</code> with <code>keywordAsId</code>.</p>



<p class="wp-block-paragraph">The rule <code>sqlName</code> on lines 112-115 combines <code>unquotedId</code> with the <code>QUOTED_ID</code> which we defined in the lexer.</p>



<p class="wp-block-paragraph">And finally, the rule qualifiedName on lines 117-119 covers the unbounded concatenation of <code>SqlName</code> with a dot. The concatenation is optional. So a <code>qualifiedName</code> could look 100% the same as a <code>sqlName</code>. We could remove the <code>schema</code> in the rule <code>lockTableObject</code> and use <code>qualifiedName</code> for <code>table</code> like this:</p>



<pre class="wp-block-preformatted">lockTableObject:
    table=qualifiedName
        (
              partitionExtensionClause
            | (AT_SIGN dblink=qualifiedName)
        )?
;</pre>



<p class="wp-block-paragraph">This works and is a valid representation of the grammar. However, it&#8217;s less expressive. For <code>dblink</code> we must use <code>qualifiedName</code>.&nbsp; There is no predefined, binding naming scheme that covers the number of segments for a database link name.</p>



<h3 class="wp-block-heading">SQL Statement End</h3>



<p class="wp-block-paragraph">The <code>sqlEnd</code> rule on the last line 125 defines the end of a SQL statement in SQL*Plus/SQLcl. We do not handle whitespace here as in the <code>IslandSqlScopeLexer</code>. As a result a <code>lock table</code> statement could be terminated with a slash on the same line. This might need some rework in a future version of the grammar.</p>



<h2 class="wp-block-heading">Syntax Errors</h2>



<p class="wp-block-paragraph">Let&#8217;s look at a <code>lock table</code>&nbsp; statement that uses an invalid lock mode.</p>



<pre class="wp-block-preformatted">SQL&gt; lock table dept in access exclusive mode;
lock table dept in access exclusive mode
                          *
ERROR at line 1:
ORA-01737: valid modes: [ROW] SHARE, [[SHARE] ROW] EXCLUSIVE, SHARE UPDATE</pre>



<p class="wp-block-paragraph">This is a valid lock mode in <a href="https://www.postgresql.org/docs/15/sql-lock.html">PostgresSQL 15</a>. Besides the lock mode, the syntax of the lock table statement is different to the one in the Oracle Database 21c in various places. However, it should not be too complicated to define a grammar that can handle both syntaxes. We put this on the to-do list and focus on supporting the Oracle Database grammar first.</p>



<p class="wp-block-paragraph">However, how does our grammar deal with invalid SQL statements? &#8211; Here&#8217;s a screenshot of the <a href="https://marketplace.visualstudio.com/items?itemName=phsalvisberg.islandsql">extension for Visual Studio Code</a> showing some <code>lock table</code> statements.</p>



<figure class="wp-block-image"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/02/lock-table-problems-vscode.png"><img decoding="async" width="1084" height="436" src="https://www.salvis.com/blog/wp-content/uploads/2023/02/lock-table-problems-vscode.png" alt="" class="wp-image-12215" srcset="https://www.salvis.com/blog/wp-content/uploads/2023/02/lock-table-problems-vscode.png 1084w, https://www.salvis.com/blog/wp-content/uploads/2023/02/lock-table-problems-vscode-300x121.png 300w, https://www.salvis.com/blog/wp-content/uploads/2023/02/lock-table-problems-vscode-1024x412.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2023/02/lock-table-problems-vscode-768x309.png 768w, https://www.salvis.com/blog/wp-content/uploads/2023/02/lock-table-problems-vscode-260x105.png 260w, https://www.salvis.com/blog/wp-content/uploads/2023/02/lock-table-problems-vscode-50x20.png 50w, https://www.salvis.com/blog/wp-content/uploads/2023/02/lock-table-problems-vscode-150x60.png 150w, https://www.salvis.com/blog/wp-content/uploads/2023/02/lock-table-problems-vscode-1x1.png 1w" sizes="(max-width:767px) 480px, (max-width:1084px) 100vw, 1084px" /></a></figure>



<p class="wp-block-paragraph">You see the word <code>access</code> wavy underlined in red. On mouse over you get the details displayed in the <code>problems</code> panel. Furthermore, you see that <code>lock_table.sql</code> is displayed in red with a number <code>3</code> indicating that this file has three problems. And the outline view indicates problems by showing symbols in red.</p>



<p class="wp-block-paragraph">That&#8217;s the cool thing when using an IDE supporting <a href="https://microsoft.github.io/language-server-protocol/">Micosoft&#8217;s Language Server Protocol</a>. We just have to provide the syntax errors and the visualization happens automatically by the IDE in a standardized manner.</p>



<p class="wp-block-paragraph">Right now the parser provides only syntax errors. However, it is relatively easy to implement a linter based on this grammar and provide the results as warnings. For example for <code>lock table</code> statements without a <code>waitOption</code>.</p>



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



<p class="wp-block-paragraph">We have not succeeded in fully supporting the <code>lock table</code> statement. Some cases cannot yet be successfully parsed. I would like to address that. To do this, we need to look a bit more at literals and expressions before we deal with more DML statements.</p>



<p class="wp-block-paragraph">Another topic is the support of more SQL dialects.&nbsp; I&#8217;d like to support PostgreSQL. Maybe it is a good time to start as soon as a DML statement is fully covered.</p>



<p class="wp-block-paragraph">Stay tuned.</p>
<p>The post <a href="https://www.salvis.com/blog/2023/02/19/islandsql-episode-3-lock-table/">IslandSQL Episode 3: Lock Table</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/2023/02/19/islandsql-episode-3-lock-table/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>IslandSQL Episode 2: All DML Statements</title>
		<link>https://www.salvis.com/blog/2023/02/07/islandsql-episode-2-all-dml-statements/</link>
					<comments>https://www.salvis.com/blog/2023/02/07/islandsql-episode-2-all-dml-statements/#comments</comments>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Mon, 06 Feb 2023 23:24:23 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[ANTLR]]></category>
		<category><![CDATA[Code Analysis]]></category>
		<category><![CDATA[IslandSQL]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[VSCode]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=12097</guid>

					<description><![CDATA[<p>Introduction In the last episode, we build the initial version of IslandSQL. An Island grammar for SQL scripts covering select statements. In this blog post, we extend the grammar to handle the remaining DML statements. The full source code is available on GitHub and the binaries on Maven Central. Lexer Changes The<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2023/02/07/islandsql-episode-2-all-dml-statements/">IslandSQL Episode 2: All DML Statements</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/2023/02/04/islandsql-episode-1-select-statement/">last episode</a>, we build the initial version of IslandSQL. An Island grammar for SQL scripts covering select statements. In this blog post, we extend the grammar to handle the remaining DML statements.</p>



<p class="wp-block-paragraph">The full source code is available on <a href="https://github.com/IslandSQL/IslandSQL/tree/v0.2.0">GitHub</a> and the binaries on <a href="https://central.sonatype.com/artifact/ch.islandsql/islandsql/0.2.0">Maven Central</a>.</p>



<h2 class="wp-block-heading">Lexer Changes</h2>



<p class="wp-block-paragraph">The lexer grammar contains a new fragment <code>COMMENT_OR_WS</code> on line 98. We use this fragment in all DML lexer rules after the starting keywords. Why? Because we can use comments beside whitespace after a keyword as in <code>with/*comment*/function e_count...</code>. The previous lexer version required a whitespace after the <code>with</code> keyword for <code>select</code> statements with a <a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__GUID-28DA0E1D-87BF-462E-BCB8-8F77921022F9">plsql_declarations</a> clause.</p>



<p class="wp-block-paragraph">I also merged the former <code>PLSQL_DECLARATION</code> rule into the <code>SELECT</code> rule. Mainly to have a single lexer rule for all DML statements. It&#8217;s more consistent and easier to understand IMO.</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(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">IslandSqlLexer.g4: based on https://github.com/IslandSQL/IslandSQL/tree/v0.2.0/</span><span role="button" tabindex="0" data-code="lexer grammar IslandSqlLexer;

options {
    superClass=IslandSqlLexerBase;
    caseInsensitive = true;
}

/*----------------------------------------------------------------------------*/
// Comments and alike to be ignored
/*----------------------------------------------------------------------------*/

ML_COMMENT: '/*' .*? '*/' -&gt; channel(HIDDEN);
SL_COMMENT: '--' .*? (EOF|SINGLE_NL) -&gt; channel(HIDDEN);

REMARK_COMMAND:
    {isBeginOfCommand()}? 'rem' ('a' ('r' 'k'?)?)?
        (WS SQLPLUS_TEXT*)? SQLPLUS_END -&gt; channel(HIDDEN)
;

PROMPT_COMMAND:
    {isBeginOfCommand()}? 'pro' ('m' ('p' 't'?)?)?
       (WS SQLPLUS_TEXT*)? SQLPLUS_END -&gt; channel(HIDDEN)
;

STRING:
    'n'?
    (
          (['] .*? ['])+
        | ('q' ['] '[' .*? ']' ['])
        | ('q' ['] '(' .*? ')' ['])
        | ('q' ['] '{' .*? '}' ['])
        | ('q' ['] '<' .*? '&gt;' ['])
        | ('q' ['] . {saveQuoteDelimiter1()}? .+? . ['] {checkQuoteDelimiter2()}?)
    ) -&gt; channel(HIDDEN)
;

CONDITIONAL_COMPILATION_DIRECTIVE: '$if' .*? '$end' -&gt; channel(HIDDEN);

/*----------------------------------------------------------------------------*/
// Islands of interest on DEFAULT_CHANNEL
/*----------------------------------------------------------------------------*/

CALL:
    {isBeginOfStatement()}? 'call' COMMENT_OR_WS+ SQL_TEXT+? SQL_END
;

DELETE:
    {isBeginOfStatement()}? 'delete' COMMENT_OR_WS+ SQL_TEXT+? SQL_END
;

EXPLAIN_PLAN:
    {isBeginOfStatement()}? 'explain' COMMENT_OR_WS+ 'plan' COMMENT_OR_WS+ SQL_TEXT+? SQL_END
;

INSERT:
    {isBeginOfStatement()}? 'insert' COMMENT_OR_WS+ SQL_TEXT+? SQL_END
;

LOCK_TABLE:
    {isBeginOfStatement()}? 'lock' COMMENT_OR_WS+ 'table' COMMENT_OR_WS+ SQL_TEXT+? SQL_END
;

MERGE:
    {isBeginOfStatement()}? 'merge' COMMENT_OR_WS+ SQL_TEXT+? SQL_END
;

UPDATE:
    {isBeginOfStatement()}? 'update' COMMENT_OR_WS+ SQL_TEXT+? SQL_END
;

SELECT:
    {isBeginOfStatement()}?
    (
          ('with' COMMENT_OR_WS+ ('function'|'procedure') SQL_TEXT+? PLSQL_DECLARATION_END)
        | ('with' COMMENT_OR_WS+ SQL_TEXT+? SQL_END)
        | (('(' COMMENT_OR_WS*)* 'select' COMMENT_OR_WS SQL_TEXT+? SQL_END)
    )
;

/*----------------------------------------------------------------------------*/
// Whitespace
/*----------------------------------------------------------------------------*/

WS: [ \t\r\n]+ -&gt; channel(HIDDEN);

/*----------------------------------------------------------------------------*/
// Any other token
/*----------------------------------------------------------------------------*/

ANY_OTHER: . -&gt; channel(HIDDEN);

/*----------------------------------------------------------------------------*/
// Fragments to name expressions and reduce code duplication
/*----------------------------------------------------------------------------*/

fragment SINGLE_NL: '\r'? '\n';
fragment CONTINUE_LINE: '-' [ \t]* SINGLE_NL;
fragment COMMENT_OR_WS: ML_COMMENT|SL_COMMENT|WS;
fragment SQLPLUS_TEXT: (~[\r\n]|CONTINUE_LINE);
fragment SQL_TEXT: (ML_COMMENT|SL_COMMENT|STRING|.);
fragment SLASH_END: SINGLE_NL WS* '/' [ \t]* (EOF|SINGLE_NL);
fragment PLSQL_DECLARATION_END: ';'? [ \t]* (EOF|SLASH_END);
fragment SQL_END:
      EOF
    | (';' [ \t]* SINGLE_NL?)
    | SLASH_END
;
fragment SQLPLUS_END: EOF|SINGLE_NL;" 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: #9CDCFE">lexer</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">grammar</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IslandSqlLexer</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">options</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">superClass</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">IslandSqlLexerBase</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">caseInsensitive</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>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Comments and alike to be ignored</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C8C8C8">ML_COMMENT</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;/*&#39;</span><span style="color: #D4D4D4"> .*? </span><span style="color: #CE9178">&#39;*/&#39;</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #4FC1FF">SL_COMMENT</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;--&#39;</span><span style="color: #D4D4D4"> .*? (</span><span style="color: #4FC1FF">EOF</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">) -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">REMARK_COMMAND</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span><span style="color: #DCDCAA">isBeginOfCommand</span><span style="color: #D4D4D4">()}? </span><span style="color: #CE9178">&#39;rem&#39;</span><span style="color: #D4D4D4"> (</span><span style="color: #CE9178">&#39;a&#39;</span><span style="color: #D4D4D4"> (</span><span style="color: #CE9178">&#39;r&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;k&#39;</span><span style="color: #D4D4D4">?)?)?</span></span>
<span class="line"><span style="color: #D4D4D4">        (</span><span style="color: #4FC1FF">WS</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SQLPLUS_TEXT</span><span style="color: #D4D4D4">*)? </span><span style="color: #4FC1FF">SQLPLUS_END</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">PROMPT_COMMAND</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span><span style="color: #DCDCAA">isBeginOfCommand</span><span style="color: #D4D4D4">()}? </span><span style="color: #CE9178">&#39;pro&#39;</span><span style="color: #D4D4D4"> (</span><span style="color: #CE9178">&#39;m&#39;</span><span style="color: #D4D4D4"> (</span><span style="color: #CE9178">&#39;p&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;t&#39;</span><span style="color: #D4D4D4">?)?)?</span></span>
<span class="line"><span style="color: #D4D4D4">       (</span><span style="color: #4FC1FF">WS</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SQLPLUS_TEXT</span><span style="color: #D4D4D4">*)? </span><span style="color: #4FC1FF">SQLPLUS_END</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">STRING</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&#39;n&#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: #CE9178">&#39;] .*? [&#39;</span><span style="color: #D4D4D4">])+</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;q&#39;</span><span style="color: #D4D4D4"> [</span><span style="color: #CE9178">&#39;] &#39;</span><span style="color: #D4D4D4">[</span><span style="color: #CE9178">&#39; .*? &#39;</span><span style="color: #D4D4D4">]</span><span style="color: #CE9178">&#39; [&#39;</span><span style="color: #D4D4D4">])</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;q&#39;</span><span style="color: #D4D4D4"> [</span><span style="color: #CE9178">&#39;] &#39;</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39; .*? &#39;</span><span style="color: #D4D4D4">)</span><span style="color: #CE9178">&#39; [&#39;</span><span style="color: #D4D4D4">])</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;q&#39;</span><span style="color: #D4D4D4"> [</span><span style="color: #CE9178">&#39;] &#39;</span><span style="color: #D4D4D4">{</span><span style="color: #CE9178">&#39; .*? &#39;</span><span style="color: #D4D4D4">}</span><span style="color: #CE9178">&#39; [&#39;</span><span style="color: #D4D4D4">])</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;q&#39;</span><span style="color: #D4D4D4"> [</span><span style="color: #CE9178">&#39;] &#39;</span><span style="color: #D4D4D4">&lt;</span><span style="color: #CE9178">&#39; .*? &#39;</span><span style="color: #D4D4D4">&gt;</span><span style="color: #CE9178">&#39; [&#39;</span><span style="color: #D4D4D4">])</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;q&#39;</span><span style="color: #D4D4D4"> [</span><span style="color: #CE9178">&#39;] . {saveQuoteDelimiter1()}? .+? . [&#39;</span><span style="color: #D4D4D4">] {</span><span style="color: #DCDCAA">checkQuoteDelimiter2</span><span style="color: #D4D4D4">()}?)</span></span>
<span class="line"><span style="color: #D4D4D4">    ) -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">CONDITIONAL_COMPILATION_DIRECTIVE</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;$if&#39;</span><span style="color: #D4D4D4"> .*? </span><span style="color: #CE9178">&#39;$end&#39;</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Islands of interest on DEFAULT_CHANNEL</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line cbp-line-highlight"><span style="color: #4FC1FF">CALL</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    {</span><span style="color: #DCDCAA">isBeginOfStatement</span><span style="color: #D4D4D4">()}? </span><span style="color: #CE9178">&#39;call&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #4FC1FF">DELETE</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    {</span><span style="color: #DCDCAA">isBeginOfStatement</span><span style="color: #D4D4D4">()}? </span><span style="color: #CE9178">&#39;delete&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #4FC1FF">EXPLAIN_PLAN</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    {</span><span style="color: #DCDCAA">isBeginOfStatement</span><span style="color: #D4D4D4">()}? </span><span style="color: #CE9178">&#39;explain&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #CE9178">&#39;plan&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #4FC1FF">INSERT</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    {</span><span style="color: #DCDCAA">isBeginOfStatement</span><span style="color: #D4D4D4">()}? </span><span style="color: #CE9178">&#39;insert&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #4FC1FF">LOCK_TABLE</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    {</span><span style="color: #DCDCAA">isBeginOfStatement</span><span style="color: #D4D4D4">()}? </span><span style="color: #CE9178">&#39;lock&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #CE9178">&#39;table&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #4FC1FF">MERGE</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    {</span><span style="color: #DCDCAA">isBeginOfStatement</span><span style="color: #D4D4D4">()}? </span><span style="color: #CE9178">&#39;merge&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #4FC1FF">UPDATE</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    {</span><span style="color: #DCDCAA">isBeginOfStatement</span><span style="color: #D4D4D4">()}? </span><span style="color: #CE9178">&#39;update&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #4FC1FF">SELECT</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    {</span><span style="color: #DCDCAA">isBeginOfStatement</span><span style="color: #D4D4D4">()}?</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    (</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">          (</span><span style="color: #CE9178">&#39;with&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ (</span><span style="color: #CE9178">&#39;function&#39;</span><span style="color: #D4D4D4">|</span><span style="color: #CE9178">&#39;procedure&#39;</span><span style="color: #D4D4D4">) </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">PLSQL_DECLARATION_END</span><span style="color: #D4D4D4">)</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;with&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">+ </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span><span style="color: #D4D4D4">)</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        | ((</span><span style="color: #CE9178">&#39;(&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">*)* </span><span style="color: #CE9178">&#39;select&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">+? </span><span style="color: #4FC1FF">SQL_END</span><span style="color: #D4D4D4">)</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    )</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Whitespace</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">WS</span><span style="color: #D4D4D4">: [ \</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">\</span><span style="color: #9CDCFE">r</span><span style="color: #D4D4D4">\</span><span style="color: #9CDCFE">n</span><span style="color: #D4D4D4">]+ -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Any other token</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">ANY_OTHER</span><span style="color: #D4D4D4">: . -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Fragments to name expressions and reduce code duplication</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;</span><span style="color: #D7BA7D">\r</span><span style="color: #CE9178">&#39;</span><span style="color: #D4D4D4">? </span><span style="color: #CE9178">&#39;</span><span style="color: #D7BA7D">\n</span><span style="color: #CE9178">&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">CONTINUE_LINE</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;-&#39;</span><span style="color: #D4D4D4"> [ \</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">]* </span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">COMMENT_OR_WS</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">ML_COMMENT</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SL_COMMENT</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">WS</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SQLPLUS_TEXT</span><span style="color: #D4D4D4">: (~[\</span><span style="color: #9CDCFE">r</span><span style="color: #D4D4D4">\</span><span style="color: #9CDCFE">n</span><span style="color: #D4D4D4">]|</span><span style="color: #4FC1FF">CONTINUE_LINE</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">: (</span><span style="color: #4FC1FF">ML_COMMENT</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SL_COMMENT</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">STRING</span><span style="color: #D4D4D4">|.);</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SLASH_END</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">WS</span><span style="color: #D4D4D4">* </span><span style="color: #CE9178">&#39;/&#39;</span><span style="color: #D4D4D4"> [ \</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">]* (</span><span style="color: #4FC1FF">EOF</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">PLSQL_DECLARATION_END</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;;&#39;</span><span style="color: #D4D4D4">? [ \</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">]* (</span><span style="color: #4FC1FF">EOF</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SLASH_END</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SQL_END</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #4FC1FF">EOF</span></span>
<span class="line"><span style="color: #D4D4D4">    | (</span><span style="color: #CE9178">&#39;;&#39;</span><span style="color: #D4D4D4"> [ \</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">]* </span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">?)</span></span>
<span class="line"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">SLASH_END</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SQLPLUS_END</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">EOF</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<h2 class="wp-block-heading">Parser Changes</h2>



<p class="wp-block-paragraph">The start rule <code>file</code> on line 11 in the parser grammar is now defined as a unbounded number of <code>dmlStatment</code>. Each <a href="https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Types-of-SQL-Statements.html#GUID-2E008D4A-F6FD-4F34-9071-7E10419CA24D">DML statement</a> is a single lexer token. It&#8217;s still not possible to produce a parse error with this grammar. We only process DML statements. Everything else is hidden and therefore ignored.</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">IslandSqlParser.g4: based on https://github.com/IslandSQL/IslandSQL/tree/v0.2.0/</span><span role="button" tabindex="0" data-code="parser grammar IslandSqlParser;

options {
    tokenVocab=IslandSqlLexer;
}

/*----------------------------------------------------------------------------*/
// Start rule
/*----------------------------------------------------------------------------*/

file: dmlStatement* EOF;

/*----------------------------------------------------------------------------*/
// Rules for reduced SQL grammar (islands of interest)
/*----------------------------------------------------------------------------*/

dmlStatement:
      callStatement
    | deleteStatement
    | explainPlanStatement
    | insertStatement
    | lockTableStatement
    | mergeStatement
    | selectStatement
    | updateStatement
;

callStatement: CALL;
deleteStatement: DELETE;
explainPlanStatement: EXPLAIN_PLAN;
insertStatement: INSERT;
lockTableStatement: LOCK_TABLE;
mergeStatement: MERGE;
updateStatement: UPDATE;
selectStatement: SELECT;" 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: #9CDCFE">parser</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">grammar</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IslandSqlParser</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">options</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">tokenVocab</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">IslandSqlLexer</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Start rule</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">file</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">dmlStatement</span><span style="color: #D4D4D4">* </span><span style="color: #4FC1FF">EOF</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Rules for reduced SQL grammar (islands of interest)</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">dmlStatement</span><span style="color: #D4D4D4">:</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">      </span><span style="color: #9CDCFE">callStatement</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">deleteStatement</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">explainPlanStatement</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">insertStatement</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">lockTableStatement</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">mergeStatement</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">selectStatement</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    | </span><span style="color: #9CDCFE">updateStatement</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">callStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">CALL</span><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">deleteStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">DELETE</span><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">explainPlanStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">EXPLAIN_PLAN</span><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">insertStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">INSERT</span><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">lockTableStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">LOCK_TABLE</span><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">mergeStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">MERGE</span><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">updateStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">UPDATE</span><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"><span style="color: #C8C8C8">selectStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">SELECT</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<h2 class="wp-block-heading">IslandSQL for VS Code</h2>



<p class="wp-block-paragraph"><a href="https://marketplace.visualstudio.com/items?itemName=phsalvisberg.islandsql">The extension</a> for Visual Studio Code version 0.2.0 finds text in all DML statements and is not limited to <code>select</code> statements anymore. And a symbol for each DML statement is shown now in the outline view.</p>



<figure class="wp-block-image"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/02/demo-vscode.png"><img loading="lazy" decoding="async" width="1690" height="1022" src="https://www.salvis.com/blog/wp-content/uploads/2023/02/demo-vscode.png" alt="" class="wp-image-12114" srcset="https://www.salvis.com/blog/wp-content/uploads/2023/02/demo-vscode.png 1690w, https://www.salvis.com/blog/wp-content/uploads/2023/02/demo-vscode-300x181.png 300w, https://www.salvis.com/blog/wp-content/uploads/2023/02/demo-vscode-1024x619.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2023/02/demo-vscode-768x464.png 768w, https://www.salvis.com/blog/wp-content/uploads/2023/02/demo-vscode-1536x929.png 1536w, https://www.salvis.com/blog/wp-content/uploads/2023/02/demo-vscode-241x146.png 241w, https://www.salvis.com/blog/wp-content/uploads/2023/02/demo-vscode-50x30.png 50w, https://www.salvis.com/blog/wp-content/uploads/2023/02/demo-vscode-124x75.png 124w, https://www.salvis.com/blog/wp-content/uploads/2023/02/demo-vscode-1x1.png 1w" sizes="auto, (max-width:767px) 480px, (max-width:1690px) 100vw, 1690px" /></a></figure>



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



<p class="wp-block-paragraph">A grammar that can parse all DML statements sounds like something complete. However, this grammar is far from complete. For code analysis, getting a single token for a DML statement is at best a good starting point.</p>



<p class="wp-block-paragraph">What we need is a more detailed result. For this, we need to move the logic from the lexer to the parser. In the next episode, we will do this with one of the DML statements.</p>
<p>The post <a href="https://www.salvis.com/blog/2023/02/07/islandsql-episode-2-all-dml-statements/">IslandSQL Episode 2: All DML Statements</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/2023/02/07/islandsql-episode-2-all-dml-statements/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>IslandSQL Episode 1:  Select Statement</title>
		<link>https://www.salvis.com/blog/2023/02/04/islandsql-episode-1-select-statement/</link>
					<comments>https://www.salvis.com/blog/2023/02/04/islandsql-episode-1-select-statement/#comments</comments>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Sat, 04 Feb 2023 12:00:04 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[ANTLR]]></category>
		<category><![CDATA[Code Analysis]]></category>
		<category><![CDATA[IslandSQL]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[utPLSQL]]></category>
		<category><![CDATA[VSCode]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=12006</guid>

					<description><![CDATA[<p>Introduction An island grammar focuses only on a small part of a grammar. The island represents the small, interesting part and the sea the rest. In this blog post, I explain the components of an island grammar for SQL scripts named IslandSQL. In the first iteration, we focus on the select&#160;statement. Everything<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2023/02/04/islandsql-episode-1-select-statement/">IslandSQL Episode 1:  Select Statement</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">An island grammar focuses only on a small part of a grammar. The island represents the small, interesting part and the sea the rest. In this blog post, I explain the components of an island grammar for SQL scripts named IslandSQL. In the first iteration, we focus on the <code>select</code>&nbsp;statement. Everything else is not of interest for the time being.</p>



<h2 class="wp-block-heading">Use Case</h2>



<p class="wp-block-paragraph">Let&#8217;s assume we want to write an extension for Visual Studio Code that can find text in <code>select</code> statements within SQL files of a workspace. So what is the difference to VSCode&#8217;s integrated text search? Well, the text search does not know what a <code>select</code> statement is. It finds occurrences of the search text in all kinds of places. In fact, identifying a <code>select</code> statement is not as easy as one might think.</p>



<p class="wp-block-paragraph">Let&#8217;s look at 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);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">demo1.sql: No select statements</span><span role="button" tabindex="0" data-code="/* select * from t1; */
-- select * from t2;
remark select * from t3;
prompt select * from t4;
begin
    sys.dbms_output.put_line('irrelevant: select * from t5;');
end;
/
create or replace procedure p is
begin
   $if false $then irrelevant: select * from t6; $end
   null;
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: #6A9955">/* select * from t1; */</span></span>
<span class="line"><span style="color: #6A9955">-- select * from t2;</span></span>
<span class="line"><span style="color: #D4D4D4">remark </span><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> * </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> t3;</span></span>
<span class="line"><span style="color: #D4D4D4">prompt </span><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> * </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> t4;</span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">    sys.dbms_output.put_line(</span><span style="color: #CE9178">&#39;irrelevant: select * from t5;&#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 style="color: #569CD6">create</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">replace</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">procedure</span><span style="color: #D4D4D4"> p </span><span style="color: #569CD6">is</span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">   $</span><span style="color: #569CD6">if</span><span style="color: #D4D4D4"> false $</span><span style="color: #569CD6">then</span><span style="color: #D4D4D4"> irrelevant: </span><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> * </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> t6; $</span><span style="color: #569CD6">end</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span></code></pre></div>



<p class="wp-block-paragraph">This SQL script does not contain relevant <code>select</code> statements. A <code>select</code> statement within a comment is hardly relevant. The same is true for <code>select</code> statements in remark and prompt commands. And I consider <code>select</code> statements within string literals and conditional compilation text also as irrelevant, at least in this example.</p>



<p class="wp-block-paragraph">So let&#8217;s look at another 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);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">demo2.sql: Variants of select statements</span><span role="button" tabindex="0" data-code="-- simple
select * from dept;
-- subquery_factoring_clause
with
   d as (
      select * from dept
   )
select * from d;
-- plsql_declarations
with
   function e_count (in_deptno in dept.deptno%type) return integer is
      l_count integer;
   begin
      select count(*)
        into l_count
        from emp;
      return l_count;
   end e_count;
select deptno, e_count(deptno)
  from dept
/
-- unterminated
select * 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: #6A9955">-- simple</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"> dept;</span></span>
<span class="line"><span style="color: #6A9955">-- subquery_factoring_clause</span></span>
<span class="line"><span style="color: #569CD6">with</span></span>
<span class="line"><span style="color: #D4D4D4">   d </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> * </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept</span></span>
<span class="line"><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"> d;</span></span>
<span class="line"><span style="color: #6A9955">-- plsql_declarations</span></span>
<span class="line"><span style="color: #569CD6">with</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> e_count (in_deptno </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> dept.deptno%</span><span style="color: #569CD6">type</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">integer</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span></span>
<span class="line"><span style="color: #D4D4D4">      l_count </span><span style="color: #569CD6">integer</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">count</span><span style="color: #D4D4D4">(*)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">into</span><span style="color: #D4D4D4"> l_count</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> emp;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">return</span><span style="color: #D4D4D4"> l_count;</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">end</span><span style="color: #D4D4D4"> e_count;</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> deptno, e_count(deptno)</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> dept</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span>
<span class="line"><span style="color: #6A9955">-- unterminated</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"> dept</span></span></code></pre></div>



<p class="wp-block-paragraph">This example script contains four <code>select</code> statements. As you can see, a <code>select</code> statement does not necessarily need to start with the <code>select</code> keyword. Furthermore a <code>select</code> statement can end on semicolon or slash or EOF (end-of-file). In fact, when using <a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__GUID-28DA0E1D-87BF-462E-BCB8-8F77921022F9">plsql_declarations</a> the statement must end on a slash (or EOF).</p>



<p class="wp-block-paragraph">Here&#8217;s a screenshot of the VSCode extension after searching for the regular expression <code>.+</code> in the demo workspace, highlighting the third search result.</p>



<figure class="wp-block-image"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/02/islandsql-vscode-demo2.png"><img loading="lazy" decoding="async" width="1752" height="1108" src="https://www.salvis.com/blog/wp-content/uploads/2023/02/islandsql-vscode-demo2.png" alt="IslandSQL VSCode extension: search result" class="wp-image-12010" srcset="https://www.salvis.com/blog/wp-content/uploads/2023/02/islandsql-vscode-demo2.png 1752w, https://www.salvis.com/blog/wp-content/uploads/2023/02/islandsql-vscode-demo2-300x190.png 300w, https://www.salvis.com/blog/wp-content/uploads/2023/02/islandsql-vscode-demo2-1024x648.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2023/02/islandsql-vscode-demo2-768x486.png 768w, https://www.salvis.com/blog/wp-content/uploads/2023/02/islandsql-vscode-demo2-1536x971.png 1536w, https://www.salvis.com/blog/wp-content/uploads/2023/02/islandsql-vscode-demo2-231x146.png 231w, https://www.salvis.com/blog/wp-content/uploads/2023/02/islandsql-vscode-demo2-50x32.png 50w, https://www.salvis.com/blog/wp-content/uploads/2023/02/islandsql-vscode-demo2-119x75.png 119w, https://www.salvis.com/blog/wp-content/uploads/2023/02/islandsql-vscode-demo2-1x1.png 1w" sizes="auto, (max-width:767px) 480px, (max-width:1752px) 100vw, 1752px" /></a></figure>



<h2 class="wp-block-heading">Lexer Grammar</h2>



<p class="wp-block-paragraph">The responsibility of the lexer is to convert a stream of characters to a stream of tokens. We use <a href="https://www.antlr.org/">ANTLR 4</a> to generate our lexer with Java as the target language.</p>



<p class="wp-block-paragraph">Here&#8217;s the grammar definition for our lexer.</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">IslandSqlLexer.g4: based on https://github.com/IslandSQL/IslandSQL/tree/v0.1.0/</span><span role="button" tabindex="0" data-code="lexer grammar IslandSqlLexer;

options {
    superClass=IslandSqlLexerBase;
    caseInsensitive = true;
}

/*----------------------------------------------------------------------------*/
// Comments and alike to be ignored
/*----------------------------------------------------------------------------*/

ML_COMMENT: '/*' .*? '*/' -&gt; channel(HIDDEN);
SL_COMMENT: '--' .*? (EOF|SINGLE_NL) -&gt; channel(HIDDEN);
REMARK_COMMAND:
    {isBeginOfCommand()}? 'rem' ('a' ('r' 'k'?)?)?
        (WS SQLPLUS_TEXT*)? SQLPLUS_END -&gt; channel(HIDDEN)
;
PROMPT_COMMAND:
    {isBeginOfCommand()}? 'pro' ('m' ('p' 't'?)?)?
       (WS SQLPLUS_TEXT*)? SQLPLUS_END -&gt; channel(HIDDEN)
;
STRING:
    'n'?
    (
          (['] .*? ['])+
        | ('q' ['] '[' .*? ']' ['])
        | ('q' ['] '(' .*? ')' ['])
        | ('q' ['] '{' .*? '}' ['])
        | ('q' ['] '<' .*? '&gt;' ['])
        | ('q' ['] . {saveQuoteDelimiter1()}? .+? . ['] {checkQuoteDelimiter2()}?)
    ) -&gt; channel(HIDDEN)
;
CONDITIONAL_COMPILATION_DIRECTIVE: '$if' .*? '$end' -&gt; channel(HIDDEN);

/*----------------------------------------------------------------------------*/
// Islands of interest on DEFAULT_CHANNEL
/*----------------------------------------------------------------------------*/

PLSQL_DECLARATION:
    {isBeginOfStatement()}? 'with' WS
        ('function'|'procedure') SQL_TEXT*?  PLSQL_DECLARATION_END
;
SELECT:
    {isBeginOfStatement()}? ('with'|('(' WS?)* 'select') SQL_TEXT*? SQL_END
;

/*----------------------------------------------------------------------------*/
// Whitespace
/*----------------------------------------------------------------------------*/

WS: [ \t\r\n]+ -&gt; channel(HIDDEN);

/*----------------------------------------------------------------------------*/
// Any other token
/*----------------------------------------------------------------------------*/

ANY_OTHER: . -&gt; channel(HIDDEN);

/*----------------------------------------------------------------------------*/
// Fragments to name expressions and reduce code duplication
/*----------------------------------------------------------------------------*/

fragment SINGLE_NL: '\r'? '\n';
fragment CONTINUE_LINE: '-' [ \t]* SINGLE_NL;
fragment SQLPLUS_TEXT: (~[\r\n]|CONTINUE_LINE);
fragment SQL_TEXT: (ML_COMMENT|SL_COMMENT|STRING|.);
fragment SLASH_END: SINGLE_NL WS* '/' [ \t]* (EOF|SINGLE_NL);
fragment PLSQL_DECLARATION_END: ';'? [ \t]* (EOF|SLASH_END);
fragment SQL_END:
      EOF
    | (';' [ \t]* SINGLE_NL?)
    | SLASH_END
;
fragment SQLPLUS_END: EOF|SINGLE_NL;" 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: #9CDCFE">lexer</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">grammar</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IslandSqlLexer</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">options</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">superClass</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">IslandSqlLexerBase</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">caseInsensitive</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>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Comments and alike to be ignored</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C8C8C8">ML_COMMENT</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;/*&#39;</span><span style="color: #D4D4D4"> .*? </span><span style="color: #CE9178">&#39;*/&#39;</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #4FC1FF">SL_COMMENT</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;--&#39;</span><span style="color: #D4D4D4"> .*? (</span><span style="color: #4FC1FF">EOF</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">) -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #4FC1FF">REMARK_COMMAND</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span><span style="color: #DCDCAA">isBeginOfCommand</span><span style="color: #D4D4D4">()}? </span><span style="color: #CE9178">&#39;rem&#39;</span><span style="color: #D4D4D4"> (</span><span style="color: #CE9178">&#39;a&#39;</span><span style="color: #D4D4D4"> (</span><span style="color: #CE9178">&#39;r&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;k&#39;</span><span style="color: #D4D4D4">?)?)?</span></span>
<span class="line"><span style="color: #D4D4D4">        (</span><span style="color: #4FC1FF">WS</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SQLPLUS_TEXT</span><span style="color: #D4D4D4">*)? </span><span style="color: #4FC1FF">SQLPLUS_END</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">PROMPT_COMMAND</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span><span style="color: #DCDCAA">isBeginOfCommand</span><span style="color: #D4D4D4">()}? </span><span style="color: #CE9178">&#39;pro&#39;</span><span style="color: #D4D4D4"> (</span><span style="color: #CE9178">&#39;m&#39;</span><span style="color: #D4D4D4"> (</span><span style="color: #CE9178">&#39;p&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;t&#39;</span><span style="color: #D4D4D4">?)?)?</span></span>
<span class="line"><span style="color: #D4D4D4">       (</span><span style="color: #4FC1FF">WS</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SQLPLUS_TEXT</span><span style="color: #D4D4D4">*)? </span><span style="color: #4FC1FF">SQLPLUS_END</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">STRING</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&#39;n&#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: #CE9178">&#39;] .*? [&#39;</span><span style="color: #D4D4D4">])+</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;q&#39;</span><span style="color: #D4D4D4"> [</span><span style="color: #CE9178">&#39;] &#39;</span><span style="color: #D4D4D4">[</span><span style="color: #CE9178">&#39; .*? &#39;</span><span style="color: #D4D4D4">]</span><span style="color: #CE9178">&#39; [&#39;</span><span style="color: #D4D4D4">])</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;q&#39;</span><span style="color: #D4D4D4"> [</span><span style="color: #CE9178">&#39;] &#39;</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39; .*? &#39;</span><span style="color: #D4D4D4">)</span><span style="color: #CE9178">&#39; [&#39;</span><span style="color: #D4D4D4">])</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;q&#39;</span><span style="color: #D4D4D4"> [</span><span style="color: #CE9178">&#39;] &#39;</span><span style="color: #D4D4D4">{</span><span style="color: #CE9178">&#39; .*? &#39;</span><span style="color: #D4D4D4">}</span><span style="color: #CE9178">&#39; [&#39;</span><span style="color: #D4D4D4">])</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;q&#39;</span><span style="color: #D4D4D4"> [</span><span style="color: #CE9178">&#39;] &#39;</span><span style="color: #D4D4D4">&lt;</span><span style="color: #CE9178">&#39; .*? &#39;</span><span style="color: #D4D4D4">&gt;</span><span style="color: #CE9178">&#39; [&#39;</span><span style="color: #D4D4D4">])</span></span>
<span class="line"><span style="color: #D4D4D4">        | (</span><span style="color: #CE9178">&#39;q&#39;</span><span style="color: #D4D4D4"> [</span><span style="color: #CE9178">&#39;] . {saveQuoteDelimiter1()}? .+? . [&#39;</span><span style="color: #D4D4D4">] {</span><span style="color: #DCDCAA">checkQuoteDelimiter2</span><span style="color: #D4D4D4">()}?)</span></span>
<span class="line"><span style="color: #D4D4D4">    ) -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">CONDITIONAL_COMPILATION_DIRECTIVE</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;$if&#39;</span><span style="color: #D4D4D4"> .*? </span><span style="color: #CE9178">&#39;$end&#39;</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Islands of interest on DEFAULT_CHANNEL</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">PLSQL_DECLARATION</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span><span style="color: #DCDCAA">isBeginOfStatement</span><span style="color: #D4D4D4">()}? </span><span style="color: #CE9178">&#39;with&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">WS</span></span>
<span class="line"><span style="color: #D4D4D4">        (</span><span style="color: #CE9178">&#39;function&#39;</span><span style="color: #D4D4D4">|</span><span style="color: #CE9178">&#39;procedure&#39;</span><span style="color: #D4D4D4">) </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">*?  </span><span style="color: #4FC1FF">PLSQL_DECLARATION_END</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #4FC1FF">SELECT</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span><span style="color: #DCDCAA">isBeginOfStatement</span><span style="color: #D4D4D4">()}? (</span><span style="color: #CE9178">&#39;with&#39;</span><span style="color: #D4D4D4">|(</span><span style="color: #CE9178">&#39;(&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">WS</span><span style="color: #D4D4D4">?)* </span><span style="color: #CE9178">&#39;select&#39;</span><span style="color: #D4D4D4">) </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">*? </span><span style="color: #4FC1FF">SQL_END</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Whitespace</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">WS</span><span style="color: #D4D4D4">: [ \</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">\</span><span style="color: #9CDCFE">r</span><span style="color: #D4D4D4">\</span><span style="color: #9CDCFE">n</span><span style="color: #D4D4D4">]+ -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Any other token</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">ANY_OTHER</span><span style="color: #D4D4D4">: . -&gt; </span><span style="color: #DCDCAA">channel</span><span style="color: #D4D4D4">(</span><span style="color: #4FC1FF">HIDDEN</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Fragments to name expressions and reduce code duplication</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;</span><span style="color: #D7BA7D">\r</span><span style="color: #CE9178">&#39;</span><span style="color: #D4D4D4">? </span><span style="color: #CE9178">&#39;</span><span style="color: #D7BA7D">\n</span><span style="color: #CE9178">&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">CONTINUE_LINE</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;-&#39;</span><span style="color: #D4D4D4"> [ \</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">]* </span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SQLPLUS_TEXT</span><span style="color: #D4D4D4">: (~[\</span><span style="color: #9CDCFE">r</span><span style="color: #D4D4D4">\</span><span style="color: #9CDCFE">n</span><span style="color: #D4D4D4">]|</span><span style="color: #4FC1FF">CONTINUE_LINE</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SQL_TEXT</span><span style="color: #D4D4D4">: (</span><span style="color: #4FC1FF">ML_COMMENT</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SL_COMMENT</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">STRING</span><span style="color: #D4D4D4">|.);</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SLASH_END</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">WS</span><span style="color: #D4D4D4">* </span><span style="color: #CE9178">&#39;/&#39;</span><span style="color: #D4D4D4"> [ \</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">]* (</span><span style="color: #4FC1FF">EOF</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">PLSQL_DECLARATION_END</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;;&#39;</span><span style="color: #D4D4D4">? [ \</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">]* (</span><span style="color: #4FC1FF">EOF</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SLASH_END</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SQL_END</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #4FC1FF">EOF</span></span>
<span class="line"><span style="color: #D4D4D4">    | (</span><span style="color: #CE9178">&#39;;&#39;</span><span style="color: #D4D4D4"> [ \</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">]* </span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">?)</span></span>
<span class="line"><span style="color: #D4D4D4">    | </span><span style="color: #4FC1FF">SLASH_END</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #9CDCFE">fragment</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SQLPLUS_END</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">EOF</span><span style="color: #D4D4D4">|</span><span style="color: #4FC1FF">SINGLE_NL</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<h3 class="wp-block-heading">Lexer Options</h3>



<p class="wp-block-paragraph">On lines 3-6 we define the grammar <a href="https://github.com/antlr/antlr4/blob/master/doc/options.md">options</a>.</p>



<p class="wp-block-paragraph">The first option defines the superclass that the generated lexer class should extend from. We use this class to define semantic predicates that can be used in the lexer grammar. Semantic predicates are very powerful. However, they bind a grammar to a target language. Of course, you can implement a superclass in different target languages. But would you want to do that for every supported <a href="https://github.com/antlr/antlr4/blob/master/doc/targets.md">target language</a>?</p>



<p class="wp-block-paragraph">The second option defines the grammar as case-insensitive. This simplifies the grammar. We can simply write <code>select</code> instead of <code>S E L E C T</code> where every letter is a fragment (e.g.&nbsp;<code>fragment S: [sS];</code>).</p>



<h3 class="wp-block-heading">Channels</h3>



<p class="wp-block-paragraph">A token can be either ignored (skipped) or placed on a channel. ANTLR provides by default the following two channels:</p>



<ul class="wp-block-list">
<li><code>DEFAULT_CHANNEL</code>: for visible tokens that are relevant to the parser grammar</li>



<li><code>HIDDEN</code>: for tokens that are not relevant to the parser grammar</li>
</ul>



<p class="wp-block-paragraph">We do not skip tokens in this grammar. This has the advantage that we can access hidden tokens when we need to. For example, for accessing hints or for lossless serialisation of chosen parts.</p>



<h3 class="wp-block-heading">Comments and Alike</h3>



<p class="wp-block-paragraph">On lines 8-33, we define hidden tokens using <a href="https://github.com/antlr/antlr4/blob/master/doc/lexer-rules.md">lexer rules</a>.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">The notation for the token definitions should be familiar to those with regular expression experience.<br />&#8212; Terence Parr, The Definitive ANTLR 4 Reference, 2nd edition, page 36</p>
</blockquote>



<p class="wp-block-paragraph">The tokens defined in this section are similar to comments and therefore should be ignored and placed on the hidden channel.</p>



<p class="wp-block-paragraph">The order of the rules is important in case of conflicting definitions. The first rule wins.&nbsp;<code>ML_COMMENT</code> defines a multiline comment starting with <code>/*</code>&nbsp; and ending with <code>*/</code>. The rules defined afterwards&nbsp;cannot define tokens that are a subset of <code>ML_COMMENT</code>. For example,&nbsp; a <code>select</code> statement within a <code>ML_COMMENT</code> is not visible for subsequent rules. This is the reason for the rules in this section. We want to hide <code>select</code> statements within comments and alike.</p>



<p class="wp-block-paragraph">However, it is possible to define a token that contains a <code>ML_COMMENT</code>, e.g. in a <code>select</code> statement.</p>



<h3 class="wp-block-heading">Islands of Interest</h3>



<p class="wp-block-paragraph">You find the islands of interest on lines 35-45. The rule <code>PLSQL_DECLARATION</code> covers the <code>select</code> statement with a <a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__GUID-28DA0E1D-87BF-462E-BCB8-8F77921022F9">plsql_declarations</a> clause. And the rule <code>SELECT</code> covers the <code>select</code> statement without a <a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__GUID-28DA0E1D-87BF-462E-BCB8-8F77921022F9">plsql_declarations</a> clause. Identifying the end of the <code>select</code> statement is a bit tricky.</p>



<p class="wp-block-paragraph">This definition works in many cases, but it will falsely match subqueries in other statements such as <code>insert</code>, <code>update</code>, <code>delete</code>, <code>merge</code>, etc. In such cases, everything up to the next semicolon is considered part of the <code>select</code> statement. We will address this flaw in a future version of the grammar.</p>



<p class="wp-block-paragraph">How do we ignore semicolons in comments and strings? By using the fragment <code>SQL_TEXT</code>. A <code>SQL_TEXT</code> is either a <code>ML_COMMENT</code>, a <code>SL_COMMENT</code>, a <code>STRING</code> or any other character (<code>.</code>). Again, the order is important. The lexer considers comments and strings as single tokens. A semicolon in comments or strings is not visible. As a result, a semicolon in comments or strings will not be interpreted as the end of a <code>select</code> statement.</p>



<p class="wp-block-paragraph">Did you wonder why I use ANTLR instead of regular expressions? Well, it&#8217;s simply not possible to write a regular expression that can match a complete <code>select</code> statement ending on a semicolon while ignoring the semicolons in comments and strings. Simply put, ANTLR is more powerful.</p>



<p class="wp-block-paragraph">These two rules produce a single token for the whole <code>select</code> statement. This is simple and enough for our current use case. However, in the coming versions of the grammar, we will rewrite this section to parse a <code>select</code> statement completely and address the issues with subqueries in other statements.</p>



<h3 class="wp-block-heading">Whitespace</h3>



<p class="wp-block-paragraph">The <code>WS</code> rule on line 51 defines whitespace characters. They are not relevant for the parser, hence we put them on the <code>HIDDEN</code> channel.</p>



<h3 class="wp-block-heading">Other Tokens</h3>



<p class="wp-block-paragraph">The <code>ANY_OTHER</code> rule on line 57 covers any other character. They are not relevant for the parser and we put them also on the <code>HIDDEN</code> channel.</p>



<h3 class="wp-block-heading">Fragments</h3>



<p class="wp-block-paragraph">And finally, on lines 59-74 we have fragments. A fragment allows one to name an expression and use the fragment name instead of the expression in other fragments or rules. This makes the grammar more readable without introducing additional token types.</p>



<h2 class="wp-block-heading">Parser Grammar</h2>



<p class="wp-block-paragraph">We use the output of the lexer &#8211; the token stream &#8211; in the parser. By default, only the tokens on the <code>DEFAULT_CHANNEL</code> are visible in the parser grammar. This makes the grammar quite simple.</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">IslandSqlParser.g4: based on https://github.com/IslandSQL/IslandSQL/tree/v0.1.0/</span><span role="button" tabindex="0" data-code="parser grammar IslandSqlParser;

options {
    tokenVocab=IslandSqlLexer;
}

/*----------------------------------------------------------------------------*/
// Start rule
/*----------------------------------------------------------------------------*/

file: selectStatement* EOF;

/*----------------------------------------------------------------------------*/
// Rules for reduced SQL grammar (islands of interest)
/*----------------------------------------------------------------------------*/

selectStatement: PLSQL_DECLARATION | SELECT;" 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: #9CDCFE">parser</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">grammar</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IslandSqlParser</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">options</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">tokenVocab</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">IslandSqlLexer</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Start rule</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C8C8C8">file</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">selectStatement</span><span style="color: #D4D4D4">* </span><span style="color: #4FC1FF">EOF</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"><span style="color: #6A9955">// Rules for reduced SQL grammar (islands of interest)</span></span>
<span class="line"><span style="color: #6A9955">/*----------------------------------------------------------------------------*/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C8C8C8">selectStatement</span><span style="color: #D4D4D4">: </span><span style="color: #4FC1FF">PLSQL_DECLARATION</span><span style="color: #D4D4D4"> | </span><span style="color: #4FC1FF">SELECT</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<h3 class="wp-block-heading">Parser Options</h3>



<p class="wp-block-paragraph">On line 4 we include the token vocabulary based on the lexer grammar. The vocabulary defines integer values for each token type, e.g. <code>PLSQL_DECLARATION=7</code> or <code>SELECT=8</code>. The token stream uses these integer values to identify token types. Integers are shorter than their string counterparts and therefore use fewer resources.</p>



<h3 class="wp-block-heading">Start Rule</h3>



<p class="wp-block-paragraph">You find the <a href="https://github.com/antlr/antlr4/blob/master/doc/parser-rules.md#start-rules-and-eof">start rule</a> <code>file</code> on line 11. This is the entry point for the parser. The root node of the parse tree.</p>



<p class="wp-block-paragraph">A <code>file</code>&nbsp;may contain an unbounded number of <code>selectStatement</code> rules. And a file ends on the pseudo token<code>EOF</code> (end-of-file). This way we ensure that the parser reads the complete file.</p>



<h3 class="wp-block-heading">Select Statement</h3>



<p class="wp-block-paragraph">On line 17 the <code>selectStatement</code>&nbsp;is defined either as a <code>PLSQL_DECLARATION</code> or <code>SELECT</code> token.</p>



<p class="wp-block-paragraph">That&#8217;s it. All other tokens are hidden and invisible to the parser.</p>



<p class="wp-block-paragraph">Furthermore, it&#8217;s not possible to produce a parse error with this grammar. Everything that is not a <code>selectStatement</code>&nbsp;is on the hidden channel and irrelevant.</p>



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



<p class="wp-block-paragraph">ANTLR is a parser generator. It takes the lexer and parser grammar as input and produces a lexer and parser in a chosen target language as output.</p>



<p class="wp-block-paragraph">However, there are also ANTLR interpreters. As a plugin in IDEs such as IntelliJ, as a standalone application or as a web application. After pasting the grammers into the UI you can play with it. Here&#8217;s a screenshot of the web variant of <a href="http://lab.antlr.org/">ANTLR lab</a>.</p>



<figure class="wp-block-image"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/02/antlr_lab.png"><img loading="lazy" decoding="async" width="2334" height="1358" src="https://www.salvis.com/blog/wp-content/uploads/2023/02/antlr_lab.png" alt="" class="wp-image-12047" srcset="https://www.salvis.com/blog/wp-content/uploads/2023/02/antlr_lab.png 2334w, https://www.salvis.com/blog/wp-content/uploads/2023/02/antlr_lab-300x175.png 300w, https://www.salvis.com/blog/wp-content/uploads/2023/02/antlr_lab-1024x596.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2023/02/antlr_lab-768x447.png 768w, https://www.salvis.com/blog/wp-content/uploads/2023/02/antlr_lab-1536x894.png 1536w, https://www.salvis.com/blog/wp-content/uploads/2023/02/antlr_lab-2048x1192.png 2048w, https://www.salvis.com/blog/wp-content/uploads/2023/02/antlr_lab-251x146.png 251w, https://www.salvis.com/blog/wp-content/uploads/2023/02/antlr_lab-50x29.png 50w, https://www.salvis.com/blog/wp-content/uploads/2023/02/antlr_lab-129x75.png 129w, https://www.salvis.com/blog/wp-content/uploads/2023/02/antlr_lab-1x1.png 1w" sizes="auto, (max-width:767px) 480px, (max-width:2334px) 100vw, 2334px" /></a></figure>



<p class="wp-block-paragraph">What about semantic predicates? &#8211; The interpreter acts as the call returned true. As a result, for example, <code>xselect * from dual;</code> is falsely recognized as a <code>select</code> statement. Nevertheless, this is usually good enough to explore most parts of an ANTLR grammar.</p>



<h2 class="wp-block-heading">IslandSQL on GitHub</h2>



<p class="wp-block-paragraph">The source code of the IslandSQL parser is available on <a href="https://github.com/IslandSQL/IslandSQL">GitHub</a>, licensed under the Apache License, Version 2.0.</p>



<p class="wp-block-paragraph">However, you will not find any test cases in this repo. I have written 92 test cases for the initial version 0.1.0. They are stored in a private repository. I do not plan to release them. It&#8217;s a way to make an unfriendly fork harder. Not right now. But once the grammar has evolved to cover a significant subset of SQL of the relevant database management systems, the situation might be different.</p>



<h2 class="wp-block-heading">IslandSQL on Maven Central</h2>



<p class="wp-block-paragraph">The IslandSQL parser is available on <a href="https://central.sonatype.com/artifact/ch.islandsql/islandsql/0.1.0">Maven Central</a>. This makes integration into your preferred build system easy.</p>



<p class="wp-block-paragraph">And using the parser is also easy. Here is 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);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">Demo.java</span><span role="button" tabindex="0" data-code="import ch.islandsql.grammar.IslandSqlDocument;
import ch.islandsql.grammar.IslandSqlParser;

class Demo {
    public static void main(String[] args) {
        var doc = IslandSqlDocument.parse(&quot;&quot;&quot;
                /* select * from t1; */
                -- select * from t2;
                rem select * from t3;
                prompt select * from t4;
                -- simple
                select * from dept;
                -- subquery_factoring_clause
                with d as (select * from dept) select * from d;
                -- other statements
                delete from t5;
                update t6 set c1 = null;
                commit;
                &quot;&quot;&quot;);
        System.out.println(doc.getFile().getText());
        System.out.println(&quot;----------&quot;);
        doc.getFile().children.forEach(child -&gt; System.out.print(child.getText()));
        System.out.println(&quot;\n----------&quot;);
        doc.getAllContentsOfType(IslandSqlParser.SelectStatementContext.class)
                .forEach(stmt -&gt; System.out.print(stmt.getText()));
    }
}" 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.IslandSqlDocument;</span></span>
<span class="line"><span style="color: #569CD6">import</span><span style="color: #D4D4D4"> ch.islandsql.grammar.IslandSqlParser;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Demo</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">doc</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">IslandSqlDocument</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">parse</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;&quot;&quot;</span></span>
<span class="line"><span style="color: #CE9178">                /* select * from t1; */</span></span>
<span class="line"><span style="color: #CE9178">                -- select * from t2;</span></span>
<span class="line"><span style="color: #CE9178">                rem select * from t3;</span></span>
<span class="line"><span style="color: #CE9178">                prompt select * from t4;</span></span>
<span class="line"><span style="color: #CE9178">                -- simple</span></span>
<span class="line"><span style="color: #CE9178">                select * from dept;</span></span>
<span class="line"><span style="color: #CE9178">                -- subquery_factoring_clause</span></span>
<span class="line"><span style="color: #CE9178">                with d as (select * from dept) select * from d;</span></span>
<span class="line"><span style="color: #CE9178">                -- other statements</span></span>
<span class="line"><span style="color: #CE9178">                delete from t5;</span></span>
<span class="line"><span style="color: #CE9178">                update t6 set c1 = null;</span></span>
<span class="line"><span style="color: #CE9178">                commit;</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: #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">getFile</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 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: #CE9178">&quot;----------&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><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 style="color: #9CDCFE">children</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">forEach</span><span style="color: #D4D4D4">(child </span><span style="color: #569CD6">-&gt;</span><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">print</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">child</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 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: #CE9178">&quot;</span><span style="color: #D7BA7D">\n</span><span style="color: #CE9178">----------&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><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">IslandSqlParser</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">SelectStatementContext</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">forEach</span><span style="color: #D4D4D4">(stmt </span><span style="color: #569CD6">-&gt;</span><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">print</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">stmt</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></code></pre></div>



<p class="wp-block-paragraph">The output of the main method is:</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">Output of Demo.java</span><span role="button" tabindex="0" data-code="select * from dept;
with d as (select * from dept) select * from d;
<EOF&gt;
----------
select * from dept;
with d as (select * from dept) select * from d;
<EOF&gt;
----------
select * from dept;
with d as (select * from dept) select * from d;" 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">select * from dept;</span></span>
<span class="line"><span style="color: #D4D4D4">with d as (select * from dept) select * from d;</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">select * from dept;</span></span>
<span class="line"><span style="color: #D4D4D4">with d as (select * from dept) select * from d;</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">select * from dept;</span></span>
<span class="line"><span style="color: #D4D4D4">with d as (select * from dept) select * from d;</span></span></code></pre></div>



<h2 class="wp-block-heading">IslandSQL on Visual Studio Code Marketplace</h2>



<p class="wp-block-paragraph">The extension for IslandSQL is available in the <a href="https://marketplace.visualstudio.com/items?itemName=phsalvisberg.islandsql">Visual Studio Code Marketplace</a>. You can install it directly from any VS Code installation.</p>



<p class="wp-block-paragraph">Agreed, this extension is currently of limited value. However, it was a good opportunity to learn about VSCode extension development and how to use the tooling around Microsoft&#8217;s Language Server Protocol (LSP) to integrate a grammar that is written in Java.</p>



<p class="wp-block-paragraph">I am sure I can use this knowledge for other projects like utPLSQL once <a href="https://www.thatjeffsmith.com/archive/2022/10/whats-next-for-oracle-sql-developer-a-quick-sneek-peek/">SQL Developer for VScode</a> is available.</p>



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



<p class="wp-block-paragraph">I plan to extend the IslandSQL grammar step by step and blog about the progress. At some point, it will be necessary to move the logic from the lexer to the parser. Before that, I&#8217;ll be working on the lexer side a bit longer.</p>



<p class="wp-block-paragraph">Adding the missing DML statements to the grammar will be the next item on my to-do list.</p>



<p class="wp-block-paragraph">Another topic is utPLSQL. The utPLSQL annotations in package specifications could be easily parsed with a dedicated island grammar. We could visualise test suite hierarchies in the IDE and also consider tags. Of course, we would duplicate some of utPLSQL&#8217;s code in the database. The advantage of such an approach is that we know where a test package is located in the file system. This helps in navigating to the right place, e.g. after test execution failures and could greatly improve the experience of file-based development (compared to SQL Developer). I am looking forward to the next generation of SQL Developer based on VS Codium, where such an extension would bring the most value.</p>
<p>The post <a href="https://www.salvis.com/blog/2023/02/04/islandsql-episode-1-select-statement/">IslandSQL Episode 1:  Select Statement</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/2023/02/04/islandsql-episode-1-select-statement/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
