Oracle
 sql >> Datenbank >  >> RDS >> Oracle

node-oracledb-Fehler beim Ausführen der gespeicherten Prozedur NJS-012

Aktualisierung 28.08.2019:

Node-oracledb hat in v4 (veröffentlicht am 25.07.2019) Unterstützung für SQL-Objekttypen und PL/SQL-Datensatztypen hinzugefügt. Weitere Informationen finden Sie in diesem Abschnitt des Dokuments:https://oracle. github.io/node-oracledb/doc/api.html#objects

Ausgehend von genau denselben Objekten wie zuvor aufgeführt, kann das folgende JavaScript nun verwendet werden, um die Arbeit mit weitaus weniger Codezeilen als zuvor zu erledigen:

const oracledb = require('oracledb');
const config = require('./db-config.js');

async function runTest() {
  let conn;

  try {  
    const sql = 
     `call xxeta_grid_user_context_pkg.extract_grid_details(
        p_user_name      => :P_USER_NAME,
        p_content_type   => :P_CONTENT_TYPE,
        p_project_number => :P_PROJECT_NUMBER,
        op_grid_tab_typ  => :OP_GRID_TAB_TYP
      )`;

    const binds = {
      P_USER_NAME: 'Jane Doe',
      P_CONTENT_TYPE: 'Some Content Type',
      P_PROJECT_NUMBER: '123',
      OP_GRID_TAB_TYP: {
        dir: oracledb.BIND_OUT,
        type: 'HR.XXETA_GRID_CONTEXT_TAB_TYP'
      } 
    }

    conn = await oracledb.getConnection(config);

    const result = await conn.execute(
      sql,
      binds
    );

    const gridContexts = [];

    for (let x = 0; x < result.outBinds.OP_GRID_TAB_TYP.length; x += 1) {
      gridContexts.push({
        gridViewId: result.outBinds.OP_GRID_TAB_TYP[x].GRID_VIEW_ID,
        gridViewName: result.outBinds.OP_GRID_TAB_TYP[x].GRID_VIEW_NAME,
        userName: result.outBinds.OP_GRID_TAB_TYP[x].USER_NAME,
        projectNumber: result.outBinds.OP_GRID_TAB_TYP[x].PROJECT_NUMBER
      });
    }

    console.log(gridContexts);
  } catch (err) {
    console.error(err);
  } finally {
    if (conn) {
      try {
        await conn.close();
      } catch (err) {
        console.error(err);
      }
    }
  }
}

runTest();

Vorherige Antwort:

Komplexe Typen werden derzeit nicht unterstützt. Das von Ihnen angegebene Out-Bind fällt in diese Kategorie. Bis solche Typen direkt unterstützt werden, müssen Sie etwas Wrapper-Code hinzufügen, um den komplexen Typ in einen oder mehrere einfache Typen aufzuteilen. Ein Beispiel dafür zeige ich hier: https://jsao.io/2017/01/plsql-record-types-and-the-node-js-driver/

Das Ziel in diesem Beitrag ist es, eine gespeicherte Prozedur aufzurufen, die ein Array eines benutzerdefinierten Datensatztyps akzeptiert. Um es aufzurufen, muss ich zuerst einige einfache Array-Typen deklarieren, an die ich mich binden möchte. Dann kann ich diese Arrays verwenden, um das komplexere Array zu erstellen und die Prozedur aufzurufen.

In Ihrem Fall müssen Sie umgekehrt vorgehen. Deklarieren Sie im PL/SQL-Block eine lokale Variable vom Typ APPS.XXETA_GRID_CONTEXT_TAB_TYP. Nachdem die Prozedur aufgerufen wurde, iterieren Sie dann über das Array und verwenden Sie es, um einige einfache Arrays (VARCHAR2, NUMBER oder DATE) zu füllen, und verwenden Sie diese als Ihre ausgehenden Bindungen.

Aktualisierung:

Vorausgesetzt, Sie haben die folgenden Objekte:

create or replace type xxeta_grid_context_rec_typ as object (
  grid_view_id   number(15),
  grid_view_name varchar2(240),
  user_name      varchar2(30),
  project_number varchar2(5)
)
/

create or replace type xxeta_grid_context_tab_typ as table of xxeta_grid_context_rec_typ
/

create or replace package xxeta_grid_user_context_pkg
as

