<?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>SmartDB Archives - Philipp Salvisberg&#039;s Blog</title>
	<atom:link href="https://www.salvis.com/blog/tag/smartdb/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.salvis.com/blog/tag/smartdb/</link>
	<description>Database-centric development</description>
	<lastBuildDate>Wed, 12 Mar 2025 09:22:04 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://www.salvis.com/blog/wp-content/uploads/2014/04/favicon.png</url>
	<title>SmartDB Archives - Philipp Salvisberg&#039;s Blog</title>
	<link>https://www.salvis.com/blog/tag/smartdb/</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/smartdb/feed/"/>
	<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[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>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>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></p>



<p>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>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>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>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>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" data-code="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;
/" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> 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>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>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>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" data-code="create or replace and compile java source named &quot;Util&quot; 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';
/" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">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>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>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>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" data-code="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)';
/" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> 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>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>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" data-code="create or replace function to_epoch_js2(&quot;in_ts&quot; in timestamp)
   return number is
      mle language javascript ' return in_ts.valueOf();';
/" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> 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>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>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>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>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>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>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>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>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 class="wp-block-heading" id="using-a-3rd-party-javascript-library">Using a 3rd Party JavaScript Library</h2>



<p>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" data-code="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';" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">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" data-code="VERSION    LANGUAGE_NAME       LENGTH(MODULE)
---------- ---------------- ----------------- 
13.12.0    JAVASCRIPT                  123260" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">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>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>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" data-code="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   =&gt; in_email,
                in_options =&gt; json('
                   {
                      &quot;allow_display_name&quot;: false,
                      &quot;allow_undescores&quot;: false,
                      &quot;require_display_name&quot;: false,
                      &quot;allow_utf8_local_part&quot;: true,
                      &quot;require_tld&quot;: true,
                      &quot;allow_ip_domain&quot;: false,
                      &quot;domain_specific_validation&quot;: false,
                      &quot;blacklisted_chars&quot;: &quot;&quot;,
                      &quot;ignore_max_length&quot;: false,
                      &quot;host_blacklist&quot;: [&quot;dubious.com&quot;],
                      &quot;host_whitelist&quot;: []
                   }
                ')
             );
   end is_email;
end validator_api;
/" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">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;: [&quot;dubious.com&quot;],</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>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" data-code="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&gt;'),
          ('esther.muster@dubious.com')
       ) test_data (e_mail);" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> 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" data-code="E_MAIL                                      IS_VALID
