{"id":13526,"date":"2024-07-29T16:00:55","date_gmt":"2024-07-29T14:00:55","guid":{"rendered":"https:\/\/www.salvis.com\/blog\/?p=13526"},"modified":"2024-07-29T16:11:16","modified_gmt":"2024-07-29T14:11:16","slug":"islandsql-final-episode-10-parsing-pl-pgsql","status":"publish","type":"post","link":"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/","title":{"rendered":"IslandSQL Final Episode 10: Parsing PL\/pgSQL"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\" id=\"introduction\">Introduction<\/h2>\n\n\n\n<p>IslandSQL is a parser for SQL files targeting OracleDB or PostgreSQL. The parser is available on <a href=\"https:\/\/central.sonatype.com\/artifact\/ch.islandsql\/islandsql\">Maven Central<\/a> and can process SQL*Plus, SQLcl or psql statements besides SQL statements. However, the focus is on statements with static DML statements and code in PL\/SQL and PL\/pgSQL. For static code analysis, for example.<\/p>\n\n\n\n<p>In PostgreSQL <code>create function<\/code>, <code>create procedure<\/code> and <code>do<\/code> accept code as a string. This simplifies parsing and the implementation of additional languages. As a result, you can write functions and procedures in SQL, PL\/pgSQL, PL\/Tcl, PL\/Perl and PL\/Python in any standard PostgreSQL distribution.<\/p>\n\n\n\n<p>Starting with IslandSQL version 0.10 it&#8217;s possible to parse SQL and PL\/pgSQL in strings and extend the parse tree accordingly. In this blog post, I will explain how this works.<\/p>\n\n\n\n<p>This\u00a0<a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=phsalvisberg.islandsql\">VS Code extension<\/a>\u00a0uses IslandSQL in a language server to report syntax errors and to produce parse trees as shown in this blog post.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"plpgsql_as_string\">PL\/pgSQL as String<\/h2>\n\n\n\n<p>Let&#8217;s look at a <code>do<\/code> statement executing a PL\/pgSQL block provided as a string.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">1) hello_world.sql<\/span><span role=\"button\" tabindex=\"0\" data-code=\"do '\nbegin\n   raise notice $$Hello World!$$;\nend\n';\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D4D4D4\">do <\/span><span style=\"color: #CE9178\">&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">begin<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">   raise notice $$Hello World!$$;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">end<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">&#39;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"NOTICE:  Hello World!\nDO\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D4D4D4\">NOTICE:  Hello World!<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">DO<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>The parse tree in IslandSQL version 0.9 looks as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized is-style-default\"><a href=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/07\/1-plpgsql-string-only.svg\"><img wpfc-lazyload-disable=\"true\" decoding=\"async\" src=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/07\/1-plpgsql-string-only.svg\" alt=\"Parse tree with PL\/pgSQL as string\" class=\"wp-image-13529\" style=\"width:310px\"\/><\/a><\/figure>\n\n\n\n<p>Look at the parse tree. It is quite simple. Interesting is the PL\/pgSQL block. The content in single quotes is represented as a single token. The big rectangle at the bottom. It&#8217;s a single token regardless of the code size.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"plpgsql_as_subtree\">PL\/pgSQL as Subtree<\/h2>\n\n\n\n<p>Parsing PL\/pgSQL as a string is easy. The lexer produces the token for the string containing the PL\/pgSQL code. The parser does not need to understand the PL\/pgSQL at all.<\/p>\n\n\n\n<p>But this does not help analyse the PL\/pgSQL code. We need a parser that <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>understands PL\/pgSQL <\/li>\n\n\n\n<li>parses PL\/pgSQL code provided as a string<\/li>\n\n\n\n<li>extends the main parse tree by sub-parse trees with PL\/pgSQL code<\/li>\n<\/ul>\n\n\n\n<p>The IslandSQL parser in version 0.10 does exactly that. It produces this parse tree by default:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><a href=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/07\/2-plpgsql-string-and-subtree.svg\"><img wpfc-lazyload-disable=\"true\" decoding=\"async\" src=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/07\/2-plpgsql-string-and-subtree.svg\" alt=\"Parse tree with PL\/pgSQL as string and as subtree\" class=\"wp-image-13540\" style=\"width:550px\"\/><\/a><\/figure>\n\n\n\n<p>The PL\/pgSQL code is represented twice in this parse tree. Once as a single token. And once as a node named <code>postgresqlPlpgsqlCode<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"plpgsql_as_subtree_only\">PL\/pgSQL as Subtree Only<\/h2>\n\n\n\n<p>Maybe you do not like it when PL\/pgSQL code is represented twice in the parse tree. In this case, you can override the default options when creating an IslandSQL document.<\/p>\n\n\n\n<p>The IslandSQL library requires Java 8 or newer. In the next example, we use Java 22 to reduce boilerplate code. <a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/22\/language\/implicitly-declared-classes-and-instance-main-methods.html\">Implicitly declared classes<\/a> are still in preview. Hence we have to pass the parameters <code>--enable-preview --source 22<\/code> when running the <code>HelloWorld.java<\/code> program. <\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Explaining HelloWorld.java<\/h5>\n\n\n\n<p>In line 13 we create the IslandSQL document with a series of parameters. One of them is <code>removeCode(true)<\/code> in line 19 which oversteers the default behaviour and removes the code as a string from the parse tree.<\/p>\n\n\n\n<p>In line 21 we print a profile. Thanks to Cary Millsap, I can&#8217;t deal with performance issues without thinking about a bicycle, a Ferrari and kissing&#8230; The profile helps to understand where the parser has spent its time.<\/p>\n\n\n\n<p>Finally, in lines 22 and 23 we print the parse tree. Once as a simple textual hierarchy and once as a <a href=\"https:\/\/www.graphviz.org\/doc\/info\/lang.html\">DOT<\/a> graph. You can visualise the result in <a href=\"https:\/\/edotor.net\/?engine=dot#digraph%20islandSQL%20%7B%0A%20%20bgcolor%3D%22transparent%22%0A%20%20%221155757579%22%20%5Bshape%3Dellipse%20label%3D%22file%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%221155757579%22%20-%3E%20%221785111044%22%0A%20%20%221155757579%22%20-%3E%20%221482748887%22%0A%20%20%221785111044%22%20%5Bshape%3Dellipse%20label%3D%22statement%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%221785111044%22%20-%3E%20%22494894055%22%0A%20%20%22494894055%22%20%5Bshape%3Dellipse%20label%3D%22doStatement%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22494894055%22%20-%3E%20%221123226989%22%0A%20%20%22494894055%22%20-%3E%20%22500885941%22%0A%20%20%221123226989%22%20%5Bshape%3Dellipse%20label%3D%22postgresqlDo%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%221123226989%22%20-%3E%20%221115381650%22%0A%20%20%221123226989%22%20-%3E%20%22616412281%22%0A%20%20%221115381650%22%20%5Bshape%3Dbox%20label%3D%22do%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22616412281%22%20%5Bshape%3Dellipse%20label%3D%22postgresqlPlpgsqlCode%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22616412281%22%20-%3E%20%222118096382%22%0A%20%20%22616412281%22%20-%3E%20%22878861517%22%0A%20%20%22616412281%22%20-%3E%20%22746394140%22%0A%20%20%222118096382%22%20%5Bshape%3Dbox%20label%3D%22begin%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22878861517%22%20%5Bshape%3Dellipse%20label%3D%22plsqlStatement%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22878861517%22%20-%3E%20%221705665942%22%0A%20%20%221705665942%22%20%5Bshape%3Dellipse%20label%3D%22postgresqlRaiseStatement%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%221705665942%22%20-%3E%20%221731763384%22%0A%20%20%221705665942%22%20-%3E%20%221100619942%22%0A%20%20%221705665942%22%20-%3E%20%2287242619%22%0A%20%20%221705665942%22%20-%3E%20%22864248990%22%0A%20%20%221731763384%22%20%5Bshape%3Dbox%20label%3D%22raise%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%221100619942%22%20%5Bshape%3Dellipse%20label%3D%22raiseLevel%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%221100619942%22%20-%3E%20%22285074186%22%0A%20%20%22285074186%22%20%5Bshape%3Dbox%20label%3D%22notice%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%2287242619%22%20%5Bshape%3Dellipse%20label%3D%22dollarString%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%2287242619%22%20-%3E%20%2215892131%22%0A%20%20%2215892131%22%20%5Bshape%3Dbox%20label%3D%22%24%24Hello%20World!%24%24%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22864248990%22%20%5Bshape%3Dbox%20label%3D%22%3B%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22746394140%22%20%5Bshape%3Dbox%20label%3D%22end%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22500885941%22%20%5Bshape%3Dellipse%20label%3D%22sqlEnd%22%20style%3Dfilled%20fillcolor%3D%22%23bfe6ff%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%22500885941%22%20-%3E%20%22484841769%22%0A%20%20%22484841769%22%20%5Bshape%3Dbox%20label%3D%22%3B%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%20%20%221482748887%22%20%5Bshape%3Dbox%20label%3D%22%3CEOF%3E%22%20style%3Dfilled%20fillcolor%3D%22%23fadabd%22%20fontname%3D%22Helvetica%22%5D%0A%7D%0A\">Edotor.net<\/a>, for example.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">2) HelloWorld.java<\/span><span role=\"button\" tabindex=\"0\" data-code=\"import ch.islandsql.grammar.IslandSqlDialect;\nimport ch.islandsql.grammar.IslandSqlDocument;\nimport ch.islandsql.grammar.util.ParseTreeUtil;\n\nvoid main() {\n    var source = &quot;&quot;&quot;\n            do '\n            begin\n               raise notice $$Hello World!$$;\n            end\n            ';\n            &quot;&quot;&quot;;\n    var doc = new IslandSqlDocument.Builder()\n            .sql(source)\n            .hideOutOfScopeTokens(false)\n            .dialect(IslandSqlDialect.POSTGRESQL)\n            .profile(true)\n            .subtrees(true)\n            .removeCode(true)\n            .build();\n    System.out.println(doc.getParserMetrics().printProfile());\n    System.out.println(ParseTreeUtil.printParseTree(doc.getFile()));\n    System.out.println(ParseTreeUtil.dotParseTree(doc.getFile()));\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">import<\/span><span style=\"color: #D4D4D4\"> ch.islandsql.grammar.IslandSqlDialect;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">import<\/span><span style=\"color: #D4D4D4\"> ch.islandsql.grammar.IslandSqlDocument;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">import<\/span><span style=\"color: #D4D4D4\"> ch.islandsql.grammar.util.ParseTreeUtil;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #4EC9B0\">void<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">main<\/span><span style=\"color: #D4D4D4\">() {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">source<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;&quot;&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">            do &#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">            begin<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">               raise notice $$Hello World!$$;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">            end<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">            &#39;;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">            &quot;&quot;&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">doc<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #C586C0\">new<\/span><span style=\"color: #D4D4D4\"> IslandSqlDocument.<\/span><span style=\"color: #DCDCAA\">Builder<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            .<\/span><span style=\"color: #DCDCAA\">sql<\/span><span style=\"color: #D4D4D4\">(source)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            .<\/span><span style=\"color: #DCDCAA\">hideOutOfScopeTokens<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">false<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            .<\/span><span style=\"color: #DCDCAA\">dialect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">IslandSqlDialect<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">POSTGRESQL<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            .<\/span><span style=\"color: #DCDCAA\">profile<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">true<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            .<\/span><span style=\"color: #DCDCAA\">subtrees<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">true<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            .<\/span><span style=\"color: #DCDCAA\">removeCode<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">true<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            .<\/span><span style=\"color: #DCDCAA\">build<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">System<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">out<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">println<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">doc<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">getParserMetrics<\/span><span style=\"color: #D4D4D4\">().<\/span><span style=\"color: #DCDCAA\">printProfile<\/span><span style=\"color: #D4D4D4\">());<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">System<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">out<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">println<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">ParseTreeUtil<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">printParseTree<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">doc<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">getFile<\/span><span style=\"color: #D4D4D4\">()));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">System<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">out<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">println<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">ParseTreeUtil<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">dotParseTree<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">doc<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">getFile<\/span><span style=\"color: #D4D4D4\">()));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"java --enable-preview --source 22 -cp .:islandsql-0.10.0.jar:antlr4-runtime-4.13.1.jar HelloWorld.java\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #DCDCAA\">java<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">--enable-preview<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">--source<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">22<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-cp<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">.:islandsql-0.10.0.jar:antlr4-runtime-4.13.1.jar<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">HelloWorld.java<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"Profile\n=======\n\nTotal memory used by parser    : 5\u2019164 KB\nTotal time spent in parser     : 27.918 ms\nTotal time recorded by profiler: 14.167 ms (100%)\n\nRule Name (Decision)                          Time (ms) Percent Invocations Lookahead Max Lookahead Ambiguities Errors\n---------------------------------------- -------------- ------- ----------- --------- ------------- ----------- ------\nstring (1887)                                    10.302   72.72           2         0             0           0      0\nplsqlStatement (1129)                             1.337    9.44           1         0             0           0      0\npostgresqlDo (576)                                0.750    5.30           1         0             0           0      0\npostgresqlPlpgsqlCode (6)                         0.735    5.19           2         0             0           0      0\nstatement (11)                                    0.566    3.99           1         0             0           0      0\nsqlEnd (1888)                                     0.314    2.21           1         0             0           0      0\npostgresqlRaiseStatement (1260)                   0.134    0.95           1         0             0           0      0\npostgresqlRaiseStatement (1269)                   0.030    0.21           1         0             0           0      0\n\nfile\n  statement\n    doStatement\n      postgresqlDo\n        K_DO:do\n        postgresqlPlpgsqlCode\n          K_BEGIN:begin\n          plsqlStatement\n            postgresqlRaiseStatement\n              K_RAISE:raise\n              raiseLevel\n                K_NOTICE:notice\n              string:dollarString\n                DOLLAR_STRING:$$Hello World!$$\n              SEMI:;\n          K_END:end\n      sqlEnd\n        SEMI:;\n  &lt;EOF&gt;\n\ndigraph islandSQL {\n  bgcolor=&quot;transparent&quot;\n  &quot;1155757579&quot; [shape=ellipse label=&quot;file&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]\n  &quot;1155757579&quot; -&gt; &quot;1785111044&quot;\n  &quot;1155757579&quot; -&gt; &quot;1482748887&quot;\n  &quot;1785111044&quot; [shape=ellipse label=&quot;statement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]\n  &quot;1785111044&quot; -&gt; &quot;494894055&quot;\n  &quot;494894055&quot; [shape=ellipse label=&quot;doStatement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]\n  &quot;494894055&quot; -&gt; &quot;1123226989&quot;\n  &quot;494894055&quot; -&gt; &quot;500885941&quot;\n  &quot;1123226989&quot; [shape=ellipse label=&quot;postgresqlDo&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]\n  &quot;1123226989&quot; -&gt; &quot;1115381650&quot;\n  &quot;1123226989&quot; -&gt; &quot;616412281&quot;\n  &quot;1115381650&quot; [shape=box label=&quot;do&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]\n  &quot;616412281&quot; [shape=ellipse label=&quot;postgresqlPlpgsqlCode&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]\n  &quot;616412281&quot; -&gt; &quot;2118096382&quot;\n  &quot;616412281&quot; -&gt; &quot;878861517&quot;\n  &quot;616412281&quot; -&gt; &quot;746394140&quot;\n  &quot;2118096382&quot; [shape=box label=&quot;begin&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]\n  &quot;878861517&quot; [shape=ellipse label=&quot;plsqlStatement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]\n  &quot;878861517&quot; -&gt; &quot;1705665942&quot;\n  &quot;1705665942&quot; [shape=ellipse label=&quot;postgresqlRaiseStatement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]\n  &quot;1705665942&quot; -&gt; &quot;1731763384&quot;\n  &quot;1705665942&quot; -&gt; &quot;1100619942&quot;\n  &quot;1705665942&quot; -&gt; &quot;87242619&quot;\n  &quot;1705665942&quot; -&gt; &quot;864248990&quot;\n  &quot;1731763384&quot; [shape=box label=&quot;raise&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]\n  &quot;1100619942&quot; [shape=ellipse label=&quot;raiseLevel&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]\n  &quot;1100619942&quot; -&gt; &quot;285074186&quot;\n  &quot;285074186&quot; [shape=box label=&quot;notice&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]\n  &quot;87242619&quot; [shape=ellipse label=&quot;dollarString&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]\n  &quot;87242619&quot; -&gt; &quot;15892131&quot;\n  &quot;15892131&quot; [shape=box label=&quot;$$Hello World!$$&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]\n  &quot;864248990&quot; [shape=box label=&quot;;&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]\n  &quot;746394140&quot; [shape=box label=&quot;end&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]\n  &quot;500885941&quot; [shape=ellipse label=&quot;sqlEnd&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]\n  &quot;500885941&quot; -&gt; &quot;484841769&quot;\n  &quot;484841769&quot; [shape=box label=&quot;;&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]\n  &quot;1482748887&quot; [shape=box label=&quot;&lt;EOF&gt;&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D4D4D4\">Profile<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">=======<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"><\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">Total memory used by parser    : 5\u2019164 KB<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">Total time spent in parser     : 27.918 ms<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">Total time recorded by profiler: 14.167 ms (100%)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"><\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">Rule Name (Decision)                          Time (ms) Percent Invocations Lookahead Max Lookahead Ambiguities Errors<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">---------------------------------------- -------------- ------- ----------- --------- ------------- ----------- ------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">string (1887)                                    10.302   72.72           2         0             0           0      0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">plsqlStatement (1129)                             1.337    9.44           1         0             0           0      0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">postgresqlDo (576)                                0.750    5.30           1         0             0           0      0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">postgresqlPlpgsqlCode (6)                         0.735    5.19           2         0             0           0      0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">statement (11)                                    0.566    3.99           1         0             0           0      0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">sqlEnd (1888)                                     0.314    2.21           1         0             0           0      0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">postgresqlRaiseStatement (1260)                   0.134    0.95           1         0             0           0      0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">postgresqlRaiseStatement (1269)                   0.030    0.21           1         0             0           0      0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"><\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">file<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  statement<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    doStatement<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      postgresqlDo<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        K_DO:do<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        postgresqlPlpgsqlCode<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">          K_BEGIN:begin<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">          plsqlStatement<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            postgresqlRaiseStatement<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">              K_RAISE:raise<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">              raiseLevel<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                K_NOTICE:notice<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">              string:dollarString<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                DOLLAR_STRING:$$Hello World!$$<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">              SEMI:;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">          K_END:end<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      sqlEnd<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        SEMI:;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &lt;EOF&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"><\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">digraph islandSQL {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  bgcolor=&quot;transparent&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1155757579&quot; [shape=ellipse label=&quot;file&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1155757579&quot; -&gt; &quot;1785111044&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1155757579&quot; -&gt; &quot;1482748887&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1785111044&quot; [shape=ellipse label=&quot;statement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1785111044&quot; -&gt; &quot;494894055&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;494894055&quot; [shape=ellipse label=&quot;doStatement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;494894055&quot; -&gt; &quot;1123226989&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;494894055&quot; -&gt; &quot;500885941&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1123226989&quot; [shape=ellipse label=&quot;postgresqlDo&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1123226989&quot; -&gt; &quot;1115381650&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1123226989&quot; -&gt; &quot;616412281&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1115381650&quot; [shape=box label=&quot;do&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;616412281&quot; [shape=ellipse label=&quot;postgresqlPlpgsqlCode&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;616412281&quot; -&gt; &quot;2118096382&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;616412281&quot; -&gt; &quot;878861517&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;616412281&quot; -&gt; &quot;746394140&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;2118096382&quot; [shape=box label=&quot;begin&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;878861517&quot; [shape=ellipse label=&quot;plsqlStatement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;878861517&quot; -&gt; &quot;1705665942&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1705665942&quot; [shape=ellipse label=&quot;postgresqlRaiseStatement&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1705665942&quot; -&gt; &quot;1731763384&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1705665942&quot; -&gt; &quot;1100619942&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1705665942&quot; -&gt; &quot;87242619&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1705665942&quot; -&gt; &quot;864248990&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1731763384&quot; [shape=box label=&quot;raise&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1100619942&quot; [shape=ellipse label=&quot;raiseLevel&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1100619942&quot; -&gt; &quot;285074186&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;285074186&quot; [shape=box label=&quot;notice&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;87242619&quot; [shape=ellipse label=&quot;dollarString&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;87242619&quot; -&gt; &quot;15892131&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;15892131&quot; [shape=box label=&quot;$$Hello World!$$&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;864248990&quot; [shape=box label=&quot;;&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;746394140&quot; [shape=box label=&quot;end&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;500885941&quot; [shape=ellipse label=&quot;sqlEnd&quot; style=filled fillcolor=&quot;#bfe6ff&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;500885941&quot; -&gt; &quot;484841769&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;484841769&quot; [shape=box label=&quot;;&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  &quot;1482748887&quot; [shape=box label=&quot;&lt;EOF&gt;&quot; style=filled fillcolor=&quot;#fadabd&quot; fontname=&quot;Helvetica&quot;]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>The parse tree looks now like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><a href=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/07\/3-plpgsql-subtree-only.svg\"><img wpfc-lazyload-disable=\"true\" decoding=\"async\" src=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/07\/3-plpgsql-subtree-only.svg\" alt=\"Parse tree with PL\/pgSQL as subtree only\" class=\"wp-image-13539\" style=\"width:380px\"\/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"sql_dialect\">SQL Dialect<\/h2>\n\n\n\n<p>In line 16 of the previous <code>HelloWorld.java<\/code> program we set the dialect to <code>POSTGRESQL<\/code>.  Is that required? &#8211; No, it&#8217;s not. But when do we need to set the SQL dialect in IslandSQL? &#8211; When the lexical incompatibility between OracleDB and PostgreSQL leads to syntax errors in the code to be parsed. <\/p>\n\n\n\n<p>What? &#8211; Let me explain.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"identifiers\">Identifiers<\/h2>\n\n\n\n<p>OracleDB and PostgreSQL use different characters to build an identifier. The following table shows the differences. The allowed characters are listed in square brackets. Read <code>\\p{Alpha}<\/code> as any alphabetic letter in the character set of the database.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>DBMS<\/th><th>Allowed as First Character<\/th><th>Allowed in Subsequent Characters<\/th><\/tr><\/thead><tbody><tr><td>OracleDB<\/td><td><code>[\\p{Alpha}]<\/code><\/td><td>[_$#0-9\\p{Alpha}]<\/td><\/tr><tr><td>PostgreSQL<\/td><td><code>[_\\p{Alpha}]<\/code><\/td><td>[_$0-9\\p{Alpha}]<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>PostgreSQL allows identifiers that start with an underscore. That&#8217;s not a problem. However, OracleDB allows the hash sign (<code>#<\/code>) to be used in an identifier. That leads to unexpected results when the PostgreSQL code uses the <a href=\"https:\/\/www.postgresql.org\/docs\/current\/functions-bitstring.html\">bitwise XOR operator<\/a> without spaces around it. Here&#8217;s an example<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">3) One or two identifiers in select_list?<\/span><span role=\"button\" tabindex=\"0\" data-code=\"select a#b from t;\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">select<\/span><span style=\"color: #D4D4D4\"> a#b <\/span><span style=\"color: #569CD6\">from<\/span><span style=\"color: #D4D4D4\"> t;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>PostgreSQL expects that the columns <code>a<\/code> and <code>b<\/code> exists in table <code>t<\/code>.<\/p>\n\n\n\n<p>OracleDB expects that the column <code>a#b<\/code> exists in table <code>t<\/code>.<\/p>\n\n\n\n<p>In this case, IslandSQL can parse the code without errors. However, the parse tree might not look as expected. That&#8217;s a documented limitation and cannot be influenced by setting the dialect. At least not in version 0.10 of IslandSQL. Nevertheless, it shows the impact of a lexical incompatibility.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"inquiry_directives\">Inquiry Directives<\/h2>\n\n\n\n<p>PL\/SQL supports predefined and custom <a href=\"https:\/\/docs.oracle.com\/en\/database\/oracle\/oracle-database\/23\/lnpls\/plsql-language-fundamentals.html#GUID-E918087C-D5A8-4CEE-841B-5333DE6D4C15\">Inquiry Directives<\/a>. These directives are lexically incompatible with PostgreSQL <a href=\"https:\/\/www.postgresql.org\/docs\/current\/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING\">dollar-quoted string constants<\/a>.<\/p>\n\n\n\n<p>Here&#8217;s an example:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">4) Using custom inquiry directives<\/span><span role=\"button\" tabindex=\"0\" data-code=\"alter session set plsql_ccflags = 'custom1:41, custom2:42';\nbegin\n   dbms_output.put_line($$custom1);\n   dbms_output.put_line($$custom2 || '(2)');\nend;\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #DCDCAA\">alter session<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">set<\/span><span style=\"color: #D4D4D4\"> plsql_ccflags = <\/span><span style=\"color: #CE9178\">&#39;custom1:41, custom2:42&#39;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">begin<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #DCDCAA\">dbms_output.<\/span><span style=\"color: #4EC9B0\">put_line<\/span><span style=\"color: #D4D4D4\">($$custom1);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #DCDCAA\">dbms_output.<\/span><span style=\"color: #4EC9B0\">put_line<\/span><span style=\"color: #D4D4D4\">($$custom2 || <\/span><span style=\"color: #CE9178\">&#39;(2)&#39;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">end<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>By default, this causes a parse error, because\u00a0<code>$$custom1);\\n dbms_output.put_line($$<\/code>\u00a0is identified as a dollar-quoted string constant by the lexer. As a result, the code is interpreted like this:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">5) Visualising how two custom inquiry directives  are treated as a string<\/span><span role=\"button\" tabindex=\"0\" data-code=\"alter session set plsql_ccflags = 'custom1:41, custom2:42';\nbegin\n   dbms_output.put_line('custom1);\n   dbms_output.put_line('custom2 || '(2)');\nend;\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #DCDCAA\">alter session<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">set<\/span><span style=\"color: #D4D4D4\"> plsql_ccflags = <\/span><span style=\"color: #CE9178\">&#39;custom1:41, custom2:42&#39;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">begin<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #DCDCAA\">dbms_output.<\/span><span style=\"color: #4EC9B0\">put_line<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;custom1);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">   dbms_output.put_line(&#39;<\/span><span style=\"color: #D4D4D4\">custom2 || <\/span><span style=\"color: #CE9178\">&#39;(2)&#39;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">end<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>This makes it clearer, why we get a syntax error in line 4 at <code>custom2<\/code>.<\/p>\n\n\n\n<p>In this case, we have to set the SQL dialect to <code>ORACLEDB<\/code> to parse <code>custom_inquiry_directives.sql<\/code> without errors. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"predefined_inquiry_directives\">Predefined Inquiry Directives<\/h2>\n\n\n\n<p>To simplify the use, we want to avoid specifying the SQL dialect. One way to achieve that is to handle predefined inquiry directives in the <code>GENERIC<\/code> SQL dialect.<\/p>\n\n\n\n<p>Here&#8217;s an example, that does not report syntax errors:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">6) Using predefined inquiry directives<\/span><span role=\"button\" tabindex=\"0\" data-code=\"begin\n   dbms_output.put_line($$plsql_line);\n   dbms_output.put_line($$plsql_line || '(2)');\nend;\" 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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #DCDCAA\">dbms_output.<\/span><span style=\"color: #4EC9B0\">put_line<\/span><span style=\"color: #D4D4D4\">($$plsql_line);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #DCDCAA\">dbms_output.<\/span><span style=\"color: #4EC9B0\">put_line<\/span><span style=\"color: #D4D4D4\">($$plsql_line || <\/span><span style=\"color: #CE9178\">&#39;(2)&#39;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">end<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>We know the predefined inquiry directives and can deal with them in the lexer.<\/p>\n\n\n\n<p>However, this special treatment can cause problems in corner cases like this one:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">7) Using the name of a predefined inquiry directive at the start of a dollar-quoted string constant<\/span><span role=\"button\" tabindex=\"0\" data-code=\"do '\nbegin\n   raise notice $$plsql_line is a predefined inquiry directive$$;\nend\n';\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D4D4D4\">do <\/span><span style=\"color: #CE9178\">&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">begin<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">   raise notice $$plsql_line is a predefined inquiry directive$$;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">end<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">&#39;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>In such cases, we should use the <code>POSTGRESQL<\/code> dialect to avoid parse errors.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"detect_sql_dialect\">Detect SQL Dialect<\/h2>\n\n\n\n<p>Is there a way to detect the SQL dialect of an SQL input automatically? Sure. Several. I&#8217;m sure there is a way to use an LLM to get a reasonable result. I&#8217;m more of a rule-based guy. So we could parse the code with one dialect and on parse errors try other dialects. If all dialects produce errors, we could choose the one with the fewest errors.<\/p>\n\n\n\n<p>This sounds costly, right? Therefore I decided to start with a simple SQL dialect detection mechanism. The current implementation looks like this:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">8) Excerpt of IslandSqlDocument.java in version 0.10.0<\/span><span role=\"button\" tabindex=\"0\" data-code=\"private static IslandSqlDialect guessDialect(String sql) {\n    return sql.contains(&quot;\\n\/\\n&quot;) ? IslandSqlDialect.ORACLEDB : IslandSqlDialect.GENERIC;\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">private<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">static<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">IslandSqlDialect<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">guessDialect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #4EC9B0\">String<\/span><span style=\"color: #D4D4D4\"> sql) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">sql<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">contains<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;<\/span><span style=\"color: #D7BA7D\">\\n<\/span><span style=\"color: #CE9178\">\/<\/span><span style=\"color: #D7BA7D\">\\n<\/span><span style=\"color: #CE9178\">&quot;<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #C586C0\">?<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">IslandSqlDialect<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">ORACLEDB<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">:<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">IslandSqlDialect<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">GENERIC<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>In other words, if the code contains a slash followed by a newline character in the first column of a line, then we go with the <code>ORACLEDB<\/code> dialect. In all other cases, we go with the <code>GENERIC<\/code> SQL dialect.<\/p>\n\n\n\n<p>My first version was even simpler. However, I had to add a final <code>\\n<\/code> to the search string to ensure that SQL code containing multiline comments is not recognized as <code>ORACLEDB<\/code> dialect. Files with Windows newline characters are always recognized as GENERIC. That&#8217;s the price when trying to keep things simple and fast.<\/p>\n\n\n\n<p>Now, the ORACLEDB SQL dialect is correctly detected in the next example. As a result, no syntax errors are reported.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">9) Using custom inquiry directives in a PL\/SQL Block ending on slash<\/span><span role=\"button\" tabindex=\"0\" data-code=\"alter session set plsql_ccflags = 'custom1:41, custom2:42';\nbegin\n   dbms_output.put_line($$custom1);\n   dbms_output.put_line($$custom2 || '(2)');\nend;\n\/\n\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #DCDCAA\">alter session<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">set<\/span><span style=\"color: #D4D4D4\"> plsql_ccflags = <\/span><span style=\"color: #CE9178\">&#39;custom1:41, custom2:42&#39;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">begin<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #DCDCAA\">dbms_output.<\/span><span style=\"color: #4EC9B0\">put_line<\/span><span style=\"color: #D4D4D4\">($$custom1);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #DCDCAA\">dbms_output.<\/span><span style=\"color: #4EC9B0\">put_line<\/span><span style=\"color: #D4D4D4\">($$custom2 || <\/span><span style=\"color: #CE9178\">&#39;(2)&#39;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">end<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">\/<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p>The SQL dialect detection mechanism kicks in when no SQL dialect is specified (<code>null<\/code>). <\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"conclusion\">Conclusion<\/h2>\n\n\n\n<p>Developing a single grammar for OracleDB and PostgreSQL was an interesting work. I learned a lot about the underlying DBMS. I often looked at the grammar documentation and did not understand it fully. So I had to run the provided examples or create some myself. The typical test cases are based on working examples, extended by tests based on the cartesian product of a subset of clauses that verified if I had defined the order, the optionality, and the cardinality according to the documentation.<\/p>\n\n\n\n<p>A challenge is the undocumented stuff. There are various reasons why something is not documented. In the end, it does not matter why something is missing. The parser fails when processing code that works but should not according to the docs. This cannot be covered by tests based on the official documentation. I found some bugs while processing real-life code. And I expect to find more.<\/p>\n\n\n\n<p>This is the season finale of IslandSQL. There won&#8217;t be a second season. However, there might be some spin-offs since I plan to build products based on IslandSQL. Therefore I plan to keep the parser compatible with the latest versions of OracleDB and PostgreSQL.<\/p>\n\n\n\n<p>Feedback is welcome. Please leave your comments on this blog post or open an issue in the <a href=\"https:\/\/github.com\/IslandSQL\/IslandSQL\">IslandSQL GitHub repository<\/a> for questions, bugs or feature requests.<\/p>\n\n\n\n<p>Thank you.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction IslandSQL is a parser for SQL files targeting OracleDB or PostgreSQL. The parser is available on Maven Central and can process SQL*Plus, SQLcl or psql statements besides SQL statements. However, the focus is on statements with static DML statements and code in PL\/SQL and PL\/pgSQL. For static code analysis, for example.<span class=\"excerpt-hellip\"> [\u2026]<\/span><\/p>\n","protected":false},"author":1,"featured_media":13527,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[139,86,137,140,111,85],"class_list":["post-13526","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oracle","tag-antlr","tag-code-analysis","tag-islandsql","tag-oracle-26ai","tag-postgresql","tag-sql"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>IslandSQL Final Episode 10: Parsing PL\/pgSQL - Philipp Salvisberg&#039;s Blog<\/title>\n<meta name=\"description\" content=\"In this final episode, we look at parse trees of statements containing PL\/pgSQL and how to deal with lexical incompatibilities.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"IslandSQL Final Episode 10: Parsing PL\/pgSQL - Philipp Salvisberg&#039;s Blog\" \/>\n<meta property=\"og:description\" content=\"In this final episode, we look at parse trees of statements containing PL\/pgSQL and how to deal with lexical incompatibilities.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/\" \/>\n<meta property=\"og:site_name\" content=\"Philipp Salvisberg&#039;s Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-07-29T14:00:55+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-07-29T14:11:16+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/07\/IslandSQL10c.png\" \/>\n\t<meta property=\"og:image:width\" content=\"512\" \/>\n\t<meta property=\"og:image:height\" content=\"512\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Philipp Salvisberg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@phsalvisberg\" \/>\n<meta name=\"twitter:site\" content=\"@phsalvisberg\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Philipp Salvisberg\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/07\\\/29\\\/islandsql-final-episode-10-parsing-pl-pgsql\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/07\\\/29\\\/islandsql-final-episode-10-parsing-pl-pgsql\\\/\"},\"author\":{\"name\":\"Philipp Salvisberg\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#\\\/schema\\\/person\\\/34352245c48678b1a5a05d4bc1339515\"},\"headline\":\"IslandSQL Final Episode 10: Parsing PL\\\/pgSQL\",\"datePublished\":\"2024-07-29T14:00:55+00:00\",\"dateModified\":\"2024-07-29T14:11:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/07\\\/29\\\/islandsql-final-episode-10-parsing-pl-pgsql\\\/\"},\"wordCount\":1412,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#\\\/schema\\\/person\\\/34352245c48678b1a5a05d4bc1339515\"},\"image\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/07\\\/29\\\/islandsql-final-episode-10-parsing-pl-pgsql\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2024\\\/07\\\/IslandSQL10c.png\",\"keywords\":[\"ANTLR\",\"Code Analysis\",\"IslandSQL\",\"Oracle 26ai\",\"PostgreSQL\",\"SQL\"],\"articleSection\":[\"Oracle\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/07\\\/29\\\/islandsql-final-episode-10-parsing-pl-pgsql\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/07\\\/29\\\/islandsql-final-episode-10-parsing-pl-pgsql\\\/\",\"url\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/07\\\/29\\\/islandsql-final-episode-10-parsing-pl-pgsql\\\/\",\"name\":\"IslandSQL Final Episode 10: Parsing PL\\\/pgSQL - Philipp Salvisberg&#039;s Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/07\\\/29\\\/islandsql-final-episode-10-parsing-pl-pgsql\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/07\\\/29\\\/islandsql-final-episode-10-parsing-pl-pgsql\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2024\\\/07\\\/IslandSQL10c.png\",\"datePublished\":\"2024-07-29T14:00:55+00:00\",\"dateModified\":\"2024-07-29T14:11:16+00:00\",\"description\":\"In this final episode, we look at parse trees of statements containing PL\\\/pgSQL and how to deal with lexical incompatibilities.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/07\\\/29\\\/islandsql-final-episode-10-parsing-pl-pgsql\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/07\\\/29\\\/islandsql-final-episode-10-parsing-pl-pgsql\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/07\\\/29\\\/islandsql-final-episode-10-parsing-pl-pgsql\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2024\\\/07\\\/IslandSQL10c.png\",\"contentUrl\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2024\\\/07\\\/IslandSQL10c.png\",\"width\":512,\"height\":512,\"caption\":\"IslandSQL Final Episode 10: Parsing PL\\\/pgSQL\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/07\\\/29\\\/islandsql-final-episode-10-parsing-pl-pgsql\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"IslandSQL Final Episode 10: Parsing PL\\\/pgSQL\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/\",\"name\":\"Philipp Salvisberg&#039;s Blog\",\"description\":\"Database-centric development\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#\\\/schema\\\/person\\\/34352245c48678b1a5a05d4bc1339515\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#\\\/schema\\\/person\\\/34352245c48678b1a5a05d4bc1339515\",\"name\":\"Philipp Salvisberg\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2010\\\/11\\\/phs_trivadis4.jpg\",\"url\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2010\\\/11\\\/phs_trivadis4.jpg\",\"contentUrl\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2010\\\/11\\\/phs_trivadis4.jpg\",\"width\":400,\"height\":400,\"caption\":\"Philipp Salvisberg\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2010\\\/11\\\/phs_trivadis4.jpg\"},\"sameAs\":[\"http:\\\/\\\/www.salvis.com\\\/\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"IslandSQL Final Episode 10: Parsing PL\/pgSQL - Philipp Salvisberg&#039;s Blog","description":"In this final episode, we look at parse trees of statements containing PL\/pgSQL and how to deal with lexical incompatibilities.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/","og_locale":"en_US","og_type":"article","og_title":"IslandSQL Final Episode 10: Parsing PL\/pgSQL - Philipp Salvisberg&#039;s Blog","og_description":"In this final episode, we look at parse trees of statements containing PL\/pgSQL and how to deal with lexical incompatibilities.","og_url":"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/","og_site_name":"Philipp Salvisberg&#039;s Blog","article_published_time":"2024-07-29T14:00:55+00:00","article_modified_time":"2024-07-29T14:11:16+00:00","og_image":[{"width":512,"height":512,"url":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/07\/IslandSQL10c.png","type":"image\/png"}],"author":"Philipp Salvisberg","twitter_card":"summary_large_image","twitter_creator":"@phsalvisberg","twitter_site":"@phsalvisberg","twitter_misc":{"Written by":"Philipp Salvisberg","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/#article","isPartOf":{"@id":"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/"},"author":{"name":"Philipp Salvisberg","@id":"https:\/\/www.salvis.com\/blog\/#\/schema\/person\/34352245c48678b1a5a05d4bc1339515"},"headline":"IslandSQL Final Episode 10: Parsing PL\/pgSQL","datePublished":"2024-07-29T14:00:55+00:00","dateModified":"2024-07-29T14:11:16+00:00","mainEntityOfPage":{"@id":"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/"},"wordCount":1412,"commentCount":0,"publisher":{"@id":"https:\/\/www.salvis.com\/blog\/#\/schema\/person\/34352245c48678b1a5a05d4bc1339515"},"image":{"@id":"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/#primaryimage"},"thumbnailUrl":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/07\/IslandSQL10c.png","keywords":["ANTLR","Code Analysis","IslandSQL","Oracle 26ai","PostgreSQL","SQL"],"articleSection":["Oracle"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/","url":"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/","name":"IslandSQL Final Episode 10: Parsing PL\/pgSQL - Philipp Salvisberg&#039;s Blog","isPartOf":{"@id":"https:\/\/www.salvis.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/#primaryimage"},"image":{"@id":"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/#primaryimage"},"thumbnailUrl":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/07\/IslandSQL10c.png","datePublished":"2024-07-29T14:00:55+00:00","dateModified":"2024-07-29T14:11:16+00:00","description":"In this final episode, we look at parse trees of statements containing PL\/pgSQL and how to deal with lexical incompatibilities.","breadcrumb":{"@id":"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/#primaryimage","url":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/07\/IslandSQL10c.png","contentUrl":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/07\/IslandSQL10c.png","width":512,"height":512,"caption":"IslandSQL Final Episode 10: Parsing PL\/pgSQL"},{"@type":"BreadcrumbList","@id":"https:\/\/www.salvis.com\/blog\/2024\/07\/29\/islandsql-final-episode-10-parsing-pl-pgsql\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.salvis.com\/blog\/"},{"@type":"ListItem","position":2,"name":"IslandSQL Final Episode 10: Parsing PL\/pgSQL"}]},{"@type":"WebSite","@id":"https:\/\/www.salvis.com\/blog\/#website","url":"https:\/\/www.salvis.com\/blog\/","name":"Philipp Salvisberg&#039;s Blog","description":"Database-centric development","publisher":{"@id":"https:\/\/www.salvis.com\/blog\/#\/schema\/person\/34352245c48678b1a5a05d4bc1339515"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.salvis.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.salvis.com\/blog\/#\/schema\/person\/34352245c48678b1a5a05d4bc1339515","name":"Philipp Salvisberg","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2010\/11\/phs_trivadis4.jpg","url":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2010\/11\/phs_trivadis4.jpg","contentUrl":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2010\/11\/phs_trivadis4.jpg","width":400,"height":400,"caption":"Philipp Salvisberg"},"logo":{"@id":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2010\/11\/phs_trivadis4.jpg"},"sameAs":["http:\/\/www.salvis.com\/"]}]}},"_links":{"self":[{"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/posts\/13526","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/comments?post=13526"}],"version-history":[{"count":25,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/posts\/13526\/revisions"}],"predecessor-version":[{"id":13563,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/posts\/13526\/revisions\/13563"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/media\/13527"}],"wp:attachment":[{"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/media?parent=13526"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/categories?post=13526"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/tags?post=13526"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}