denoland / deno

A modern runtime for JavaScript and TypeScript.
https://deno.com
MIT License
93.53k stars 5.18k forks source link

node-compat: npm:oracledb(thin mode) #20924

Open chibat opened 9 months ago

chibat commented 9 months ago

Node compat doesn’t work for npm:oracledb(thin mode). The steps to reproduce are summarized below.

test repository: https://github.com/chibat/oracledb-test

$ git clone https://github.com/chibat/oracledb-test.git
$ cd oracledb-test

start oracle database

$ docker run --name test -p 1521:1521 -e ORACLE_RANDOM_PASSWORD="y" -v ${PWD}/init_scripts:/container-entrypoint-initdb.d gvenzl/oracle-xe

main.js

// @deno-types="npm:@types/oracledb"
import oracledb from "npm:oracledb@6.2.0";

const conn = await oracledb.getConnection({connectString: "localhost:1521/XEPDB1", user: "test", password: "test"});
const result = await conn.execute("select table_name from tabs");
console.log(result);
conn.close();

Deno

$ cd deno
$ deno --version
deno 1.37.2 (release, x86_64-unknown-linux-gnu)
v8 11.8.172.13
typescript 5.2.2
$ deno task start
Task start deno run --allow-sys --allow-env --allow-net main.ts
error: Uncaught (in promise) TypeError: The "string" argument must be of type string or an instance of Buffer or ArrayBuffer. Received undefined
    at Function.byteLength (ext:deno_node/internal/buffer.mjs:359:11)
    at WritePacket.writeKeyValue (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/protocol/packet.js:514:32)
    at AuthMessage.encode (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/protocol/messages/auth.js:186:11)
    at Protocol._encodeMessage (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/protocol/protocol.js:108:20)
    at Protocol._processMessage (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/protocol/protocol.js:151:18)
    at ThinConnectionImpl.connect (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/connection.js:687:30)
    at eventLoopTick (ext:core/01_core.js:183:11)
    at async Object.getConnection (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/oracledb.js:642:3)
    at async file:///home/chiba/oracledb-test/deno/main.ts:4:14

Node

$ cd node
$ npm install
{
  metaData: [
    {
      name: 'TABLE_NAME',
      dbType: [DbType DB_TYPE_VARCHAR],
      nullable: false,
      byteSize: 128,
      dbTypeName: 'VARCHAR2',
      fetchType: [DbType DB_TYPE_VARCHAR]
    }
  ],
  rows: [
    [ 'REGIONS' ],
    [ 'COUNTRIES' ],
    [ 'CITIES' ],
    [ 'CURRENCIES' ],
    [ 'CURRENCIES_COUNTRIES' ]
  ]
}

Bun

$ bun index.mjs
{
  metaData: [
    {
      name: "TABLE_NAME",
      dbType: [DbType DB_TYPE_VARCHAR],
      nullable: false,
      byteSize: 128,
      dbTypeName: "VARCHAR2",
      fetchType: [DbType DB_TYPE_VARCHAR]
    }
  ],
  rows: [
    [ "REGIONS" ], [ "COUNTRIES" ], [ "CITIES" ], [ "CURRENCIES" ], [ "CURRENCIES_COUNTRIES" ]
  ]
}

related issue: oracle/node-oracledb#1258

chibat commented 9 months ago

I have debugged it and found that process.argv0 is handled differently.

$ node
> process.argv0
'node'

$ deno
> import process from "node:process"
undefined
> process.argv0
undefined

$ bash -c 'exec -a customArgv0 node'
> process.argv0
'customArgv0'

$ bash -c 'exec -a customArgv0 deno'
> import process from "node:process"
undefined
> process.argv0
undefined
chibat commented 9 months ago

Perhaps support for aes-256-cbc, aes-192-cbc will also be required. https://github.com/denoland/deno/blob/7561f6eceacc46c6f4f5f66cf03e627821b64f02/ext/node/ops/crypto/cipher.rs#L26

I bypassed the process.argv0 issue and tested it.

error: Uncaught (in promise) TypeError: Unknown cipher
    at new Decipheriv (ext:deno_node/internal/crypto/cipher.ts:140:13)
    at Object.createDecipheriv (node:crypto:28:10)
    at EncryptDecrypt._decrypt (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/protocol/encryptDecrypt.js:45:29)
    at EncryptDecrypt.updateVerifierData (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/protocol/encryptDecrypt.js:142:34)
    at AuthMessage.encode (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/protocol/messages/auth.js:211:14)
    at Protocol._encodeMessage (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/protocol/protocol.js:108:20)
    at Protocol._processMessage (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/protocol/protocol.js:151:18)
    at ThinConnectionImpl.connect (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/connection.js:700:30)
    at eventLoopTick (ext:core/01_core.js:183:11)
    at async Object.getConnection (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/oracledb.js:642:3)
chibat commented 9 months ago

@bartlomieju @kt3k Thank you for fixing. I did a test with a canary release.

$ deno task start
Task start deno run --allow-sys --allow-env --allow-net --reload main.ts
error: Uncaught (in promise) TypeError: Unknown cipher
    at new Decipheriv (ext:deno_node/internal/crypto/cipher.ts:140:13)
    at Object.createDecipheriv (node:crypto:28:10)
    at EncryptDecrypt._decrypt (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/protocol/encryptDecrypt.js:45:29)
    at EncryptDecrypt.updateVerifierData (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/protocol/encryptDecrypt.js:141:34)
    at AuthMessage.encode (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/protocol/messages/auth.js:211:14)
    at Protocol._encodeMessage (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/protocol/protocol.js:108:20)
    at Protocol._processMessage (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/protocol/protocol.js:151:18)
    at ThinConnectionImpl.connect (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/thin/connection.js:700:30)
    at eventLoopTick (ext:core/01_core.js:183:11)
    at async Object.getConnection (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.2.0/lib/oracledb.js:642:3)