----------------------------------------- ----------
esther.muster@example.com                          1
Esther Muster &lt;esther.muster@example.com&gt;          0
esther.muster@dubious.com                          0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">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>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" data-code="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`, [by_percent, deptno]);
}
/
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)';
/" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #9CDCFE">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">, [</span><span style="color: #9CDCFE">by_percent</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">deptno</span><span style="color: #D4D4D4">]);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span>
<span class="line"><span style="color: #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>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" data-code="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;
/" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> 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>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" data-code="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;
/" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> 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>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>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>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>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>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" data-code="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 &quot;increase_salary&quot;;
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)';
/" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line 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>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>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>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>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>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>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>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></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>
		<item>
		<title>SmartDB as of 2018-08-21</title>
		<link>https://www.salvis.com/blog/2018/08/28/smartdb-as-of-2018-08-21/</link>
					<comments>https://www.salvis.com/blog/2018/08/28/smartdb-as-of-2018-08-21/#comments</comments>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Tue, 28 Aug 2018 20:36:02 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[SmartDB]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=8867</guid>

					<description><![CDATA[<p>Introduction This is a transcription of the recorded Ask TOM #SmartDB Office Hours from August 21, 2018, where Bryn Llewellyn presented an updated, narrow definition of the Smart Database Paradigm (SmartDB).&#160;It covers the time between 05:55 to 12:19. A big thank you to Bryn&#160;for taking the time to clarify the SmartDB definition.<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2018/08/28/smartdb-as-of-2018-08-21/">SmartDB as of 2018-08-21</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Introduction</h2>



<p>This is a transcription of the <a href="https://youtu.be/VEBbH7cJ0gE?t=355">recorded Ask TOM #SmartDB Office Hours from August 21, 2018</a>, where Bryn Llewellyn presented an updated, narrow definition of the Smart Database Paradigm (SmartDB).&nbsp;It covers the time between 05:55 to 12:19. A big thank you to Bryn&nbsp;for taking the time to clarify the SmartDB definition.</p>



<p>I highly recommend watching the whole recording. Personally, however,&nbsp;I find it easier to browse through written documents, rather than watch videos and/or listen to audio streams. I hope you find this transcription useful, as well.</p>



<p>I took the liberty of adding headers for the SmartDB properties I&#8217;ve described in <a href="https://www.salvis.com/blog/2018/07/18/is-your-application-smartdb/">this post</a>. At that time I assumed that all these five properties were mandatory, which in fact only holds true for the first two.</p>



<h2 class="wp-block-heading">SmartDB Definition</h2>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>This I think is the terse and appropriate definition of our Smart Database Paradigm. And it’s as simple as this.</p>
</blockquote>



<figure class="wp-block-image"><a href="https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_1.png"><img loading="lazy" decoding="async" width="1662" height="936" src="https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_1.png" alt="" class="wp-image-8870" srcset="https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_1.png 1662w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_1-300x169.png 300w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_1-768x433.png 768w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_1-1024x577.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_1-260x146.png 260w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_1-50x28.png 50w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_1-133x75.png 133w" sizes="auto, (max-width:767px) 480px, (max-width:1662px) 100vw, 1662px" /></a></figure>



<h3 class="wp-block-heading">1. The connect user does not own database objects</h3>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>By conventional regime of credentials publication – you know there is a database and there is client code that connects and it would be a miracle if anyone would set up any regime where ordinary client code connects as <code>sys</code>&nbsp;and from that you can deduce that client code is given credentials of certain users, so that it connects and do stuff. And it’s not given credentials of other users who are considered to be more private within the database. And it’s very simple to arrange that you give credentials out to the outside world only to schemas (there is no reason that it should be only one, but it’s easier to talk as it is one) […] which are empty of objects and which when they are created have zero privileges apart from the obvious <code>create session</code>.</p>



<p>That’s the starting point. And we won’t fuss with whatever public privileges, there’s no sensible way to talk ‘bout that and we leave that out of the picture.</p>
</blockquote>



<h3 class="wp-block-heading">2. The connect user can execute PL/SQL API units only</h3>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>And then […] the user who owns that empty schema is given exactly and only execute privileges on a well-defined set of PL/SQL subprograms who have been designed to be the API of the application backend that the database hosts to the outside world. And that means by construction the only sensible thing, why I should say the only thing at all you can do (if you don’t trouble ourselves with <code>select * from all_users</code>&nbsp;or something silly like that) is execute these API subprograms. And they’re designed to be single operations, so it would be very funny, if you wrote <code>begin</code>&nbsp;and then <code>api.number1;</code>, <code>api.number2;</code>&nbsp;and so on, but here is no way to stop anyone doing that. But the spirit of it is, that each time you do a top-level database call, you call just one subprogram. And indeed, it’s the case that these very straight forward procedural set of steps ensures, that the people who know the credentials you’ve given out, can only invoke your API subprograms.</p>



<p>And that is the Smart Database Paradigm.</p>
</blockquote>



<h2 class="wp-block-heading">SmartDB Recommendations</h2>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Everything else that we say under the umbrella of it, is let’s say recommendations, icing on the cake and notions that could be useful as applications get bigger and bigger and more complex.</p>
</blockquote>



<h3 class="wp-block-heading">3. PL/SQL API units handle transactions</h3>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>But you can see that a straight corollary of that statement of the paradigm is that, obviously we assume that there&#8217;s tables and someone’s gonna put stuff in and get stuff out by <code>select</code>. Where those SQL gonna come from? Well, they cannot come from the outside world by construction. In other words, the <code>insert</code>, <code>update</code>, <code>delete</code>&nbsp;and <code>commit</code>&nbsp;of course, and <code>select</code>&nbsp;statements that […] must be issued to implement the application’s purpose, they can only come out of PL/SQL code inside the database. Okay. So, if I state the paradigm as I did at first, then this bit here, let me highlight it</p>
</blockquote>



<figure class="wp-block-image"><a href="https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_2.png"><img loading="lazy" decoding="async" width="1662" height="166" src="https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_2.png" alt="" class="wp-image-8871" srcset="https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_2.png 1662w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_2-300x30.png 300w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_2-768x77.png 768w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_2-1024x102.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_2-260x26.png 260w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_2-50x5.png 50w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_2-150x15.png 150w" sizes="auto, (max-width:767px) 480px, (max-width:1662px) 100vw, 1662px" /></a></figure>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>is not a statement of the paradigm, it’s a theorem that you could deduce from that axiom that is the paradigm. Okay.</p>
</blockquote>



<h3 class="wp-block-heading">4. SQL statements are written by human hand</h3>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>And now this bit</p>
</blockquote>



<figure class="wp-block-image"><a href="https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_3.png"><img loading="lazy" decoding="async" width="1662" height="115" src="https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_3.png" alt="" class="wp-image-8872" srcset="https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_3.png 1662w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_3-300x21.png 300w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_3-768x53.png 768w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_3-1024x71.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_3-260x18.png 260w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_3-50x3.png 50w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_3-150x10.png 150w" sizes="auto, (max-width:767px) 480px, (max-width:1662px) 100vw, 1662px" /></a></figure>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>has troubled a lot of people. It’s not […] at all a requirement that you use only static SQL, it’s just a happy fact, that the huge majority of requirements for SQL and ordinary OLTP applications are well met by PL/SQL static SQL. And that’s why I’ve put the word “probably” there. And there’s a huge advantage in using static SQL of course, because of all the rich metadata that you can get to learn various properties of the application in a heartbeat like these days in 12.2 where are the <code>inserts</code>&nbsp;happening and what tables are involved and what <code>inserts</code>&nbsp;at what statement locations, right. Just by querying up the right metadata tables.</p>



<p>And this one here</p>
</blockquote>



<figure class="wp-block-image"><a href="https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_4.png"><img loading="lazy" decoding="async" width="1662" height="104" src="https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_4.png" alt="" class="wp-image-8873" srcset="https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_4.png 1662w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_4-300x19.png 300w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_4-768x48.png 768w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_4-1024x64.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_4-260x16.png 260w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_4-50x3.png 50w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_4-150x9.png 150w" sizes="auto, (max-width:767px) 480px, (max-width:1662px) 100vw, 1662px" /></a></figure>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>is hugely contentious. My point (and Toon’s too) is that SQL is a very natural language. It maps perfectly on to the way people talk about the information requirement in the business world. All this entity-relationship modeling stuff that maps so directly onto tables. And if you write your SQL ordinarily by human hand, well it’s not going to be that difficult in the common case, because it wraps, I should say maps so obviously to the real world that your application is modeling. That’s not to say that there’s anything in the Smart Database Paradigm that prohibits generated SQL. Not at all. And there was a huge misunderstanding about that in Twitter. Rather it means, that it’s not particularly remarkable if one writes SQL to achieve the end goal.</p>



<p>There’s gotta be programming involved. Some of the programming is in PL/SQL and some of it is in SQL. These two languages are a very natural fit for the task at hand, that’s all.</p>
</blockquote>



<h3 class="wp-block-heading">5. SQL statements exploit the full power of set-based SQL</h3>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>And then the next bit, again you know,</p>
</blockquote>



<figure class="wp-block-image"><a href="https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_5.png"><img loading="lazy" decoding="async" width="1662" height="147" src="https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_5.png" alt="" class="wp-image-8874" srcset="https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_5.png 1662w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_5-300x27.png 300w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_5-768x68.png 768w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_5-1024x91.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_5-260x23.png 260w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_5-50x4.png 50w, https://www.salvis.com/blog/wp-content/uploads/2018/08/atoh_smartdb_5-150x13.png 150w" sizes="auto, (max-width:767px) 480px, (max-width:1662px) 100vw, 1662px" /></a></figure>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>it would be so so sensible and proper to exploit the full set-based power of SQL. You can get correct result if you do row-by-row slow-by-slow. But why would you do that, if you understand SQL, which you would. And if you write this stuff by hand, which you likely to find easy enough, that you wouldn’t worry doing it any other way. And the same goes about using the bulk binding constructs.</p>
</blockquote>
<p>The post <a href="https://www.salvis.com/blog/2018/08/28/smartdb-as-of-2018-08-21/">SmartDB as of 2018-08-21</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/2018/08/28/smartdb-as-of-2018-08-21/feed/</wfw:commentRss>
			<slash:comments>12</slash:comments>
		
		
			</item>
		<item>
		<title>SmartDB as of 2018-06-12</title>
		<link>https://www.salvis.com/blog/2018/08/28/smartdb-as-of-2018-06-12/</link>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Tue, 28 Aug 2018 20:35:52 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[SmartDB]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=8856</guid>

					<description><![CDATA[<p>This is a transcription of Bryn Llewellyn&#8217;s talk Guarding Your Data Behind a Hard Shell PL/SQL API—the Detail recorded at Kscope18. It covers the time between 08:06 to 11:03. This definition was the starting position for my previous SmartDB and PinkDB-related posts. In the meantime, Bryn provided an updated, narrow definition of the Smart<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2018/08/28/smartdb-as-of-2018-06-12/">SmartDB as of 2018-06-12</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>This is a transcription of Bryn Llewellyn&#8217;s talk <a href="https://youtu.be/q8F713K-Qfw?list=PLdtXkK5KBY56RKLbtH4-wyDvZhe7UZ1bB&amp;t=486">Guarding Your Data Behind a Hard Shell PL/SQL API—the Detail</a> recorded at Kscope18. It covers the time between 08:06 to 11:03. This definition was the starting position for my previous SmartDB and PinkDB-related posts.</p>



<p>In the meantime, Bryn provided an updated, narrow definition of the Smart Database Paradigm (SmartDB). I recommend to stop reading here and instead read the <a href="https://www.salvis.com/blog/2018/08/28/smartdb-as-of-2018-08-21/">next post</a>.</p>



<h2 class="wp-block-heading">SmartDB Definition &#8211; Kscope18 &#8211; June, 12 2018</h2>



<figure class="wp-block-image"><a href="https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_1.png"><img loading="lazy" decoding="async" width="1616" height="905" src="https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_1.png" alt="" class="wp-image-8857" srcset="https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_1.png 1616w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_1-300x168.png 300w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_1-768x430.png 768w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_1-1024x573.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_1-260x146.png 260w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_1-50x28.png 50w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_1-134x75.png 134w" sizes="auto, (max-width:767px) 480px, (max-width:1616px) 100vw, 1616px" /></a></figure>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>This is another way of finally summarizing the notion, the Smart Database Paradigm, whose hashtag you see there.</p>
</blockquote>



<figure class="wp-block-image"><a href="https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_2.png"><img loading="lazy" decoding="async" width="1616" height="288" src="https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_2.png" alt="" class="wp-image-8858" srcset="https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_2.png 1616w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_2-300x53.png 300w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_2-768x137.png 768w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_2-1024x182.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_2-260x46.png 260w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_2-50x9.png 50w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_2-150x27.png 150w" sizes="auto, (max-width:767px) 480px, (max-width:1616px) 100vw, 1616px" /></a></figure>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>This is if you like the basic definition of it. We ensure that this primitive anonymous block (this is what we encourage,&nbsp; that is the only thing that is allowed to do anything when you do a database call), can only do, what the second thing shows. So, the first is the principle in words, and this is the principle illustrated in code. Okay.</p>
</blockquote>



<figure class="wp-block-image"><a href="https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_3.png"><img loading="lazy" decoding="async" width="1616" height="162" src="https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_3.png" alt="" class="wp-image-8859" srcset="https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_3.png 1616w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_3-300x30.png 300w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_3-768x77.png 768w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_3-1024x103.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_3-260x26.png 260w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_3-50x5.png 50w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_3-150x15.png 150w" sizes="auto, (max-width:767px) 480px, (max-width:1616px) 100vw, 1616px" /></a></figure>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>And finally, if we say this is the basic central axiom of the Smart Database Paradigm, then what we see here, in Euclid’s way of seeing the world, is a theorem. And the theorem is, that <code>insert</code>, <code>update</code>, <code>delete</code>, <code>commit</code>&nbsp;and <code>select</code>&nbsp;and for that matter <code>rollback</code> &#8211; I said them in funny order, but you know what I mean &#8211; the classic SQL statements that are sufficient to implement an ordinary OLTP application, they can come only out of PL/SQL code. Okay. You see that, that’s just a theorem following from this simple axiom here stated in words and reinforced here in an illustration.</p>
</blockquote>



<figure class="wp-block-image"><a href="https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_4.png"><img loading="lazy" decoding="async" width="1616" height="174" src="https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_4.png" alt="" class="wp-image-8860" srcset="https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_4.png 1616w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_4-300x32.png 300w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_4-768x83.png 768w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_4-1024x110.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_4-260x28.png 260w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_4-50x5.png 50w, https://www.salvis.com/blog/wp-content/uploads/2018/08/kscope18_smartdb_4-150x16.png 150w" sizes="auto, (max-width:767px) 480px, (max-width:1616px) 100vw, 1616px" /></a></figure>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>So then. And the final bit of the definition of the SmartDB paradigm is squishy. Everything I’ve said up to that point is hard and fast. You could walk up to a database, interrogate a few people, connect, do a few queries and you would soon see, hard shell or not.</p>



<p>The next bit you wouldn’t see. You would have to establish it and it’s a sliding scale. But basically, it says that everything that’s done to establish the world that’s exposed by the hard shell is done by intelligent, mature human beings, who’ve studied their trade, and have really done the whole thing. Designed the optimal set of tables and constraints, the optimal data model. They know SQL inside out and they know how to write the best SQL for the best use case. They know how to take advantage of set-based SQL in the ordinary sense, analytic functions, match recognize, you name it. It’s their stock-in-trade. And of course, they know also how to write PL/SQL.</p>



<p>But in this way of thinking about this world, I have to say, that the PL/SQL is typically no more than a kind of orchestration glue, whose purpose is to issue the SQL you’ve designed against the optimal data model, that you’ve designed. In other words, this is old-fashioned and unashamedly so, there’s no frameworks, there’s no point and click, it’s genuine intellectual achievement by people who’ve practiced their trade and being prepared to study what’s needed to study to get that far. And that part, of course, of SmartDB paradigm is harder to pin down.</p>
</blockquote>
<p>The post <a href="https://www.salvis.com/blog/2018/08/28/smartdb-as-of-2018-06-12/">SmartDB as of 2018-06-12</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
