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

<image>
	<url>https://www.salvis.com/blog/wp-content/uploads/2014/04/favicon.png</url>
	<title>JoelKallmanDay Archives - Philipp Salvisberg&#039;s Blog</title>
	<link>https://www.salvis.com/blog/tag/joelkallmanday/</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/joelkallmanday/feed/"/>
	<item>
		<title>Some Thoughts About Joel and AI #JoelKallmanDay</title>
		<link>https://www.salvis.com/blog/2026/10/14/some-thoughts-about-joel-and-ai-joelkallmanday/</link>
					<comments>https://www.salvis.com/blog/2026/10/14/some-thoughts-about-joel-and-ai-joelkallmanday/#respond</comments>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Tue, 13 Oct 2026 22:01:00 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[JoelKallmanDay]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=25305</guid>

					<description><![CDATA[<p>Where I Saw Joel for the First Time I remember Joel Kallman’s talk on the boat at APEX World 2019 in Rotterdam very well. I was sitting in the front row on the right, about two metres away from Joel, enjoying his talk. Because I was that close, I could see the<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2026/10/14/some-thoughts-about-joel-and-ai-joelkallmanday/">Some Thoughts About Joel and AI #JoelKallmanDay</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 id="where-i-saw-joel-for-the-first-time" class="wp-block-heading">Where I Saw Joel for the First Time</h2>



<p class="wp-block-paragraph"></p><p>I remember Joel Kallman’s talk on the boat at APEX World 2019 in Rotterdam very well. I was sitting in the front row on the right, about two metres away from Joel, enjoying his talk. Because I was that close, I could see the screen of his laptop. He made use of the available technology: presenter view, which allows you to read your prepared text word for word or just ensure that you do not forget to mention an important point. Some people like using presenter view, and others think you should know your slides and therefore just see what the attendees see. I’m in the latter group, also because I was always afraid of mixing up the presenter and audience views and not being able to fix it in time, especially when switching between slides and live demos. So mirroring was and still is easier for me.</p>



<p class="wp-block-paragraph"></p><p>The talk was excellent. The content was good. It was well presented. It was his talk. The fact that he used technology to support his presentation does not change that. So at what point does using technology change who we consider the author?</p>



<p class="wp-block-paragraph"></p><p>I wonder what Joel would think about AI as we know it today.</p>



<h2 id="how-i-looked-things-up-in-my-early-days" class="wp-block-heading">How I Looked Things Up in My Early Days</h2>



<p class="wp-block-paragraph"></p><p>When I was in school, I liked Duden’s <a href="https://books.google.ch/books?id=F80TAQAAMAAJ" target="_blank" rel="noopener">Sinn- und sachverwandte Wörter</a> the most. You could look up a word and find synonyms and words with similar meanings. I spent a lot of time looking up words and was constantly irritated by my inability to easily put letters in alphabetical order in my head to decide whether I had to go forwards or backwards. Is &#8220;m&#8221; before &#8220;o&#8221;? So I silently say &#8220;a, b, c, d, e, f, g, h, i, j, k, l, m, n, o&#8221; to the melody of the alphabet song we learned in my first school year (similar to <a href="https://open.spotify.com/track/0HMtOkTYNPUMIqrxs9iJWT?si=8b7ba4c5d6ee499f" target="_blank" rel="noopener">this</a>). And ah, yes, &#8220;m&#8221; is before &#8220;o&#8221;. So backwards… Sounds silly, but &#8220;a, b, c, d, e, f, g&#8221; is probably the phrase I use most in my life.</p>



<p class="wp-block-paragraph"></p><p>Back then, I thought it was fancy not to repeat words in the next sentence in my essays, and basically in general, because we were taught that it was a good thing. In the meantime, I have come to believe that you should use the same word to refer to the same thing, regardless of how often it appears in a text. It is less ambiguous. In other words, it is clearer and easier to understand. I believe this is true in IT and in business in general. For poetry, this might be different, but that’s for sure not my domain.</p>



<p class="wp-block-paragraph"></p><p>I also used Duden’s <a href="https://en.wikipedia.org/wiki/Duden" target="_blank" rel="noopener">Die deutsche Rechtschreibung</a> and the <a href="https://en.wikipedia.org/wiki/Brockhaus_Enzyklop%C3%A4die" target="_blank" rel="noopener">Brockhaus Enzyklopädie</a> to look things up and sometimes stumbled across something interesting while scanning the pages for the original term. Driven by curiosity, I learnt a few things along the way.</p>



<p class="wp-block-paragraph"></p><p>In any case, even back then, what I wrote was influenced by things I had read. Sometimes intentionally and, over time, for sure also unintentionally. Learning words and ways of expressing things from others is different from presenting their text or ideas as my own without acknowledgement. That would be <a href="https://www.ox.ac.uk/students/academic/guidance/skills/plagiarism" target="_blank" rel="noopener">plagiarism</a>. But if I could measure how much of my writing was influenced by others, the percentage might well be substantial.</p>



<p class="wp-block-paragraph"></p><p>What I want to say is that I started asking for help very early. Often I asked my father, because he basically knew everything and had a perfect memory. It was easier for me to ask him than to look it up myself (remember, I always had to repeat &#8220;a, b, c, d&#8221; in my head). But more often than not, he just gave me the right book so I could look it up myself and was available to discuss things.</p>



<p class="wp-block-paragraph"></p><p>Since then, many technological inventions have improved our ability to look things up ourselves.</p>



<h2 id="my-first-contact-with-ai" class="wp-block-heading">My First Contact With AI</h2>



<p class="wp-block-paragraph"></p><p>I guess my first use of AI tools was DeepL. I didn’t know that at the time, but DeepL has been using neural networks to translate text since its launch in 2017. See <a href="https://www.deepl.com/en/blog/how-does-deepl-work" target="_blank" rel="noopener">How does DeepL work?</a> for an explanation of the technology.</p>



<p class="wp-block-paragraph"></p><p>Before DeepL offered DeepL Write, I often translated a text from German to English, then the English result back to German, and that result again to English. I made some adjustments in between and repeated the process until I was satisfied. It usually produced a good result, something I felt I could have written myself if given enough time. I provided the initial input as German text, after all, right?</p>



<h2 id="autocomplition-and-refactoring" class="wp-block-heading">Autocomplition &amp; Refactoring</h2>



<p class="wp-block-paragraph"></p><p>Long before today’s AI assistants, IDEs already provided autocompletion and refactoring based on rules. Autocompletion used information about the programming language and the code, and refactoring applied hand-written transformation rules. I used the <a href="https://www.jetbrains.com/help/inspectopedia/Convert2streamapi.html" target="_blank" rel="noopener">Loop can be collapsed with Stream API</a> transformation and similar transformations just to better understand newer language alternatives. Some of them I kept, with or without adaptations, and some of them I completely reverted. Once I had reviewed and committed the changes to version control, I considered it my code. I was driving the development, after all, right?</p>



<p class="wp-block-paragraph"></p><p>Nowadays, IntelliJ IDEA’s <a href="https://www.jetbrains.com/help/idea/full-line-code-completion.html" target="_blank" rel="noopener">Full Line Code Completion</a> plugin, available as part of the Ultimate subscription, uses a local deep learning model to complete code. So, even if I don’t use an AI assistant to create code, I use local AI to complete code, which I then claim as my own. I was driving the development, after all, right?</p>



<h2 id="does-it-matter" class="wp-block-heading">Does It Matter?</h2>



<p class="wp-block-paragraph"></p><p>I guess it depends. On the size of the result, the overall change, the potential impact and so on. When I’m in the driver’s seat, I decide what to accept and take responsibility for the result. However, with large results, I am easily overwhelmed and unable to decide quickly. Being in the driver’s seat is only useful if I can still understand and assess what I’m accepting.</p>



<p class="wp-block-paragraph"></p><p>A presenter view, a dictionary and an AI assistant do different things. AI can produce a whole text or a large amount of code. If the AI writes the code, what makes it &#8220;my code&#8221;? With spec-driven development, I might think of myself as the owner of the guardrails I give the AI: the specifications, including the input for test cases. But that is a topic for another post.</p>



<p class="wp-block-paragraph"></p><p>When you ask the CEO of a startup company whether they developed the company’s product alone, they will most probably say no and explain who else was involved in making it happen. It is usually a team effort. Even products from single-person companies often involve help from somebody or something behind the scenes.</p>



<p class="wp-block-paragraph"></p><p>AI tools are becoming part of that process. Just tools, but tools that can improve our efficiency. Ignoring them where they are useful may put us at a disadvantage in a functioning market economy. But using them does not automatically make us more efficient. The time needed to check and correct the result also counts.</p>



<p class="wp-block-paragraph"></p><p>So for me, the question is how we can use AI tools in a beneficial way and in which contexts that makes sense.</p>



<h2 id="yes-i-use-ai-on-this-blog" class="wp-block-heading"><p><span style="font-size: 30px;">Yes, I Use AI on This Blog</span></p></h2>



<p class="wp-block-paragraph"></p><p>So yes, I use AI on this blog too. You can see this very clearly in the featured images: most of those published since 29 July 2024 were generated by AI. I also use tools such as Grammarly, DeepL and AI assistants to help with the text. For this post, I started with my own draft and used AI to review the language and logic and help write this ending.</p>



<p class="wp-block-paragraph"></p><p>The memories, opinions and the reason for writing this post are mine. I decide what to keep, what to change and what to publish. And I remain responsible for the result. For me, that is an important part of being the author, even when I have help.</p>



<p class="wp-block-paragraph"></p><p>Looking something up in a book, translating a text and asking AI for a suggestion are different kinds of help. I need to understand what each tool contributes and decide whether it is useful for what I want to say. Sometimes it is. Sometimes I have to change it or start again.</p>



<p class="wp-block-paragraph"></p><p>I cannot know what Joel would think about today’s AI. But I remember his talk and what he shared with us. Presenter view was part of how he delivered it, and it was still his talk. That memory is a useful reminder for my own work: I can use the available tools and still put my own thoughts and care into what I share.</p>



<p class="wp-block-paragraph"></p><p>And yes, I still consider this my blog post. Without blushing ;-)</p>
<p>The post <a href="https://www.salvis.com/blog/2026/10/14/some-thoughts-about-joel-and-ai-joelkallmanday/">Some Thoughts About Joel and AI #JoelKallmanDay</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.salvis.com/blog/2026/10/14/some-thoughts-about-joel-and-ai-joelkallmanday/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Is SYSDATE Deterministic? #JoelKallmanDay</title>
		<link>https://www.salvis.com/blog/2025/10/15/is-sysdate-deterministic-joelkallmanday/</link>
					<comments>https://www.salvis.com/blog/2025/10/15/is-sysdate-deterministic-joelkallmanday/#comments</comments>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Tue, 14 Oct 2025 22:00:00 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[JoelKallmanDay]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[SQL]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=14035</guid>

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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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

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



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

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


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



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



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



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



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

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



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

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


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



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



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



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



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



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



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


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



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



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



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



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

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



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

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

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


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



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



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



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



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



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



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



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



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



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



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



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



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

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



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


Function APPDATE compiled

Left the loop after 3224661 iterations


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



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



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



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



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



<p class="wp-block-paragraph">The idea of providing a custom function that returns <code>SYSDATE</code> with a centrally defined offset might have worked in our case. But providing a solution that behaves like <code>SYSDATE</code> is much more challenging than I thought. We would need something that is evaluated once in a SQL statement and per call in other cases. Passing <code>SYSDATE</code> as a default parameter to a deterministic function does the trick. Either way, I&#8217;m glad we opted for the simpler solution, which meant there was no need to change the code base.</p>
<p>The post <a href="https://www.salvis.com/blog/2025/10/15/is-sysdate-deterministic-joelkallmanday/">Is SYSDATE Deterministic? #JoelKallmanDay</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.salvis.com/blog/2025/10/15/is-sysdate-deterministic-joelkallmanday/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>PL/SQL vs. JavaScript in the Oracle Database 23ai #JoelKallmanDay</title>
		<link>https://www.salvis.com/blog/2024/10/16/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday/</link>
					<comments>https://www.salvis.com/blog/2024/10/16/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday/#comments</comments>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Wed, 16 Oct 2024 02:22:28 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[JoelKallmanDay]]></category>
		<category><![CDATA[Oracle 26ai]]></category>
		<category><![CDATA[PinkDB]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[SmartDB]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=13635</guid>

					<description><![CDATA[<p>JavaScript is the first language supported by the Multilingual Engine (MLE) in Oracle Database 23ai. Having additional languages in the Oracle Database allows us to use existing libraries within the database. Also, it makes it easier for those without PL/SQL skills to get started with database development. Wasn&#8217;t that also the argument<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2024/10/16/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday/">PL/SQL vs. JavaScript in the Oracle Database 23ai #JoelKallmanDay</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">JavaScript is the first language supported by the Multilingual Engine (MLE) in Oracle Database 23ai. Having additional languages in the Oracle Database allows us to use existing libraries within the database. Also, it makes it easier for those without PL/SQL skills to get started with database development. Wasn&#8217;t that also the argument for Java in the database? What is easier and better in JavaScript than in Java? How performant are JavaScript modules? When is JavaScript a good alternative to PL/SQL and when is it not?</p>



<p class="wp-block-paragraph">This is a translation of my German article &#8220;PL/SQL oder JavaScript in der Oracle Datenbank 23ai?&#8221; published in the <a href="https://www.salvis.com/blog/wp-content/uploads/2024/10/06_2024-Red_Stack_Magazin-DTk-WEB-Philipp_Salvisberg_PLSQL_oder_JavaScript_in_der_Oracl.pdf">Red Stack Magazine</a> No. 6/2024 on 11 October 2024.</p>



<h2 class="wp-block-heading">Why Do We Need Code in the Database?</h2>



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



<p class="wp-block-paragraph">I see the following reasons for this.</p>



<ol class="wp-block-list">
<li>We bring the code to the data rather than the data to the code. This allows us to process the data efficiently on the database server and deliver the result to the client in just a few network round trips. This uses fewer resources, is more cost-effective and faster than if we had to transport the data to the client and process it there.</li>



<li>We take responsibility for the quality of the data stored in the database. Typically, we write data once and read it often. Therefore, we should store data correctly so that consumers can rely on the data when they read it. In this sense, the logic for validating the data belongs in the database. This logic is often more extensive than what today&#8217;s database constraints provide. In other words, we need code in the database as part of an API to keep our data consistent and correct.</li>
</ol>



<p class="wp-block-paragraph">Even if your database applications do not follow the principles of SmartDB or <a href="https://www.salvis.com/blog/2018/07/18/the-pink-database-paradigm-pinkdb-2/">PinkDB</a>, there are benefits to selectively using code in the database. And if your company policy categorically forbids code in the database, it is probably time to reconsider.</p>



<h2 class="wp-block-heading">PL/SQL Without SQL</h2>



<p class="wp-block-paragraph">Let&#8217;s pretend we need a function to convert a timestamp to Unix time. Wikipedia defines the <a href="https://en.wikipedia.org/wiki/Unix_time">Unix time</a> as follows.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Unix time is a date and time representation widely used in&nbsp;computing. It measures time by the number of non-leap seconds that have elapsed since 00:00:00 UTC on 1 January 1970, the Unix epoch.</p>
</blockquote>



<p class="wp-block-paragraph">Listing 1 shows how we can implement this in PL/SQL.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">Listing 1: to_epoch_plsql</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>create or replace function to_epoch_plsql(
   in_ts in timestamp
) return number is
   co_epoch_date constant timestamp with time zone := 
      timestamp '1970-01-01 00:00:00 UTC';
   l_interval    interval day(9) to second (3);
begin
   l_interval := in_ts - co_epoch_date;
   return 1000 * (extract(second from l_interval)
         + extract(minute from l_interval) * 60
         + extract(hour from l_interval) * 60 * 60
         + extract(day from l_interval) * 60 * 60 * 24);
end;
/</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> function to_epoch_plsql(</span></span>
<span class="line"><span style="color: #D4D4D4">   in_ts </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">timestamp</span></span>
<span class="line"><span style="color: #D4D4D4">) </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">number</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span></span>
<span class="line"><span style="color: #D4D4D4">   co_epoch_date </span><span style="color: #569CD6">constant</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">timestamp with time zone</span><span style="color: #D4D4D4"> := </span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">timestamp</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1970-01-01 00:00:00 UTC&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #9CDCFE">l_interval</span><span style="color: #D4D4D4">    interval day(</span><span style="color: #B5CEA8">9</span><span style="color: #D4D4D4">) to second (</span><span style="color: #B5CEA8">3</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #9CDCFE">l_interval</span><span style="color: #D4D4D4"> := in_ts - co_epoch_date;</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">1000</span><span style="color: #D4D4D4"> * (</span><span style="color: #DCDCAA">extract</span><span style="color: #D4D4D4">(second </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">l_interval</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">         + </span><span style="color: #DCDCAA">extract</span><span style="color: #D4D4D4">(minute </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">l_interval</span><span style="color: #D4D4D4">) * </span><span style="color: #B5CEA8">60</span></span>
<span class="line"><span style="color: #D4D4D4">         + </span><span style="color: #DCDCAA">extract</span><span style="color: #D4D4D4">(hour </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">l_interval</span><span style="color: #D4D4D4">) * </span><span style="color: #B5CEA8">60</span><span style="color: #D4D4D4"> * </span><span style="color: #B5CEA8">60</span></span>
<span class="line"><span style="color: #D4D4D4">         + </span><span style="color: #DCDCAA">extract</span><span style="color: #D4D4D4">(day </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">l_interval</span><span style="color: #D4D4D4">) * </span><span style="color: #B5CEA8">60</span><span style="color: #D4D4D4"> * </span><span style="color: #B5CEA8">60</span><span style="color: #D4D4D4"> * </span><span style="color: #B5CEA8">24</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 <code>to_epoch_plsql</code> function expects a <code>timestamp</code>, a <code>timestamp with timezone</code> would be better. We have omitted this to keep the example as simple as possible. Although the solution may seem simple, we are reimplementing existing functionality. We had to find out how Unix time works, what role time zones play, what leap seconds are for, and that Unix time is used in milliseconds, not seconds.</p>



<p class="wp-block-paragraph">Wouldn&#8217;t it be nice to be able to use an existing, tested function in the database to keep our application&#8217;s code to a minimum? Even though there is no <code>to_epoch</code> function in SQL, the Java Development Kit (JDK) offers such functionality. The Oracle Java Virtual Machine (OJVM) is an embedded component of the Oracle Database 23.5. It&#8217;s a JDK version 11.</p>



<h2 class="wp-block-heading">Java Without SQL</h2>



<p class="wp-block-paragraph">The Oracle Database has supported Java stored procedures since version 8i Release 1. This means that we can provide a <code>to_epoch_java</code> function as shown in Listing 2.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">Listing 2: to_epoch_java</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>create or replace and compile java source named "Util" as
public class Util {
   public static long toEpoch(java.sql.Timestamp ts) {
      return ts.getTime();
   }
}
/
create or replace function to_epoch_java(in_ts in timestamp) 
  return number is language java name 
    'Util.toEpoch(java.sql.Timestamp) return java.lang.long';
/</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">and</span><span style="color: #D4D4D4"> compile </span><span style="color: #569CD6">java</span><span style="color: #D4D4D4"> source named </span><span style="color: #CE9178">&quot;Util&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">as</span></span>
<span class="line"><span style="color: #D4D4D4">public class Util {</span></span>
<span class="line"><span style="color: #D4D4D4">   public static </span><span style="color: #569CD6">long</span><span style="color: #D4D4D4"> toEpoch(</span><span style="color: #569CD6">java</span><span style="color: #D4D4D4">.</span><span style="color: #569CD6">sql</span><span style="color: #D4D4D4">.</span><span style="color: #569CD6">Timestamp</span><span style="color: #D4D4D4"> ts) {</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> ts.getTime();</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: #569CD6">create or replace</span><span style="color: #D4D4D4"> function to_epoch_java(in_ts </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">timestamp</span><span style="color: #D4D4D4">) </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">number</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">language</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">java</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">name</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&#39;Util.toEpoch(java.sql.Timestamp) return java.lang.long&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span></code></pre></div>



<p class="wp-block-paragraph">For Java, we need to create a class and a call specification. The purpose of the call specification is, among other things, to map the types of input and output data between SQL and Java. For example, to map the return value of <code>java.lang.long</code> to <code>number</code>.</p>



<p class="wp-block-paragraph">The code no longer contains the formula for converting a timestamp to Unix time, but it is quite extensive. Is there an easy way in JavaScript?</p>



<h2 class="wp-block-heading">JavaScript Without SQL</h2>



<p class="wp-block-paragraph">With Oracle Database 23ai, we can create JavaScript modules.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">Listing 3: to_epoch_js</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>create or replace mle module util_mod language javascript as   
export function toEpoch(ts) {
   return ts.valueOf();
}
/
create or replace function to_epoch_js(in_ts in timestamp) 
   return number is 
      mle module util_mod 
      signature 'toEpoch(Date)';
/</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> mle module util_mod </span><span style="color: #569CD6">language</span><span style="color: #D4D4D4"> javascript </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4">   </span></span>
<span class="line"><span style="color: #D4D4D4">export function toEpoch(ts) {</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> ts.valueOf();</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">create or replace</span><span style="color: #D4D4D4"> function to_epoch_js(in_ts </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">timestamp</span><span style="color: #D4D4D4">) </span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">number</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">      mle module util_mod </span></span>
<span class="line"><span style="color: #D4D4D4">      signature </span><span style="color: #CE9178">&#39;toEpoch(Date)&#39;</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 implementation of to_<code>epoch_js</code> in Listing 3 is similar to <code>to_epoch_java</code>. A module in JavaScript and then an MLE call specification. However, it is no longer necessary to fully map the input data types in JavaScript. The Oracle Database defines default values. These can be overridden, but do not need to be explicitly defined as in Java. It is not possible to map the output data type. In this case, it must be possible to convert the return value to a <code>number</code>, otherwise, a runtime error will occur.</p>



<p class="wp-block-paragraph">However, the implementation for this simple case is quite extensive. Oracle has probably realised this and provided an alternative.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">Listing 4: to_epoch_js2 – inline MLE call specification</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>create or replace function to_epoch_js2("in_ts" in timestamp)
   return number is
      mle language javascript ' return in_ts.valueOf();';
/</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> function to_epoch_js2(</span><span style="color: #CE9178">&quot;in_ts&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">timestamp</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">number</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span></span>
<span class="line"><span style="color: #D4D4D4">      mle </span><span style="color: #569CD6">language</span><span style="color: #D4D4D4"> javascript </span><span style="color: #CE9178">&#39; return in_ts.valueOf();&#39;</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 <code>to_epoch_js2</code> function in Listing 4 is equivalent to <code>to_epoch_js</code> but significantly simpler than any of the other variants. However, an inline MLE call specification is only applicable to JavaScript code without dependencies on other modules, this means for JavaScript code without an import command.</p>



<h2 class="wp-block-heading">Performance of <code>to_epoch_...</code></h2>



<p class="wp-block-paragraph">Anyone who has worked with Java stored procedures in the database knows that the initialisation of the OJVM in a new database session slows down the response time considerably. This is not the case with MLE because it uses a GraalVM native image. Simply put, it reads only the memory contents of a file, similar to waking your laptop from hibernation. This makes it possible to start a Java program within a millisecond. The native image is integrated into the database as a shared library <code>$ORACLE_HOME/lib/libmle.so</code>. This means that the MLE provides JavaScript via Java, but is completely independent of the OJVM.</p>



<p class="wp-block-paragraph">In Figure 1 we compare the runtimes of 100,000 function calls. Instead of seconds, we use a normalised unit of time, which makes comparing easier and results less dependent on the hardware stack used.</p>



<p class="wp-block-paragraph">All experiments were performed using the Oracle Database 23.5 Free Edition on an AMD Ryzen R1600 processor-based system. The shortest time of five repetitions was taken into account. You can reproduce these experiments using the scripts in <a href="https://github.com/PhilippSalvisberg/js23c">this GitHub repository</a>.</p>



<figure class="wp-block-image size-large is-style-default"><a href="https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure1.png"><img fetchpriority="high" decoding="async" width="1024" height="440" src="https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure1-1024x440.png" alt="Figure 1: Runtime of 100K calls of to_epoch_..." class="wp-image-13656" srcset="https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure1-1024x440.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure1-300x129.png 300w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure1-768x330.png 768w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure1-1536x660.png 1536w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure1-2048x880.png 2048w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure1-150x64.png 150w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure1-480x206.png 480w" sizes="(max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption"><em>Figure 1: Runtime of 100K calls of to_epoch_&#8230;</em></figcaption></figure>



<p class="wp-block-paragraph">The <code>to_epoch_plsql</code>, <code>to_epoch_java</code> and <code>to_epoch_js</code> variants are called from a PL/SQL loop. This means 100,000 context switches between PL/SQL and Java or JavaScript. The fourth variant, <code>to_epoch_jsloop</code>, calls <code>toEpoch</code> from a JavaScript loop. In this case, the context switching between PL/SQL and JavaScript makes processing about 50 times slower.</p>



<p class="wp-block-paragraph">Based on these results, we should avoid context switching between PL/SQL and JavaScript if possible. The performance of JavaScript in the database is impressive in this case. Quite different from the OJVM.</p>



<h2 class="wp-block-heading">Memory Usage of <code>to_epoch_...</code></h2>



<p class="wp-block-paragraph">Figure 2 shows the maximum memory used at the end of a <code>to_epoch_…</code> function call. The call was made in a new database session and contains the memory requirements of the measuring instruments.</p>



<figure class="wp-block-image size-large"><a href="https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure2.png"><img decoding="async" width="1024" height="440" src="https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure2-1024x440.png" alt="Max. Memory Usage After Single Call" class="wp-image-13659" srcset="https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure2-1024x440.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure2-300x129.png 300w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure2-768x330.png 768w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure2-1536x660.png 1536w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure2-2048x880.png 2048w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure2-150x64.png 150w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure2-480x206.png 480w" sizes="(max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption"><em>Figure 2: Max. memory usage after a single call</em></figcaption></figure>



<p class="wp-block-paragraph">JavaScript uses significantly more memory than PL/SQL. If you take this into account when sizing the database server and connection pools, this should not be a problem nowadays.</p>



<h2 id="using-a-3rd-party-javascript-library" class="wp-block-heading">Using a 3rd Party JavaScript Library</h2>



<p class="wp-block-paragraph">Let&#8217;s say we want to validate email addresses in our database without actually sending a test email. The rules for a valid <a href="https://en.wikipedia.org/wiki/Email_address">email address</a> are quite extensive. In the JavaScript ecosystem, we can find open-source libraries for such requirements that can be used in the database without modification. For this example, we use <a href="https://www.npmjs.com/package/validator">validator.js</a>, which can validate not only email addresses but also credit card numbers, EAN, IBAN and much more. Using SQLcl&#8217;s script command, we can <a href="https://www.salvis.com/blog/2023/11/26/installing-mle-modules-in-the-oracle-database/">load npm modules</a> directly into the database.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">Listing 5: Load validator.js from npm as validator_mod into the database</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>script https://raw.githubusercontent.com/PhilippSalvisberg/mle-sqlcl/main/mle.js install validator_mod https://esm.run/validator@13.12.0 13.12.0

select version, language_name, length(module)
  from user_mle_modules
 where module_name = 'VALIDATOR_MOD';</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">script https://</span><span style="color: #569CD6">raw</span><span style="color: #D4D4D4">.githubusercontent.com/PhilippSalvisberg/mle-sqlcl/main/mle.js install validator_mod https://esm.run/validator@</span><span style="color: #B5CEA8">13.12</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">13.12</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">0</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> version, language_name, </span><span style="color: #DCDCAA">length</span><span style="color: #D4D4D4">(module)</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> user_mle_modules</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> module_name = </span><span style="color: #CE9178">&#39;VALIDATOR_MOD&#39;</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



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



<p class="wp-block-paragraph">The script <code>mle.js</code> in Listing 5 is not read from the local file system as usual but via a URL from GitHub. The script creates a JavaScript module <code>validator_mod</code> with the contents of the URL <a href="https://esm.run/validator@13.12.0">https://esm.run/validator@13.12.0</a>, which is a minimised, browser-optimised version of the validator.js module in the <a href="https://www.npmjs.com/package/validator">npm</a> software registry. The last parameter <code>13.12.0</code> is the version of the module stored in the Oracle Data Dictionary.</p>



<p class="wp-block-paragraph">In Listing 6, we create the MLE call specification in a PL/SQL package. The <code>is_mail</code> function accepts only a string as a parameter. The validator options are defined in the package body. This simplifies uniform use in the database application.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">Listing 6: PL/SQL package validator_api </span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>create or replace package validator_api is
   function is_email(
      in_email in varchar2
   ) return boolean deterministic;
end validator_api;
/
create or replace package body validator_api is
   function is_email_internal(
      in_email   in varchar2,
      in_options in json
   ) return boolean deterministic as mle module validator_mod 
   signature 'default.isEmail(string, any)';

   function is_email(
      in_email in varchar2
   ) return boolean deterministic is
   begin
      return is_email_internal(
                in_email   => in_email,
                in_options => json('
                   {
                      "allow_display_name": false,
                      "allow_undescores": false,
                      "require_display_name": false,
                      "allow_utf8_local_part": true,
                      "require_tld": true,
                      "allow_ip_domain": false,
                      "domain_specific_validation": false,
                      "blacklisted_chars": "",
                      "ignore_max_length": false,
                      "host_blacklist": &#91;"dubious.com"&#93;,
                      "host_whitelist": []
                   }
                ')
             );
   end is_email;
end validator_api;
/</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">package</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">validator_api</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">is_email</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">      in_email </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">varchar2</span></span>
<span class="line"><span style="color: #D4D4D4">   ) </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">boolean</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">deterministic</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4"> validator_api;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span>
<span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">package body</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">validator_api</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">is_email_internal</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">      in_email   </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">varchar2</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      in_options </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> json</span></span>
<span class="line"><span style="color: #D4D4D4">   ) </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">boolean</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">deterministic</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> mle module validator_mod </span></span>
<span class="line"><span style="color: #D4D4D4">   signature </span><span style="color: #CE9178">&#39;default.isEmail(string, any)&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">is_email</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">      in_email </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">varchar2</span></span>
<span class="line"><span style="color: #D4D4D4">   ) </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">boolean</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">deterministic</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> is_email_internal(</span></span>
<span class="line"><span style="color: #D4D4D4">                in_email   =&gt; in_email,</span></span>
<span class="line"><span style="color: #D4D4D4">                in_options =&gt; json(</span><span style="color: #CE9178">&#39;</span></span>
<span class="line"><span style="color: #CE9178">                   {</span></span>
<span class="line"><span style="color: #CE9178">                      &quot;allow_display_name&quot;: false,</span></span>
<span class="line"><span style="color: #CE9178">                      &quot;allow_undescores&quot;: false,</span></span>
<span class="line"><span style="color: #CE9178">                      &quot;require_display_name&quot;: false,</span></span>
<span class="line"><span style="color: #CE9178">                      &quot;allow_utf8_local_part&quot;: true,</span></span>
<span class="line"><span style="color: #CE9178">                      &quot;require_tld&quot;: true,</span></span>
<span class="line"><span style="color: #CE9178">                      &quot;allow_ip_domain&quot;: false,</span></span>
<span class="line"><span style="color: #CE9178">                      &quot;domain_specific_validation&quot;: false,</span></span>
<span class="line"><span style="color: #CE9178">                      &quot;blacklisted_chars&quot;: &quot;&quot;,</span></span>
<span class="line"><span style="color: #CE9178">                      &quot;ignore_max_length&quot;: false,</span></span>
<span class="line"><span style="color: #CE9178">                      &quot;host_blacklist&quot;: &#91;&quot;dubious.com&quot;&#93;,</span></span>
<span class="line"><span style="color: #CE9178">                      &quot;host_whitelist&quot;: []</span></span>
<span class="line"><span style="color: #CE9178">                   }</span></span>
<span class="line"><span style="color: #CE9178">                &#39;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">             );</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">end</span><span style="color: #D4D4D4"> is_email;</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4"> validator_api;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span></code></pre></div>



<p class="wp-block-paragraph">Listing 7 shows the use of the validator in SQL. The second email address is invalid because of the <code>allow_display_name</code> option. The third e-mail address is formally correct, but it uses a domain listed under <code>host_blacklist</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(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">Listing 7: Validate email addresses</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>select e_mail, validator_api.is_email(e_mail) as is_valid
  from (values
          ('esther.muster@example.com'),
          ('Esther Muster &lt;esther.muster@example.com>'),
          ('esther.muster@dubious.com')
       ) test_data (e_mail);</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> e_mail, validator_api.is_email(e_mail) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> is_valid</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">values</span></span>
<span class="line"><span style="color: #D4D4D4">          (</span><span style="color: #CE9178">&#39;esther.muster@example.com&#39;</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">          (</span><span style="color: #CE9178">&#39;Esther Muster &lt;esther.muster@example.com&gt;&#39;</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">          (</span><span style="color: #CE9178">&#39;esther.muster@dubious.com&#39;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">       ) test_data (e_mail);</span></span></code></pre></div>



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



<h2 class="wp-block-heading">JavaScript With SQL</h2>



<p class="wp-block-paragraph">The MLE provides a global variable <code>session</code> of type <a href="https://oracle-samples.github.io/mle-modules/docs/mle-js-oracledb/23ai/classes/api.IConnection.html">IConnection</a> to communicate with the current database session. Listing 8 shows an example of a simple update statement using bind variables.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">Listing 8: increase_salary_js </span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>create or replace mle module increase_salary_mod 
language javascript as
export function increase_salary(deptno, by_percent) {
   session.execute(`
      update emp
         set sal = sal + sal * :by_percent / 100
         where deptno = :deptno`, &#91;by_percent, deptno&#93;);
}
/
create or replace procedure increase_salary_js(
   in_deptno     in number,
   in_by_percent in number
) as mle module increase_salary_mod
signature 'increase_salary(number, number)';
/</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #9CDCFE">create</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">or</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">replace</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">mle</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">module</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">increase_salary_mod</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #4EC9B0">language</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">javascript</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">as</span></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">increase_salary</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">deptno</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">by_percent</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">      update emp</span></span>
<span class="line"><span style="color: #CE9178">         set sal = sal + sal * :by_percent / 100</span></span>
<span class="line"><span style="color: #CE9178">         where deptno = :deptno`</span><span style="color: #D4D4D4">, &#91;</span><span style="color: #9CDCFE">by_percent</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">deptno</span><span style="color: #D4D4D4">&#93;);</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: #9CDCFE">create</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">or</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">replace</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">procedure</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">increase_salary_js</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #9CDCFE">in_deptno</span><span style="color: #D4D4D4">     </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">number</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #9CDCFE">in_by_percent</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">number</span></span>
<span class="line"><span style="color: #D4D4D4">) </span><span style="color: #C586C0">as</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">mle</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">module</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">increase_salary_mod</span></span>
<span class="line"><span style="color: #9CDCFE">signature</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;increase_salary(number, number)&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span></code></pre></div>



<h2 class="wp-block-heading">PL/SQL With SQL</h2>



<p class="wp-block-paragraph">Listing 9 shows the PL/SQL counterpart to the JavaScript code in Listing 8, using dynamic SQL with bind variables.</p>



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



<p class="wp-block-paragraph">Experienced PL/SQL developers would not write it this way, as syntax and semantic errors are only thrown at runtime. In addition, it is more expensive for the Oracle Database to execute dynamic SQL, and the use of database objects is not stored in the Oracle Data Dictionary. Instead, experienced PL/SQL developers use static SQL whenever possible and sensible. The code is shorter and SQL injection is impossible. Listing 10 shows the static SQL variant.</p>



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



<h2 class="wp-block-heading">Performance of <code>increase_salary_...</code></h2>



<p class="wp-block-paragraph">Figure 3 compares the runtimes of 100,000 procedure calls in a PL/SQL loop. Only <code>increase_salary_jsloop</code> uses a JavaScript loop. This avoids 100,000 context switches between PL/SQL and JavaScript. In other words, the difference between <code>increase_salary_js</code> and <code>increase_salary_jsloop</code> is the cost of 100,000 context switches.</p>



<figure class="wp-block-image size-large"><a href="https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure3.png"><img decoding="async" width="1024" height="440" src="https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure3-1024x440.png" alt="Runtime of 100,000 procedure calls" class="wp-image-13673" srcset="https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure3-1024x440.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure3-300x129.png 300w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure3-768x330.png 768w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure3-1536x660.png 1536w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure3-2048x880.png 2048w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure3-150x64.png 150w, https://www.salvis.com/blog/wp-content/uploads/2024/10/Figure3-480x206.png 480w" sizes="(max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption"><em>Figure 3: Runtime of 100,000 procedure calls</em></figcaption></figure>



<p class="wp-block-paragraph">In the Oracle Database version 23.5, JavaScript is about 5 to 6 times slower than PL/SQL in this example when we use dynamic SQL. In the Oracle Database version 23.3, the difference was a factor of 7, which makes me optimistic that we can expect further performance improvements in future versions.</p>



<p class="wp-block-paragraph">Based on these experiments, it is difficult to make general statements about the performance differences between PL/SQL and JavaScript. However, it appears that PL/SQL code with SQL statements has an advantage over JavaScript.</p>



<h2 class="wp-block-heading">MLE Environment</h2>



<p class="wp-block-paragraph">Accessing the network using the <a href="https://oracle-samples.github.io/mle-modules/docs/mle-js-fetch/23ai/">JavaScript Fetch API</a> is possible, If the appropriate permissions have been granted using the PL/SQL package <code><a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/arpls/DBMS_NETWORK_ACL_ADMIN.html">dbms_network_acl_admin</a></code>. However, for security reasons, JavaScript cannot access the database server&#8217;s file system.</p>



<p class="wp-block-paragraph">JavaScript runtime environments such as Node.js, Deno, Bun or web browsers, access the file system to import other JavaScript modules. For that, you need an MLE environment in the Oracle Database. Listing 11 shows how to create and use it.</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">Listing 11: Using an MLE environment</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>create or replace mle env demo_env
    imports(
        'increase_salary' module increase_salary_mod,
        'validator'       module validator_mod,
        'util'            module util_mod
    )
    language options  'js.strict=true, js.console=false,
                       js.polyglot-builtin=true'
;
create or replace mle module increase_salary_loop_mod 
language javascript as   
import {increase_salary} from "increase_salary";
export function increase_salary_loop(deptno,by_percent,times){
   for (let i=0; i&lt;times; i++) {
      increase_salary(deptno, by_percent);
   }
}
/
create or replace procedure increase_salary_jsloop(
   in_deptno     in number,
   in_by_percent in number,
   in_times      in number
) as mle module increase_salary_loop_mod
env demo_env
signature 'increase_salary_loop(number, number, number)';
/</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line cbp-line-highlight"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> mle env demo_env</span></span>
<span class="line"><span style="color: #D4D4D4">    imports(</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        </span><span style="color: #CE9178">&#39;increase_salary&#39;</span><span style="color: #D4D4D4"> module increase_salary_mod,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #CE9178">&#39;validator&#39;</span><span style="color: #D4D4D4">       module validator_mod,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #CE9178">&#39;util&#39;</span><span style="color: #D4D4D4">            module util_mod</span></span>
<span class="line"><span style="color: #D4D4D4">    )</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">language</span><span style="color: #D4D4D4"> options  </span><span style="color: #CE9178">&#39;js.strict=true, js.console=false,</span></span>
<span class="line"><span style="color: #CE9178">                       js.polyglot-builtin=true&#39;</span></span>
<span class="line"><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> mle module increase_salary_loop_mod </span></span>
<span class="line"><span style="color: #569CD6">language</span><span style="color: #D4D4D4"> javascript </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4">   </span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">import {increase_salary} </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;increase_salary&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">export function increase_salary_loop(deptno,by_percent,times){</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> (let i=</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">; i&lt;times; i++) {</span></span>
<span class="line"><span style="color: #D4D4D4">      increase_salary(deptno, by_percent);</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: #569CD6">create or replace</span><span style="color: #D4D4D4"> procedure increase_salary_jsloop(</span></span>
<span class="line"><span style="color: #D4D4D4">   in_deptno     </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">number</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">   in_by_percent </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">number</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">   in_times      </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">number</span></span>
<span class="line"><span style="color: #D4D4D4">) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> mle module increase_salary_loop_mod</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">env demo_env</span></span>
<span class="line"><span style="color: #D4D4D4">signature </span><span style="color: #CE9178">&#39;increase_salary_loop(number, number, number)&#39;</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 MLE environment <code>demo_env</code> maps the import name <code>increase_salary</code> to the MLE module <code>increase_salary_mod</code>. This import is used in the MLE module <code>increase_salary_loop_mod</code>. However, the MLE environment is not assigned there. This is only done in the MLE call specification <code>increase_salary_jsloop</code>.</p>



<p class="wp-block-paragraph">MLE environments allow JavaScript code to be structured in the same way inside and outside the database. In most cases, a single MLE environment will be sufficient for an application. Multiple MLE environments are required if different language options are used per module, or if different versions of a module are to be loaded with the same import name.</p>



<h2 class="wp-block-heading">Is Tom Kyte’s Mantra Still Valid?</h2>



<p class="wp-block-paragraph">One of the things Tom Kyte is famous for is his mantra. There are several variations, but all have the same message. This variant is from Expert Oracle Database Architecture, Third Edition, 2014. On page 3 he writes:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">I have a pretty simple mantra when it comes to developing database software, one that has been consistent for many years:</p>



<ul class="wp-block-list">
<li>You should do it in a single SQL statement if at all possible. And believe it or not, it is almost always possible. This statement is even truer as time goes on. SQL is an extremely powerful language.</li>



<li>If you can’t do it in a single SQL Statement, do it in PL/SQL—as little PL/SQL as possible! Follow the saying that goes &#8220;more code = more bugs, less code = less bugs.&#8221;</li>



<li>If you can’t do it in PL/SQL, try a Java stored procedure. The times this is necessary are extremely rare nowadays with Oracle9i and above. PL/SQL is an extremely competent, fully featured 3GL.</li>



<li>If you can’t do it in Java, do it in a C external procedure. This is most frequently the approach when raw speed or using a third-party API written in C is needed.</li>



<li>If you can’t do it in a C external routine, you might want to seriously think about why it is you need to do it.</li>
</ul>
</blockquote>



<p class="wp-block-paragraph">With Oracle Database 23ai, I would put JavaScript on the same level as PL/SQL. Before Java, definitely. Furthermore, it is not just a question of whether something can be done in SQL or PL/SQL. If we need a functionality that already exists in the JavaScript ecosystem, we should consider using it rather than reimplementing it in SQL or PL/SQL just because it&#8217;s possible. Ultimately, it is also about the maintainability of the application and the technical debt we are incurring.</p>



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



<p class="wp-block-paragraph">MLE was introduced as an experimental feature at Oracle Open World 2017. Since then, MLE and the underlying GraalVM technology have been continuously improved and have reached a good, production-ready state in Oracle Database 23ai. It is ideally suited for integrating existing, tested functionality from the JavaScript ecosystem into the Oracle Database.</p>



<p class="wp-block-paragraph">We still need to figure out how to develop, test, debug and deploy JavaScript with SQL. In any case, JavaScript is a real alternative to PL/SQL, even if PL/SQL scores with static SQL and better performance.</p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://www.salvis.com/blog/2024/10/16/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday/">PL/SQL vs. JavaScript in the Oracle Database 23ai #JoelKallmanDay</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.salvis.com/blog/2024/10/16/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
	</channel>
</rss>
