oracle / oracle/node-oracledb

executeMany() offsets index of dbl returning variables on index

Open
#1,683 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug dependency issue
Dominant language
JavaScript
Stars
2.4k
Forks
1.1k
PR merge metrics
No merged PRs in 30d

Description

  1. What versions are you using?

platform: darwin
version: v20.11.1
arch: x64
oracledb: 5.5.0 (reproducible in latest 6.x)
clientVersion: 19.3.0.0.0

  1. Is it an error or a hang or a crash?

Error

  1. What error(s) or behavior you are seeing?

When encountering batchErrors, the index / values of dbms returning can become offset incorrectly

// results.batchErrors
[
  [Error: ORA-12899: value too large for column "REPRODUCTION_CONTRACT_TABLE"."CURRENCY_CODE" (actual: 46, maximum: 20)] {
    errorNum: 12899,
    offset: 1
  }
]

// results.outBidns
[
  {
    contractLineIdOut: [ 10000000050 ],
    contractIdOut: [ 100 ],
    creationDateOut: [ 2021-01-01T05:00:00.000Z ],
    lineItemOut: [ 'Line Item 1' ]
  },
  {
    contractLineIdOut: [],
    contractIdOut: [],
    creationDateOut: [],
    lineItemOut: []
  },
  {
    contractLineIdOut: [ 4.089930721500069e-28 ],
    contractIdOut: [ 10000000059 ],
    creationDateOut: [ 9309-01-01T12:00:00.000Z ],
    lineItemOut: [ 'xy\x01\t\x17\x01\x01' ]
  }
]

Expected: Third item in array has the correct lineItemOut, correct number of contractIdOut

[
  {
    contractLineIdOut: [ 10000000050 ],
    contractIdOut: [ 100 ],
    creationDateOut: [ 2021-01-01T05:00:00.000Z ],
    lineItemOut: [ 'Line Item 1' ]
  },
  {
    contractLineIdOut: [],
    contractIdOut: [],
    creationDateOut: [],
    lineItemOut: []
  },
  {
    contractLineIdOut: [ 10000000059 ],
    contractIdOut: [ 800 ],
    creationDateOut: [ 2021-01-10T05:00:00.000Z ],
    lineItemOut: [ 'Line Item 8' ]
  }
]