procedure extract_grid_details(
  p_user_name      in varchar2,
  p_content_type   in varchar2,
  p_project_number in varchar2,
  op_grid_tab_typ  out xxeta_grid_context_tab_typ
);

end;
/

create or replace package body xxeta_grid_user_context_pkg
as

procedure extract_grid_details(
  p_user_name      in varchar2,
  p_content_type   in varchar2,
  p_project_number in varchar2,
  op_grid_tab_typ  out xxeta_grid_context_tab_typ
)

is

  l_xxeta_grid_context_rec xxeta_grid_context_rec_typ;

begin

  op_grid_tab_typ := xxeta_grid_context_tab_typ();

  for x in 1 .. 3
  loop
    l_xxeta_grid_context_rec := xxeta_grid_context_rec_typ(
      grid_view_id   => x,
      grid_view_name => 'Some Grid View',
      user_name      => p_user_name,
      project_number => p_project_number
    );

    op_grid_tab_typ.extend();

    op_grid_tab_typ(x) := l_xxeta_grid_context_rec;
  end loop;

end;

end;
/

Der folgende Node.js-Code kann die gespeicherte Prozedur aufrufen und die Werte aus dem komplexen out-Parameter abrufen.

const oracledb = require('oracledb');
const config = require('./dbConfig.js');

async function runTest() {
  let conn;

  try {
    const userName = 'Jane Doe';
    const contentType = 'Some Content Type';
    const projectNumber = '123';

    // This is what we want to populate with records/objects that come out
    // of the procedure.
    const gridContexts = [];

    // We start by declaring some other arrays, one for each field in the
    // xxeta_grid_context_rec_typ type.
    const gridViewIds = [];
    const gridViewNames = [];
    const userNames = [];
    const projectNumbers = []; 

    conn = await oracledb.getConnection(config);

    // Then we execute the procedure with a little wrapper code to populate
    // the individual arrays.
    let result = await conn.execute(
     `declare

        -- This is a local variable that you'll use to get the out data from
        -- the procedure.
        l_xxeta_grid_context_tab xxeta_grid_context_tab_typ;

      begin

        xxeta_grid_user_context_pkg.extract_grid_details(
          p_user_name      => :user_name,
          p_content_type   => :content_type,
          p_project_number => :project_number,
          op_grid_tab_typ  => l_xxeta_grid_context_tab
        );

        -- Now that the local variable is populated, iterate over it to
        -- populate the individual out binds.
        for x in 1 .. l_xxeta_grid_context_tab.count
        loop
          :grid_view_ids(x) := l_xxeta_grid_context_tab(x).grid_view_id;
          :grid_view_names(x) := l_xxeta_grid_context_tab(x).grid_view_name;
          :user_names(x) := l_xxeta_grid_context_tab(x).user_name;
          :project_numbers(x) := l_xxeta_grid_context_tab(x).project_number;
        end loop;

      end;`,
      {
        user_name: userName,
        content_type: contentType,
        project_number: projectNumber,
        grid_view_ids: {
          dir: oracledb.BIND_OUT,
          type: oracledb.NUMBER,
          maxArraySize: 200
        },
        grid_view_names: {
          dir: oracledb.BIND_OUT,
          type: oracledb.STRING,
          maxArraySize: 200
        },
        user_names: {
          dir: oracledb.BIND_OUT,
          type: oracledb.STRING,
          maxArraySize: 200
        },
        project_numbers: {
          dir: oracledb.BIND_OUT,
          type: oracledb.STRING,
          maxArraySize: 200
        }
      }
    );

    // At this point you can access the individual arrays to populate the 
    // original target array with objects. This is optional, you can work
    // with the individual arrays directly as well.
    for (let x = 0; x < result.outBinds.grid_view_ids.length; x += 1) {
      gridContexts.push({
        gridViewId: result.outBinds.grid_view_ids[x],
        gridViewName: result.outBinds.grid_view_names[x],
        userName: result.outBinds.user_names[x],
        projectNumber: result.outBinds.project_numbers[x]
      });
    }

    console.log(gridContexts);
  } catch (err) {
    console.error(err);
  } finally {
    if (conn) {
      try {
        await conn.close();
      } catch (err) {
        console.error(err);
      }
    }
  }
}

runTest();

Ich hoffe das hilft! Die direkte Unterstützung komplexer Typen steht auf der Liste der Verbesserungen, ich kann nur nicht sagen, wann sie verfügbar sein wird.