oceanbase 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/License +19 -0
- package/README.md +250 -0
- package/index.d.ts +1 -0
- package/index.js +77 -0
- package/lib/auth_41.js +95 -0
- package/lib/auth_plugins/caching_sha2_password.js +108 -0
- package/lib/auth_plugins/caching_sha2_password.md +18 -0
- package/lib/auth_plugins/index.js +8 -0
- package/lib/auth_plugins/mysql_clear_password.js +17 -0
- package/lib/auth_plugins/mysql_native_password.js +34 -0
- package/lib/auth_plugins/sha256_password.js +68 -0
- package/lib/base/connection.js +978 -0
- package/lib/base/pool.js +237 -0
- package/lib/base/pool_connection.js +70 -0
- package/lib/commands/auth_switch.js +111 -0
- package/lib/commands/binlog_dump.js +109 -0
- package/lib/commands/change_user.js +68 -0
- package/lib/commands/client_handshake.js +241 -0
- package/lib/commands/close_statement.js +18 -0
- package/lib/commands/command.js +54 -0
- package/lib/commands/execute.js +112 -0
- package/lib/commands/index.js +27 -0
- package/lib/commands/ping.js +36 -0
- package/lib/commands/prepare.js +143 -0
- package/lib/commands/query.js +366 -0
- package/lib/commands/quit.js +29 -0
- package/lib/commands/register_slave.js +27 -0
- package/lib/commands/server_handshake.js +203 -0
- package/lib/compressed_protocol.js +127 -0
- package/lib/connection.js +12 -0
- package/lib/connection_config.js +326 -0
- package/lib/constants/charset_encodings.js +316 -0
- package/lib/constants/charsets.js +317 -0
- package/lib/constants/client.js +40 -0
- package/lib/constants/commands.js +36 -0
- package/lib/constants/cursor.js +8 -0
- package/lib/constants/encoding_charset.js +50 -0
- package/lib/constants/errors.js +3973 -0
- package/lib/constants/field_flags.js +20 -0
- package/lib/constants/server_status.js +44 -0
- package/lib/constants/session_track.js +11 -0
- package/lib/constants/ssl_profiles.js +11 -0
- package/lib/constants/types.js +64 -0
- package/lib/create_connection.js +10 -0
- package/lib/create_pool.js +10 -0
- package/lib/create_pool_cluster.js +9 -0
- package/lib/helpers.js +86 -0
- package/lib/packet_parser.js +195 -0
- package/lib/packets/auth_next_factor.js +35 -0
- package/lib/packets/auth_switch_request.js +38 -0
- package/lib/packets/auth_switch_request_more_data.js +33 -0
- package/lib/packets/auth_switch_response.js +30 -0
- package/lib/packets/binary_row.js +95 -0
- package/lib/packets/binlog_dump.js +33 -0
- package/lib/packets/binlog_query_statusvars.js +115 -0
- package/lib/packets/change_user.js +97 -0
- package/lib/packets/close_statement.js +21 -0
- package/lib/packets/column_definition.js +291 -0
- package/lib/packets/execute.js +214 -0
- package/lib/packets/handshake.js +112 -0
- package/lib/packets/handshake_response.js +144 -0
- package/lib/packets/index.js +152 -0
- package/lib/packets/packet.js +931 -0
- package/lib/packets/prepare_statement.js +27 -0
- package/lib/packets/prepared_statement_header.js +16 -0
- package/lib/packets/query.js +27 -0
- package/lib/packets/register_slave.js +46 -0
- package/lib/packets/resultset_header.js +124 -0
- package/lib/packets/ssl_request.js +25 -0
- package/lib/packets/text_row.js +47 -0
- package/lib/parsers/binary_parser.js +235 -0
- package/lib/parsers/parser_cache.js +68 -0
- package/lib/parsers/static_binary_parser.js +213 -0
- package/lib/parsers/static_text_parser.js +152 -0
- package/lib/parsers/string.js +50 -0
- package/lib/parsers/text_parser.js +214 -0
- package/lib/pool.js +12 -0
- package/lib/pool_cluster.js +369 -0
- package/lib/pool_config.js +30 -0
- package/lib/pool_connection.js +12 -0
- package/lib/promise/connection.js +222 -0
- package/lib/promise/inherit_events.js +27 -0
- package/lib/promise/make_done_cb.js +19 -0
- package/lib/promise/pool.js +112 -0
- package/lib/promise/pool_cluster.js +54 -0
- package/lib/promise/pool_connection.js +19 -0
- package/lib/promise/prepared_statement_info.js +32 -0
- package/lib/results_stream.js +38 -0
- package/lib/server.js +37 -0
- package/package.json +80 -0
- package/promise.d.ts +131 -0
- package/promise.js +202 -0
- package/typings/mysql/LICENSE.txt +15 -0
- package/typings/mysql/index.d.ts +95 -0
- package/typings/mysql/info.txt +1 -0
- package/typings/mysql/lib/Auth.d.ts +30 -0
- package/typings/mysql/lib/Connection.d.ts +453 -0
- package/typings/mysql/lib/Pool.d.ts +69 -0
- package/typings/mysql/lib/PoolCluster.d.ts +90 -0
- package/typings/mysql/lib/PoolConnection.d.ts +10 -0
- package/typings/mysql/lib/Server.d.ts +11 -0
- package/typings/mysql/lib/constants/CharsetToEncoding.d.ts +8 -0
- package/typings/mysql/lib/constants/Charsets.d.ts +326 -0
- package/typings/mysql/lib/constants/Types.d.ts +70 -0
- package/typings/mysql/lib/constants/index.d.ts +5 -0
- package/typings/mysql/lib/parsers/ParserCache.d.ts +4 -0
- package/typings/mysql/lib/parsers/index.d.ts +18 -0
- package/typings/mysql/lib/parsers/typeCast.d.ts +54 -0
- package/typings/mysql/lib/protocol/packets/Field.d.ts +10 -0
- package/typings/mysql/lib/protocol/packets/FieldPacket.d.ts +27 -0
- package/typings/mysql/lib/protocol/packets/OkPacket.d.ts +23 -0
- package/typings/mysql/lib/protocol/packets/ProcedurePacket.d.ts +13 -0
- package/typings/mysql/lib/protocol/packets/ResultSetHeader.d.ts +18 -0
- package/typings/mysql/lib/protocol/packets/RowDataPacket.d.ts +9 -0
- package/typings/mysql/lib/protocol/packets/index.d.ts +28 -0
- package/typings/mysql/lib/protocol/packets/params/ErrorPacketParams.d.ts +6 -0
- package/typings/mysql/lib/protocol/packets/params/OkPacketParams.d.ts +9 -0
- package/typings/mysql/lib/protocol/sequences/ExecutableBase.d.ts +40 -0
- package/typings/mysql/lib/protocol/sequences/Prepare.d.ts +65 -0
- package/typings/mysql/lib/protocol/sequences/Query.d.ts +170 -0
- package/typings/mysql/lib/protocol/sequences/QueryableBase.d.ts +40 -0
- package/typings/mysql/lib/protocol/sequences/Sequence.d.ts +5 -0
- package/typings/mysql/lib/protocol/sequences/promise/ExecutableBase.d.ts +21 -0
- package/typings/mysql/lib/protocol/sequences/promise/QueryableBase.d.ts +21 -0
package/License
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2016 Andrey Sidorov (sidorares@yandex.ru) and contributors
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
|
11
|
+
all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
[npm-image]: https://img.shields.io/npm/v/oceanbase.svg
|
|
2
|
+
[npm-url]: https://npmjs.com/package/oceanbase
|
|
3
|
+
[node-version-image]: https://img.shields.io/node/v/oceanbase.svg
|
|
4
|
+
[node-version-url]: https://nodejs.org/en/download
|
|
5
|
+
[downloads-image]: https://img.shields.io/npm/dm/oceanbase.svg
|
|
6
|
+
[downloads-url]: https://npmjs.com/package/oceanbase
|
|
7
|
+
[license-url]: https://github.com/sidorares/node-mysql2/blob/master/License
|
|
8
|
+
[license-image]: https://img.shields.io/npm/l/oceanbase.svg?maxAge=2592000
|
|
9
|
+
[node-mysql]: https://github.com/mysqljs/mysql
|
|
10
|
+
[mysqljs]: https://github.com/mysqljs
|
|
11
|
+
[mysql-native]: https://github.com/sidorares/nodejs-mysql-native
|
|
12
|
+
[sidorares]: https://github.com/sidorares
|
|
13
|
+
[TooTallNate]: https://gist.github.com/TooTallNate
|
|
14
|
+
[starttls.js]: https://gist.github.com/TooTallNate/848444
|
|
15
|
+
[node-mariasql]: https://github.com/mscdex/node-mariasql
|
|
16
|
+
[contributors]: https://github.com/sidorares/node-mysql2/graphs/contributors
|
|
17
|
+
[contributing]: https://github.com/sidorares/node-mysql2/blob/master/Contributing.md
|
|
18
|
+
[docs-base]: https://sidorares.github.io/node-mysql2/docs
|
|
19
|
+
[docs-base-zh-CN]: https://sidorares.github.io/node-mysql2/zh-CN/docs
|
|
20
|
+
[docs-base-pt-BR]: https://sidorares.github.io/node-mysql2/pt-BR/docs
|
|
21
|
+
[docs-prepared-statements]: https://sidorares.github.io/node-mysql2/docs/documentation/prepared-statements
|
|
22
|
+
[docs-mysql-server]: https://sidorares.github.io/node-mysql2/docs/documentation/mysql-server
|
|
23
|
+
[docs-promise-wrapper]: https://sidorares.github.io/node-mysql2/docs/documentation/promise-wrapper
|
|
24
|
+
[docs-authentication-switch]: https://sidorares.github.io/node-mysql2/docs/documentation/authentication-switch
|
|
25
|
+
[docs-streams]: https://sidorares.github.io/node-mysql2/docs/documentation/extras
|
|
26
|
+
[docs-typescript-docs]: https://sidorares.github.io/node-mysql2/docs/documentation/typescript-examples
|
|
27
|
+
[docs-qs-pooling]: https://sidorares.github.io/node-mysql2/docs#using-connection-pools
|
|
28
|
+
[docs-qs-first-query]: https://sidorares.github.io/node-mysql2/docs#first-query
|
|
29
|
+
[docs-qs-using-prepared-statements]: https://sidorares.github.io/node-mysql2/docs#using-prepared-statements
|
|
30
|
+
[docs-examples]: https://sidorares.github.io/node-mysql2/docs/examples
|
|
31
|
+
[docs-faq]: https://sidorares.github.io/node-mysql2/docs/faq
|
|
32
|
+
[docs-documentation]: https://sidorares.github.io/node-mysql2/docs/documentation
|
|
33
|
+
[docs-contributing]: https://sidorares.github.io/node-mysql2/docs/contributing/website
|
|
34
|
+
[coverage]: https://img.shields.io/codecov/c/github/sidorares/node-mysql2
|
|
35
|
+
[coverage-url]: https://app.codecov.io/github/sidorares/node-mysql2
|
|
36
|
+
[ci-url]: https://github.com/sidorares/node-mysql2/actions/workflows/ci-coverage.yml?query=branch%3Amaster
|
|
37
|
+
[ci-image]: https://img.shields.io/github/actions/workflow/status/sidorares/node-mysql2/ci-coverage.yml?event=push&style=flat&label=CI&branch=master
|
|
38
|
+
|
|
39
|
+
# OceanBase Driver for Node.js
|
|
40
|
+
|
|
41
|
+
[![NPM Version][npm-image]][npm-url]
|
|
42
|
+
[![NPM Downloads][downloads-image]][downloads-url]
|
|
43
|
+
[![Node.js Version][node-version-image]][node-version-url]
|
|
44
|
+
[![GitHub Workflow Status (with event)][ci-image]][ci-url]
|
|
45
|
+
[![Codecov][coverage]][coverage-url]
|
|
46
|
+
[![License][license-image]][license-url]
|
|
47
|
+
|
|
48
|
+
> High-performance OceanBase database client driver built on top of [MySQL2][node-mysql]. Fully compatible with MySQL protocol, with additional support for OceanBase Oracle tenant protocol. Supports prepared statements, non-utf8 encodings, binary log protocol, compression, SSL and [much more][docs-documentation].
|
|
49
|
+
|
|
50
|
+
**Table of Contents**
|
|
51
|
+
|
|
52
|
+
- [About This Driver](#about-this-driver)
|
|
53
|
+
- [Key Features](#key-features)
|
|
54
|
+
- [Installation](#installation)
|
|
55
|
+
- [Quick Start](#quick-start)
|
|
56
|
+
- [Documentation](#documentation)
|
|
57
|
+
- [Acknowledgements](#acknowledgements)
|
|
58
|
+
- [Contributing](#contributing)
|
|
59
|
+
|
|
60
|
+
## About This Driver
|
|
61
|
+
|
|
62
|
+
This driver is built on top of the [MySQL2][node-mysql] project, extending support for OceanBase database while maintaining all MySQL2 functionality.
|
|
63
|
+
|
|
64
|
+
**OceanBase** is a distributed relational database that is fully compatible with MySQL protocol. This driver extends the MySQL protocol with additional support for **OceanBase Oracle tenant protocol**, enabling you to:
|
|
65
|
+
|
|
66
|
+
- Connect to OceanBase MySQL tenants using MySQL mode
|
|
67
|
+
- Connect to OceanBase Oracle tenants using Oracle mode
|
|
68
|
+
- Seamlessly migrate existing MySQL2 code without API changes
|
|
69
|
+
|
|
70
|
+
This driver is fully API compatible with [MySQL2][node-mysql], and you can directly refer to the [MySQL2 official documentation][docs-documentation] for usage.
|
|
71
|
+
|
|
72
|
+
## Key Features
|
|
73
|
+
|
|
74
|
+
### OceanBase-Specific Features
|
|
75
|
+
|
|
76
|
+
- ✅ **OceanBase MySQL Tenant Support** - Fully compatible with MySQL protocol
|
|
77
|
+
- ✅ **OceanBase Oracle Tenant Support** - Enable Oracle compatibility mode via `mode: 'oracle'` option
|
|
78
|
+
- ✅ **Dual Mode Support** - Single driver supports both MySQL and Oracle modes
|
|
79
|
+
|
|
80
|
+
### MySQL2 Original Features
|
|
81
|
+
|
|
82
|
+
- ⚡ **Faster / Better Performance** - Optimized performance
|
|
83
|
+
- 📝 **[Prepared Statements][docs-prepared-statements]** - Support for prepared statements, improving performance and security
|
|
84
|
+
- 📊 **MySQL Binary Log Protocol** - Support for binary log parsing
|
|
85
|
+
- 🖥️ **[MySQL Server][docs-mysql-server]** - Can create MySQL-compatible servers
|
|
86
|
+
- 🌐 **Extended support for Encoding and Collation** - Support for multiple character sets and collations
|
|
87
|
+
- 🔄 **[Promise Wrapper][docs-promise-wrapper]** - Native Promise support
|
|
88
|
+
- 🗜️ **Compression** - Support for connection compression
|
|
89
|
+
- 🔒 **SSL and [Authentication Switch][docs-authentication-switch]** - Support for SSL connections and multiple authentication methods
|
|
90
|
+
- 🌊 **[Custom Streams][docs-streams]** - Support for custom data streams
|
|
91
|
+
- 💧 **[Connection Pooling][docs-qs-pooling]** - Built-in connection pool management
|
|
92
|
+
|
|
93
|
+
## Installation
|
|
94
|
+
|
|
95
|
+
This driver is free from native bindings and can be installed on Linux, Mac OS or Windows without any issues.
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
npm install --save oceanbase
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
## Quick Start
|
|
103
|
+
|
|
104
|
+
### Connecting to OceanBase MySQL Tenant
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
const oceanbase = require('oceanbase');
|
|
108
|
+
|
|
109
|
+
const connection = oceanbase.createConnection({
|
|
110
|
+
host: 'localhost',
|
|
111
|
+
user: 'root',
|
|
112
|
+
password: 'password',
|
|
113
|
+
database: 'test'
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
connection.query('SELECT * FROM users', (err, results) => {
|
|
117
|
+
if (err) throw err;
|
|
118
|
+
console.log(results);
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Connecting to OceanBase Oracle Tenant
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
const oceanbase = require('oceanbase');
|
|
126
|
+
|
|
127
|
+
// Use mode: 'oracle' option to enable Oracle mode
|
|
128
|
+
const connection = oceanbase.createConnection({
|
|
129
|
+
host: 'localhost',
|
|
130
|
+
user: 'oracle_user',
|
|
131
|
+
password: 'password',
|
|
132
|
+
database: 'oracle_db',
|
|
133
|
+
mode: 'oracle' // Key: Enable Oracle tenant mode
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
connection.query('SELECT * FROM users', (err, results) => {
|
|
137
|
+
if (err) throw err;
|
|
138
|
+
console.log(results);
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Connecting with Tenant and Cluster
|
|
143
|
+
|
|
144
|
+
OceanBase supports cluster and tenant fields. When connecting, you can specify `tenant` and `cluster` options, and the driver will automatically format the username as `username@tenant#cluster`:
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
const oceanbase = require('oceanbase');
|
|
148
|
+
|
|
149
|
+
// Using tenant and cluster options
|
|
150
|
+
const connection = oceanbase.createConnection({
|
|
151
|
+
host: 'localhost',
|
|
152
|
+
user: 'myuser',
|
|
153
|
+
password: 'password',
|
|
154
|
+
database: 'mydb',
|
|
155
|
+
tenant: 'mytenant', // Tenant name
|
|
156
|
+
cluster: 'mycluster' // Cluster name
|
|
157
|
+
// Username will be automatically formatted as: myuser@mytenant#mycluster
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// You can also use URL query parameters
|
|
161
|
+
const connection2 = oceanbase.createConnection({
|
|
162
|
+
uri: 'mysql://myuser:password@localhost:3306/mydb?tenant=mytenant&cluster=mycluster'
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// If username already contains @ or #, it will be used as-is
|
|
166
|
+
const connection3 = oceanbase.createConnection({
|
|
167
|
+
host: 'localhost',
|
|
168
|
+
user: 'myuser@mytenant#mycluster', // Already formatted
|
|
169
|
+
password: 'password',
|
|
170
|
+
database: 'mydb'
|
|
171
|
+
// tenant and cluster options will be ignored if username is already formatted
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Using Connection Pool (Oracle Mode)
|
|
176
|
+
|
|
177
|
+
```javascript
|
|
178
|
+
const oceanbase = require('oceanbase');
|
|
179
|
+
|
|
180
|
+
const pool = oceanbase.createPool({
|
|
181
|
+
host: 'localhost',
|
|
182
|
+
user: 'oracle_user',
|
|
183
|
+
password: 'password',
|
|
184
|
+
database: 'oracle_db',
|
|
185
|
+
mode: 'oracle' // Oracle tenant mode
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
pool.query('SELECT * FROM users', (err, results) => {
|
|
189
|
+
if (err) throw err;
|
|
190
|
+
console.log(results);
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Using Promise API
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
const oceanbase = require('oceanbase/promise');
|
|
198
|
+
|
|
199
|
+
async function queryData() {
|
|
200
|
+
const connection = await oceanbase.createConnection({
|
|
201
|
+
host: 'localhost',
|
|
202
|
+
user: 'root',
|
|
203
|
+
password: 'password',
|
|
204
|
+
database: 'test',
|
|
205
|
+
mode: 'oracle' // Optional: Oracle mode
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
const [rows] = await connection.execute('SELECT * FROM users WHERE id = ?', [1]);
|
|
209
|
+
console.log(rows);
|
|
210
|
+
|
|
211
|
+
await connection.end();
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Documentation
|
|
216
|
+
|
|
217
|
+
This driver's usage documentation is fully compatible with [MySQL2][node-mysql]. You can refer to the following MySQL2 official documentation:
|
|
218
|
+
|
|
219
|
+
- [Quickstart][docs-base]
|
|
220
|
+
- [First Query][docs-qs-first-query], [Using Prepared Statements][docs-qs-using-prepared-statements], [Using Connection Pools][docs-qs-pooling] and more.
|
|
221
|
+
- [Documentation][docs-documentation]
|
|
222
|
+
- [Examples][docs-examples]
|
|
223
|
+
- [FAQ][docs-faq]
|
|
224
|
+
|
|
225
|
+
### Oracle Mode Notes
|
|
226
|
+
|
|
227
|
+
When connecting to OceanBase Oracle tenants, you need to add the `mode: 'oracle'` option to your connection configuration:
|
|
228
|
+
|
|
229
|
+
```javascript
|
|
230
|
+
{
|
|
231
|
+
host: 'your-host',
|
|
232
|
+
user: 'your-user',
|
|
233
|
+
password: 'your-password',
|
|
234
|
+
database: 'your-database',
|
|
235
|
+
mode: 'oracle' // Enable Oracle tenant mode
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
When `mode` is not specified or set to `mode: 'mysql'`, the standard MySQL protocol will be used (suitable for MySQL tenants).
|
|
240
|
+
|
|
241
|
+
### Tenant and Cluster Configuration
|
|
242
|
+
|
|
243
|
+
OceanBase supports multi-tenant architecture with cluster and tenant concepts. The driver automatically formats usernames when `tenant` and/or `cluster` options are provided:
|
|
244
|
+
|
|
245
|
+
- **`tenant`** (optional): The tenant name. When provided, username will be formatted as `username@tenant`
|
|
246
|
+
- **`cluster`** (optional): The cluster name. When provided, username will be formatted as `username@tenant#cluster` (if tenant is also provided) or `username#cluster` (if only cluster is provided)
|
|
247
|
+
|
|
248
|
+
**Note**: If the username already contains `@` or `#` characters, the driver will use it as-is and ignore the `tenant` and `cluster` options to avoid duplicate formatting.
|
|
249
|
+
|
|
250
|
+
|
package/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './typings/mysql/index.js';
|
package/index.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const SqlString = require('sqlstring');
|
|
4
|
+
|
|
5
|
+
const ConnectionConfig = require('./lib/connection_config.js');
|
|
6
|
+
const parserCache = require('./lib/parsers/parser_cache.js');
|
|
7
|
+
|
|
8
|
+
const Connection = require('./lib/connection.js');
|
|
9
|
+
|
|
10
|
+
exports.createConnection = require('./lib/create_connection.js');
|
|
11
|
+
exports.connect = exports.createConnection;
|
|
12
|
+
exports.Connection = Connection;
|
|
13
|
+
exports.ConnectionConfig = ConnectionConfig;
|
|
14
|
+
|
|
15
|
+
const Pool = require('./lib/pool.js');
|
|
16
|
+
const PoolCluster = require('./lib/pool_cluster.js');
|
|
17
|
+
const createPool = require('./lib/create_pool.js');
|
|
18
|
+
const createPoolCluster = require('./lib/create_pool_cluster.js');
|
|
19
|
+
|
|
20
|
+
exports.createPool = createPool;
|
|
21
|
+
|
|
22
|
+
exports.createPoolCluster = createPoolCluster;
|
|
23
|
+
|
|
24
|
+
exports.createQuery = Connection.createQuery;
|
|
25
|
+
|
|
26
|
+
exports.Pool = Pool;
|
|
27
|
+
|
|
28
|
+
exports.PoolCluster = PoolCluster;
|
|
29
|
+
|
|
30
|
+
exports.createServer = function (handler) {
|
|
31
|
+
const Server = require('./lib/server.js');
|
|
32
|
+
const s = new Server();
|
|
33
|
+
if (handler) {
|
|
34
|
+
s.on('connection', handler);
|
|
35
|
+
}
|
|
36
|
+
return s;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
exports.PoolConnection = require('./lib/pool_connection.js');
|
|
40
|
+
exports.authPlugins = require('./lib/auth_plugins');
|
|
41
|
+
exports.escape = SqlString.escape;
|
|
42
|
+
exports.escapeId = SqlString.escapeId;
|
|
43
|
+
exports.format = SqlString.format;
|
|
44
|
+
exports.raw = SqlString.raw;
|
|
45
|
+
|
|
46
|
+
exports.__defineGetter__(
|
|
47
|
+
'createConnectionPromise',
|
|
48
|
+
() => require('./promise.js').createConnection
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
exports.__defineGetter__(
|
|
52
|
+
'createPoolPromise',
|
|
53
|
+
() => require('./promise.js').createPool
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
exports.__defineGetter__(
|
|
57
|
+
'createPoolClusterPromise',
|
|
58
|
+
() => require('./promise.js').createPoolCluster
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
exports.__defineGetter__('Types', () => require('./lib/constants/types.js'));
|
|
62
|
+
|
|
63
|
+
exports.__defineGetter__('Charsets', () =>
|
|
64
|
+
require('./lib/constants/charsets.js')
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
exports.__defineGetter__('CharsetToEncoding', () =>
|
|
68
|
+
require('./lib/constants/charset_encodings.js')
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
exports.setMaxParserCache = function (max) {
|
|
72
|
+
parserCache.setMaxCache(max);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
exports.clearParserCache = function () {
|
|
76
|
+
parserCache.clearCache();
|
|
77
|
+
};
|
package/lib/auth_41.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
4.1 authentication: (http://bazaar.launchpad.net/~mysql/mysql-server/5.5/view/head:/sql/password.c)
|
|
5
|
+
|
|
6
|
+
SERVER: public_seed=create_random_string()
|
|
7
|
+
send(public_seed)
|
|
8
|
+
|
|
9
|
+
CLIENT: recv(public_seed)
|
|
10
|
+
hash_stage1=sha1("password")
|
|
11
|
+
hash_stage2=sha1(hash_stage1)
|
|
12
|
+
reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
|
|
13
|
+
|
|
14
|
+
// this three steps are done in scramble()
|
|
15
|
+
|
|
16
|
+
send(reply)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
SERVER: recv(reply)
|
|
20
|
+
hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
|
|
21
|
+
candidate_hash2=sha1(hash_stage1)
|
|
22
|
+
check(candidate_hash2==hash_stage2)
|
|
23
|
+
|
|
24
|
+
server stores sha1(sha1(password)) ( hash_stag2)
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const crypto = require('crypto');
|
|
28
|
+
|
|
29
|
+
function sha1(msg, msg1, msg2) {
|
|
30
|
+
const hash = crypto.createHash('sha1');
|
|
31
|
+
hash.update(msg);
|
|
32
|
+
if (msg1) {
|
|
33
|
+
hash.update(msg1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (msg2) {
|
|
37
|
+
hash.update(msg2);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return hash.digest();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function xor(a, b) {
|
|
44
|
+
const result = Buffer.allocUnsafe(a.length);
|
|
45
|
+
for (let i = 0; i < a.length; i++) {
|
|
46
|
+
result[i] = a[i] ^ b[i];
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
exports.xor = xor;
|
|
52
|
+
|
|
53
|
+
function token(password, scramble1, scramble2) {
|
|
54
|
+
if (!password) {
|
|
55
|
+
return Buffer.alloc(0);
|
|
56
|
+
}
|
|
57
|
+
const stage1 = sha1(password);
|
|
58
|
+
return exports.calculateTokenFromPasswordSha(stage1, scramble1, scramble2);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
exports.calculateTokenFromPasswordSha = function (
|
|
62
|
+
passwordSha,
|
|
63
|
+
scramble1,
|
|
64
|
+
scramble2
|
|
65
|
+
) {
|
|
66
|
+
// we use AUTH 41 here, and we need only the bytes we just need.
|
|
67
|
+
const authPluginData1 = scramble1.slice(0, 8);
|
|
68
|
+
const authPluginData2 = scramble2.slice(0, 12);
|
|
69
|
+
const stage2 = sha1(passwordSha);
|
|
70
|
+
const stage3 = sha1(authPluginData1, authPluginData2, stage2);
|
|
71
|
+
return xor(stage3, passwordSha);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
exports.calculateToken = token;
|
|
75
|
+
|
|
76
|
+
exports.verifyToken = function (publicSeed1, publicSeed2, token, doubleSha) {
|
|
77
|
+
const hashStage1 = xor(token, sha1(publicSeed1, publicSeed2, doubleSha));
|
|
78
|
+
const candidateHash2 = sha1(hashStage1);
|
|
79
|
+
return candidateHash2.compare(doubleSha) === 0;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
exports.doubleSha1 = function (password) {
|
|
83
|
+
return sha1(sha1(password));
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
function xorRotating(a, seed) {
|
|
87
|
+
const result = Buffer.allocUnsafe(a.length);
|
|
88
|
+
const seedLen = seed.length;
|
|
89
|
+
|
|
90
|
+
for (let i = 0; i < a.length; i++) {
|
|
91
|
+
result[i] = a[i] ^ seed[i % seedLen];
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
exports.xorRotating = xorRotating;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// https://mysqlserverteam.com/mysql-8-0-4-new-default-authentication-plugin-caching_sha2_password/
|
|
4
|
+
|
|
5
|
+
const PLUGIN_NAME = 'caching_sha2_password';
|
|
6
|
+
const crypto = require('crypto');
|
|
7
|
+
const { xor, xorRotating } = require('../auth_41');
|
|
8
|
+
|
|
9
|
+
const REQUEST_SERVER_KEY_PACKET = Buffer.from([2]);
|
|
10
|
+
const FAST_AUTH_SUCCESS_PACKET = Buffer.from([3]);
|
|
11
|
+
const PERFORM_FULL_AUTHENTICATION_PACKET = Buffer.from([4]);
|
|
12
|
+
|
|
13
|
+
const STATE_INITIAL = 0;
|
|
14
|
+
const STATE_TOKEN_SENT = 1;
|
|
15
|
+
const STATE_WAIT_SERVER_KEY = 2;
|
|
16
|
+
const STATE_FINAL = -1;
|
|
17
|
+
|
|
18
|
+
function sha256(msg) {
|
|
19
|
+
const hash = crypto.createHash('sha256');
|
|
20
|
+
hash.update(msg);
|
|
21
|
+
return hash.digest();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function calculateToken(password, scramble) {
|
|
25
|
+
if (!password) {
|
|
26
|
+
return Buffer.alloc(0);
|
|
27
|
+
}
|
|
28
|
+
const stage1 = sha256(Buffer.from(password));
|
|
29
|
+
const stage2 = sha256(stage1);
|
|
30
|
+
const stage3 = sha256(Buffer.concat([stage2, scramble]));
|
|
31
|
+
return xor(stage1, stage3);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function encrypt(password, scramble, key) {
|
|
35
|
+
const stage1 = xorRotating(Buffer.from(`${password}\0`, 'utf8'), scramble);
|
|
36
|
+
return crypto.publicEncrypt(
|
|
37
|
+
{
|
|
38
|
+
key,
|
|
39
|
+
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
|
|
40
|
+
},
|
|
41
|
+
stage1
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports =
|
|
46
|
+
(pluginOptions = {}) =>
|
|
47
|
+
({ connection }) => {
|
|
48
|
+
let state = 0;
|
|
49
|
+
let scramble = null;
|
|
50
|
+
|
|
51
|
+
const password = connection.config.password;
|
|
52
|
+
|
|
53
|
+
const authWithKey = (serverKey) => {
|
|
54
|
+
const _password = encrypt(password, scramble, serverKey);
|
|
55
|
+
state = STATE_FINAL;
|
|
56
|
+
return _password;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return (data) => {
|
|
60
|
+
switch (state) {
|
|
61
|
+
case STATE_INITIAL:
|
|
62
|
+
scramble = data.slice(0, 20);
|
|
63
|
+
state = STATE_TOKEN_SENT;
|
|
64
|
+
return calculateToken(password, scramble);
|
|
65
|
+
|
|
66
|
+
case STATE_TOKEN_SENT:
|
|
67
|
+
if (FAST_AUTH_SUCCESS_PACKET.equals(data)) {
|
|
68
|
+
state = STATE_FINAL;
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (PERFORM_FULL_AUTHENTICATION_PACKET.equals(data)) {
|
|
73
|
+
const isSecureConnection =
|
|
74
|
+
typeof pluginOptions.overrideIsSecure === 'undefined'
|
|
75
|
+
? connection.config.ssl || connection.config.socketPath
|
|
76
|
+
: pluginOptions.overrideIsSecure;
|
|
77
|
+
if (isSecureConnection) {
|
|
78
|
+
state = STATE_FINAL;
|
|
79
|
+
return Buffer.from(`${password}\0`, 'utf8');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// if client provides key we can save one extra roundrip on first connection
|
|
83
|
+
if (pluginOptions.serverPublicKey) {
|
|
84
|
+
return authWithKey(pluginOptions.serverPublicKey);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
state = STATE_WAIT_SERVER_KEY;
|
|
88
|
+
return REQUEST_SERVER_KEY_PACKET;
|
|
89
|
+
}
|
|
90
|
+
throw new Error(
|
|
91
|
+
`Invalid AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_TOKEN_SENT state.`
|
|
92
|
+
);
|
|
93
|
+
case STATE_WAIT_SERVER_KEY:
|
|
94
|
+
if (pluginOptions.onServerPublicKey) {
|
|
95
|
+
pluginOptions.onServerPublicKey(data);
|
|
96
|
+
}
|
|
97
|
+
return authWithKey(data);
|
|
98
|
+
case STATE_FINAL:
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_FINAL state.`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
throw new Error(
|
|
105
|
+
`Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in state ${state}`
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
##
|
|
2
|
+
|
|
3
|
+
https://dev.mysql.com/doc/refman/8.0/en/caching-sha2-pluggable-authentication.html
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
const mysql = require('mysql');
|
|
7
|
+
mysql.createConnection({
|
|
8
|
+
authPlugins: {
|
|
9
|
+
caching_sha2_password: mysql.authPlugins.caching_sha2_password({
|
|
10
|
+
onServerPublikKey: function (key) {
|
|
11
|
+
console.log(key);
|
|
12
|
+
},
|
|
13
|
+
serverPublicKey: 'xxxyyy',
|
|
14
|
+
overrideIsSecure: true, //
|
|
15
|
+
}),
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
```
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
caching_sha2_password: require('./caching_sha2_password'),
|
|
5
|
+
mysql_clear_password: require('./mysql_clear_password'),
|
|
6
|
+
mysql_native_password: require('./mysql_native_password'),
|
|
7
|
+
sha256_password: require('./sha256_password'),
|
|
8
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function bufferFromStr(str) {
|
|
4
|
+
return Buffer.from(`${str}\0`);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const create_mysql_clear_password_plugin = (pluginOptions) =>
|
|
8
|
+
function mysql_clear_password_plugin({ connection, command }) {
|
|
9
|
+
const password =
|
|
10
|
+
command.password || pluginOptions.password || connection.config.password;
|
|
11
|
+
|
|
12
|
+
return function (/* pluginData */) {
|
|
13
|
+
return bufferFromStr(password);
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
module.exports = create_mysql_clear_password_plugin;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
//const PLUGIN_NAME = 'mysql_native_password';
|
|
4
|
+
const auth41 = require('../auth_41.js');
|
|
5
|
+
|
|
6
|
+
module.exports =
|
|
7
|
+
(pluginOptions) =>
|
|
8
|
+
({ connection, command }) => {
|
|
9
|
+
const password =
|
|
10
|
+
command.password || pluginOptions.password || connection.config.password;
|
|
11
|
+
const passwordSha1 =
|
|
12
|
+
command.passwordSha1 ||
|
|
13
|
+
pluginOptions.passwordSha1 ||
|
|
14
|
+
connection.config.passwordSha1;
|
|
15
|
+
return (data) => {
|
|
16
|
+
const authPluginData1 = data.slice(0, 8);
|
|
17
|
+
const authPluginData2 = data.slice(8, 20);
|
|
18
|
+
let authToken;
|
|
19
|
+
if (passwordSha1) {
|
|
20
|
+
authToken = auth41.calculateTokenFromPasswordSha(
|
|
21
|
+
passwordSha1,
|
|
22
|
+
authPluginData1,
|
|
23
|
+
authPluginData2
|
|
24
|
+
);
|
|
25
|
+
} else {
|
|
26
|
+
authToken = auth41.calculateToken(
|
|
27
|
+
password,
|
|
28
|
+
authPluginData1,
|
|
29
|
+
authPluginData2
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return authToken;
|
|
33
|
+
};
|
|
34
|
+
};
|