{"id":16340,"library":"dmdb","title":"DMDB Database Driver for Node.js","description":"DMDB is a native Node.js driver for the Dameng 8 (DM8) relational database, providing direct database connectivity and interaction. The current stable version is 1.0.48286 (as of March 2026), with a frequent release cadence, often monthly or bi-monthly, addressing bugs, performance, and new features. Key differentiators include its tight integration with the DM8 ecosystem, official support for Node.js versions 12 and above, and extensions for popular ORMs like TypeORM and Knex via `typeorm-dm` and `knex-dm` packages. The driver supports features like connection pooling, statement caching, and optional Snappy compression for internal communication. It also aims for compatibility with OracleDB-like API patterns, which is a significant aspect for developers migrating or working with similar database drivers.","status":"active","version":"1.0.48286","language":"javascript","source_language":"en","source_url":null,"tags":["javascript","typescript"],"install":[{"cmd":"npm install dmdb","lang":"bash","label":"npm"},{"cmd":"yarn add dmdb","lang":"bash","label":"yarn"},{"cmd":"pnpm add dmdb","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Optional dependency for Snappy compression if enabled on the DM8 server. Offers better performance than snappyjs.","package":"snappy","optional":true},{"reason":"Optional dependency for Snappy compression if enabled on the DM8 server. A pure JavaScript implementation with better compatibility on some platforms.","package":"snappyjs","optional":true}],"imports":[{"note":"The primary way to import the main driver object containing functions like `createPool` and `getConnection`. While CommonJS `require` might work in older Node.js setups, ESM `import` is the recommended standard.","wrong":"const dmdb = require('dmdb');","symbol":"dmdb","correct":"import dmdb from 'dmdb';"},{"note":"Type import for database connection objects, used for type-checking in TypeScript projects. The actual connection object is returned by `dmdb.getConnection()` or from a pool.","wrong":"import { DmConnection } from 'dmdb';","symbol":"Connection","correct":"import { Connection } from 'dmdb';"},{"note":"Type import for connection pool objects, used for type-checking. The actual pool object is created via `dmdb.createPool()`.","symbol":"Pool","correct":"import { Pool } from 'dmdb';"},{"note":"A constant used for `dmdb.outBindFormat` global configuration to ensure out-bind parameters are always returned as arrays, providing backward compatibility after v1.0.43524.","symbol":"OUT_FORMAT_ARRAY","correct":"import { OUT_FORMAT_ARRAY } from 'dmdb';"}],"quickstart":{"code":"import dmdb from 'dmdb';\n\ninterface MyQueryResult {\n  id: number;\n  name: string;\n}\n\nasync function runDbOperations() {\n  let connection: dmdb.Connection | undefined;\n  let pool: dmdb.Pool | undefined;\n\n  try {\n    // Create a connection pool\n    pool = await dmdb.createPool({\n      user: process.env.DB_USER ?? 'SYSDBA',\n      password: process.env.DB_PASSWORD ?? 'SYSDBA',\n      connectString: process.env.DB_CONNECT_STRING ?? 'localhost:5236/DAMENG',\n      poolMin: 2,\n      poolMax: 4,\n      poolIncrement: 1,\n      poolAlias: 'default'\n    });\n    console.log('Connection pool created successfully.');\n\n    // Get a connection from the pool\n    connection = await pool.getConnection();\n    console.log('Connection obtained from pool.');\n\n    // Execute a simple query\n    const querySql = 'SELECT 1 AS id, \\'Hello DMDB\\' AS name FROM DUAL';\n    const result: dmdb.Result<MyQueryResult> = await connection.execute(querySql);\n    console.log('Query Result:', result.rows?.[0]);\n\n    // Execute a DML statement with bind parameters\n    const insertSql = 'INSERT INTO my_test_table (id, value) VALUES (:1, :2)';\n    const bindParams = [1001, 'Test Value'];\n    const insertResult = await connection.execute(insertSql, bindParams, { autoCommit: true });\n    console.log('Rows inserted:', insertResult.rowsAffected); \n\n    // Execute a query to fetch data from the inserted table\n    const fetchSql = 'SELECT id, value FROM my_test_table WHERE id = :id';\n    const fetchResult: dmdb.Result<{ id: number; value: string }> = await connection.execute(fetchSql, { id: 1001 });\n    console.log('Fetched data:', fetchResult.rows?.[0]);\n\n  } catch (err: any) {\n    console.error('Database operation failed:', err.message);\n  } finally {\n    if (connection) {\n      try {\n        await connection.close();\n        console.log('Connection released back to pool.');\n      } catch (closeErr: any) {\n        console.error('Error closing connection:', closeErr.message);\n      }\n    }\n    if (pool) {\n      try {\n        await pool.close();\n        console.log('Connection pool closed.');\n      } catch (poolCloseErr: any) {\n        console.error('Error closing pool:', poolCloseErr.message);\n      }\n    }\n  }\n}\n\n// A small helper to create the table if it doesn't exist\nasync function setupTable() {\n  let connection: dmdb.Connection | undefined;\n  try {\n    connection = await dmdb.getConnection({\n      user: process.env.DB_USER ?? 'SYSDBA',\n      password: process.env.DB_PASSWORD ?? 'SYSDBA',\n      connectString: process.env.DB_CONNECT_STRING ?? 'localhost:5236/DAMENG',\n    });\n    await connection.execute(`\n      BEGIN\n        EXECUTE IMMEDIATE 'DROP TABLE my_test_table';\n      EXCEPTION\n        WHEN OTHERS THEN\n          IF SQLCODE != -942 THEN\n            RAISE;\n          END IF;\n      END;\n    `);\n    await connection.execute(`\n      CREATE TABLE my_test_table (\n        id NUMBER(10) PRIMARY KEY,\n        value VARCHAR2(50)\n      )\n    `);\n    console.log('Table my_test_table ensured.');\n  } catch (err: any) {\n    console.error('Table setup failed:', err.message);\n  } finally {\n    if (connection) {\n      await connection.close();\n    }\n  }\n}\n\nsetupTable().then(() => runDbOperations());","lang":"typescript","description":"This quickstart demonstrates how to establish a connection pool, obtain a connection, execute a simple `SELECT` query, perform an `INSERT` with bind parameters, and properly close connections and the pool. It also includes a basic table setup/teardown."},"warnings":[{"fix":"Update application code to process `outBinds` as column-grouped arrays. Review the `index.d.ts` for updated interface definitions.","message":"The format of `Results.outBinds` for `Connection.executeMany()` changed from row-grouped to column-grouped to align with OracleDB's behavior. Applications relying on the previous row-grouped format will need adjustment.","severity":"breaking","affected_versions":">=1.0.48286"},{"fix":"Avoid using `getRowCount()`. If a row count is strictly necessary before iteration, consider using an aggregate query (e.g., `COUNT(*)`) instead or collecting all rows into an array first.","message":"The `ResultSet.getRowCount()` interface has been removed because it is incompatible with forward-only result sets.","severity":"breaking","affected_versions":">=1.0.48286"},{"fix":"Explicitly specify the `'default'` alias when creating or retrieving connection pools, or ensure you use a consistent, named alias.","message":"The default alias for connection pools has changed from `null` or `undefined` to `'default'`. Attempting to retrieve a pool without specifying an alias, or using a non-existent alias, will now result in an error.","severity":"breaking","affected_versions":">=1.0.48286"},{"fix":"For backward compatibility, set the global configuration `dmdb.outBindFormat = dmdb.OUT_FORMAT_ARRAY` immediately after importing the driver. Otherwise, update your code to handle dynamic `outBinds` formats based on your bind parameter style.","message":"The return format of `Result.outBinds`/`Results.outBinds` is no longer fixed as an array. It now depends on whether bind parameters were positioned (returns array) or named (returns object).","severity":"breaking","affected_versions":">=1.0.43524"},{"fix":"Explicitly handle `NaN`, `Infinity`, and `-Infinity` values in your application logic. Convert them to `NULL` or other appropriate database-compatible values before binding if `NULL` is the desired behavior, or ensure they are not passed.","message":"When binding `NaN`, `Infinity`, or `-Infinity` values as parameters, the driver now throws an error instead of implicitly binding them as `NULL`.","severity":"breaking","affected_versions":">=1.0.43524"},{"fix":"Review SQL statements and bind parameter definitions. If `DOUBLE` precision is explicitly required for integer-like numbers, specify the bind type explicitly. Otherwise, ensure your database schema and application can handle `BIGINT`.","message":"The default bind type for `number` parameters that represent integers has changed from `DOUBLE` to `BIGINT`. This may affect applications that rely on implicit type conversion or expect `DOUBLE` precision for integer values.","severity":"breaking","affected_versions":">=1.0.38220"},{"fix":"If DMDB server-side compression is enabled, ensure either `snappy` (for performance) or `snappyjs` (for compatibility) is explicitly installed as a dependency in your project: `npm install snappy` or `npm install snappyjs`.","message":"The `snappy` and `snappyjs` dependencies are now optional. If Snappy compression is enabled on the DM8 server, one of these packages *must* be installed in your project, otherwise communication will fail.","severity":"gotcha","affected_versions":">=1.0.34946"},{"fix":"Remove any usage of `ExecuteOptions.outFormat` for controlling `outBinds`. Ensure your code expects `outBinds` to be an array, especially if you had adapted to the v1.0.31017 behavior.","message":"A previous feature allowing `ExecuteOptions.outFormat` to control `Result.outBinds` format (array/object) was rolled back due to conflicts with `typeorm-dm`. `outBinds` are now fixed to return as arrays again. This can cause breaking changes if you adopted the short-lived `outFormat` option.","severity":"breaking","affected_versions":"1.0.33801"},{"fix":"Verify date and time handling in your application, especially if working with multiple time zones. Ensure your database and application explicitly handle time zone conversions as intended.","message":"The driver fixed an issue where date/time types had incorrect conversions in different time zones. Applications relying on the previous (incorrect) timezone behavior might see altered date/time values.","severity":"gotcha","affected_versions":">=1.0.32369"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Upgrade to dmdb v1.0.48286 or later. Ensure your string lengths are within defined database column limits.","cause":"Error when inserting strings of certain lengths using bind parameters, likely due to internal buffer handling or length calculation issues.","error":"[6067] 字符串截断"},{"fix":"Upgrade to dmdb v1.0.45146 or later. Consider upgrading your Dameng database server if the issue persists with older versions.","cause":"Occurs when connecting to older database versions and attempting to insert long strings via bind parameters, indicating a mismatch in data type handling.","error":"Bind param data failed by invalid param data type"},{"fix":"Upgrade to dmdb v1.0.45146 or later. Avoid interleaved SQL execution or concurrent operations on `ResultSet` and `Lob` objects. Process one result set completely before executing other queries or operating on another `ResultSet`.","cause":"Executing arbitrary SQL statements between fetching a query result set and iterating through that result set can lead to this error. Also, concurrent operations on ResultSet or Lob objects are not supported.","error":"[-2002] 执行未准备SQL语句"},{"fix":"Ensure the number of bind parameters supplied in the `execute()` or `executeMany()` call exactly matches the number of placeholders (e.g., `:1`, `:2`, or `:name`) in your SQL statement.","cause":"Providing more positional bind parameters than there are placeholders in the SQL statement.","error":"绑定参数个数过多"},{"fix":"Upgrade to dmdb v1.0.46190 or later. Ensure your database character set is correctly configured to handle multi-byte characters like emojis.","cause":"Occurs when reading large fields (LOBs) containing emoji characters in stream mode, indicating an issue with length or offset calculation for multi-byte characters.","error":"[6057] 长度或偏移错误"}],"ecosystem":"npm"}