Integração de JavaScript com Stored Procedures no Oracle Database

Por que utilizar JavaScript em Stored Proceduers?

JavaScript é uma das linguagens de programação mais populares. Além de sua sintaxe simplificada e suporte a recursos modernos, um fator-chave para sua adoção é o vasto ecossistema de módulos reutilizáveis disponíveis para diversas plataformas, como navegadoers e ambientes de servidor.

Invocando JavaScript no Banco de Dados

O código JavaScript pode ser executado dinamicamente ou através de especificações de chamada. As especificações podem referenciar módulos MLE (Multilingual Engine) ou funções JavaScript inline.

Existem duas abordagens principais para rodar JavaScript no lado do servidor:

  • Execução dinâmica utilizando o pacote DBMS_MLE.
  • Uso de código PL/SQL que invoca funções exportadas de módulos JavaScript (chamadas de invocação via módulo MLE) ou funções definidas diretamente no DDL.

Execução Dinâmica

O exemplo abaixo demonstra como executar código JavaScript de forma dinâmica:

SET SERVEROUTPUT ON;
DECLARE
    v_ctx DBMS_MLE.context_handle_t;
    v_source CLOB;
BEGIN
    v_ctx := DBMS_MLE.create_context;
    v_source := q'~
        console.log('Mensagem de teste via DBMS_MLE')
    ~';
    DBMS_MLE.eval(
        context_handle => v_ctx,
        language_id => 'JAVASCRIPT',
        source => v_source,
        source_name => 'Trecho JS'
    );
END;
/
Mensagem de teste via DBMS_MLE
Procedimento PL/SQL concluído com sucesso.

Este trecho ilustra conceitos essenciais:

  • Um contexto de execução deve ser criado explicitamente.
  • O código JavaScript é fornecido como uma variável CLOB ou VARCHAR2.
  • O contexto precisa ser avaliado diretamente.

Ao executar JavaScript dinamicamente, há uma integração entre PL/SQL e JavaScript. O snippet não é reutilizável fora desse contexto. A saída de console.log é redirecionada para DBMS_OUTPUT.

Invocação via Módulo MLE

Módulos JavaScript podem ser criados como objetos de schema e persistidos no banco de dados.

Após a definição, o módulo pode ser utilizado em SQL e PL/SQL. Veja a criação de um módulo:

CREATE OR REPLACE MLE MODULE modulo_saudacao
LANGUAGE JAVASCRIPT AS
function saudacao() {
    console.log('Olá, este é um módulo JavaScript');
}
export { saudacao }
/
Módulo MLE criado.

Para invocar a função exportada, é necessário uma especificação de chamada PL/SQL:

CREATE OR REPLACE PROCEDURE proc_saudacao
AS MLE MODULE modulo_saudacao
SIGNATURE 'saudacao()';
/
Procedimento criado.

A especificação de chamada expõe a função saudacao(). A partir daí, ela pode ser chamada como qualquer outro procedimento PL/SQL:

SET SERVEROUTPUT ON
BEGIN
    proc_saudacao;
END;
/
Olá, este é um módulo JavaScript
Procedimento PL/SQL concluído com sucesso.

Ambiente de Execução Restrita (Execução PURE)

A palavra-chave PURE pode ser usada em ambientes MLE e especificações de chamada inline para criar um contexto JavaScript restrito. Neste modo, o código não pode acessar APIs de banco de dados com estado, como drivers SQL ou interfaces de funções externas (FFI).

Execuções PURE são úteis para isolar código, como bibliotecas JavaScript de terceiros, reduzindo superfícies de ataque. Elas também permitem que desenvolvedores com permissões mínimas criem funções definidas pelo usuário sem acesso adicional a recursos do banco.

Durante a execução PURE, as seguintes APIs não estão disponíveis:

  • mle-js-oracledb
  • mle-js-plsql-ffi
  • mle-js-fetch
  • Classes globais como session, soda e funções como require.

APIs que não interagem com o estado do banco, como js-encodings, permanecem acessíveis.

Exemplo de definição de um módulo PURE e sua invocação:

CREATE OR REPLACE MLE MODULE modulo_puro
LANGUAGE JAVASCRIPT AS
export function mensagemPura() {
    console.log('Execução em ambiente restrito');
}
/
Módulo MLE criado.

