ошибка node-oracledb при выполнении хранимой процедуры NJS-012

Я использую Node 8.9.4, Hapi 17.4 и Oracledb 2.2.

При попытке вызвать хранимую процедуру я получаю сообщение об ошибке «NJS-012: обнаружен недопустимый тип данных привязки в параметре 2». Ничего из того, что я смог сделать, похоже, не решило проблему. Код, вызывающий процедуру:

async function getSavedViews(req, h, server) {
    let connection = await server.app.db.getConnection();

    let bindVars = {
        P_USER_NAME:   req.payload.user_name,
        P_CONTENT_TYPE: req.payload.content_type,
        P_PROJECT_NUMBER: req.payload.project_number,
        OP_GRID_TAB_TYP: { dir: server.app.db.BIND_OUT, type: server.app.db.ARRAY } 
    }

    let res = server.methods.response();

    try {
        res.error = false;
        res.msg = "Retrieved saved views.";
        res.data = await connection.execute(
            `BEGIN APPS.XXETA_GRID_USER_CONTEXT_PKG.EXTRACT_GRID_DETAILS(:P_USER_NAME, :P_CONTENT_TYPE, :P_PROJECT_NUMBER, :OP_GRID_TAB_TYP); END;`,
            bindVars
        );
    } catch (err) {
        server.app.logger.error(err.message);
        res.error = true;
        res.msg = err.message,
        res.data = [];
    }

    return res;
}

Хранимая процедура описывается как:

Снимок экрана Oracle

Ошибка, которую я получаю от моего регистратора: 2018-08-06 15:02:20 ОШИБКА NJS-012: обнаружен недопустимый тип данных привязки в параметре 2

Любая помощь будет оценена по достоинству.

ОБНОВЛЕНИЕ:

Сложный тип, являющийся связанной переменной, выглядит так ...

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)
   )

person Andrew Cooper    schedule 06.08.2018    source источник
comment
Привязка определяемых пользователем типов теперь поддерживается в node-oracledb 4, см. oracle .github.io / node-oracledb / doc / api.html # objects   -  person Christopher Jones    schedule 21.08.2019


Ответы (1)


Обновление 2019/08/28:

В Node-oracledb добавлена ​​поддержка типов объектов SQL и типов записей PL / SQL в версии 4 (выпущена 25 июля 2019 г.). Подробнее см. В этом разделе документа: https://oracle.github.io/node-oracledb/doc/api.html#objects.

Учитывая те же самые объекты, что и перечисленные ранее, теперь можно использовать следующий JavaScript для выполнения работы с гораздо меньшим количеством строк кода, чем раньше:

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();

Предыдущий ответ:

Сложные типы в настоящее время не поддерживаются. Указанная вами исходящая привязка попадает в эту категорию. Пока такие типы не будут поддерживаться напрямую, вам нужно будет добавить немного кода оболочки, чтобы разбить сложный тип на один или несколько простых типов. Я показываю здесь пример: https://jsao.io/2017/01/plsql-record-types-and-the-node-js-driver/

Цель этого поста - вызвать хранимую процедуру, которая принимает массив настраиваемого типа записи. Чтобы вызвать его, мне сначала нужно объявить несколько простых типов массивов для привязки. Затем я могу использовать эти массивы для создания более сложного массива и вызова процедуры.

В вашем случае вам нужно будет сделать наоборот. В блоке PL / SQL объявите локальную переменную типа APPS.XXETA_GRID_CONTEXT_TAB_TYP. Затем, после вызова процедуры, выполните итерацию по массиву и используйте его для заполнения некоторых простых массивов (VARCHAR2, NUMBER или DATE) и используйте их в качестве исходящих привязок.

Обновлять:

Если у вас есть следующие объекты:

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;
/

Следующий код Node.js может вызывать хранимую процедуру и получать значения из сложного выходного параметра.

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();

Надеюсь, это поможет! Прямая поддержка сложных типов находится в списке улучшений, просто не могу сказать, когда она появится.

person Dan McGhan    schedule 06.08.2018
comment
Придется ли мне изменить хранимую процедуру в базе данных? Если так, то это не сработает. У меня вообще нет возможности изменять базу данных. Пожалуйста, извините, если этот вопрос звучит идиотским. Я почти ничего не знаю о PLSQL. - person Andrew Cooper; 07.08.2018
comment
Нет, вам не нужно будет изменять хранимую процедуру. Покажите мне, как выглядит APPS.XXETA_GRID_CONTEXT_TAB_TYP, и я дополню свой ответ примером. - person Dan McGhan; 07.08.2018
comment
Спасибо, Дэн. Я сделаю это, как только узнаю. Мои разрешения в базе данных позволяют мне видеть только подпись. Я не вижу, как выглядит этот нестандартный тип. Администратор базы данных должен будет сказать мне. - person Andrew Cooper; 07.08.2018
comment
Дэн, я обновил исходный пост сложным шрифтом. - person Andrew Cooper; 07.08.2018