{"id":13635,"date":"2024-10-16T04:22:28","date_gmt":"2024-10-16T02:22:28","guid":{"rendered":"https:\/\/www.salvis.com\/blog\/?p=13635"},"modified":"2025-03-12T10:22:04","modified_gmt":"2025-03-12T09:22:04","slug":"pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday","status":"publish","type":"post","link":"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/","title":{"rendered":"PL\/SQL vs. JavaScript in the Oracle Database 23ai #JoelKallmanDay"},"content":{"rendered":"\n<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>\n\n\n\n<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>\n\n\n\n<h2 class=\"wp-block-heading\">Why Do We Need Code in the Database?<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>I see the following reasons for this.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<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>\n\n\n\n<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>\n<\/ol>\n\n\n\n<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>\n\n\n\n<h2 class=\"wp-block-heading\">PL\/SQL Without SQL<\/h2>\n\n\n\n<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>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<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>\n<\/blockquote>\n\n\n\n<p>Listing 1 shows how we can implement this in PL\/SQL.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);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(\n   in_ts in timestamp\n) return number is\n   co_epoch_date constant timestamp with time zone := \n      timestamp '1970-01-01 00:00:00 UTC';\n   l_interval    interval day(9) to second (3);\nbegin\n   l_interval := in_ts - co_epoch_date;\n   return 1000 * (extract(second from l_interval)\n         + extract(minute from l_interval) * 60\n         + extract(hour from l_interval) * 60 * 60\n         + extract(day from l_interval) * 60 * 60 * 24);\nend;\n\/\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">create or replace<\/span><span style=\"color: #D4D4D4\"> function to_epoch_plsql(<\/span><\/span>\n<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>\n<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>\n<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>\n<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>\n<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>\n<span class=\"line\"><span style=\"color: #569CD6\">begin<\/span><\/span>\n<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>\n<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>\n<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>\n<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>\n<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>\n<span class=\"line\"><span style=\"color: #569CD6\">end<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">\/<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<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>\n\n\n\n<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>\n\n\n\n<h2 class=\"wp-block-heading\">Java Without SQL<\/h2>\n\n\n\n<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>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);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\npublic class Util {\n   public static long toEpoch(java.sql.Timestamp ts) {\n      return ts.getTime();\n   }\n}\n\/\ncreate or replace function to_epoch_java(in_ts in timestamp) \n  return number is language java name \n    'Util.toEpoch(java.sql.Timestamp) return java.lang.long';\n\/\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">public class Util {<\/span><\/span>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> ts.getTime();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">\/<\/span><\/span>\n<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>\n<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>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">\/<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<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>\n\n\n\n<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>\n\n\n\n<h2 class=\"wp-block-heading\">JavaScript Without SQL<\/h2>\n\n\n\n<p>With Oracle Database 23ai, we can create JavaScript modules.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);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   \nexport function toEpoch(ts) {\n   return ts.valueOf();\n}\n\/\ncreate or replace function to_epoch_js(in_ts in timestamp) \n   return number is \n      mle module util_mod \n      signature 'toEpoch(Date)';\n\/\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">export function toEpoch(ts) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> ts.valueOf();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #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>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      mle module util_mod <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      signature <\/span><span style=\"color: #CE9178\">&#39;toEpoch(Date)&#39;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">\/<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>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>\n\n\n\n<p>However, the implementation for this simple case is quite extensive. Oracle has probably realised this and provided an alternative.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">Listing 4: to_epoch_js2 \u2013 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)\n   return number is\n      mle language javascript ' return in_ts.valueOf();';\n\/\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">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>\n<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>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">\/<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<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>\n\n\n\n<h2 class=\"wp-block-heading\">Performance of <code>to_epoch_...<\/code><\/h2>\n\n\n\n<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>\n\n\n\n<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>\n\n\n\n<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>\n\n\n\n<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 loading=\"lazy\" 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=\"auto, (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>\n\n\n\n<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>\n\n\n\n<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>\n\n\n\n<h2 class=\"wp-block-heading\">Memory Usage of <code>to_epoch_...<\/code><\/h2>\n\n\n\n<p>Figure 2 shows the maximum memory used at the end of a <code>to_epoch_\u2026<\/code> function call. The call was made in a new database session and contains the memory requirements of the measuring instruments.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/10\/Figure2.png\"><img loading=\"lazy\" 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=\"auto, (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>\n\n\n\n<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>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"using-a-3rd-party-javascript-library\">Using a 3rd Party JavaScript Library<\/h2>\n\n\n\n<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>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">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\n\nselect version, language_name, length(module)\n  from user_mle_modules\n 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>\n<span class=\"line\"><\/span>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">from<\/span><span style=\"color: #D4D4D4\"> user_mle_modules<\/span><\/span>\n<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>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--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)\n---------- ---------------- ----------------- \n13.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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">---------- ---------------- ----------------- <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">13.12.0    JAVASCRIPT                  123260<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<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>\n\n\n\n<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>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);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\n   function is_email(\n      in_email in varchar2\n   ) return boolean deterministic;\nend validator_api;\n\/\ncreate or replace package body validator_api is\n   function is_email_internal(\n      in_email   in varchar2,\n      in_options in json\n   ) return boolean deterministic as mle module validator_mod \n   signature 'default.isEmail(string, any)';\n\n   function is_email(\n      in_email in varchar2\n   ) return boolean deterministic is\n   begin\n      return is_email_internal(\n                in_email   =&gt; in_email,\n                in_options =&gt; json('\n                   {\n                      &quot;allow_display_name&quot;: false,\n                      &quot;allow_undescores&quot;: false,\n                      &quot;require_display_name&quot;: false,\n                      &quot;allow_utf8_local_part&quot;: true,\n                      &quot;require_tld&quot;: true,\n                      &quot;allow_ip_domain&quot;: false,\n                      &quot;domain_specific_validation&quot;: false,\n                      &quot;blacklisted_chars&quot;: &quot;&quot;,\n                      &quot;ignore_max_length&quot;: false,\n                      &quot;host_blacklist&quot;: [&quot;dubious.com&quot;],\n                      &quot;host_whitelist&quot;: []\n                   }\n                ')\n             );\n   end is_email;\nend validator_api;\n\/\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">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>\n<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>\n<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>\n<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>\n<span class=\"line\"><span style=\"color: #569CD6\">end<\/span><span style=\"color: #D4D4D4\"> validator_api;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">\/<\/span><\/span>\n<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>\n<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>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      in_options <\/span><span style=\"color: #569CD6\">in<\/span><span style=\"color: #D4D4D4\"> json<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   ) <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #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>\n<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>\n<span class=\"line\"><\/span>\n<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>\n<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>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #569CD6\">begin<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> is_email_internal(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                in_email   =&gt; in_email,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                in_options =&gt; json(<\/span><span style=\"color: #CE9178\">&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">                   {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">                      &quot;allow_display_name&quot;: false,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">                      &quot;allow_undescores&quot;: false,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">                      &quot;require_display_name&quot;: false,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">                      &quot;allow_utf8_local_part&quot;: true,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">                      &quot;require_tld&quot;: true,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">                      &quot;allow_ip_domain&quot;: false,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">                      &quot;domain_specific_validation&quot;: false,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">                      &quot;blacklisted_chars&quot;: &quot;&quot;,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">                      &quot;ignore_max_length&quot;: false,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">                      &quot;host_blacklist&quot;: [&quot;dubious.com&quot;],<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">                      &quot;host_whitelist&quot;: []<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">                   }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">                &#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">             );<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #569CD6\">end<\/span><span style=\"color: #D4D4D4\"> is_email;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">end<\/span><span style=\"color: #D4D4D4\"> validator_api;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">\/<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<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>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">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\n  from (values\n          ('esther.muster@example.com'),\n          ('Esther Muster &lt;esther.muster@example.com&gt;'),\n          ('esther.muster@dubious.com')\n       ) 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>\n<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>\n<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>\n<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>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">       ) test_data (e_mail);<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--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\n----------------------------------------- ----------\nesther.muster@example.com                          1\nEsther Muster &lt;esther.muster@example.com&gt;          0\nesther.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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">----------------------------------------- ----------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">esther.muster@example.com                          1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">Esther Muster &lt;esther.muster@example.com&gt;          0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">esther.muster@dubious.com                          0<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">JavaScript With SQL<\/h2>\n\n\n\n<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>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);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 \nlanguage javascript as\nexport function increase_salary(deptno, by_percent) {\n   session.execute(`\n      update emp\n         set sal = sal + sal * :by_percent \/ 100\n         where deptno = :deptno`, [by_percent, deptno]);\n}\n\/\ncreate or replace procedure increase_salary_js(\n   in_deptno     in number,\n   in_by_percent in number\n) as mle module increase_salary_mod\nsignature 'increase_salary(number, number)';\n\/\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #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>\n<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>\n<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>\n<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>\n<span class=\"line\"><span style=\"color: #CE9178\">      update emp<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">         set sal = sal + sal * :by_percent \/ 100<\/span><\/span>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #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>\n<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>\n<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>\n<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>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">\/<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">PL\/SQL With SQL<\/h2>\n\n\n\n<p>Listing 9 shows the PL\/SQL counterpart to the JavaScript code in Listing 8, using dynamic SQL with bind variables.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);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(\n   in_deptno     in number,\n   in_by_percent in number\n) is\nbegin\n   execute immediate '\n      update emp\n         set sal = sal + sal * :by_percent \/ 100\n      where deptno = :deptno' using in_by_percent, in_deptno;\nend increase_salary_dplsql;\n\/\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">create or replace<\/span><span style=\"color: #D4D4D4\"> procedure increase_salary_dplsql(<\/span><\/span>\n<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>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #569CD6\">is<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">begin<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #DCDCAA\">execute immediate<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">      update emp<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">         set sal = sal + sal * :by_percent \/ 100<\/span><\/span>\n<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>\n<span class=\"line\"><span style=\"color: #569CD6\">end<\/span><span style=\"color: #D4D4D4\"> increase_salary_dplsql;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">\/<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<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>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);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(\n   in_deptno     in number,\n   in_by_percent in number\n) is\nbegin\n   update emp\n      set sal = sal + sal * in_by_percent \/ 100\n    where deptno = in_deptno;\nend increase_salary_plsql;\n\/\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">create or replace<\/span><span style=\"color: #D4D4D4\"> procedure increase_salary_plsql(<\/span><\/span>\n<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>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #569CD6\">is<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">begin<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #569CD6\">update<\/span><span style=\"color: #D4D4D4\"> emp<\/span><\/span>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">where<\/span><span style=\"color: #D4D4D4\"> deptno = in_deptno;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">end<\/span><span style=\"color: #D4D4D4\"> increase_salary_plsql;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">\/<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Performance of <code>increase_salary_...<\/code><\/h2>\n\n\n\n<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>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/10\/Figure3.png\"><img loading=\"lazy\" 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=\"auto, (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>\n\n\n\n<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>\n\n\n\n<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>\n\n\n\n<h2 class=\"wp-block-heading\">MLE Environment<\/h2>\n\n\n\n<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>\n\n\n\n<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>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">Listing 11: Using an MLE environment<\/span><span role=\"button\" tabindex=\"0\" data-code=\"create or replace mle env demo_env\n    imports(\n        'increase_salary' module increase_salary_mod,\n        'validator'       module validator_mod,\n        'util'            module util_mod\n    )\n    language options  'js.strict=true, js.console=false,\n                       js.polyglot-builtin=true'\n;\ncreate or replace mle module increase_salary_loop_mod \nlanguage javascript as   \nimport {increase_salary} from &quot;increase_salary&quot;;\nexport function increase_salary_loop(deptno,by_percent,times){\n   for (let i=0; i&lt;times; i++) {\n      increase_salary(deptno, by_percent);\n   }\n}\n\/\ncreate or replace procedure increase_salary_jsloop(\n   in_deptno     in number,\n   in_by_percent in number,\n   in_times      in number\n) as mle module increase_salary_loop_mod\nenv demo_env\nsignature 'increase_salary_loop(number, number, number)';\n\/\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line cbp-line-highlight\"><span style=\"color: #569CD6\">create or replace<\/span><span style=\"color: #D4D4D4\"> mle env demo_env<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    imports(<\/span><\/span>\n<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>\n<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>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    )<\/span><\/span>\n<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>\n<span class=\"line\"><span style=\"color: #CE9178\">                       js.polyglot-builtin=true&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">create or replace<\/span><span style=\"color: #D4D4D4\"> mle module increase_salary_loop_mod <\/span><\/span>\n<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>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">export function increase_salary_loop(deptno,by_percent,times){<\/span><\/span>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      increase_salary(deptno, by_percent);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">create or replace<\/span><span style=\"color: #D4D4D4\"> procedure increase_salary_jsloop(<\/span><\/span>\n<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>\n<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>\n<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>\n<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>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">env demo_env<\/span><\/span>\n<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>\n<span class=\"line\"><span style=\"color: #D4D4D4\">\/<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<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>\n\n\n\n<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>\n\n\n\n<h2 class=\"wp-block-heading\">Is Tom Kyte\u2019s Mantra Still Valid?<\/h2>\n\n\n\n<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>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>I have a pretty simple mantra when it comes to developing database software, one that has been consistent for many years:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<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>\n\n\n\n<li>If you can\u2019t do it in a single SQL Statement, do it in PL\/SQL\u2014as little PL\/SQL as possible! Follow the saying that goes &#8220;more code = more bugs, less code = less bugs.&#8221;<\/li>\n\n\n\n<li>If you can\u2019t 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>\n\n\n\n<li>If you can\u2019t 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>\n\n\n\n<li>If you can\u2019t do it in a C external routine, you might want to seriously think about why it is you need to do it.<\/li>\n<\/ul>\n<\/blockquote>\n\n\n\n<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>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<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>\n\n\n\n<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>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<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\"> [\u2026]<\/span><\/p>\n","protected":false},"author":1,"featured_media":13695,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[135,140,109,13,103],"class_list":["post-13635","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oracle","tag-javascript","tag-oracle-26ai","tag-pinkdb","tag-plsql","tag-smartdb"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>PL\/SQL vs. JavaScript in the Oracle Database 23ai #JoelKallmanDay - Philipp Salvisberg&#039;s Blog<\/title>\n<meta name=\"description\" content=\"What is easier and better in JavaScript than in Java? When is JavaScript a good alternative to PL\/SQL and when is it not?\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"PL\/SQL vs. JavaScript in the Oracle Database 23ai #JoelKallmanDay - Philipp Salvisberg&#039;s Blog\" \/>\n<meta property=\"og:description\" content=\"What is easier and better in JavaScript than in Java? When is JavaScript a good alternative to PL\/SQL and when is it not?\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/\" \/>\n<meta property=\"og:site_name\" content=\"Philipp Salvisberg&#039;s Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-10-16T02:22:28+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-03-12T09:22:04+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/10\/plsql_vs_javscript4.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"1024\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"author\" content=\"Philipp Salvisberg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@phsalvisberg\" \/>\n<meta name=\"twitter:site\" content=\"@phsalvisberg\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Philipp Salvisberg\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/10\\\/16\\\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/10\\\/16\\\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\\\/\"},\"author\":{\"name\":\"Philipp Salvisberg\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#\\\/schema\\\/person\\\/34352245c48678b1a5a05d4bc1339515\"},\"headline\":\"PL\\\/SQL vs. JavaScript in the Oracle Database 23ai #JoelKallmanDay\",\"datePublished\":\"2024-10-16T02:22:28+00:00\",\"dateModified\":\"2025-03-12T09:22:04+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/10\\\/16\\\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\\\/\"},\"wordCount\":2232,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#\\\/schema\\\/person\\\/34352245c48678b1a5a05d4bc1339515\"},\"image\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/10\\\/16\\\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2024\\\/10\\\/plsql_vs_javscript4.webp\",\"keywords\":[\"JavaScript\",\"Oracle 26ai\",\"PinkDB\",\"PL\\\/SQL\",\"SmartDB\"],\"articleSection\":[\"Oracle\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/10\\\/16\\\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/10\\\/16\\\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\\\/\",\"url\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/10\\\/16\\\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\\\/\",\"name\":\"PL\\\/SQL vs. JavaScript in the Oracle Database 23ai #JoelKallmanDay - Philipp Salvisberg&#039;s Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/10\\\/16\\\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/10\\\/16\\\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2024\\\/10\\\/plsql_vs_javscript4.webp\",\"datePublished\":\"2024-10-16T02:22:28+00:00\",\"dateModified\":\"2025-03-12T09:22:04+00:00\",\"description\":\"What is easier and better in JavaScript than in Java? When is JavaScript a good alternative to PL\\\/SQL and when is it not?\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/10\\\/16\\\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/10\\\/16\\\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/10\\\/16\\\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2024\\\/10\\\/plsql_vs_javscript4.webp\",\"contentUrl\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2024\\\/10\\\/plsql_vs_javscript4.webp\",\"width\":1024,\"height\":1024,\"caption\":\"PL\\\/SQL vs. JavaScrit in the Oracle Database 23ai\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2024\\\/10\\\/16\\\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"PL\\\/SQL vs. JavaScript in the Oracle Database 23ai #JoelKallmanDay\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/\",\"name\":\"Philipp Salvisberg&#039;s Blog\",\"description\":\"Database-centric development\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#\\\/schema\\\/person\\\/34352245c48678b1a5a05d4bc1339515\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#\\\/schema\\\/person\\\/34352245c48678b1a5a05d4bc1339515\",\"name\":\"Philipp Salvisberg\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2010\\\/11\\\/phs_trivadis4.jpg\",\"url\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2010\\\/11\\\/phs_trivadis4.jpg\",\"contentUrl\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2010\\\/11\\\/phs_trivadis4.jpg\",\"width\":400,\"height\":400,\"caption\":\"Philipp Salvisberg\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2010\\\/11\\\/phs_trivadis4.jpg\"},\"sameAs\":[\"http:\\\/\\\/www.salvis.com\\\/\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"PL\/SQL vs. JavaScript in the Oracle Database 23ai #JoelKallmanDay - Philipp Salvisberg&#039;s Blog","description":"What is easier and better in JavaScript than in Java? When is JavaScript a good alternative to PL\/SQL and when is it not?","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/","og_locale":"en_US","og_type":"article","og_title":"PL\/SQL vs. JavaScript in the Oracle Database 23ai #JoelKallmanDay - Philipp Salvisberg&#039;s Blog","og_description":"What is easier and better in JavaScript than in Java? When is JavaScript a good alternative to PL\/SQL and when is it not?","og_url":"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/","og_site_name":"Philipp Salvisberg&#039;s Blog","article_published_time":"2024-10-16T02:22:28+00:00","article_modified_time":"2025-03-12T09:22:04+00:00","og_image":[{"width":1024,"height":1024,"url":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/10\/plsql_vs_javscript4.webp","type":"image\/webp"}],"author":"Philipp Salvisberg","twitter_card":"summary_large_image","twitter_creator":"@phsalvisberg","twitter_site":"@phsalvisberg","twitter_misc":{"Written by":"Philipp Salvisberg","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/#article","isPartOf":{"@id":"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/"},"author":{"name":"Philipp Salvisberg","@id":"https:\/\/www.salvis.com\/blog\/#\/schema\/person\/34352245c48678b1a5a05d4bc1339515"},"headline":"PL\/SQL vs. JavaScript in the Oracle Database 23ai #JoelKallmanDay","datePublished":"2024-10-16T02:22:28+00:00","dateModified":"2025-03-12T09:22:04+00:00","mainEntityOfPage":{"@id":"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/"},"wordCount":2232,"commentCount":2,"publisher":{"@id":"https:\/\/www.salvis.com\/blog\/#\/schema\/person\/34352245c48678b1a5a05d4bc1339515"},"image":{"@id":"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/#primaryimage"},"thumbnailUrl":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/10\/plsql_vs_javscript4.webp","keywords":["JavaScript","Oracle 26ai","PinkDB","PL\/SQL","SmartDB"],"articleSection":["Oracle"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/","url":"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/","name":"PL\/SQL vs. JavaScript in the Oracle Database 23ai #JoelKallmanDay - Philipp Salvisberg&#039;s Blog","isPartOf":{"@id":"https:\/\/www.salvis.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/#primaryimage"},"image":{"@id":"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/#primaryimage"},"thumbnailUrl":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/10\/plsql_vs_javscript4.webp","datePublished":"2024-10-16T02:22:28+00:00","dateModified":"2025-03-12T09:22:04+00:00","description":"What is easier and better in JavaScript than in Java? When is JavaScript a good alternative to PL\/SQL and when is it not?","breadcrumb":{"@id":"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/#primaryimage","url":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/10\/plsql_vs_javscript4.webp","contentUrl":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2024\/10\/plsql_vs_javscript4.webp","width":1024,"height":1024,"caption":"PL\/SQL vs. JavaScrit in the Oracle Database 23ai"},{"@type":"BreadcrumbList","@id":"https:\/\/www.salvis.com\/blog\/2024\/10\/16\/pl-sql-vs-javascript-in-the-oracle-database-23ai-joelkallmanday\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.salvis.com\/blog\/"},{"@type":"ListItem","position":2,"name":"PL\/SQL vs. JavaScript in the Oracle Database 23ai #JoelKallmanDay"}]},{"@type":"WebSite","@id":"https:\/\/www.salvis.com\/blog\/#website","url":"https:\/\/www.salvis.com\/blog\/","name":"Philipp Salvisberg&#039;s Blog","description":"Database-centric development","publisher":{"@id":"https:\/\/www.salvis.com\/blog\/#\/schema\/person\/34352245c48678b1a5a05d4bc1339515"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.salvis.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.salvis.com\/blog\/#\/schema\/person\/34352245c48678b1a5a05d4bc1339515","name":"Philipp Salvisberg","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2010\/11\/phs_trivadis4.jpg","url":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2010\/11\/phs_trivadis4.jpg","contentUrl":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2010\/11\/phs_trivadis4.jpg","width":400,"height":400,"caption":"Philipp Salvisberg"},"logo":{"@id":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2010\/11\/phs_trivadis4.jpg"},"sameAs":["http:\/\/www.salvis.com\/"]}]}},"_links":{"self":[{"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/posts\/13635","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/comments?post=13635"}],"version-history":[{"count":55,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/posts\/13635\/revisions"}],"predecessor-version":[{"id":13854,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/posts\/13635\/revisions\/13854"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/media\/13695"}],"wp:attachment":[{"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/media?parent=13635"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/categories?post=13635"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/tags?post=13635"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}