How to Run JavaScript Dynamically with DBMS_MLE

Evaluate JavaScript source at run time inside the database, run SQL from JavaScript, and find where JavaScript errors happened.

Oracle AI Database 26ai runs JavaScript inside the database with the Multilingual Engine, MLE. Besides JavaScript modules stored as schema objects, DBMS_MLE can run JavaScript source given as text at run time: create an execution context, evaluate code in it, and drop it. The code can call SQL in the same session.

Code for This Guide

The main examples are in the examples/pkg-mle folder of the Oracle Database 26ai code repository on GitHub, each with its output. They use NIMBUS, the sample schema of a fictional airline, which you can install with the scripts in the setup/nimbus folder.

They come from Oracle Database 26ai SQL and PL/SQL Book.

Syntax

ctx := dbms_mle.create_context();
dbms_mle.eval(ctx, 'JAVASCRIPT', source [, source_name => 'name']);
dbms_mle.drop_context(ctx);
dbms_mle.get_ctx_error_stack(ctx)       -- JavaScript lines of the last error

Running dynamic JavaScript needs the EXECUTE DYNAMIC MLE privilege. console.log writes to DBMS_OUTPUT.

Evaluate JavaScript

Example:

declare
  ctx dbms_mle.context_handle_t;
begin
  ctx := dbms_mle.create_context();
  dbms_mle.eval(ctx, 'JAVASCRIPT', q'[
    const flights = ["NM150", "NM101", "NM205"];
    console.log(`${flights.length} flights: ${flights.join(", ")}`);
    console.log("6 x 7 =", 6 * 7);
  ]');
  dbms_mle.drop_context(ctx);
end;
/

Output:

3 flights: NM150, NM101, NM205
6 x 7 = 42

PL/SQL procedure successfully completed.

The JavaScript joins an array with a template string and multiplies two numbers; both lines arrive through DBMS_OUTPUT.

Run SQL and Handle Errors

Example:

declare
  ctx    dbms_mle.context_handle_t := dbms_mle.create_context();
  v_st   dbms_mle.error_frames_t;
begin
  -- JavaScript can run SQL in the same session, through the session object
  dbms_mle.eval(ctx, 'JAVASCRIPT', source_name => 'feed_check', source => q'[
    const result = session.execute(
      "select count(*) as n from flights where status = :s", ["CANCELLED"]);
    console.log("cancelled flights:", result.rows[0].N);
    throw new Error("fuel price feed missing");
  ]');
exception
  when others then
    dbms_output.put_line(sqlerrm);
    v_st := dbms_mle.get_ctx_error_stack(ctx);           -- where it happened in JavaScript
    for i in 1 .. v_st.count loop
      dbms_output.put_line('  at line ' || v_st(i).line || ', column ' || v_st(i).col);
    end loop;
    dbms_mle.drop_context(ctx);
end;
/

Output:

cancelled flights: 50
ORA-04161: Error: fuel price feed missing
  at line 5, column 11

PL/SQL procedure successfully completed.

session.execute runs a query with a bind variable and returns the rows, here 50 cancelled flights. The JavaScript then throws an error, which reaches PL/SQL as ORA-04161, and GET_CTX_ERROR_STACK gives the line and column in the JavaScript source named feed_check.

Things to Know

  • A context keeps its state until it is dropped: variables declared at the top level, with const, let, or var, are still there in later EVAL calls.
  • For code used often, create an MLE module and call its functions through PL/SQL call specifications instead.
  • Drop contexts when done; each one holds memory in the session.

Related Guides

Conclusion

DBMS_MLE runs JavaScript source text inside the database, with SQL access through the session object and error positions from the context's error stack. Use it for dynamic scripts, and MLE modules for code you call regularly.

Vinish Kapoor
Vinish Kapoor

An Oracle ACE, author of four books on Oracle APEX, SQL and PL/SQL, and Oracle Forms, and a software developer building Oracle database applications since 2001.

guest

0 Comments
Oldest
Newest Most Voted