mirror of
https://github.com/mariadb-corporation/mariadb-connector-nodejs.git
synced 2025-08-15 21:22:32 +00:00
Merge branch 'develop' into maintenance/3.x
# Conflicts: # CHANGELOG.md # documentation/promise-api.md # lib/misc/errors.js # lib/pool-base.js # package.json # test/integration/test-pool.js # types/mariadb-tests.ts
This commit is contained in:
@ -41,15 +41,16 @@ jobs:
|
||||
- env: srv=mariadb v=10.3 local=1
|
||||
- env: srv=mariadb v=10.4 local=1
|
||||
- env: srv=mariadb v=10.5 local=1
|
||||
- env: srv=mariadb v=10.5 local=1
|
||||
- env: srv=mariadb v=10.7 local=1
|
||||
- env: srv=mariadb v=10.6 local=1
|
||||
node_js: 14
|
||||
- env: srv=mariadb v=10.5 local=1
|
||||
- env: srv=mariadb v=10.6 local=1
|
||||
node_js: 12
|
||||
- env: srv=mariadb v=10.6 BENCH=1 local=1
|
||||
- if: type = push AND fork = false
|
||||
env: srv=maxscale
|
||||
- if: type = push AND fork = false
|
||||
env: srv=mariadb-es v=10.5
|
||||
env: srv=mariadb-es v=10.6
|
||||
- if: type = push AND fork = false
|
||||
env: srv=skysql RUN_LONG_TEST=0
|
||||
- if: type = push AND fork = false
|
||||
|
@ -46,7 +46,14 @@ This methods are compatible with mysql2 with some differences:
|
||||
* permit streaming parameters
|
||||
* execute use by default a prepared cache that hasn't infinite length.
|
||||
* implement mariadb 10.6 skipping metadata when possible for better performance
|
||||
* Doesn't have a unprepare methods.
|
||||
* Doesn't have a unprepare methods.
|
||||
|
||||
## [2.5.5](https://github.com/mariadb-corporation/mariadb-connector-nodejs/tree/2.5.5) (19 Oct 2021)
|
||||
[Full Changelog](https://github.com/mariadb-corporation/mariadb-connector-nodejs/compare/2.5.4...2.5.5)
|
||||
|
||||
* [CONJS-170] Pool.query(undefined) never release connection
|
||||
* [CONJS-173] not permitting providing null as a value without an array
|
||||
* [CONJS-175] Missing leakDetectionTimeout option in Typescript description
|
||||
|
||||
## [2.5.4](https://github.com/mariadb-corporation/mariadb-connector-nodejs/tree/2.5.4) (08 Jun 2021)
|
||||
[Full Changelog](https://github.com/mariadb-corporation/mariadb-connector-nodejs/compare/2.5.3...2.5.4)
|
||||
|
30
README.md
30
README.md
@ -99,33 +99,7 @@ The MariaDB Connector is available through the Node.js repositories. You can in
|
||||
```
|
||||
$ npm install mariadb
|
||||
```
|
||||
|
||||
Using ECMAScript < 2017:
|
||||
|
||||
```js
|
||||
const mariadb = require('mariadb');
|
||||
const pool = mariadb.createPool({host: process.env.DB_HOST, user: process.env.DB_USER, connectionLimit: 5});
|
||||
pool.getConnection()
|
||||
.then(conn => {
|
||||
|
||||
conn.query("SELECT 1 as val")
|
||||
.then(rows => { // rows: [ {val: 1}, meta: ... ]
|
||||
return conn.query("INSERT INTO myTable value (?, ?)", [1, "mariadb"]);
|
||||
})
|
||||
.then(res => { // res: { affectedRows: 1, insertId: 1, warningStatus: 0 }
|
||||
conn.release(); // release to pool
|
||||
})
|
||||
.catch(err => {
|
||||
conn.release(); // release to pool
|
||||
})
|
||||
|
||||
}).catch(err => {
|
||||
//not connected
|
||||
});
|
||||
```
|
||||
|
||||
Using ECMAScript 2017:
|
||||
|
||||
example:
|
||||
```js
|
||||
const mariadb = require('mariadb');
|
||||
const pool = mariadb.createPool({host: process.env.DB_HOST, user: process.env.DB_USER, connectionLimit: 5});
|
||||
@ -141,8 +115,6 @@ async function asyncFunction() {
|
||||
const res = await conn.query("INSERT INTO myTable value (?, ?)", [1, "mariadb"]);
|
||||
// res: { affectedRows: 1, insertId: 1, warningStatus: 0 }
|
||||
|
||||
} catch (err) {
|
||||
throw err;
|
||||
} finally {
|
||||
if (conn) conn.release(); //release to pool
|
||||
}
|
||||
|
@ -15,23 +15,28 @@ Install the mariadb Connector using npm
|
||||
$ npm install mariadb
|
||||
```
|
||||
|
||||
You can then uses the Connector in your application code with the Promise API. For instance,
|
||||
You can then use the Connector in your application code with the Promise API. For instance,
|
||||
|
||||
```js
|
||||
const mariadb = require('mariadb');
|
||||
|
||||
async function main() {
|
||||
let conn;
|
||||
try {
|
||||
conn = await mariadb.createConnection({ host: 'mydb.com', user: 'myUser', password: 'myPwd' });
|
||||
const rows = await conn.query('select 1', [2]);
|
||||
console.log(rows); // [{ "1": 1 }]
|
||||
} catch (e) {
|
||||
// handle errors
|
||||
} finally {
|
||||
if (conn) conn.end();
|
||||
}
|
||||
async function asyncFunction() {
|
||||
const conn = await mariadb.createConnection({
|
||||
host: 'mydb.com',
|
||||
user: 'myUser',
|
||||
password: 'myPwd'
|
||||
});
|
||||
|
||||
try {
|
||||
const res = await conn.query('select 1', [2]);
|
||||
console.log(res); // [{ "1": 1 }]
|
||||
return res;
|
||||
} finally {
|
||||
conn.end();
|
||||
}
|
||||
}
|
||||
|
||||
asyncFunction();
|
||||
```
|
||||
|
||||
# Installation
|
||||
@ -151,13 +156,13 @@ $ npm install dotenv
|
||||
then configure dotenv to load all .env files
|
||||
|
||||
```js
|
||||
const mariadb = require('mariadb');
|
||||
require('dotenv').config()
|
||||
const conn = await mariadb.createConnection({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PWD
|
||||
});
|
||||
require('dotenv').config();
|
||||
|
||||
const conn = await mariadb.createConnection({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PWD
|
||||
});
|
||||
```
|
||||
|
||||
with a .env file containing
|
||||
@ -168,6 +173,15 @@ DB_PWD=secretPasswrd
|
||||
```
|
||||
.env files must NOT be pushed into repository, using .gitignore
|
||||
|
||||
|
||||
### Default options consideration
|
||||
|
||||
For new project, enabling option `supportBigInt` is recommended (It will be in a future 3.x version).
|
||||
|
||||
This option permits to avoid exact value for big integer (value > 2^53) (see [javascript ES2020
|
||||
BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) )
|
||||
|
||||
|
||||
# Promise API
|
||||
|
||||
**Base:**
|
||||
@ -241,16 +255,15 @@ Creates a new [Connection](#connection-api) object.
|
||||
**Example:**
|
||||
|
||||
```javascript
|
||||
let conn;
|
||||
try {
|
||||
conn = await mariadb.createConnection({
|
||||
host: 'mydb.com',
|
||||
user: 'myUser',
|
||||
password: 'myPwd'
|
||||
});
|
||||
console.log('connected ! connection id is ' + conn.threadId);
|
||||
const conn = await mariadb.createConnection({
|
||||
host: 'mydb.com',
|
||||
user: 'myUser',
|
||||
password: 'myPwd'
|
||||
});
|
||||
console.log("connected ! connection id is " + conn.threadId);
|
||||
} catch (err) {
|
||||
console.log('not connected due to error: ' + err);
|
||||
console.log("not connected due to error: " + err);
|
||||
}
|
||||
```
|
||||
|
||||
@ -294,8 +307,7 @@ It defaults to `/tmp/mysql.sock` on Unix-like operating systems and `MySQL` on W
|
||||
For instance, on Unix a connection might look like this:
|
||||
|
||||
```javascript
|
||||
|
||||
const conn = await mariadb.createConnection({
|
||||
const conn = await mariadb.createConnection({
|
||||
socketPath: '/tmp/mysql.sock',
|
||||
user: 'root'
|
||||
});
|
||||
@ -366,24 +378,18 @@ Creates a new pool cluster. Cluster handle multiple pools, giving high availabil
|
||||
**Example:**
|
||||
|
||||
```javascript
|
||||
const mariadb = require('mariadb');
|
||||
|
||||
const cluster = mariadb.createPoolCluster();
|
||||
cluster.add('master', { host: 'mydb1.com', user: 'myUser', connectionLimit: 5 });
|
||||
cluster.add('slave1', { host: 'mydb2.com', user: 'myUser', connectionLimit: 5 });
|
||||
cluster.add('slave2', { host: 'mydb3.com', user: 'myUser', connectionLimit: 5 });
|
||||
|
||||
//getting a connection from slave1 or slave2 using round-robin
|
||||
async function get() {
|
||||
let conn;
|
||||
try {
|
||||
conn = await cluster.getConnection(/^slave*$, "RR");
|
||||
const row = await conn.query('SELECT 1');
|
||||
conn.end();
|
||||
return row[0]['@node'];
|
||||
} finally {
|
||||
if (conn) conn.end();
|
||||
}
|
||||
const conn = await cluster.getConnection(/slave*/, "RR");
|
||||
try {
|
||||
const rows = await conn.query("SELECT 1");
|
||||
return rows[0]["1"];
|
||||
} finally {
|
||||
conn.end();
|
||||
}
|
||||
```
|
||||
|
||||
@ -462,7 +468,7 @@ console.log(rows); //[ { 'NOW()': '2018-07-02 19:06:38' }, meta: [ ... ] ]
|
||||
|
||||
### Placeholder
|
||||
|
||||
To prevent SQL Injection attacks, queries permit the use of question marks as placeholders. The Connection escapes values according to their type. Values can be of native JavaScript types, Buffers, Readables, objects with `toSQLString` methods, or objects that can be stringified (that is, `JSON.stringfy`).
|
||||
To prevent SQL Injection attacks, queries permit the use of question marks as placeholders. The Connection escapes values according to their type. Values can be of native JavaScript types, Buffers, Readables, objects with `toSQLString` methods, or objects that can be stringified (that is, `JSON.stringify`).
|
||||
|
||||
When streaming, objects that implement Readable are streamed automatically. But, there are two server system variables that may interfere:
|
||||
|
||||
@ -472,10 +478,11 @@ When streaming, objects that implement Readable are streamed automatically. But
|
||||
For instance,
|
||||
|
||||
```js
|
||||
await connection.query(
|
||||
'INSERT INTO someTable VALUES (?, ?, ?)',
|
||||
[1, Buffer.from('c327a97374', 'hex'), 'mariadb']
|
||||
);
|
||||
const res = await connection.query("INSERT INTO someTable VALUES (?, ?, ?)", [
|
||||
1,
|
||||
Buffer.from("c327a97374", "hex"),
|
||||
"mariadb",
|
||||
]);
|
||||
//will send INSERT INTO someTable VALUES (1, _BINARY '.\'.st', 'mariadb')
|
||||
```
|
||||
|
||||
@ -500,7 +507,7 @@ Queries return two different kinds of results, depending on the type of query yo
|
||||
* `warningStatus`: An integer indicating whether the query ended with a warning.
|
||||
|
||||
```js
|
||||
connection.query('CREATE TABLE animals (' +
|
||||
await connection.query('CREATE TABLE animals (' +
|
||||
'id MEDIUMINT NOT NULL AUTO_INCREMENT,' +
|
||||
'name VARCHAR(30) NOT NULL,' +
|
||||
'PRIMARY KEY (id))');
|
||||
@ -954,13 +961,14 @@ Rolls back the current transaction, if there is one active. The Connector track
|
||||
|
||||
```javascript
|
||||
try {
|
||||
conn.beginTransaction();
|
||||
conn.query('INSERT INTO testTransaction values (?)', ['test1']);
|
||||
conn.query('INSERT INTO testTransaction values (?)', ['test2']);
|
||||
conn.commit();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
conn.rollback();
|
||||
|
||||
await conn.beginTransaction();
|
||||
await conn.query("INSERT INTO testTransaction values ('test')");
|
||||
await conn.query("INSERT INTO testTransaction values ('test2')");
|
||||
await conn.commit();
|
||||
|
||||
} catch(err) {
|
||||
await conn.rollback();
|
||||
}
|
||||
```
|
||||
|
||||
@ -1288,26 +1296,21 @@ const pool = mariadb.createPool({ host: 'mydb.com', user:'myUser' });
|
||||
pool.query(
|
||||
"CREATE TABLE parse(autoId int not null primary key auto_increment, c1 int, c2 int, c3 int, c4 varchar(128), c5 int)"
|
||||
);
|
||||
pool
|
||||
.batch("INSERT INTO `parse`(c1,c2,c3,c4,c5) values (1, ?, 2, ?, 3)",
|
||||
[[1, "john"], [2, "jack"]])
|
||||
.then(res => {
|
||||
//res = { affectedRows: 2, insertId: 1, warningStatus: 0 }
|
||||
let res = await pool.batch(
|
||||
"INSERT INTO `parse`(c1,c2,c3,c4,c5) values (1, ?, 2, ?, 3)",
|
||||
[[1, "john"], [2, "jack"]]
|
||||
);
|
||||
//res = { affectedRows: 2, insertId: 1, warningStatus: 0 }
|
||||
|
||||
assert.equal(res.affectedRows, 2);
|
||||
pool
|
||||
.query("select * from `parse`")
|
||||
.then(res => {
|
||||
/*
|
||||
res = [
|
||||
{ autoId: 1, c1: 1, c2: 1, c3: 2, c4: 'john', c5: 3 },
|
||||
{ autoId: 2, c1: 1, c2: 2, c3: 2, c4: 'jack', c5: 3 },
|
||||
meta: ...
|
||||
}
|
||||
*/
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
assert.equal(res.affectedRows, 2);
|
||||
res = await pool.query("select * from `parse`");
|
||||
/*
|
||||
res = [
|
||||
{ autoId: 1, c1: 1, c2: 1, c3: 2, c4: 'john', c5: 3 },
|
||||
{ autoId: 2, c1: 1, c2: 2, c3: 2, c4: 'jack', c5: 3 },
|
||||
meta: ...
|
||||
}
|
||||
*/
|
||||
```
|
||||
|
||||
## `pool.end() → Promise`
|
||||
@ -1323,7 +1326,7 @@ pool.end()
|
||||
.then(() => {
|
||||
//connections have been ended properly
|
||||
})
|
||||
.catch(err => {});
|
||||
.catch(err => console.log);
|
||||
```
|
||||
|
||||
## `pool.escape(value) → String`
|
||||
@ -1389,7 +1392,7 @@ poolCluster.end()
|
||||
.then(() => {
|
||||
//pools have been ended properly
|
||||
})
|
||||
.catch(err => {});
|
||||
.catch(err => console.log);
|
||||
```
|
||||
|
||||
|
||||
@ -1461,10 +1464,10 @@ cluster.add("slave1-south", { host: 'mydb5.com', user: 'myUser', connectionLimit
|
||||
|
||||
const masterCluster = cluster.of('master*');
|
||||
const northSlaves = cluster.of(/^slave?-north/, 'RANDOM');
|
||||
northSlaves.getConnection()
|
||||
.then(conn => {
|
||||
//use that connection
|
||||
})
|
||||
|
||||
const conn = await northSlaves.getConnection();
|
||||
// use that connection
|
||||
|
||||
```
|
||||
|
||||
### `filtered pool cluster`
|
||||
|
0
lib/pool-base.js
Normal file
0
lib/pool-base.js
Normal file
@ -139,6 +139,36 @@ describe('Pool', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('undefined query', async function () {
|
||||
const pool = base.createPool({ connectionLimit: 1 });
|
||||
try {
|
||||
await pool.query(undefined);
|
||||
throw new Error('must have thrown an error');
|
||||
} catch (err) {
|
||||
assert(err.message.includes('sql parameter is mandatory'));
|
||||
assert.equal(err.sqlState, 'HY000');
|
||||
assert.equal(err.errno, 45049);
|
||||
assert.equal(err.code, 'ER_POOL_UNDEFINED_SQL');
|
||||
} finally {
|
||||
await pool.end();
|
||||
}
|
||||
});
|
||||
|
||||
it('undefined batch', async function () {
|
||||
const pool = base.createPool({ connectionLimit: 1 });
|
||||
try {
|
||||
await pool.batch(undefined);
|
||||
throw new Error('must have thrown an error');
|
||||
} catch (err) {
|
||||
assert(err.message.includes('sql parameter is mandatory'));
|
||||
assert.equal(err.sqlState, 'HY000');
|
||||
assert.equal(err.errno, 45049);
|
||||
assert.equal(err.code, 'ER_POOL_UNDEFINED_SQL');
|
||||
} finally {
|
||||
await pool.end();
|
||||
}
|
||||
});
|
||||
|
||||
it('query with null placeholder', async function () {
|
||||
const pool = base.createPool({ connectionLimit: 1 });
|
||||
let rows = await pool.query('select ? as a', [null]);
|
||||
@ -212,8 +242,14 @@ describe('Pool', () => {
|
||||
});
|
||||
|
||||
it('pool with wrong authentication connection', async function () {
|
||||
if (process.env.srv === 'maxscale' || process.env.srv === 'skysql' || process.env.srv === 'skysql-ha') this.skip();
|
||||
if (
|
||||
process.env.srv === 'maxscale' ||
|
||||
process.env.srv === 'skysql' ||
|
||||
process.env.srv === 'skysql-ha'
|
||||
)
|
||||
this.skip();
|
||||
this.timeout(10000);
|
||||
let err;
|
||||
let pool;
|
||||
try {
|
||||
pool = base.createPool({
|
||||
@ -252,29 +288,26 @@ describe('Pool', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('create pool', function (done) {
|
||||
if (process.env.srv === 'maxscale' || process.env.srv === 'skysql' || process.env.srv === 'skysql-ha') this.skip();
|
||||
it('create pool', async function () {
|
||||
if (
|
||||
process.env.srv === 'maxscale' ||
|
||||
process.env.srv === 'skysql' ||
|
||||
process.env.srv === 'skysql-ha'
|
||||
)
|
||||
this.skip();
|
||||
this.timeout(5000);
|
||||
const pool = base.createPool({ connectionLimit: 1 });
|
||||
const initTime = Date.now();
|
||||
pool.getConnection().then((conn) => {
|
||||
conn.query('SELECT SLEEP(1)').then(() => {
|
||||
conn.release();
|
||||
});
|
||||
});
|
||||
pool.getConnection().then((conn) => {
|
||||
conn
|
||||
.query('SELECT SLEEP(1)')
|
||||
.then(() => {
|
||||
const time = Date.now() - initTime;
|
||||
assert(time >= 1980, 'expected > 2s, but was ' + time);
|
||||
conn.release();
|
||||
return pool.end();
|
||||
})
|
||||
.then(() => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
let conn = await pool.getConnection();
|
||||
await conn.query('SELECT SLEEP(1)');
|
||||
conn.release();
|
||||
|
||||
await pool.getConnection();
|
||||
await conn.query('SELECT SLEEP(1)');
|
||||
const time = Date.now() - initTime;
|
||||
assert(time >= 1980, 'expected > 2s, but was ' + time);
|
||||
conn.release();
|
||||
await pool.end();
|
||||
});
|
||||
|
||||
it('pool execute', async function () {
|
||||
|
2
types/index.d.ts
vendored
2
types/index.d.ts
vendored
@ -743,6 +743,8 @@ export interface PoolCluster {
|
||||
of(pattern: undefined | null | false, selector: string): FilteredPoolCluster;
|
||||
remove(pattern: string): void;
|
||||
getConnection(pattern?: string, selector?: string): Promise<PoolConnection>;
|
||||
|
||||
on(ev: 'remove', callback: (nodekey: string) => void): PoolCluster
|
||||
}
|
||||
|
||||
export interface UpsertResult {
|
||||
|
Reference in New Issue
Block a user