Perhaps support for aes-256-cbc, aes-192-cbc will also be required. https://github.com/denoland/deno/blob/7561f6eceacc46c6f4f5f66cf03e627821b64f02/ext/node/ops/crypto/cipher.rs#L26

Also, regarding the fix of process.argv0. The result when explicitly specifying the process name is different from Node.js.

Node

$ bash -c 'exec -a customArgv0 node'
> process.argv0
'customArgv0'

Deno

$ deno --version
deno 1.37.2+5095af7 (canary, x86_64-unknown-linux-gnu)
v8 11.8.172.13
typescript 5.2.2
$ bash -c 'exec -a customArgv0 deno'
> import process from "node:process"
undefined
> process.argv0
"deno"
bartlomieju commented 9 months ago

@chibat can you please open a separate issue for this problem?

chibat commented 9 months ago

@bartlomieju I have created the Issue.

20934

chibat commented 9 months ago

I have debugged this issue. I understood that it depends on the following Issue.

18455

  • [ ] crypto.Decipheriv.prototype.setAutoPadding

21804

baqsoft commented 8 months ago

@chibat As a workaround for missing "aes-256-cbc" it is possible to override functions "createCipheriv" and "createDecipheriv" with ones from https://github.com/browserify/browserify-aes Just create a patched module:

import browserify from 'https://esm.sh/browserify-aes';
import crypto from 'node:crypto';

crypto.createDecipheriv = browserify.createDecipheriv;
crypto.createCipheriv = browserify.createCipheriv;

export default crypto;

and configure Deno's importMap to use it specifically for oracledb's scope:

{
  ....
  "scopes": {
      "https://esm.sh/v135/oracledb@6.2.0/": {
        "node:crypto": "./polyfills/crypto.ts"
       }
    }
}
kt3k commented 8 months ago

Let's reopen as this doesn't look resolved

r-dahlstedt-linux-guy commented 7 months ago

There is something that is going on when you hit release 1.39.0 where after connecting to the database when a query is issued it just hangs. All other versions from 1.37.x and 1.38.x all work perfectly fine with the exact same script. The actual Node.js package did just change to a new release (6.3.0) on December 21st but even when using the previous release (6.2.0) from October 11th which again worked until 1.39.0 the same hanging issue occurs. When running the bulk of the same script, the only difference being is the way the package is imported, Node.js has no similar issue with either version of the package up through release 21.5.0.

r-dahlstedt-linux-guy commented 6 months ago

I just tried again using 1.39.4 and its still just hangs. As soon as I switch back to 1.38.5 it works. Something substantially had to change when import npm modules such that when executing methods in the module, perhaps through those that are called through await (i.e. getConnection which is where mine hangs) they seemingly go into never never land.

bartlomieju commented 6 months ago

@r-dahlstedt-linux-guy are you using a TLS connection?

r-dahlstedt-linux-guy commented 6 months ago

No

chibat commented 6 months ago
$ deno --version
deno 1.40.3 (release, x86_64-unknown-linux-gnu)
v8 12.1.285.6
typescript 5.3.3
$ deno task start
Task start deno run --allow-sys --allow-env --allow-net main.js
error: Uncaught (in promise) Error: Not implemented: crypto.Decipheriv.prototype.setAutoPadding
    at notImplemented (ext:deno_node/_utils.ts:9:9)
    at Decipheriv.setAutoPadding (ext:deno_node/internal/crypto/cipher.ts:163:5)
    at EncryptDecrypt._decrypt (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.3.0/lib/thin/protocol/encryptDecrypt.js:46:14)
    at EncryptDecrypt.updateVerifierData (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.3.0/lib/thin/protocol/encryptDecrypt.js:141:34)
    at AuthMessage.encode (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.3.0/lib/thin/protocol/messages/auth.js:210:14)
    at Protocol._encodeMessage (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.3.0/lib/thin/protocol/protocol.js:108:20)
    at Protocol._processMessage (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.3.0/lib/thin/protocol/protocol.js:151:18)
    at ThinConnectionImpl.connect (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.3.0/lib/thin/connection.js:703:30)
    at eventLoopTick (ext:core/01_core.js:64:7)
    at async Object.getConnection (file:///home/chiba/.cache/deno/npm/registry.npmjs.org/oracledb/6.3.0/lib/oracledb.js:653:3)

We moved forward.

salva-dev commented 1 week ago

Today I get the same error as @chibat . Does anyone know when this issue is expected to be resolved? Is there any workarround while it is being resolved? I love deno and I am trying to test it in my company but we use oracle as database for almost everything.

Thank you so much for making deno, it's great, and adding oracle support would be a great improvement.

chibat commented 1 week ago

@salva-dev I am hoping that once the following issue, PR, is resolved, this issue will also be resolved.

21804, #22228

I confirm that the following comment workaround works well. https://github.com/denoland/deno/issues/20924#issuecomment-1827671623

I believe thick mode, which uses a native Oracle client, will also work. https://node-oracledb.readthedocs.io/en/latest/user_guide/initialization.html#enabling-node-oracledb-thick-mode But we would be happier if it worked in thin mode.

salva-dev commented 6 days ago

@chibat , thanks a lot. The workaround works for me!!. I look forward to the integration of the PR with enthusiasm. Deno is great and I think it is present and future of js in server. I am testing it in my company where they let me, for cli's it is a marvel and now with the oracle support I will use it to do many backend services. Thanks again.