if the currency code was valid it would also update multiple rows

  {
    contractLineIdOut: [ 10000000055, 10000000056 ],
    contractIdOut: [ 600, 600 ],
    creationDateOut: [ 2021-01-06T05:00:00.000Z, 2021-01-07T05:00:00.000Z ],
    lineItemOut: [ 'Line Item 6', 'Line Item 6' ]
  },
  1. Include a runnable Node.js script that shows the problem.
  let connection;
  const createTableAndSeed = async () => {
    try {
      connection = await oracledb.getConnection({
        user: oracleConnectionInfo.getKnexConnectionObject().user,
        password: oracleConnectionInfo.getKnexConnectionObject().password,
        connectString: oracleConnectionInfo.getConnectionString(),
      });

      const creationTable = `
          CREATE TABLE REPRODUCTION_CONTRACT_TABLE (
                    CONTRACT_LINE_ID         NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY INCREMENT BY 1 START WITH 10000000000 MAXVALUE 999999999999999999999999999 CACHE 1000
                    , CONTRACT_ID            NUMBER NOT NULL
                    , CREATION_DATE          DATE
                    , CURRENCY_CODE          VARCHAR2(20)
                    , LINE_ITEM              VARCHAR2(500)
                    , CONSTRAINT CONTRACT_LINE_PK PRIMARY KEY (CONTRACT_LINE_ID) ENABLE
          );
      `;

      await connection.execute(creationTable);

      const sql = `
          INSERT INTO REPRODUCTION_CONTRACT_TABLE
          (CONTRACT_ID, CREATION_DATE, CURRENCY_CODE, LINE_ITEM) 
          VALUES (:contract_id, TO_DATE(:creation_date, 'YYYY-MM-DD'), :currency_code, :line_item)
        `;

      const binds = [
        { contract_id: 100, creation_date: '2021-01-01', currency_code: 'USD', line_item: 'Line Item 1' },
        { contract_id: 200, creation_date: '2021-01-02', currency_code: 'USD', line_item: 'Line Item 2' },
        { contract_id: 300, creation_date: '2021-01-03', currency_code: 'USD', line_item: 'Line Item 3' },
        { contract_id: 400, creation_date: '2021-01-04', currency_code: 'USD', line_item: 'Line Item 4' },
        { contract_id: 500, creation_date: '2021-01-05', currency_code: 'USD', line_item: 'Line Item 5' },
        { contract_id: 600, creation_date: '2021-01-06', currency_code: 'USD', line_item: 'Line Item 6' },
        { contract_id: 600, creation_date: '2021-01-07', currency_code: 'USD', line_item: 'Line Item 6' },
        { contract_id: 700, creation_date: '2021-01-08', currency_code: 'USD', line_item: 'Line Item 7' },
        { contract_id: 700, creation_date: '2021-01-09', currency_code: 'USD', line_item: 'Line Item 7' },
        { contract_id: 800, creation_date: '2021-01-10', currency_code: 'USD', line_item: 'Line Item 8' },
      ];

      const options = {
        autoCommit: true, // Automatically commit after each insert
        bindDefs: {
          contract_id: { type: oracledb.NUMBER },
          creation_date: { type: oracledb.STRING, maxSize: 10 },
          currency_code: { type: oracledb.STRING, maxSize: 3 },
          line_item: { type: oracledb.STRING, maxSize: 50 },
        },
      };

      const result = await connection.executeMany(sql, binds, options);
      console.log('Rows inserted:', result.rowsAffected);
    } catch (err) {
      console.log(err);
    } finally {
      connection.close();
    }
  };

  const update = async () => {
    const update = `
    update REPRODUCTION_CONTRACT_TABLE
    SET
    CONTRACT_ID         =:contractId,
    CURRENCY_CODE       =:currencyCode
    WHERE LINE_ITEM     =:lineItem
    RETURNING CONTRACT_LINE_ID, CONTRACT_ID, CREATION_DATE, LINE_ITEM INTO :contractLineIdOut, :contractIdOut, :creationDateOut, :lineItemOut
    `;

    const binds = [
      {
        contractId: 100,
        currencyCode: 'USD',
        lineItem: 'Line Item 1',
      },
      {
        contractId: 600,
        currencyCode: 'USD Values Is Way To Long To Fit In The Column',
        lineItem: 'Line Item 6',
      },
      {
        contractId: 800,
        currencyCode: 'USD',
        lineItem: 'Line Item 8',
      },
    ];

    const options = {
      autoCommit: true,
      batchErrors: true,
      bindDefs: {
        contractId: { type: oracledb.NUMBER },
        currencyCode: { maxSize: 512, type: oracledb.STRING },
        lineItem: { type: oracledb.STRING, maxSize: 512 },
        contractLineIdOut: { type: oracledb.NUMBER, dir: oracledb.BIND_OUT },
        contractIdOut: { type: oracledb.NUMBER, dir: oracledb.BIND_OUT },
        creationDateOut: { type: oracledb.DATE, dir: oracledb.BIND_OUT },
        lineItemOut: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 512 },
      },
    };
    let result;
    let connection;
    try {
      connection = await oracledb.getConnection({
        user: oracleConnectionInfo.getKnexConnectionObject().user,
        password: oracleConnectionInfo.getKnexConnectionObject().password,
        connectString: oracleConnectionInfo.getConnectionString(),
      });

      result = await connection.executeMany(update, binds, options);
    } catch (err) {
      console.log(err);
    } finally {
      connection.commit();
      connection.close();
    }

    console.log(result?.batchErrors);
    console.log(result?.outBinds);
  };

  await createTableAndSeed();
  await update();
      

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the provided Node.js reproduction and inspect executeMany() results, especially batchErrors and outBinds for the failed batch item. Compare the observed values with the expected returned-variable arrays and identify the offset behavior. Done means the failing case returns the correct values for the third item and multi-row update without corrupting output.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js, sql
Domain
backend-api-design, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.