CREATE OR REPLACE MLE ENV env_puro
IMPORTS( 'modulo_puro' MODULE modulo_puro) PURE;
Ambiente MLE criado.

CREATE OR REPLACE PROCEDURE proc_puro
AS MLE MODULE modulo_puro ENV env_puro SIGNATURE 'mensagemPura';
/
Procedimento criado.

-- Alternativa inline
CREATE OR REPLACE PROCEDURE proc_puro_inline
AS MLE LANGUAGE JAVASCRIPT PURE
{{
    console.log('Chamada inline em ambiente PURE');
}};
/
Procedimento criado.

Para execução dinâmica com PURE, utilize um ambiente criado com a palavra-chave:

SET SERVEROUTPUT ON;
DECLARE
    v_ctx dbms_mle.context_handle_t;
    v_snippet CLOB;
BEGIN
    v_ctx := dbms_mle.create_context(environment => 'ENV_PURO');
    v_snippet := q'~
        console.log('Execução dinâmica MLE em modo PURE');
    ~';
    dbms_mle.eval(v_ctx, 'JAVASCRIPT', v_snippet);
    dbms_mle.drop_context(v_ctx);
EXCEPTION
    WHEN OTHERS THEN
        dbms_mle.drop_context(v_ctx);
        RAISE;
END;
/
Execução dinâmica MLE em modo PURE
Procedimento PL/SQL concluído com sucesso.

Exemplo Prático: Acesso a Dados com Depuração

O código abaixo demonstra como acessar o banco de dados usando mle-js-oracledb em um módulo não restrito. As variáveis e estruturas foram adaptadas para clareza:

CREATE OR REPLACE MLE MODULE modulo_debug
LANGUAGE JAVASCRIPT AS

import conexao from "mle-js-oracledb";

export function contarTabelas() {
    const db = conexao.defaultConnection();
    
    console.log("Fase 1: Verificando conectividade");
    const teste = db.execute(`SELECT 'OK' as status FROM dual`);
    console.log("Resultado do teste: " + JSON.stringify(teste.rows[0]));
    
    console.log("Fase 2: Consultando metadados");
    const meta = db.execute(`
        SELECT COUNT(*) as contagem 
        FROM user_tables 
        WHERE table_name = 'TABELA_EXEMPLO'
    `);
    console.log("Tabela existe: " + JSON.stringify(meta.rows[0]));
    
    console.log("Fase 3: Contagem final");
    const resultado = db.execute(`
        SELECT COUNT(*) as total 
        FROM tabela_exemplo
    `);
    
    console.log("Dados finais: " + JSON.stringify(resultado));
    
    return resultado.rows[0][0];
}
/
Módulo MLE criado.

Criando a função PL/SQL correspondente:

CREATE OR REPLACE FUNCTION fn_contar_tabelas
RETURN NUMBER
AS MLE MODULE modulo_debug
SIGNATURE 'contarTabelas';
/
Função criada.

Executanod a função e observando a saída:

SELECT fn_contar_tabelas() FROM DUAL;

FN_CONTAR_TABELAS()
-------------------
Fase 1: Verificando conectividade
Resultado do teste: {"STATUS":"OK"}
Fase 2: Consultando metadados
Tabela existe: {"CONTAGEM":1}
Fase 3: Contagem final
Dados finais: {"metaData":[{"name":"TOTAL"}],"rows":[{"TOTAL":5}]}
5

Parâmetros de Controle em PDB/CDB

O recurso MLE é controlado pelo parâmetro mle_prog_languages. Desativando-o:

ALTER SYSTEM SET mle_prog_languages=off;

Qualquer chamada a funções MLE resultará em erro:

SELECT fn_contar_tabelas() FROM DUAL;
ORA-00439: recurso não habilitado: MLE

Reativando o recurso:

ALTER SYSTEM SET mle_prog_languages=all;
SELECT fn_contar_tabelas() FROM DUAL;
-- Saída normal como anteriormente

Para detalhes adicionais, consulte a documentação oficial do Oracle Database sobre MLE.

Tags: OracleDatabase JavaScriptMLE DBMS_MLE OracleMLE StoredProcedures

Publicado em 6-4 00:39 por Thomas