Overview of Multilingual Engine for JavaScript
MLE allows you to run and store JavaScript directly in the Oracle Database.
Using MLE enables users of the Oracle Database to run the following, written in JavaScript:
-
Stored procedures
-
Stored functions
-
Code in a PL/SQL package namespace
-
Anonymous, dynamic code snippets (in a way that is similar to
DBMS_SQL
)
MLE is supported when connecting to the database using a dedicated server connection on Linux x86-64 or Linux for Arm (aarch64). Certain data types are not supported, listed in full at Unsupported Data Types.
Note:
Shared server connections and those using Database Resident Connection Pool (DRCP) cannot make use of MLE.Topics
- JavaScript Implementation Details
The MLE implementation of JavaScript is compliant with ECMAScript 2023. - Invoking JavaScript in the Database
JavaScript can be invoked through dynamic execution or through call specifications, which either reference MLE modules or inline JavaScript functions. - Introduction to Dynamic Execution
Anonymous JavaScript code snippets can be executed via theDBMS_MLE
PL/SQL package. - Introduction to MLE Module Calls
It is possible to create JavaScript modules as schema objects that are stored persistently in the database. - About MLE Execution Contexts
An MLE execution context is a standalone, isolated runtime environment, designed to contain all runtime state associated with the execution of JavaScript code. Runtime state includes global variables as well as the state of the language environment. - About Restricted Execution Contexts
ThePURE
keyword can be specified on MLE environments and JavaScript inline call specifications to create restricted JavaScript execution contexts.
JavaScript Implementation Details
The MLE implementation of JavaScript is compliant with ECMAScript 2023.
Adhering to the ECMA standard, the JavaScript implementation as found in MLE is consciously created as a pure
implementation. Native JavaScript network and file I/O operations are not
supported in the same way that they are in Node.js and Deno for security reasons. The
use of network and file I/O is possible with MLE,
however, you must employ PL/SQL APIs such as UTL_HTTP
and
UTL_FILE
.
The WEB API, Fetch, is not available by default in the global space but can be enabled
by importing mle-js-fetch
.
Objects not included in the ECMA standard, including common objects used in
front-end code such as the Window object, are also not available with MLE. Nevertheless, MLE does provide easy and efficient access to
SQL, which is able to execute close to the data. Console output is passed to
DBMS_OUTPUT
by default but can be redirected and stored in a user
provided CLOB if required.
Users require specific privileges before they can interact with MLE. These can broadly be classified into:
-
Permission to use MLE and run JavaScript code
-
Execute dynamic JavaScript in the database
-
Create JavaScript modules and externalize them via PL/SQL code
The database engine throws an error if you lack sufficient privileges required for the use of JavaScript.
See Also:
System and Object Privileges Required for Working with JavaScript in MLE for more information about privileges
Parent topic: Overview of Multilingual Engine for JavaScript
Invoking JavaScript in the Database
JavaScript can be invoked through dynamic execution or through call specifications, which either reference MLE modules or inline JavaScript functions.
Generally speaking, server-side JavaScript code can be invoked in two ways:
-
Dynamically via the
DBMS_MLE
package -
Using PL/SQL code referencing functions exported in JavaScript modules (so-called MLE module calls) or functions defined directly in the DDL
Regardless of which of the two methods is used, all JavaScript code runs in an execution context. Its purpose is to encapsulate all runtime state associated with the processing of JavaScript code. The MLE execution context corresponds to the ECMAScript execution context for JavaScript.
Before you can execute any JavaScript in the database, you must ensure that MLE is not disabled for your session, PDB, or CDB. For information about how to confirm this, see MLE_PROG_LANGUAGES Initialization Parameter. In order to take full advantage of MLE, you must have necessary privileges to execute the JavaScript language, execute dynamic MLE, create MLE schema objects, and so on.
See Also:
-
System and Object Privileges Required for Working with JavaScript in MLE
-
Ecma-international.org for more information about the ECMAScript execution context
Parent topic: Overview of Multilingual Engine for JavaScript
Introduction to Dynamic Execution
Anonymous JavaScript code snippets can be executed via the
DBMS_MLE
PL/SQL package.
The procedure DBMS_MLE.eval()
is used to execute dynamic MLE snippets. The procedure takes the following
arguments:
Argument Name | Type | Optional? |
---|---|---|
CONTEXT_HANDLE |
RAW(16) | N |
LANGUAGE_ID |
VARCHAR2(64) | N |
SOURCE |
CLOB | N |
RESULT |
CLOB | Y |
SOURCE_NAME |
VARCHAR2 | Y |
The argument SOURCE_NAME
is optionally used to provide a name for the
otherwise randomly-named JavaScript code block.
JavaScript code can be provided inline with PL/SQL as shown in the following code:
SET SERVEROUTPUT ON;
DECLARE
l_ctx DBMS_MLE.context_handle_t;
l_jscode CLOB;
BEGIN
l_ctx := DBMS_MLE.create_context;
l_jscode := q'~
console.log('Hello World, this is DBMS_MLE')
~';
DBMS_MLE.eval(
context_handle => l_ctx,
language_id => 'JAVASCRIPT',
source => l_jscode,
source_name => 'My JS Snippet'
);
END;
/
Executing this example will result in the following being printed:
Hello World, this is DBMS_MLE
The code provided above demonstrates the following concepts of invoking JavaScript code dynamically:
-
An execution context must be explicitly created
-
JavaScript code is provided as a Character Large Object (CLOB) or
VARCHAR2
variable -
The context must be explicitly evaluated
Both PL/SQL and JavaScript are present when you execute JavaScript dynamically. The code
snippets provided are not reusable outside of their namespace. The output of the call to
console.log
is passed to DBMS_OUTPUT
for printing
on the screen.
See Also:
-
Overview of Dynamic MLE Execution for more details about dynamic execution with MLE
- Returning the Result of the Last Execution for more information about the
RESULT
argument of the procedureDBMS_MLE.eval()
Parent topic: Overview of Multilingual Engine for JavaScript
Introduction to MLE Module Calls
It is possible to create JavaScript modules as schema objects that are stored persistently in the database.
Once a JavaScript module has been defined, it can be used in SQL and PL/SQL as shown below:
CREATE OR REPLACE MLE MODULE helloWorld_module
LANGUAGE JAVASCRIPT AS
function helloWorld() {
console.log('Hello World, this is a JS module');
}
export { helloWorld }
/
Before the exported JavaScript function can be invoked, a call specification
must be defined. The code snippet below shows how to create a call specification for the
JavaScript helloWorld()
function in PL/SQL:
CREATE OR REPLACE PROCEDURE helloWorld_proc
AS MLE MODULE helloWorld_module
SIGNATURE 'helloWorld()';
/
The call specification, referred to as an MLE module call, publishes the JavaScript function
helloWorld()
. It can then be used just like any other PL/SQL
procedure. The following snippet shows how to invoke the function along with the
results:
SET SERVEROUTPUT ON
BEGIN
helloWorld_proc;
END;
/
Result:
Hello World, this is a JS module
In addition to custom-built JavaScript modules as shown in the provided code, it is possible to load third-party JavaScript modules into the database. Note that Oracle recommends performing a security screening of third-party code according to industry best practice.
See Also:
-
MLE JavaScript Modules and Environments for details about MLE modules and environments
-
MLE Security for more information about MLE security features and recommendations
Parent topic: Overview of Multilingual Engine for JavaScript
About MLE Execution Contexts
An MLE execution context is a standalone, isolated runtime environment, designed to contain all runtime state associated with the execution of JavaScript code. Runtime state includes global variables as well as the state of the language environment.
-
With dynamic MLE execution, where you can create and use dynamic MLE contexts explicitly
-
For calls from SQL and PL/SQL to functions exported by an MLE module
Dynamic Execution
Properties of dynamic MLE contexts are determined by the environment used at the moment the execution context is created. You have explicit control over which execution context is used for each dynamic MLE snippet, with each execution context running code on behalf of a single user.
There is no limit to how many dynamic MLE execution contexts can be created in a session, or how they are shared across different code snippets. Code snippets in JavaScript share all global variables with other code snippets running in the same execution context.
MLE Modules
Contexts for MLE module calls from SQL or PL/SQL are created implicitly on demand. Here, the properties are determined by the MLE environment referenced in the call specification at the moment of context creation. The environment can be used to specify language options and to make MLE modules available for import.
MLE modules never share an execution context with other modules or dynamic MLE snippets. Additionally, separate execution contexts are used when code from the same MLE module is executed on behalf of different users. MLE creates a dedicated execution context for each combination of MLE module and environment. Two call specifications that specify either different modules or different environments are executed in separate module contexts.
See Also:
-
Specifying Environments for MLE Modules for more information about MLE environments
- Execution Contexts for information about how execution contexts are used to enforce runtime state isolation
Parent topic: Overview of Multilingual Engine for JavaScript
About Restricted Execution Contexts
The PURE
keyword can be specified on MLE environments and JavaScript inline
call specifications to create restricted JavaScript execution contexts.
In-database JavaScript code can leverage database functionality, such as SQL execution, using APIs like the MLE JavaScript SQL Driver and SODA. PURE execution disallows access to stateful database APIs inside JavaScript, meaning the execution is completely unprivileged. In a PURE environment, JavaScript code cannot read or write any database state, such as tables, procedures, and objects.
The only possible interaction with the database during PURE
execution is through inputs and outputs to JavaScript code. This can
be in the form of data provided to MLE from the database through user-defined function
arguments for call specifications, as well as symbols exported using
DBMS_MLE.EXPORT_TO_MLE
. Reference types,
such as LOBs passed to MLE,
can be accessed (read or written) during PURE execution.
Additionally, PURE execution does not restrict access to supported
data types.
In many situations, JavaScript user-defined functions are purely computational and don't require access to powerful APIs such as the MLE JavaScript SQL driver or the Foreign Function Interface (FFI). PURE execution serves as a method to isolate certain code, such as third-party JavaScript libraries, from the database itself. This isolation can reduce the attack surface of supply chain attacks, in which access to the database state is a security concern. Using PURE execution also allows less-privileged developers to create these restricted user-defined functions without requiring additional access or privileges to the database state or network.
The following JavaScript APIs and global classes and functions are not available during PURE execution:
- JavaScript APIs:
mle-js-oracledb
mle-js-plsql-ffi
mle-js-fetch
- Global classes and functions:
session
soda
plsffi
oracledb
require
JavaScript APIs that do not interact with database state,
such as mle-js-plsqltypes
and
mle-js-encodings
remain accessible during
PURE execution.
The PURE
keyword can be specified in inline
call specifications, in module call specifications, and using
DBMS_MLE
. The following are examples of the
syntax in each case:
-
Module call specification:
CREATE OR REPLACE MLE MODULE pure_mod LANGUAGE JAVASCRIPT AS export function helloWorld() { console.log('Hello World, this is a JS module'); } / CREATE OR REPLACE MLE ENV pure_env IMPORTS( 'pure_mod' MODULE pure_mod) PURE; CREATE OR REPLACE PROCEDURE helloWorld AS MLE MODULE pure_mod ENV pure_env SIGNATURE 'helloWorld'; /
-
Inline call specification:
CREATE OR REPLACE PROCEDURE helloWorld AS MLE LANGUAGE JAVASCRIPT PURE {{ console.log('Hello World, this is a JS inlined call specification'); }}; /
-
Using
DBMS_MLE
:SET SERVEROUTPUT ON; DECLARE l_ctx dbms_mle.context_handle_t; l_snippet CLOB; BEGIN -- to specify PURE execution with DBMS_MLE, use an environment -- that has been created with the PURE keyword l_ctx := dbms_mle.create_context(environment => 'PURE_ENV'); l_snippet := q'~ console.log('Hello World, this is dynamic MLE execution'); ~'; dbms_mle.eval(l_ctx, 'JAVASCRIPT', l_snippet); dbms_mle.drop_context(l_ctx); EXCEPTION WHEN OTHERS THEN dbms_mle.drop_context(l_ctx); RAISE; END; /
Parent topic: Overview of Multilingual Engine for JavaScript