{"id":4529,"date":"2025-02-11T08:52:20","date_gmt":"2025-02-11T16:52:20","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/plsql-to-javascript-udf-conversion-tool\/"},"modified":"2025-02-11T08:52:20","modified_gmt":"2025-02-11T16:52:20","slug":"plsql-to-javascript-udf-conversion-tool","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/ko\/plsql-to-javascript-udf-conversion-tool\/","title":{"rendered":"A Tool to Ease Your Transition From Oracle PL\/SQL to Couchbase JavaScript UDF"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\"><span>What is PL\/SQL?<\/span><\/h2>\n\n\n\n<p><span>PL\/SQL is a procedural language designed specifically to embrace SQL statements within its syntax. It includes procedural language elements such as conditions and loops, and can handle exceptions (run-time errors).<\/span><\/p>\n\n\n\n<p><span>PL\/SQL is native to Oracle databases, and databases like IBM DB2, PostgreSQL, and MySQL support PL\/SQL constructs through compatibility features.<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span>What is a JavaScript UDF?<\/span><\/h2>\n\n\n\n<p><span>JavaScript UDF is Couchbase\u2019s alternative to PL\/SQL.<\/span><\/p>\n\n\n\n<p><span>JavaScript UDF brings JavaScript&#8217;s general-purpose scripting flexibility to databases, allowing for dynamic and powerful operations across modern database systems and enhances flexibility in data querying, processing, and transformation.<\/span><\/p>\n\n\n\n<p><span>Most modern databases like Couchbase, MongoDB, Snowflake, and Google BigQuery support JavaScript UDF.<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span>The problem<\/span><\/h2>\n\n\n\n<p><span>A common problem seen by users migrating from Oracle to Couchbase is porting their PL\/SQL scripts. Instead of supporting PL\/SQL, Couchbase lets users construct user-defined functions in JavaScript (supported since 2021).<\/span><span><br>\n<\/span><span><br>\n<\/span><span>JavaScript UDFs allow easy, intuitive manipulation of variant and JSON data. Variant objects passed to a UDF are transformed to native JavaScript types and values.<\/span><\/p>\n\n\n\n<p><span>The unintended consequence of this is that the majority of RDBMS that have been in existence for the last ten years have strongly encouraged developers to access the database using their procedural extensions to SQL (PL\/pgSQL, PL\/SQL), which support procedural constructs, integration with SQL, error handling, functions and procedures, triggers, and cursors, or at the very least, functions and procedures (like Sakila). For any attempt to move away from them, all of their scripts would need to be rewritten.<\/span><\/p>\n\n\n\n<p><span>Rewriting code is often a tedious task, especially when dealing with PL\/SQL scripts that have been written in the 2000s and maintained since then. These scripts can be complex, often extending to thousands of lines, which can be overwhelming for the average enterprise user.<\/span><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span>Solution<\/span><\/h3>\n\n\n\n<p><span>The ideal approach would be to develop a whole new PL\/SQL evaluator, but that would require an excessive amount of engineering hours, and for the same use case, we already have a modern, stable, and fast JSEvaluator; So why support another evaluator?<\/span><\/p>\n\n\n\n<p><span>This makes the problem a perfect use-case to leverage the ongoing advances in AI and LLMs. And that&#8217;s what we have done here. We have used Generative AI models to <\/span><b>automate the conversion of PL\/SQL to JSUDF<\/b><span>.<\/span><span><br>\n<\/span><span><br>\n<\/span><span>As of June 2024, <a href=\"https:\/\/platform.openai.com\/docs\/models\/gpt-4-turbo-and-gpt-4\">models have a limited context window<\/a>, w<\/span><span>hich means longer PL\/SQL get hit with the error:\u00a0\u00a0<\/span><\/p>\n\n\n<p>[crayon nums=&#8221;false&#8221; wrap=&#8221;true&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]This model&#8217;s maximum context length is 8192 tokens. However, your messages resulted in &lt;More-than-8192&gt; tokens. Please reduce the length of the messages.[\/crayon]<\/p>\n\n\n\n<p><span>Note, that this is for GPT4.<\/span><\/p>\n\n\n\n<p><span>So do we wait for AI to become more powerful and allow more tokens (like Moore\u2019s Law but for the AI\u2019s context-length-vs-precision)?<\/span><\/p>\n\n\n\n<p><span>No, that\u2019s where <a href=\"https:\/\/www.antlr.org\/\">ANTLR<\/a>, a<\/span><span> parser generator tool, comes in. ANTLR is well-known to be used for Compiler and Interpreter Development. That way we can break the big script to smaller units that can be translated independently.<\/span><\/p>\n\n\n\n<p><span>So are we now building a <\/span><b>transpiler? <\/b><span>Well, yes and no.<\/span><span><br>\n<\/span><span><br>\n<\/span><strong>Stages in a transpiler:<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><span>Lexical Analysis (Tokenization)<\/span><\/li>\n\n\n<li><span>Syntactic Analysis (Parsing)<\/span><\/li>\n\n\n<li><span>Semantic Analysis<\/span><\/li>\n\n\n<li><span>Intermediate Representation (IR) Generation<\/span><\/li>\n\n\n<li><span>Optimization (Optional)<\/span><\/li>\n\n\n<li><span>Target Code Generation<\/span><\/li>\n\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><span>How the AI translator works<\/span><\/strong><\/h4>\n\n\n\n<p><span>Above steps 1,2 are done using ANTLR.\u00a0<\/span><span>We use ANTLR\u2019s Listener interface to <\/span><b>grab individual Procedure\/Function\/Anonymous-block<\/b><span>,\u00a0 as they are independent blocks of code. In a case where the\u00a0 Procedure\/Function\/Anonymous-block are themselves exceeding the context window, we translate at a statement level (where the LLM assumes the existence of use of variables\/function calls that aren\u2019t defined here but somewhere before).<\/span><\/p>\n\n\n\n<p><span>Subsequently, steps 3, 4, 5, and 6 are left to the LLM (e.g., GPT), i.e., translating each PL\/SQL block into a JavaScript function to the best of its ability that also preserves the operational semantics of the block and is syntactically accurate.<\/span><\/p>\n\n\n\n<p><span>The results are surprisingly quite positive; the translation is 80-85% accurate.<\/span><\/p>\n\n\n\n<p><span>Another benefit of the solution is that we reduce hallucination by focusing on one task at a time, resulting in more accurate translations.<\/span><\/p>\n\n\n\n<p><span>To visualize:<\/span><\/p>\n\n\n\n<p><a href=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/02\/image1-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-16847 size-large\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/image1-1-1024x904-1.png\" alt=\"automate the conversion of PL\/SQL to JSUDF\" width=\"900\" height=\"795\"><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span>How to use the tool<\/span><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span>Download the executable from <a href=\"https:\/\/github.com\/couchbaselabs\/plsql-to-jsudf2\/releases\/tag\/v1.0.0\">Couchbase Labs GitHub<\/a> and access the <a href=\"https:\/\/github.com\/couchbaselabs\/plsql-to-jsudf2\/blob\/master\/README.md\">README<\/a>.<\/span><span><br>\n<\/span><\/li>\n\n<\/ul>\n\n\n\n<p><span>The executable expects the following command-line arguments:<\/span><\/p>\n\n\n\n<p><span>-u: capella signin email<br>\n<\/span><span>-p: capella signin password<br>\n<\/span><span>-cpaddr: capella-url for chat-completions api<br>\n<\/span><span>-orgid: organisation id in the chat-completions api path<br>\n<\/span><span>-cbhost: node-ip: cbcluster node<br>\n<\/span><span>-cbuser: cluster-user-name: cbcluster user, added through database-acess<br>\n<\/span><span>-cbpassword: cluster-password: cbcluster password, added through database-access<br>\n<\/span><span>-cbport: query-service tls port: usually 18093<br>\n<\/span><span>filepath , i.e path to the PL\/SQL script that has to be translated<\/span><span><br>\n<\/span><span>output-&gt;\u00a0<\/span><span>In the output directory, a file with the same name as the <em>plsql<\/em> file is generated with translated JavaScript Library code.<\/span><\/p>\n\n\n\n<p><span>An example:<\/span><\/p>\n\n\n\n<p><code>cat example1.sql<\/code><\/p>\n\n\n<p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]DECLARE<br \/>\n\u00a0\u00a0\u00a0x NUMBER := 0;<br \/>\n\u00a0\u00a0\u00a0counter NUMBER := 0;<br \/>\nBEGIN<br \/>\n\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1000;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;in OUTER loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#8211;start an inner block\u00a0<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DECLARE<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x NUMBER := 0;\u00a0 &#8212; this is a local version of x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0BEGIN<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1;\u00a0 &#8212; this increments the local x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;inner loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END;<br \/>\n\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0COMMIT;<br \/>\nEND;[\/crayon]<\/p>\n\n\n\n<p><span>To briefly explain the above script:<\/span><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span>An outer loop runs for 4 iterations, incrementing x by 1000, counter by 1<\/span><span><br>\n<\/span><\/li>\n\n\n<li><span>Inner loop runs for 4 iterations, incrementing x by 1, counter by 1<\/span><span><br>\n<\/span><\/li>\n\n<\/ul>\n\n\n\n<p><span>Running the translator on the test PL\/SQL:<\/span><\/p>\n\n\n<p>[crayon nums=&#8221;false&#8221; wrap=&#8221;true&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;].\/plsql-to-jsudf -u \u00abcapella-signin-mailid\u00bb -p \u00abcapella-signin-password\u00bb -cpaddr https:\/\/api.cloud.couchbase.com -orgid \u00abcapella-organisation-id\u00bb -cbhost \u00abhostname of data node\u00bb -cbuser \u00abcbcluster username\u00bb -cbpassword \u00abcbcluster password\u00bb\u00a0 -cbport 18093 .\/translator\/test\/plsql\/example1.sql<br \/>\n[\/crayon]<\/p>\n\n\n\n<p><span>Output JSUDF:<\/span><\/p>\n\n\n\n<p><span><code>cat output\/example1.js<\/code><\/span><span><br>\n<\/span><\/p>\n\n\n<p>[crayon nums=&#8221;false&#8221; wrap=&#8221;true&#8221; lang=&#8221;js&#8221; decode=&#8221;true&#8221;]function nestedloop(){<br \/>\n\u00a0\u00a0\u00a0\u00a0var x = 0;<br \/>\n\u00a0\u00a0\u00a0\u00a0var counter = 0;<br \/>\n\u00a0\u00a0\u00a0\u00a0var querybegin = BEGIN WORK;<br \/>\n\u00a0\u00a0\u00a0\u00a0querybegin.close();<br \/>\n\u00a0\u00a0\u00a0\u00a0for (var i = 1; i &lt;= 4; i++){<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x = x + 1000;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter = counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var params = [x, counter];<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var query = N1QL(&#8216;INSERT INTO test.testscope.temp VALUES (uuid(),{&#8220;val1&#8243;:$1,&#8221;val2&#8243;:$2,&#8221;val3&#8243;:&#8221;in OUTER loop&#8221;})&#8217;,params);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0query.close();<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var x_inner = 0;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0for (var j = 1; j &lt;= 4; j++){<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x_inner = x_inner + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter = counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var params_inner = [x_inner, counter];<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var query_inner = N1QL(&#8216;INSERT INTO test.testscope.temp VALUES (uuid(),{&#8220;val1&#8243;:$1,&#8221;val2&#8243;:$2,&#8221;val3&#8243;:&#8221;inner loop&#8221;})&#8217;,params_inner);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0query_inner.close();<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}<br \/>\n\u00a0\u00a0\u00a0\u00a0}<br \/>\n\u00a0\u00a0\u00a0\u00a0var querycommit = COMMIT WORK;<br \/>\n\u00a0\u00a0\u00a0\u00a0querycommit.close();<br \/>\n}[\/crayon]<\/p>\n\n\n\n<p><span>The translated script has a function <em>nestedloop<\/em> (name generated by LLM) that does exactly what the original anonymous PL\/SQL block specifies.<\/span><\/p>\n\n\n\n<p><span>Side note: for named functions\/procedures translated JS functions will have the same name.\u00a0 For anonymous blocks LLM uses a name it comes up with.<\/span><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span>Known issues<\/span><\/h3>\n\n\n\n<p><span>PL\/SQL and JS are 2 different languages, and the way they are supported in Oracle and Couchbase doesn\u2019t allow for a clean direct mapping between the 2.\u00a0<\/span><\/p>\n\n\n\n<p><span>Below are some limitations we discovered and the workarounds we have implemented for the same:<\/span><\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span>\u200b\u200b1. console.log is not supported<\/span><\/h4>\n\n\n\n<p><span><em>DBMS_OUTPUT.PUT<\/em> builtin procedure and other 2 similar builtins, <em>DBMS_OUTPUT.PUT_LINE<\/em> and <em>DBMS_OUTPUT.NEW_LINE<\/em> are translated to <em>console.log()<\/em>, but console.log is a browser API and is not supported by Couchbase&#8217;s JavaScript evaluation implementation. This has been a frequent ask, considering the Couchbase eventing function does support <em>print()<\/em> statements but not in JavaScript UDFs.<\/span><\/p>\n\n\n\n<p><b>Workaround:<\/b><\/p>\n\n\n\n<p><span>Users are expected to create a <em>logging<\/em>\u00a0bucket.<\/span><\/p>\n\n\n\n<p><span>Logs are inserted as part of a document INSERT into `default`.`default` collection. The document would look something like:<\/span><span><br>\n<\/span><\/p>\n\n\n<p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]{<br \/>\n\u00a0\u00a0\u00a0&#8220;udf&#8221;: \u00abfunc-name\u00bb,<br \/>\n\u00a0\u00a0\u00a0&#8220;log&#8221;: \u00abargument to console.log\u00bb, \/\/ the actual log line<br \/>\n\u00a0\u00a0\u00a0&#8220;time&#8221;: \u00abcurrent ISO time string\u00bb<br \/>\n}[\/crayon]<\/p>\n\n\n\n<p><span>User can lookup his logs by selecting on logging:<\/span><\/p>\n\n\n<p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]SELECT * FROM logging WHERE udf= &#8220;\u00abfunc-name\u00bb&#8221;;<br \/>\nSELECT * FROM logging WHERE time BETWEEN &#8220;\u00abdate1\u00bb&#8221; AND &#8220;\u00abdate2\u00bb&#8221;;<br \/>\n[\/crayon]<\/p>\n\n\n\n<p><span>An example:<\/span><\/p>\n\n\n\n<p><span>The original PL\/SQL<\/span><\/p>\n\n\n<p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]BEGIN<br \/>\n\u00a0\u00a0\u00a0DBMS.OUTPUT.PUT(&#8220;Hello world!&#8221;);<br \/>\nEND;[\/crayon]<\/p>\n\n\n\n<p><span>Translated to JavaScript UDF<\/span><\/p>\n\n\n<p>[crayon nums=&#8221;false&#8221; lang=&#8221;js&#8221; decode=&#8221;true&#8221;]function helloWorld() {<br \/>\n\u00a0 \u00a0\/\/ workaround for console.log(&#8220;Hello world!&#8221;);<br \/>\n\u00a0\u00a0\u00a0var currentDate = new Date();<br \/>\n\u00a0\u00a0\u00a0var utcISOString = currentDate.toISOString();<br \/>\n\u00a0\u00a0\u00a0var params = [utcISOString,&#8217;anonymousblock1&#8242;,&#8221;Hello world!&#8221;];<br \/>\n\u00a0\u00a0\u00a0var logquery = N1QL(&#8216;INSERT INTO logging VALUES(UUID(),{&#8220;udf&#8221;:$2, &#8220;log&#8221;:$3, &#8220;time&#8221;:$1}, {&#8220;expiration&#8221;: 5*24*60*60 })&#8217;, params);<br \/>\n\u00a0\u00a0\u00a0logquery.close();<br \/>\n}<br \/>\n[\/crayon]<\/p>\n\n\n\n<p><span>This is already implemented in the tool.<\/span><\/p>\n\n\n\n<p><span><br>\n<\/span><span>To view the log:<\/span><span><br>\n<\/span><span><br>\n<\/span><\/p>\n\n\n<p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]EXECUTE FUNCTION helloWorld();<br \/>\n&#8220;results&#8221;: [<br \/>\n\u00a0\u00a0\u00a0null<br \/>\n]<\/p>\n<p>CREATE PRIMARY INDEX ON logging;<br \/>\n&#8220;results&#8221;: [<br \/>\n]<\/p>\n<p>SELECT * FROM logging;<br \/>\n&#8220;results&#8221;: [<br \/>\n\u00a0\u00a0\u00a0{&#8220;logging&#8221;:{&#8220;log&#8221;:&#8221;Hello world!&#8221;,&#8221;time&#8221;:&#8221;2024-06-26T09:20:56.000Z&#8221;,&#8221;udf&#8221;:&#8221;anonymousblock1&#8243;}}<br \/>\n][\/crayon]<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span>2. Cross Package function calls<\/span><\/h4>\n\n\n\n<p><span>Procedures\/Functions listed in the package specification are Global, and can be used from other packages via <em>\u00abpackage_name\u00bb.\u00abpublic_procedure\/function\u00bb<\/em>. But the same is not true for a JavaScript Library in Couchbase, as import-export constructs are not supported by Couchbase&#8217;s JavaScript evaluation implementation.<\/span><span><br>\n<\/span><span><br>\n<\/span><b>Workaround:<\/b><b><\/b><\/p>\n\n\n\n<p><span>In case of an interlibrary function call<em> \u00ablib_name\u00bb.\u00abfunction\u00bb()<\/em>, user is expected to have the referenced library <em>\u00ablib_name\u00bb<\/em> already created; you can verify this via <em>GET \/evaluator\/v1\/libraries<\/em><\/span><\/p>\n\n\n\n<p><span>The referenced function <em>\u00abfunction\u00bb<\/em> also is expected to be created as a global UDF; this can be verified via GET \/admin\/functions_cache or select system:functions keyspace. This way we can access the function via SQL++\/N1QL.<\/span><\/p>\n\n\n\n<p><span>An example:<\/span><\/p>\n\n\n\n<p><span><em>math_utils<\/em> Package<\/span><\/p>\n\n\n<p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]CREATE OR REPLACE PACKAGE math_utils AS<br \/>\n\u00a0\u00a0\u00a0&#8212; Public function to add two numbers<br \/>\n\u00a0\u00a0\u00a0FUNCTION add_numbers(p_num1 NUMBER, p_num2 NUMBER) RETURN NUMBER;<br \/>\nEND math_utils;<br \/>\n\/<\/p>\n<p>CREATE OR REPLACE PACKAGE BODY math_utils AS<br \/>\n\u00a0\u00a0\u00a0FUNCTION add_numbers(p_num1 NUMBER, p_num2 NUMBER) RETURN NUMBER IS<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0BEGIN<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0RETURN p_num1 + p_num2;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END add_numbers;<br \/>\nEND math_utils;<br \/>\n\/<br \/>\n[\/crayon]<\/p>\n\n\n\n<p><span><em>show_sum<\/em> Package<\/span><span><br>\n<\/span><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]DECLARE<br \/>\n\u00a0\u00a0\u00a0x NUMBER := 0;<br \/>\n\u00a0\u00a0\u00a0counter NUMBER := 0;<br \/>\nBEGIN<br \/>\n\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1000;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;in OUTER loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#8211;start an inner block\u00a0<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DECLARE<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x NUMBER := 0;\u00a0 &#8212; this is a local version of x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0BEGIN<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1;\u00a0 &#8212; this increments the local x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;inner loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END;<br \/>\n\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0COMMIT;<br \/>\nEND;[\/crayon]<\/p>\n0<\/p>\n\n\n\n<p><span>Translated code:<\/span><span><br>\n<\/span><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]DECLARE<br \/>\n\u00a0\u00a0\u00a0x NUMBER := 0;<br \/>\n\u00a0\u00a0\u00a0counter NUMBER := 0;<br \/>\nBEGIN<br \/>\n\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1000;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;in OUTER loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#8211;start an inner block\u00a0<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DECLARE<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x NUMBER := 0;\u00a0 &#8212; this is a local version of x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0BEGIN<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1;\u00a0 &#8212; this increments the local x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;inner loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END;<br \/>\n\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0COMMIT;<br \/>\nEND;[\/crayon]<\/p>\n1<\/p>\n\n\n\n<p><span>It is auto-handled by the program, with a warning that it should be verified by a human set of eyes!<\/span><\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span>3. Global Variables<\/span><\/h4>\n\n\n\n<p><span>PL\/SQL supports package level and session level global variables, but global variables are not supported in JSUDF deliberately by design as this causes concern for memory leaks.<\/span><\/p>\n\n\n\n<p><span>Suggested workaround requires manual tweaking of the generated translation. For example:<\/span><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]DECLARE<br \/>\n\u00a0\u00a0\u00a0x NUMBER := 0;<br \/>\n\u00a0\u00a0\u00a0counter NUMBER := 0;<br \/>\nBEGIN<br \/>\n\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1000;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;in OUTER loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#8211;start an inner block\u00a0<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DECLARE<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x NUMBER := 0;\u00a0 &#8212; this is a local version of x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0BEGIN<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1;\u00a0 &#8212; this increments the local x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;inner loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END;<br \/>\n\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0COMMIT;<br \/>\nEND;[\/crayon]<\/p>\n2<\/p>\n\n\n\n<p><span><br>\n<\/span><span>Any function\u00a0 that modifies a global variable must accept it as an argument and return it to the caller.<\/span><\/p>\n\n\n\n<p><span><em>increment_counter<\/em>:<\/span><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]DECLARE<br \/>\n\u00a0\u00a0\u00a0x NUMBER := 0;<br \/>\n\u00a0\u00a0\u00a0counter NUMBER := 0;<br \/>\nBEGIN<br \/>\n\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1000;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;in OUTER loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#8211;start an inner block\u00a0<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DECLARE<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x NUMBER := 0;\u00a0 &#8212; this is a local version of x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0BEGIN<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1;\u00a0 &#8212; this increments the local x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;inner loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END;<br \/>\n\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0COMMIT;<br \/>\nEND;[\/crayon]<\/p>\n3<\/p>\n\n\n\n<p><span>Any function that only reads a global can accept it as an argument.<\/span><\/p>\n\n\n\n<p><span><em>show_globals<\/em>:<\/span><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]DECLARE<br \/>\n\u00a0\u00a0\u00a0x NUMBER := 0;<br \/>\n\u00a0\u00a0\u00a0counter NUMBER := 0;<br \/>\nBEGIN<br \/>\n\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1000;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;in OUTER loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#8211;start an inner block\u00a0<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DECLARE<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x NUMBER := 0;\u00a0 &#8212; this is a local version of x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0BEGIN<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1;\u00a0 &#8212; this increments the local x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;inner loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END;<br \/>\n\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0COMMIT;<br \/>\nEND;[\/crayon]<\/p>\n4<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span>Package to Library<\/span><\/h3>\n\n\n\n<p><span>This section shows an end-to-end package-to-library conversion using the tool.<\/span><\/p>\n\n\n\n<p><span>Sample PL\/SQL package:<\/span><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]DECLARE<br \/>\n\u00a0\u00a0\u00a0x NUMBER := 0;<br \/>\n\u00a0\u00a0\u00a0counter NUMBER := 0;<br \/>\nBEGIN<br \/>\n\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1000;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;in OUTER loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#8211;start an inner block\u00a0<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DECLARE<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x NUMBER := 0;\u00a0 &#8212; this is a local version of x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0BEGIN<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1;\u00a0 &#8212; this increments the local x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;inner loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END;<br \/>\n\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0COMMIT;<br \/>\nEND;[\/crayon]<\/p>\n5<\/p>\n\n\n\n<p><span>Translation:<\/span><span><br>\n<\/span><span><br>\n<\/span><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]DECLARE<br \/>\n\u00a0\u00a0\u00a0x NUMBER := 0;<br \/>\n\u00a0\u00a0\u00a0counter NUMBER := 0;<br \/>\nBEGIN<br \/>\n\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1000;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;in OUTER loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#8211;start an inner block\u00a0<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DECLARE<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x NUMBER := 0;\u00a0 &#8212; this is a local version of x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0BEGIN<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1;\u00a0 &#8212; this increments the local x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;inner loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END;<br \/>\n\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0COMMIT;<br \/>\nEND;[\/crayon]<\/p>\n6<\/p>\n\n\n\n<p><span>Code:<\/span><span><br>\n<\/span><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]DECLARE<br \/>\n\u00a0\u00a0\u00a0x NUMBER := 0;<br \/>\n\u00a0\u00a0\u00a0counter NUMBER := 0;<br \/>\nBEGIN<br \/>\n\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1000;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;in OUTER loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#8211;start an inner block\u00a0<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DECLARE<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x NUMBER := 0;\u00a0 &#8212; this is a local version of x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0BEGIN<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1;\u00a0 &#8212; this increments the local x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;inner loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END;<br \/>\n\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0COMMIT;<br \/>\nEND;[\/crayon]<\/p>\n7<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Let\u2019s insert a new employee document<\/h4>\n\n\n\n<p><span>Create employee collection:<\/span><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]DECLARE<br \/>\n\u00a0\u00a0\u00a0x NUMBER := 0;<br \/>\n\u00a0\u00a0\u00a0counter NUMBER := 0;<br \/>\nBEGIN<br \/>\n\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1000;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;in OUTER loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#8211;start an inner block\u00a0<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DECLARE<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x NUMBER := 0;\u00a0 &#8212; this is a local version of x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0BEGIN<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1;\u00a0 &#8212; this increments the local x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;inner loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END;<br \/>\n\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0COMMIT;<br \/>\nEND;[\/crayon]<\/p>\n8<\/p>\n\n\n\n<p><span>Insert an employee:<\/span><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;]DECLARE<br \/>\n\u00a0\u00a0\u00a0x NUMBER := 0;<br \/>\n\u00a0\u00a0\u00a0counter NUMBER := 0;<br \/>\nBEGIN<br \/>\n\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1000;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;in OUTER loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#8211;start an inner block\u00a0<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DECLARE<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x NUMBER := 0;\u00a0 &#8212; this is a local version of x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0BEGIN<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0FOR i IN 1..4 LOOP<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0x := x + 1;\u00a0 &#8212; this increments the local x<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0counter := counter + 1;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0INSERT INTO temp VALUES (x, counter, &#8216;inner loop&#8217;);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0END;<br \/>\n\u00a0\u00a0\u00a0END LOOP;<br \/>\n\u00a0\u00a0\u00a0COMMIT;<br \/>\nEND;[\/crayon]<\/p>\n9<\/p>\n\n\n\n<p><span>This errors out, and <\/span><b>that\u2019s ok<\/b><span> we can fix it manually.<\/span><\/p>\n\n\n\n<p><span>Reading the reason and <em>exception: <\/em><\/span><i><span><em>Cannot INSERT non-string key 1 of type value.intValue<\/em>, <\/span><\/i><span>Ah! the key is always expected to be a string, passing <\/span><b>insert_employee(&#8220;1&#8221;, &#8220;joe&#8221;, &#8220;briggs&#8221;, 10000) <\/b><span>would do the trick, but it is unintuitive to expect <em>employee_id<\/em> to be a string.<\/span><span><br>\n<\/span><span><br>\n<\/span><span>Let\u2019s alter the generated code:<\/span><span><br>\n<\/span><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; wrap=&#8221;true&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;].\/plsql-to-jsudf -u \u00abcapella-signin-mailid\u00bb -p \u00abcapella-signin-password\u00bb -cpaddr https:\/\/api.cloud.couchbase.com -orgid \u00abcapella-organisation-id\u00bb -cbhost \u00abhostname of data node\u00bb -cbuser \u00abcbcluster username\u00bb -cbpassword \u00abcbcluster password\u00bb\u00a0 -cbport 18093 .\/translator\/test\/plsql\/example1.sql<br \/>\n[\/crayon]<\/p>\n0<\/p>\n\n\n\n<p><b><\/b><span>And recreate the UDF:<\/span><span><br>\n<\/span><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; wrap=&#8221;true&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;].\/plsql-to-jsudf -u \u00abcapella-signin-mailid\u00bb -p \u00abcapella-signin-password\u00bb -cpaddr https:\/\/api.cloud.couchbase.com -orgid \u00abcapella-organisation-id\u00bb -cbhost \u00abhostname of data node\u00bb -cbuser \u00abcbcluster username\u00bb -cbpassword \u00abcbcluster password\u00bb\u00a0 -cbport 18093 .\/translator\/test\/plsql\/example1.sql<br \/>\n[\/crayon]<\/p>\n1<\/p>\n\n\n\n<p><b><\/b><b>Trying to insert again:<\/b><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; wrap=&#8221;true&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;].\/plsql-to-jsudf -u \u00abcapella-signin-mailid\u00bb -p \u00abcapella-signin-password\u00bb -cpaddr https:\/\/api.cloud.couchbase.com -orgid \u00abcapella-organisation-id\u00bb -cbhost \u00abhostname of data node\u00bb -cbuser \u00abcbcluster username\u00bb -cbpassword \u00abcbcluster password\u00bb\u00a0 -cbport 18093 .\/translator\/test\/plsql\/example1.sql<br \/>\n[\/crayon]<\/p>\n2<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span>Update an employee:<\/span><\/h4>\n\n\n\n<p><span>Shoot! There\u2019s a goof up, employee 1 isn\u2019t Joe, it\u2019s Emily.\u00a0<\/span><\/p>\n\n\n\n<p><b>Let\u2019s update employee 1<\/b><b><\/b><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; wrap=&#8221;true&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;].\/plsql-to-jsudf -u \u00abcapella-signin-mailid\u00bb -p \u00abcapella-signin-password\u00bb -cpaddr https:\/\/api.cloud.couchbase.com -orgid \u00abcapella-organisation-id\u00bb -cbhost \u00abhostname of data node\u00bb -cbuser \u00abcbcluster username\u00bb -cbpassword \u00abcbcluster password\u00bb\u00a0 -cbport 18093 .\/translator\/test\/plsql\/example1.sql<br \/>\n[\/crayon]<\/p>\n3<\/p>\n\n\n\n<p><span>View the employee:<\/span><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; wrap=&#8221;true&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;].\/plsql-to-jsudf -u \u00abcapella-signin-mailid\u00bb -p \u00abcapella-signin-password\u00bb -cpaddr https:\/\/api.cloud.couchbase.com -orgid \u00abcapella-organisation-id\u00bb -cbhost \u00abhostname of data node\u00bb -cbuser \u00abcbcluster username\u00bb -cbpassword \u00abcbcluster password\u00bb\u00a0 -cbport 18093 .\/translator\/test\/plsql\/example1.sql<br \/>\n[\/crayon]<\/p>\n4<\/p>\n\n\n\n<p><span>Delete the employee:<\/span><\/p>\n\n\n\n<p><span>Emily left.<\/span><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; wrap=&#8221;true&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;].\/plsql-to-jsudf -u \u00abcapella-signin-mailid\u00bb -p \u00abcapella-signin-password\u00bb -cpaddr https:\/\/api.cloud.couchbase.com -orgid \u00abcapella-organisation-id\u00bb -cbhost \u00abhostname of data node\u00bb -cbuser \u00abcbcluster username\u00bb -cbpassword \u00abcbcluster password\u00bb\u00a0 -cbport 18093 .\/translator\/test\/plsql\/example1.sql<br \/>\n[\/crayon]<\/p>\n5<\/p>\n\n\n\n<p><span>Again an error with the generated code, looking at the reason and exception we can confirm that translated code encloses delete in a transaction, which wasn\u2019t the case in the original. <\/span><span><br>\n<\/span><span><br>\n<\/span><span>For transactions, buckets need to have <a href=\"https:\/\/docs.couchbase.com\/server\/current\/learn\/data\/durability.html\">durability<\/a><\/span><span>\u00a0set, but this requires more than one data server, hence the error.<\/span><span><br>\n<\/span><span><br>\n<\/span><span>The fix here is to alter the code to remove the enclosing translation:<\/span><\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; wrap=&#8221;true&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;].\/plsql-to-jsudf -u \u00abcapella-signin-mailid\u00bb -p \u00abcapella-signin-password\u00bb -cpaddr https:\/\/api.cloud.couchbase.com -orgid \u00abcapella-organisation-id\u00bb -cbhost \u00abhostname of data node\u00bb -cbuser \u00abcbcluster username\u00bb -cbpassword \u00abcbcluster password\u00bb\u00a0 -cbport 18093 .\/translator\/test\/plsql\/example1.sql<br \/>\n[\/crayon]<\/p>\n6<\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; wrap=&#8221;true&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;].\/plsql-to-jsudf -u \u00abcapella-signin-mailid\u00bb -p \u00abcapella-signin-password\u00bb -cpaddr https:\/\/api.cloud.couchbase.com -orgid \u00abcapella-organisation-id\u00bb -cbhost \u00abhostname of data node\u00bb -cbuser \u00abcbcluster username\u00bb -cbpassword \u00abcbcluster password\u00bb\u00a0 -cbport 18093 .\/translator\/test\/plsql\/example1.sql<br \/>\n[\/crayon]<\/p>\n7<\/p>\n\n\n\n<p><p>[crayon nums=&#8221;false&#8221; wrap=&#8221;true&#8221; lang=&#8221;default&#8221; decode=&#8221;true&#8221;].\/plsql-to-jsudf -u \u00abcapella-signin-mailid\u00bb -p \u00abcapella-signin-password\u00bb -cpaddr https:\/\/api.cloud.couchbase.com -orgid \u00abcapella-organisation-id\u00bb -cbhost \u00abhostname of data node\u00bb -cbuser \u00abcbcluster username\u00bb -cbpassword \u00abcbcluster password\u00bb\u00a0 -cbport 18093 .\/translator\/test\/plsql\/example1.sql<br \/>\n[\/crayon]<\/p>\n8<\/p>\n\n\n\n<p><span>Now, all functions in the original PL\/SQL work in Couchbase via JavaScript UDFs. Yes, the example is pretty trivial but you get the gist on how to go about using the tool to migrate your PL\/SQL scripts with little manual supervision. <\/span><span><br>\n<\/span><span><br>\n<\/span><span>Remember the tool is supposed to take you 80% , the other 20% still needs to be done by you, but much better than writing all of that code yourself!<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span>The future<\/span><\/h2>\n\n\n\n<p><span>This project is open source, so feel free to contribute. <\/span><span>Some ideas that have been suggested:<\/span><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><span>Critic AI that can criticize generated code to ensure manual intervention is not needed at all<\/span><\/li>\n\n\n<li><span>Currently the source code is code that just works; no thoughts for parallelism or code reuse were put to use.<\/span><\/li>\n\n<\/ol>\n\n\n\n<p><span>And also include the limitations discussed earlier.<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span>Resources<\/span><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span><a href=\"https:\/\/github.com\/couchbaselabs\/plsql-to-jsudf2\/releases\/tag\/v1.0.0\">Couchbase Labs GitHub<\/a> &#8211; PL\/SQL to JSUDF<\/span><\/li>\n\n\n<li><span><a href=\"https:\/\/www.antlr.org\/\">ANTLR<\/a> parser generator<\/span><\/li>\n\n<\/ul>\n\n\n\n<p><span>Finally, I\u2019d like to thank Kamini Jagtiani for guiding me and <\/span><span>Pierre Regazzoni<\/span><span> for helping me test the conversion tool.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>What is PL\/SQL? PL\/SQL is a procedural language designed specifically to embrace SQL statements within its syntax. It includes procedural language elements such as conditions and loops, and can handle exceptions (run-time errors). PL\/SQL is native to Oracle databases, and databases like IBM DB2, PostgreSQL, and MySQL support PL\/SQL constructs through compatibility features. What is [&hellip;]<\/p>\n","protected":false},"author":84423,"featured_media":4526,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[136,301,775,727,163,18],"tags":[911,955,728,57,195,956,682],"ppma_author":[683],"class_list":["post-4529","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-best-practices-and-tutorials","category-cloud","category-engineering","category-generative-ai-genai","category-javascript","category-n1ql-query","tag-developer-tools","tag-javascript-udf","tag-llms","tag-mysql","tag-oracle","tag-pl-sql","tag-udf"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.6 (Yoast SEO v27.6) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>A Tool to Ease Your Transition From Oracle PL\/SQL to Couchbase JavaScript UDF - The Couchbase Blog<\/title>\n<meta name=\"description\" content=\"Convert PL\/SQL to JavaScript UDFs seamlessly with an AI-powered tool. Automate Oracle PL\/SQL migration to Couchbase with high accuracy using ANTLR and LLMs.\" \/>\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.couchbase.com\/blog\/ko\/plsql-to-javascript-udf-conversion-tool\/\" \/>\n<meta property=\"og:locale\" content=\"ko_KR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"A Tool to Ease Your Transition From Oracle PL\/SQL to Couchbase JavaScript UDF\" \/>\n<meta property=\"og:description\" content=\"Convert PL\/SQL to JavaScript UDFs seamlessly with an AI-powered tool. Automate Oracle PL\/SQL migration to Couchbase with high accuracy using ANTLR and LLMs.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/ko\/plsql-to-javascript-udf-conversion-tool\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2025-02-11T16:52:20+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/blog-plsql-convert-to-javascript-udf.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2400\" \/>\n\t<meta property=\"og:image:height\" content=\"1256\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Gaurav Jayaraj - Software Engineer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Gaurav Jayaraj - Software Engineer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8\ubd84\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/plsql-to-javascript-udf-conversion-tool\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/plsql-to-javascript-udf-conversion-tool\\\/\"},\"author\":{\"name\":\"Gaurav Jayaraj - Software Engineer\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/546cec92f77cbb0b09f9b973fd1c8d42\"},\"headline\":\"A Tool to Ease Your Transition From Oracle PL\\\/SQL to Couchbase JavaScript UDF\",\"datePublished\":\"2025-02-11T16:52:20+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/plsql-to-javascript-udf-conversion-tool\\\/\"},\"wordCount\":3190,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/plsql-to-javascript-udf-conversion-tool\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/blog-plsql-convert-to-javascript-udf.png\",\"keywords\":[\"developer tools\",\"javascript UDF\",\"LLMs\",\"mysql\",\"oracle\",\"pl\\\/sql\",\"User Defined Function (UDF)\"],\"articleSection\":[\"Best Practices and Tutorials\",\"Couchbase Capella\",\"Engineering\",\"Generative AI (GenAI)\",\"JavaScript\",\"SQL++ \\\/ N1QL Query\"],\"inLanguage\":\"ko-KR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/plsql-to-javascript-udf-conversion-tool\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/plsql-to-javascript-udf-conversion-tool\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/plsql-to-javascript-udf-conversion-tool\\\/\",\"name\":\"A Tool to Ease Your Transition From Oracle PL\\\/SQL to Couchbase JavaScript UDF - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/plsql-to-javascript-udf-conversion-tool\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/plsql-to-javascript-udf-conversion-tool\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/blog-plsql-convert-to-javascript-udf.png\",\"datePublished\":\"2025-02-11T16:52:20+00:00\",\"description\":\"Convert PL\\\/SQL to JavaScript UDFs seamlessly with an AI-powered tool. Automate Oracle PL\\\/SQL migration to Couchbase with high accuracy using ANTLR and LLMs.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/plsql-to-javascript-udf-conversion-tool\\\/#breadcrumb\"},\"inLanguage\":\"ko-KR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/plsql-to-javascript-udf-conversion-tool\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/plsql-to-javascript-udf-conversion-tool\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/blog-plsql-convert-to-javascript-udf.png\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/blog-plsql-convert-to-javascript-udf.png\",\"width\":2400,\"height\":1256},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/plsql-to-javascript-udf-conversion-tool\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"A Tool to Ease Your Transition From Oracle PL\\\/SQL to Couchbase JavaScript UDF\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"ko-KR\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/06\\\/logo.svg\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/06\\\/logo.svg\",\"width\":\"1024\",\"height\":\"1024\",\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/546cec92f77cbb0b09f9b973fd1c8d42\",\"name\":\"Gaurav Jayaraj - Software Engineer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/bbb46a14616fc13176b2496886166e68b3348a81653303d78f7df462db2eb5a1?s=96&d=mm&r=g9f655fda3d24fd49bccf33982dd15670\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/bbb46a14616fc13176b2496886166e68b3348a81653303d78f7df462db2eb5a1?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/bbb46a14616fc13176b2496886166e68b3348a81653303d78f7df462db2eb5a1?s=96&d=mm&r=g\",\"caption\":\"Gaurav Jayaraj - Software Engineer\"},\"description\":\"Gaurav Jayaraj is an intern in the Query team at Couchbase R&amp;D. Gaurav is pursuing his Bachelors in Computer Science from PES University, Bangalore.\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/author\\\/gauravjayaraj\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"A Tool to Ease Your Transition From Oracle PL\/SQL to Couchbase JavaScript UDF - The Couchbase Blog","description":"Convert PL\/SQL to JavaScript UDFs seamlessly with an AI-powered tool. Automate Oracle PL\/SQL migration to Couchbase with high accuracy using ANTLR and LLMs.","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.couchbase.com\/blog\/ko\/plsql-to-javascript-udf-conversion-tool\/","og_locale":"ko_KR","og_type":"article","og_title":"A Tool to Ease Your Transition From Oracle PL\/SQL to Couchbase JavaScript UDF","og_description":"Convert PL\/SQL to JavaScript UDFs seamlessly with an AI-powered tool. Automate Oracle PL\/SQL migration to Couchbase with high accuracy using ANTLR and LLMs.","og_url":"https:\/\/www.couchbase.com\/blog\/ko\/plsql-to-javascript-udf-conversion-tool\/","og_site_name":"The Couchbase Blog","article_published_time":"2025-02-11T16:52:20+00:00","og_image":[{"width":2400,"height":1256,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/blog-plsql-convert-to-javascript-udf.png","type":"image\/png"}],"author":"Gaurav Jayaraj - Software Engineer","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Gaurav Jayaraj - Software Engineer","Est. reading time":"8\ubd84"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/plsql-to-javascript-udf-conversion-tool\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/plsql-to-javascript-udf-conversion-tool\/"},"author":{"name":"Gaurav Jayaraj - Software Engineer","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/546cec92f77cbb0b09f9b973fd1c8d42"},"headline":"A Tool to Ease Your Transition From Oracle PL\/SQL to Couchbase JavaScript UDF","datePublished":"2025-02-11T16:52:20+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/plsql-to-javascript-udf-conversion-tool\/"},"wordCount":3190,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/plsql-to-javascript-udf-conversion-tool\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/blog-plsql-convert-to-javascript-udf.png","keywords":["developer tools","javascript UDF","LLMs","mysql","oracle","pl\/sql","User Defined Function (UDF)"],"articleSection":["Best Practices and Tutorials","Couchbase Capella","Engineering","Generative AI (GenAI)","JavaScript","SQL++ \/ N1QL Query"],"inLanguage":"ko-KR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/plsql-to-javascript-udf-conversion-tool\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/plsql-to-javascript-udf-conversion-tool\/","url":"https:\/\/www.couchbase.com\/blog\/plsql-to-javascript-udf-conversion-tool\/","name":"A Tool to Ease Your Transition From Oracle PL\/SQL to Couchbase JavaScript UDF - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/plsql-to-javascript-udf-conversion-tool\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/plsql-to-javascript-udf-conversion-tool\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/blog-plsql-convert-to-javascript-udf.png","datePublished":"2025-02-11T16:52:20+00:00","description":"Convert PL\/SQL to JavaScript UDFs seamlessly with an AI-powered tool. Automate Oracle PL\/SQL migration to Couchbase with high accuracy using ANTLR and LLMs.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/plsql-to-javascript-udf-conversion-tool\/#breadcrumb"},"inLanguage":"ko-KR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/plsql-to-javascript-udf-conversion-tool\/"]}]},{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.couchbase.com\/blog\/plsql-to-javascript-udf-conversion-tool\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/blog-plsql-convert-to-javascript-udf.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/blog-plsql-convert-to-javascript-udf.png","width":2400,"height":1256},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/plsql-to-javascript-udf-conversion-tool\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"A Tool to Ease Your Transition From Oracle PL\/SQL to Couchbase JavaScript UDF"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"ko-KR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/06\/logo.svg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/06\/logo.svg","width":"1024","height":"1024","caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/546cec92f77cbb0b09f9b973fd1c8d42","name":"Gaurav Jayaraj - Software Engineer","image":{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/secure.gravatar.com\/avatar\/bbb46a14616fc13176b2496886166e68b3348a81653303d78f7df462db2eb5a1?s=96&d=mm&r=g9f655fda3d24fd49bccf33982dd15670","url":"https:\/\/secure.gravatar.com\/avatar\/bbb46a14616fc13176b2496886166e68b3348a81653303d78f7df462db2eb5a1?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/bbb46a14616fc13176b2496886166e68b3348a81653303d78f7df462db2eb5a1?s=96&d=mm&r=g","caption":"Gaurav Jayaraj - Software Engineer"},"description":"Gaurav Jayaraj is an intern in the Query team at Couchbase R&amp;D. Gaurav is pursuing his Bachelors in Computer Science from PES University, Bangalore.","url":"https:\/\/www.couchbase.com\/blog\/ko\/author\/gauravjayaraj\/"}]}},"acf":[],"authors":[{"term_id":683,"user_id":84423,"is_guest":0,"slug":"gauravjayaraj","display_name":"Gaurav Jayaraj - Software Engineer","avatar_url":{"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/unnamed-2-5.jpg","url2x":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/unnamed-2-5.jpg"},"0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/posts\/4529","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/users\/84423"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/comments?post=4529"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/posts\/4529\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/media\/4526"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/media?parent=4529"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/categories?post=4529"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/tags?post=4529"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/ppma_author?post=4529"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}