├── .editorconfig ├── .gitattributes ├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── benchmark.yml │ ├── canary.yml │ ├── ci-coverage.yml │ ├── ci-linux.yml │ ├── ci-mysql.yml │ ├── ci-osx.yml │ ├── ci-tsc-build.yml │ ├── ci-website.yml │ ├── ci-windows.yml │ ├── codeql-analysis.yml │ ├── gh-pages.yml │ ├── lint.yml │ └── release.yml ├── .gitignore ├── .nycrc ├── .prettierignore ├── .prettierrc ├── CODE_OF_CONDUCT.md ├── Changelog.md ├── Contributing.md ├── License ├── README.md ├── SECURITY.md ├── benchmarks ├── bench-fake-server.js ├── bench-insert-select-parallel.js ├── bench-insert-select-prepared.js ├── bench-insert-select.js ├── benchmark-query.js ├── benchmark-server.js ├── benchmark.js ├── http-select-and-render.js ├── httperf.sh ├── index.html ├── integration │ └── fake-server-select.js ├── test-benchmark-select-1.js └── unit │ ├── fixtures │ ├── column_definition0 │ ├── column_definition1 │ ├── column_definition10 │ ├── column_definition11 │ ├── column_definition12 │ ├── column_definition13 │ ├── column_definition14 │ ├── column_definition15 │ ├── column_definition16 │ ├── column_definition17 │ ├── column_definition18 │ ├── column_definition19 │ ├── column_definition2 │ ├── column_definition20 │ ├── column_definition21 │ ├── column_definition22 │ ├── column_definition23 │ ├── column_definition24 │ ├── column_definition25 │ ├── column_definition26 │ ├── column_definition27 │ ├── column_definition28 │ ├── column_definition29 │ ├── column_definition3 │ ├── column_definition30 │ ├── column_definition31 │ ├── column_definition32 │ ├── column_definition33 │ ├── column_definition34 │ ├── column_definition35 │ ├── column_definition36 │ ├── column_definition37 │ ├── column_definition38 │ ├── column_definition39 │ ├── column_definition4 │ ├── column_definition40 │ ├── column_definition41 │ ├── column_definition42 │ ├── column_definition5 │ ├── column_definition6 │ ├── column_definition7 │ ├── column_definition8 │ └── column_definition9 │ ├── packet_parser.js │ └── packets │ └── column_definition.js ├── codecov.yml ├── eslint.config.mjs ├── fixtures └── mysql-ssl-ca-cert.pem ├── index.d.ts ├── index.js ├── lib ├── auth_41.js ├── auth_plugins │ ├── caching_sha2_password.js │ ├── caching_sha2_password.md │ ├── index.js │ ├── mysql_clear_password.js │ ├── mysql_native_password.js │ └── sha256_password.js ├── base │ ├── connection.js │ ├── pool.js │ └── pool_connection.js ├── commands │ ├── auth_switch.js │ ├── binlog_dump.js │ ├── change_user.js │ ├── client_handshake.js │ ├── close_statement.js │ ├── command.js │ ├── execute.js │ ├── index.js │ ├── ping.js │ ├── prepare.js │ ├── query.js │ ├── quit.js │ ├── register_slave.js │ └── server_handshake.js ├── compressed_protocol.js ├── connection.js ├── connection_config.js ├── constants │ ├── charset_encodings.js │ ├── charsets.js │ ├── client.js │ ├── commands.js │ ├── cursor.js │ ├── encoding_charset.js │ ├── errors.js │ ├── field_flags.js │ ├── server_status.js │ ├── session_track.js │ ├── ssl_profiles.js │ └── types.js ├── create_connection.js ├── create_pool.js ├── create_pool_cluster.js ├── helpers.js ├── packet_parser.js ├── packets │ ├── auth_next_factor.js │ ├── auth_switch_request.js │ ├── auth_switch_request_more_data.js │ ├── auth_switch_response.js │ ├── binary_row.js │ ├── binlog_dump.js │ ├── binlog_query_statusvars.js │ ├── change_user.js │ ├── close_statement.js │ ├── column_definition.js │ ├── execute.js │ ├── handshake.js │ ├── handshake_response.js │ ├── index.js │ ├── packet.js │ ├── prepare_statement.js │ ├── prepared_statement_header.js │ ├── query.js │ ├── register_slave.js │ ├── resultset_header.js │ ├── ssl_request.js │ └── text_row.js ├── parsers │ ├── binary_parser.js │ ├── parser_cache.js │ ├── static_binary_parser.js │ ├── static_text_parser.js │ ├── string.js │ └── text_parser.js ├── pool.js ├── pool_cluster.js ├── pool_config.js ├── pool_connection.js ├── promise │ ├── connection.js │ ├── inherit_events.js │ ├── make_done_cb.js │ ├── pool.js │ ├── pool_cluster.js │ ├── pool_connection.js │ └── prepared_statement_info.js ├── results_stream.js └── server.js ├── package-lock.json ├── package.json ├── promise.d.ts ├── promise.js ├── tea.yaml ├── test ├── common.test.cjs ├── esm │ ├── integration │ │ ├── connection │ │ │ ├── test-column-inspect.test.mjs │ │ │ ├── test-execute-1.test.mjs │ │ │ └── test-vector.test.mjs │ │ ├── named-placeholders.test.mjs │ │ ├── parsers │ │ │ ├── execute-results-creation.test.mjs │ │ │ ├── json-parse.test.mjs │ │ │ ├── json-string.test.mjs │ │ │ ├── query-results-creation.test.mjs │ │ │ └── typecast-field-string.test.mjs │ │ ├── pool-cluster │ │ │ └── test-promise-wrapper.test.mjs │ │ └── test-pool.test.mjs │ ├── regressions │ │ └── 2052.test.mjs │ └── unit │ │ ├── check-extensions.test.mjs │ │ ├── parsers │ │ ├── big-numbers-strings-binary-sanitization.test.mjs │ │ ├── big-numbers-strings-text-sanitization.test.mjs │ │ ├── cache-key-serialization.test.mjs │ │ ├── ensure-safe-binary-fields.test.mjs │ │ ├── ensure-safe-text-fields.test.mjs │ │ ├── support-big-numbers-binary-sanitization.test.mjs │ │ ├── support-big-numbers-text-sanitization.test.mjs │ │ ├── timezone-binary-sanitization.test.mjs │ │ └── timezone-text-sanitization.test.mjs │ │ └── protocol │ │ └── SqlString.test.mjs ├── fixtures │ ├── custom-conf │ │ └── config-file.cnf │ ├── data.csv │ └── ssl │ │ ├── certs │ │ ├── ca-key.pem │ │ ├── ca.pem │ │ ├── client-key.pem │ │ ├── mkcerts.sh │ │ ├── server-cert.pem │ │ ├── server-key.pem │ │ └── server-req.pem │ │ └── client-flags.sh ├── integration │ ├── config │ │ ├── test-connect-timeout.test.cjs │ │ ├── test-typecast-global-false.test.cjs │ │ └── test-typecast-global-option.test.cjs │ ├── connection │ │ ├── encoding │ │ │ ├── test-charset-results.test.cjs │ │ │ ├── test-client-encodings.test.cjs │ │ │ ├── test-non-bmp-chars.test.cjs │ │ │ └── test-track-encodings.test.cjs │ │ ├── test-binary-charset-string.test.cjs │ │ ├── test-binary-longlong.test.cjs │ │ ├── test-binary-multiple-results.test.cjs │ │ ├── test-binary-notnull-nulls.test.cjs │ │ ├── test-buffer-params.test.cjs │ │ ├── test-change-user-multi-factor.test.cjs │ │ ├── test-change-user-plugin-auth.test.cjs │ │ ├── test-change-user.test.cjs │ │ ├── test-charset-encoding.test.cjs │ │ ├── test-connect-after-connection-error.test.cjs │ │ ├── test-connect-after-connection.test.cjs │ │ ├── test-connect-connection-closed-error.test.cjs │ │ ├── test-connect-sha1.test.cjs │ │ ├── test-connect-time-error.test.cjs │ │ ├── test-connect-with-uri.test.cjs │ │ ├── test-connection-reset-while-closing.test.cjs │ │ ├── test-custom-date-parameter.test.cjs │ │ ├── test-date-parameter.test.cjs │ │ ├── test-datetime.test.cjs │ │ ├── test-decimals-as-numbers.test.cjs │ │ ├── test-disconnects.test.cjs │ │ ├── test-error-events.test.cjs │ │ ├── test-errors.test.cjs │ │ ├── test-execute-and-unprepare.test.cjs │ │ ├── test-execute-bind-boolean.test.cjs │ │ ├── test-execute-bind-date.test.cjs │ │ ├── test-execute-bind-function.test.cjs │ │ ├── test-execute-bind-json.test.cjs │ │ ├── test-execute-bind-null.test.cjs │ │ ├── test-execute-bind-number.test.cjs │ │ ├── test-execute-bind-undefined.test.cjs │ │ ├── test-execute-cached.test.cjs │ │ ├── test-execute-newdecimal.test.cjs │ │ ├── test-execute-nocolumndef.test.cjs │ │ ├── test-execute-null-bitmap.test.cjs │ │ ├── test-execute-order.test.cjs │ │ ├── test-execute-signed.test.cjs │ │ ├── test-execute-type-casting.test.cjs │ │ ├── test-insert-bigint-big-number-strings.test.cjs │ │ ├── test-insert-bigint.test.cjs │ │ ├── test-insert-json.test.cjs │ │ ├── test-insert-large-blob.test.cjs │ │ ├── test-insert-negative-ai.test.cjs │ │ ├── test-insert-results.test.cjs │ │ ├── test-invalid-date-result.test.cjs │ │ ├── test-load-infile.test.cjs │ │ ├── test-multiple-results.test.cjs │ │ ├── test-named-placeholders.test.cjs │ │ ├── test-nested-tables-query.test.cjs │ │ ├── test-null-buffer.test.cjs │ │ ├── test-null-double.test.cjs │ │ ├── test-null-int.test.cjs │ │ ├── test-null.test.cjs │ │ ├── test-parameters-questionmark.test.cjs │ │ ├── test-prepare-and-close.test.cjs │ │ ├── test-prepare-simple.test.cjs │ │ ├── test-prepare-then-execute.test.cjs │ │ ├── test-protocol-errors.test.cjs │ │ ├── test-query-timeout.test.cjs │ │ ├── test-query-zero.test.cjs │ │ ├── test-quit.test.cjs │ │ ├── test-select-1.test.cjs │ │ ├── test-select-empty-string.test.cjs │ │ ├── test-select-json.test.cjs │ │ ├── test-select-negative.test.cjs │ │ ├── test-select-ssl.test.cjs │ │ ├── test-select-utf8.test.cjs │ │ ├── test-server-listen.test.cjs │ │ ├── test-signed-tinyint.test.cjs │ │ ├── test-stream-errors.test.cjs │ │ ├── test-stream.test.cjs │ │ ├── test-then-on-query.test.cjs │ │ ├── test-timestamp.test.cjs │ │ ├── test-track-state-change.test.cjs │ │ ├── test-transaction-commit.test.cjs │ │ ├── test-transaction-rollback.test.cjs │ │ ├── test-type-cast-null-fields-execute.test.cjs │ │ ├── test-type-cast-null-fields.test.cjs │ │ ├── test-type-casting-execute.test.cjs │ │ ├── test-type-casting.test.cjs │ │ ├── test-typecast-execute.test.cjs │ │ ├── test-typecast-geometry-execute.test.cjs │ │ ├── test-typecast-geometry.test.cjs │ │ ├── test-typecast-overwriting-execute.test.cjs │ │ ├── test-typecast-overwriting.test.cjs │ │ ├── test-typecast.test.cjs │ │ ├── test-update-changed-rows.test.cjs │ │ └── type-casting-tests.test.cjs │ ├── promise-wrappers │ │ ├── test-async-stack.test.cjs │ │ └── test-promise-wrappers.test.cjs │ ├── regressions │ │ ├── test-#433.test.cjs │ │ ├── test-#442.test.cjs │ │ ├── test-#485.test.cjs │ │ ├── test-#617.test.cjs │ │ ├── test-#629.test.cjs │ │ └── test-#82.test.cjs │ ├── test-auth-switch-multi-factor.test.cjs │ ├── test-auth-switch-plugin-async-error.test.cjs │ ├── test-auth-switch-plugin-error.test.cjs │ ├── test-auth-switch.test.cjs │ ├── test-handshake-unknown-packet-error.test.cjs │ ├── test-multi-result-streaming.test.cjs │ ├── test-pool-connect-error.test.cjs │ ├── test-pool-disconnect.test.cjs │ ├── test-pool-end.test.cjs │ ├── test-pool-release-idle-connection-replicate.test.cjs │ ├── test-pool-release-idle-connection-timeout.test.cjs │ ├── test-pool-release-idle-connection.test.cjs │ ├── test-pool-release.test.cjs │ ├── test-rows-as-array.test.cjs │ └── test-server-close.test.cjs ├── tsc-build │ ├── helpers.test.ts │ ├── index.test.ts │ ├── mysql │ │ ├── baseConnection.test.ts │ │ ├── constants │ │ │ ├── CharsetToEncoding.test.ts │ │ │ ├── Charsets.test.ts │ │ │ └── Types.test.ts │ │ ├── createConnection │ │ │ ├── callbacks │ │ │ │ ├── execute.test.ts │ │ │ │ └── query.test.ts │ │ │ └── promise │ │ │ │ ├── execute.test.ts │ │ │ │ └── query.test.ts │ │ ├── createPool │ │ │ ├── callbacks │ │ │ │ ├── connection.test.ts │ │ │ │ ├── createPool.test.ts │ │ │ │ ├── execute.test.ts │ │ │ │ ├── getConnection.test.ts │ │ │ │ ├── query.test.ts │ │ │ │ ├── release.test.ts │ │ │ │ └── releaseConnection.test.ts │ │ │ └── promise │ │ │ │ ├── connection.test.ts │ │ │ │ ├── execute.test.ts │ │ │ │ ├── getConnection.test.ts │ │ │ │ ├── promise.test.ts │ │ │ │ ├── query.test.ts │ │ │ │ ├── release.test.ts │ │ │ │ └── releaseConnection.test.ts │ │ ├── createPoolCluster │ │ │ ├── add.test.ts │ │ │ ├── getConnection.test.ts │ │ │ ├── of │ │ │ │ ├── getConnection.test.ts │ │ │ │ └── of.test.ts │ │ │ └── remove.test.ts │ │ └── parsers │ │ │ ├── clearParserCache.test.ts │ │ │ └── setMaxParserCache.test.ts │ ├── promise │ │ ├── baseConnection.test.ts │ │ ├── constants │ │ │ ├── CharsetToEncoding.test.ts │ │ │ ├── Charsets.test.ts │ │ │ └── Types.test.ts │ │ ├── createConnection │ │ │ ├── execute.test.ts │ │ │ └── query.test.ts │ │ ├── createPool │ │ │ ├── connection.test.ts │ │ │ ├── createPool.test.ts │ │ │ ├── execute.test.ts │ │ │ ├── getConnection.test.ts │ │ │ ├── query.test.ts │ │ │ ├── release.test.ts │ │ │ └── releaseConnection.test.ts │ │ ├── createPoolCluster │ │ │ ├── add.test.ts │ │ │ ├── getConnection.test.ts │ │ │ └── of │ │ │ │ ├── getConnection.test.ts │ │ │ │ └── of.test.ts │ │ └── parsers │ │ │ ├── clearParserCache.test.ts │ │ │ └── setMaxParserCache.test.ts │ ├── strict-checks │ │ ├── ProcedureCallPacket.test.ts │ │ ├── enableKeepAlive-and-keepAliveInitialDelay.test.ts │ │ ├── execute.test.ts │ │ ├── query.test.ts │ │ └── typeCast.test.ts │ └── tsconfig.json └── unit │ ├── commands │ ├── test-query.test.cjs │ └── test-quit.test.cjs │ ├── connection │ └── test-connection_config.test.cjs │ ├── packets │ ├── test-column-definition.test.cjs │ ├── test-datetime.test.cjs │ ├── test-ok-autoinc.test.cjs │ ├── test-ok-sessiontrack.test.cjs │ ├── test-text-row.test.cjs │ └── test-time.test.cjs │ ├── parsers │ └── test-text-parser.test.cjs │ ├── pool-cluster │ ├── test-connection-error-remove.test.cjs │ ├── test-connection-order.test.cjs │ ├── test-connection-retry.test.cjs │ ├── test-connection-rr.test.cjs │ ├── test-query.test.cjs │ ├── test-remove-by-name.test.cjs │ ├── test-remove-by-pattern.test.cjs │ ├── test-restore-events.test.cjs │ └── test-restore.test.cjs │ └── test-packet-parser.test.cjs ├── tools ├── .eslintrc ├── create-db.js ├── generate-charset-mapping.js ├── parse-field.js ├── parse-row.js └── wait-up.js ├── tsconfig.json ├── typings └── mysql │ ├── LICENSE.txt │ ├── index.d.ts │ ├── info.txt │ └── lib │ ├── Auth.d.ts │ ├── Connection.d.ts │ ├── Pool.d.ts │ ├── PoolCluster.d.ts │ ├── PoolConnection.d.ts │ ├── Server.d.ts │ ├── constants │ ├── CharsetToEncoding.d.ts │ ├── Charsets.d.ts │ ├── Types.d.ts │ └── index.d.ts │ ├── parsers │ ├── ParserCache.d.ts │ ├── index.d.ts │ └── typeCast.d.ts │ └── protocol │ ├── packets │ ├── Field.d.ts │ ├── FieldPacket.d.ts │ ├── OkPacket.d.ts │ ├── ProcedurePacket.d.ts │ ├── ResultSetHeader.d.ts │ ├── RowDataPacket.d.ts │ ├── index.d.ts │ └── params │ │ ├── ErrorPacketParams.d.ts │ │ └── OkPacketParams.d.ts │ └── sequences │ ├── ExecutableBase.d.ts │ ├── Prepare.d.ts │ ├── Query.d.ts │ ├── QueryableBase.d.ts │ ├── Sequence.d.ts │ └── promise │ ├── ExecutableBase.d.ts │ └── QueryableBase.d.ts └── website ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .purc.json ├── README.md ├── babel.config.js ├── biome.json ├── docs ├── acknowledgements.mdx ├── api-and-configurations.mdx ├── contributing │ ├── 00-index.mdx │ └── website.mdx ├── documentation │ ├── 00-index.mdx │ ├── authentication-switch.mdx │ ├── connect-on-cloudflare.mdx │ ├── extras.mdx │ ├── mysql-server.mdx │ ├── prepared-statements.mdx │ ├── promise-wrapper.mdx │ ├── ssl.mdx │ └── typescript-examples.mdx ├── examples │ ├── 00-index.mdx │ ├── binlog-watcher.mdx │ ├── connections │ │ ├── _category_.json │ │ ├── create-connection.mdx │ │ ├── create-pool.mdx │ │ └── createPoolCluster.mdx │ ├── promise-wrapper │ │ ├── _category_.json │ │ └── co-await.mdx │ ├── queries │ │ ├── _category_.json │ │ ├── prepared-statements │ │ │ ├── _category_.json │ │ │ ├── delete.mdx │ │ │ ├── index.mdx │ │ │ ├── insert.mdx │ │ │ ├── select.mdx │ │ │ └── update.mdx │ │ └── simple-queries │ │ │ ├── _category_.json │ │ │ ├── delete.mdx │ │ │ ├── index.mdx │ │ │ ├── insert.mdx │ │ │ ├── select.mdx │ │ │ └── update.mdx │ ├── tests │ │ ├── _category_.json │ │ ├── mysql-proxy.mdx │ │ ├── pool.mdx │ │ └── server.mdx │ └── typescript │ │ ├── _category_.json │ │ ├── basic-custom-class.mdx │ │ ├── procedure-call │ │ ├── 00-index.mdx │ │ ├── 01-row-as-array.mdx │ │ └── _category_.json │ │ └── row-data │ │ ├── 00-index.mdx │ │ ├── 01-row-as-array.mdx │ │ ├── 02-multi-statements.mdx │ │ ├── 03-row-as-array-multi-statements.mdx │ │ └── _category_.json ├── faq │ ├── 00-index.mdx │ └── how-to-handle-errors.mdx ├── history-and-why-mysq2.mdx ├── index.mdx └── stability-badges.mdx ├── docusaurus.config.ts ├── helpers └── extract-method-content.ts ├── i18n ├── pt-BR │ └── docusaurus-plugin-content-docs │ │ ├── current.json │ │ └── current │ │ ├── acknowledgements.mdx │ │ ├── api-and-configurations.mdx │ │ ├── contributing │ │ └── 00-index.mdx │ │ ├── history-and-why-mysq2.mdx │ │ └── index.mdx └── zh-CN │ └── docusaurus-plugin-content-docs │ ├── current.json │ └── current │ ├── acknowledgements.mdx │ ├── api-and-configurations.mdx │ ├── contributing │ └── 00-index.mdx │ ├── history-and-why-mysq2.mdx │ └── index.mdx ├── package-lock.json ├── package.json ├── plugins └── locale.ts ├── sidebars.ts ├── src ├── components │ ├── ExternalCodeEmbed.tsx │ ├── FAQ.tsx │ ├── History.tsx │ ├── Loading.tsx │ ├── PageTitle.tsx │ └── Stability.tsx ├── css │ ├── _faq.scss │ ├── _history.scss │ ├── _loading.scss │ ├── _mixins.scss │ ├── custom.scss │ └── stability │ │ ├── _dark.scss │ │ ├── _light.scss │ │ └── _main.scss └── pages │ └── index.tsx ├── static ├── .nojekyll └── img │ └── favicon.svg ├── test ├── fixtures │ └── external-code-embed │ │ ├── HistoryRecords.txt │ │ ├── Pool.txt │ │ ├── QueryOptions.txt │ │ ├── handleCompressedPacket.txt │ │ ├── handler.txt │ │ └── makeSelector.txt ├── resources │ └── external-code-embed │ │ └── random-methods.txt ├── unit │ ├── check-extensions.test.ts │ └── external-code-embed.test.ts └── utils │ └── gen-expected-extract-results.test.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_size = 2 5 | indent_style = space 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | website/** linguist-documentation 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [sidorares] 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'npm' 4 | directory: '/' 5 | schedule: 6 | interval: 'daily' 7 | - package-ecosystem: 'npm' 8 | directory: '/website' 9 | schedule: 10 | interval: 'daily' 11 | -------------------------------------------------------------------------------- /.github/workflows/ci-tsc-build.yml: -------------------------------------------------------------------------------- 1 | name: CI - TypeScript Build 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [main] 7 | 8 | workflow_dispatch: 9 | 10 | jobs: 11 | tests-tsc-build: 12 | runs-on: ubuntu-latest 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | node-version: [22] 17 | 18 | name: Node.js ${{ matrix.node-version }} 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - name: Set up Node.js ${{ matrix.node-version }} 23 | uses: actions/setup-node@v4 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | 27 | - name: Cache dependencies 28 | uses: actions/cache@v4 29 | with: 30 | path: ~/.npm 31 | key: npm-linux-${{ hashFiles('package-lock.json') }} 32 | restore-keys: npm-linux- 33 | 34 | - name: Install npm dependencies 35 | run: npm ci 36 | 37 | - name: Testing TypeScript build 38 | run: npm run test:tsc-build 39 | -------------------------------------------------------------------------------- /.github/workflows/ci-website.yml: -------------------------------------------------------------------------------- 1 | name: 'CI - Website' 2 | on: 3 | pull_request: 4 | paths: 5 | - 'website/**' 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Actions - Checkout 13 | uses: actions/checkout@v4 14 | 15 | - name: Actions - Setup NodeJS 16 | uses: actions/setup-node@v4 17 | with: 18 | node-version: 22 19 | 20 | - name: Cache Dependencies 21 | uses: actions/cache@v4 22 | with: 23 | path: ~/.npm 24 | key: npm-website-${{ hashFiles('website/package-lock.json') }} 25 | restore-keys: npm-website- 26 | 27 | - name: Installing Dependencies 28 | run: cd website && npm ci 29 | 30 | - name: Lint Checking 31 | run: cd website && npm run lintcheck 32 | 33 | - name: Checking Types 34 | run: cd website && npm run typecheck 35 | 36 | - name: Run Unit Tests 37 | run: cd website && npm run test:unit 38 | 39 | - name: Checking Build 40 | run: cd website && npm run build 41 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: 'GitHub Pages' 2 | on: 3 | push: 4 | branches: 5 | - master 6 | paths: 7 | - 'website/**' 8 | workflow_dispatch: 9 | 10 | jobs: 11 | deploy: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Actions - Checkout 15 | uses: actions/checkout@v4 16 | 17 | - name: Actions - Setup NodeJS 18 | uses: actions/setup-node@v4 19 | with: 20 | node-version: 22 21 | 22 | - name: Cache Dependencies 23 | uses: actions/cache@v4 24 | with: 25 | path: ~/.npm 26 | key: npm-website-${{ hashFiles('website/package-lock.json') }} 27 | restore-keys: npm-website- 28 | 29 | - name: Installing Dependencies 30 | run: cd website && npm ci 31 | 32 | - name: Checking Types 33 | run: cd website && npm run typecheck 34 | 35 | - name: Run Unit Tests 36 | run: cd website && npm run test:unit 37 | 38 | - name: Building Site 39 | run: cd website && npm run build 40 | 41 | - name: Deploy 42 | uses: peaceiris/actions-gh-pages@v3 43 | with: 44 | github_token: ${{ secrets.GITHUB_TOKEN }} 45 | publish_dir: ./website/build 46 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: lint 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [master] 7 | workflow_dispatch: 8 | 9 | env: 10 | NODE_VERSION: 22 11 | 12 | jobs: 13 | lint-js: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - name: Use Node.js ${{ env.NODE_VERSION }} 18 | uses: actions/setup-node@v4 19 | with: 20 | node-version: ${{ env.NODE_VERSION }} 21 | 22 | - name: Cache dependencies 23 | uses: actions/cache@v4 24 | with: 25 | path: ~/.npm 26 | key: npm-linux-${{ hashFiles('package-lock.json') }} 27 | restore-keys: npm-linux- 28 | 29 | - name: Install ESLint + ESLint configs/plugins 30 | run: npm install --only=dev 31 | 32 | - name: Lint 33 | run: npm run lint 34 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | workflow_dispatch: 6 | name: release-please 7 | permissions: 8 | contents: write 9 | pull-requests: write 10 | id-token: write 11 | jobs: 12 | release-please: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: google-github-actions/release-please-action@v3 16 | id: release 17 | with: 18 | release-type: node 19 | package-name: mysql2 20 | changelog-path: 'Changelog.md' 21 | 22 | - uses: actions/checkout@v4 23 | if: ${{ steps.release.outputs.release_created }} 24 | 25 | - uses: actions/setup-node@v4 26 | if: ${{ steps.release.outputs.release_created }} 27 | with: 28 | node-version: 22 29 | registry-url: 'https://registry.npmjs.org' 30 | 31 | - name: Cache dependencies 32 | uses: actions/cache@v4 33 | with: 34 | path: ~/.npm 35 | key: npm-linux-${{ hashFiles('package-lock.json') }} 36 | restore-keys: npm-linux- 37 | 38 | - run: npm ci 39 | if: ${{ steps.release.outputs.release_created }} 40 | 41 | - run: npm publish --provenance 42 | if: ${{ steps.release.outputs.release_created }} 43 | env: 44 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | .DS_Store 10 | .idea/ 11 | .vscode/ 12 | .npmrc 13 | coverage/ 14 | mysqldata/ 15 | 16 | tmp 17 | pids 18 | logs 19 | 20 | node_modules 21 | npm-debug.log 22 | benchmarks/results.json 23 | !test/fixtures/data.csv 24 | -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "all": true, 3 | "include": ["index.js", "promise.js", "lib/**/*.js"], 4 | "exclude": ["mysqldata/**", "node_modules/**", "test/**"], 5 | "reporter": ["text", "lcov", "cobertura"], 6 | "statements": 80, 7 | "branches": 80, 8 | "functions": 77, 9 | "lines": 80, 10 | "checkCoverage": true, 11 | "clean": true 12 | } 13 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | website/ 2 | Changelog.md 3 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": true, 6 | "quoteProps": "as-needed", 7 | "jsxSingleQuote": true, 8 | "trailingComma": "es5", 9 | "bracketSpacing": true, 10 | "bracketSameLine": false, 11 | "arrowParens": "always", 12 | "proseWrap": "preserve", 13 | "htmlWhitespaceSensitivity": "css", 14 | "endOfLine": "lf", 15 | "embeddedLanguageFormatting": "auto", 16 | "singleAttributePerLine": false 17 | } 18 | -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 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. 20 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | **Please do not file a public ticket** mentioning the vulnerability. 6 | 7 | If you believe you found a security vulnerability please contact [current maintainer](mailto:andrey.sidorov@gmail.com?subject=mysql2%20security%20vulnerability%20report) as soon as practical - the team will triage severity and plan for rectification. 8 | -------------------------------------------------------------------------------- /benchmarks/benchmark-query.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const createConnection = require('../test/common').createConnection; 4 | 5 | const sql = process.argv[2]; 6 | 7 | (function (cb) { 8 | const db = createConnection(); 9 | 10 | let left = 10000; 11 | const start = Date.now(); 12 | let prev1000 = start; 13 | function bench() { 14 | db.query(sql).on('end', () => { 15 | left--; 16 | if (left % 1000 === 0) { 17 | const curTime = Date.now(); 18 | const last1000time = curTime - prev1000; 19 | prev1000 = curTime; 20 | console.error(`${1000000 / last1000time} req/sec`); 21 | } 22 | 23 | if (left > 0) bench(); 24 | else { 25 | console.error( 26 | `${10000000 / (Date.now() - start)} req/sec (average 10000 reqs)` 27 | ); 28 | db.end(); 29 | if (cb) cb(); 30 | } 31 | }); 32 | } 33 | bench(); 34 | })(); 35 | -------------------------------------------------------------------------------- /benchmarks/benchmark.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Benchmark = require('benchmark'); 4 | const suite = new Benchmark.Suite(); 5 | 6 | function addFile(name) { 7 | const benchmarks = require(name); 8 | benchmarks.forEach((b) => { 9 | suite.add(b.name, b.fn); 10 | }); 11 | } 12 | 13 | addFile('./unit/packets/column_definition.js'); 14 | 15 | suite 16 | .on('start', async () => {}) 17 | .on('complete', () => {}) 18 | .on('cycle', (event) => { 19 | console.log(String(event.target)); 20 | }) 21 | .run(); 22 | -------------------------------------------------------------------------------- /benchmarks/http-select-and-render.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const http = require('http'); 4 | const common = require('../test/common'); 5 | const url = require('url'); 6 | 7 | const conn = common.createConnection(); 8 | const render = common.createTemplate(); 9 | const port = process.env.PORT; 10 | 11 | http 12 | .createServer((req, res) => { 13 | const q = new url.URL(req.url); 14 | if (q.pathname === '/render') { 15 | const sql = q.searchParams.get('q'); 16 | const n = q.searchParams.get('n'); 17 | let rowsTotal = []; 18 | const doQueries = function (number) { 19 | if (number === 0) { 20 | const body = render({ records: rowsTotal }); 21 | res.writeHead(200, { 22 | 'Content-Length': body.length, 23 | 'Content-Type': 'text/html', 24 | }); 25 | res.end(body); 26 | } else { 27 | conn.query(sql, (err, rows) => { 28 | // TODO: handle error 29 | rowsTotal = rowsTotal.concat(rows); 30 | doQueries(number - 1); 31 | }); 32 | } 33 | }; 34 | doQueries(n); 35 | } else { 36 | res.writeHead(404); 37 | res.end(); 38 | } 39 | }) 40 | .listen(port || 1234); 41 | -------------------------------------------------------------------------------- /benchmarks/httperf.sh: -------------------------------------------------------------------------------- 1 | httperf --port=1234 --uri='/render?q=select%20*%20from%20foos%20limit%205,10000&n=2' --num-conns=10 --num-calls=2 rate=100 2 | -------------------------------------------------------------------------------- /benchmarks/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | test 4 | 5 | 6 | -------------------------------------------------------------------------------- /benchmarks/test-benchmark-select-1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const createConnection = require('../test/common').createConnection; 4 | 5 | (function (cb) { 6 | const db = createConnection(); 7 | 8 | let left = 10000; 9 | const start = Date.now(); 10 | let prev1000 = start; 11 | function bench() { 12 | db.query('select 1').on('end', () => { 13 | left--; 14 | if (left % 1000 === 0) { 15 | const curTime = Date.now(); 16 | const last1000time = curTime - prev1000; 17 | prev1000 = curTime; 18 | console.error(`${1000000 / last1000time} req/sec`); 19 | } 20 | 21 | if (left > 0) bench(); 22 | else { 23 | console.error( 24 | `${10000000 / (Date.now() - start)} req/sec (average 10000 reqs)` 25 | ); 26 | db.end(); 27 | if (cb) cb(); 28 | } 29 | }); 30 | } 31 | bench(); 32 | })(); 33 | -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition0 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition1 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition10: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition10 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition11: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition11 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition12 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition13: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition13 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition14: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition14 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition15: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition15 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition16: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition16 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition17: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition17 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition18: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition18 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition19: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition19 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition2 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition20: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition20 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition21: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition21 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition22: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition22 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition23: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition23 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition24: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition24 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition25: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition25 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition26: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition26 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition27: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition27 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition28: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition28 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition29: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition29 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition3 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition30: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition30 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition31: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition31 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition32 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition33: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition33 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition34: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition34 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition35: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition35 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition36: -------------------------------------------------------------------------------- 1 | defmysqluseruser max_questions max_questions ? ! -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition37: -------------------------------------------------------------------------------- 1 | defmysqluseruser max_updates max_updates ? ! -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition38: -------------------------------------------------------------------------------- 1 | defmysqluserusermax_connectionsmax_connections ? ! -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition39: -------------------------------------------------------------------------------- 1 | defmysqluserusermax_user_connectionsmax_user_connections ? ! -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition4 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition40: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition40 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition41: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition41 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition42: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition42 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition5 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition6 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition7 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition8 -------------------------------------------------------------------------------- /benchmarks/unit/fixtures/column_definition9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/benchmarks/unit/fixtures/column_definition9 -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | target: 88% 6 | threshold: 2% 7 | patch: 8 | default: 9 | target: 0% 10 | threshold: 100% 11 | -------------------------------------------------------------------------------- /fixtures/mysql-ssl-ca-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDQzCCAqygAwIBAgIJAOd1tlfiGoEoMA0GCSqGSIb3DQEBBQUAMHUxCzAJBgNV 3 | BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdTZWF0dGxlMRMw 4 | EQYDVQQKEwpBbWF6b24uY29tMQwwCgYDVQQLEwNSRFMxHDAaBgNVBAMTE2F3cy5h 5 | bWF6b24uY29tL3Jkcy8wHhcNMTAwNDA1MjI0NDMxWhcNMTUwNDA0MjI0NDMxWjB1 6 | MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHU2Vh 7 | dHRsZTETMBEGA1UEChMKQW1hem9uLmNvbTEMMAoGA1UECxMDUkRTMRwwGgYDVQQD 8 | ExNhd3MuYW1hem9uLmNvbS9yZHMvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB 9 | gQDKhXGU7tizxUR5WaFoMTFcxNxa05PEjZaIOEN5ctkWrqYSRov0/nOMoZjqk8bC 10 | med9vPFoQGD0OTakPs0jVe3wwmR735hyVwmKIPPsGlaBYj1O6llIpZeQVyupNx56 11 | UzqtiLaDzh1KcmfqP3qP2dInzBfJQKjiRudo1FWnpPt33QIDAQABo4HaMIHXMB0G 12 | A1UdDgQWBBT/H3x+cqSkR/ePSIinPtc4yWKe3DCBpwYDVR0jBIGfMIGcgBT/H3x+ 13 | cqSkR/ePSIinPtc4yWKe3KF5pHcwdTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh 14 | c2hpbmd0b24xEDAOBgNVBAcTB1NlYXR0bGUxEzARBgNVBAoTCkFtYXpvbi5jb20x 15 | DDAKBgNVBAsTA1JEUzEcMBoGA1UEAxMTYXdzLmFtYXpvbi5jb20vcmRzL4IJAOd1 16 | tlfiGoEoMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAvguZy/BDT66x 17 | GfgnJlyQwnFSeVLQm9u/FIvz4huGjbq9dqnD6h/Gm56QPFdyMEyDiZWaqY6V08lY 18 | LTBNb4kcIc9/6pc0/ojKciP5QJRm6OiZ4vgG05nF4fYjhU7WClUx7cxq1fKjNc2J 19 | UCmmYqgiVkAGWRETVo+byOSDZ4swb10= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './typings/mysql/index.js'; 2 | -------------------------------------------------------------------------------- /lib/auth_plugins/caching_sha2_password.md: -------------------------------------------------------------------------------- 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 | ``` 19 | -------------------------------------------------------------------------------- /lib/auth_plugins/index.js: -------------------------------------------------------------------------------- 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 | }; 9 | -------------------------------------------------------------------------------- /lib/auth_plugins/mysql_clear_password.js: -------------------------------------------------------------------------------- 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; 18 | -------------------------------------------------------------------------------- /lib/auth_plugins/mysql_native_password.js: -------------------------------------------------------------------------------- 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 | }; 35 | -------------------------------------------------------------------------------- /lib/commands/close_statement.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Command = require('./command'); 4 | const Packets = require('../packets/index.js'); 5 | 6 | class CloseStatement extends Command { 7 | constructor(id) { 8 | super(); 9 | this.id = id; 10 | } 11 | 12 | start(packet, connection) { 13 | connection.writePacket(new Packets.CloseStatement(this.id).toPacket(1)); 14 | return null; 15 | } 16 | } 17 | 18 | module.exports = CloseStatement; 19 | -------------------------------------------------------------------------------- /lib/commands/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const ClientHandshake = require('./client_handshake.js'); 4 | const ServerHandshake = require('./server_handshake.js'); 5 | const Query = require('./query.js'); 6 | const Prepare = require('./prepare.js'); 7 | const CloseStatement = require('./close_statement.js'); 8 | const Execute = require('./execute.js'); 9 | const Ping = require('./ping.js'); 10 | const RegisterSlave = require('./register_slave.js'); 11 | const BinlogDump = require('./binlog_dump.js'); 12 | const ChangeUser = require('./change_user.js'); 13 | const Quit = require('./quit.js'); 14 | 15 | module.exports = { 16 | ClientHandshake, 17 | ServerHandshake, 18 | Query, 19 | Prepare, 20 | CloseStatement, 21 | Execute, 22 | Ping, 23 | RegisterSlave, 24 | BinlogDump, 25 | ChangeUser, 26 | Quit, 27 | }; 28 | -------------------------------------------------------------------------------- /lib/commands/ping.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Command = require('./command'); 4 | const CommandCode = require('../constants/commands'); 5 | const Packet = require('../packets/packet'); 6 | 7 | // TODO: time statistics? 8 | // usefull for queue size and network latency monitoring 9 | // store created,sent,reply timestamps 10 | class Ping extends Command { 11 | constructor(callback) { 12 | super(); 13 | this.onResult = callback; 14 | } 15 | 16 | start(packet, connection) { 17 | const ping = new Packet( 18 | 0, 19 | Buffer.from([1, 0, 0, 0, CommandCode.PING]), 20 | 0, 21 | 5 22 | ); 23 | connection.writePacket(ping); 24 | return Ping.prototype.pingResponse; 25 | } 26 | 27 | pingResponse() { 28 | // TODO: check it's OK packet. error check already done in caller 29 | if (this.onResult) { 30 | process.nextTick(this.onResult.bind(this)); 31 | } 32 | return null; 33 | } 34 | } 35 | 36 | module.exports = Ping; 37 | -------------------------------------------------------------------------------- /lib/commands/quit.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Command = require('./command.js'); 4 | const CommandCode = require('../constants/commands.js'); 5 | const Packet = require('../packets/packet.js'); 6 | 7 | class Quit extends Command { 8 | constructor(callback) { 9 | super(); 10 | this.onResult = callback; 11 | } 12 | 13 | start(packet, connection) { 14 | connection._closing = true; 15 | const quit = new Packet( 16 | 0, 17 | Buffer.from([1, 0, 0, 0, CommandCode.QUIT]), 18 | 0, 19 | 5 20 | ); 21 | if (this.onResult) { 22 | this.onResult(); 23 | } 24 | connection.writePacket(quit); 25 | return null; 26 | } 27 | } 28 | 29 | module.exports = Quit; 30 | -------------------------------------------------------------------------------- /lib/commands/register_slave.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Command = require('./command'); 4 | const Packets = require('../packets'); 5 | 6 | class RegisterSlave extends Command { 7 | constructor(opts, callback) { 8 | super(); 9 | this.onResult = callback; 10 | this.opts = opts; 11 | } 12 | 13 | start(packet, connection) { 14 | const newPacket = new Packets.RegisterSlave(this.opts); 15 | connection.writePacket(newPacket.toPacket(1)); 16 | return RegisterSlave.prototype.registerResponse; 17 | } 18 | 19 | registerResponse() { 20 | if (this.onResult) { 21 | process.nextTick(this.onResult.bind(this)); 22 | } 23 | return null; 24 | } 25 | } 26 | 27 | module.exports = RegisterSlave; 28 | -------------------------------------------------------------------------------- /lib/connection.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const BaseConnection = require('./base/connection.js'); 4 | 5 | class Connection extends BaseConnection { 6 | promise(promiseImpl) { 7 | const PromiseConnection = require('./promise/connection.js'); 8 | return new PromiseConnection(this, promiseImpl); 9 | } 10 | } 11 | 12 | module.exports = Connection; 13 | -------------------------------------------------------------------------------- /lib/constants/commands.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | SLEEP: 0x00, // deprecated 5 | QUIT: 0x01, 6 | INIT_DB: 0x02, 7 | QUERY: 0x03, 8 | FIELD_LIST: 0x04, 9 | CREATE_DB: 0x05, 10 | DROP_DB: 0x06, 11 | REFRESH: 0x07, 12 | SHUTDOWN: 0x08, 13 | STATISTICS: 0x09, 14 | PROCESS_INFO: 0x0a, // deprecated 15 | CONNECT: 0x0b, // deprecated 16 | PROCESS_KILL: 0x0c, 17 | DEBUG: 0x0d, 18 | PING: 0x0e, 19 | TIME: 0x0f, // deprecated 20 | DELAYED_INSERT: 0x10, // deprecated 21 | CHANGE_USER: 0x11, 22 | BINLOG_DUMP: 0x12, 23 | TABLE_DUMP: 0x13, 24 | CONNECT_OUT: 0x14, 25 | REGISTER_SLAVE: 0x15, 26 | STMT_PREPARE: 0x16, 27 | STMT_EXECUTE: 0x17, 28 | STMT_SEND_LONG_DATA: 0x18, 29 | STMT_CLOSE: 0x19, 30 | STMT_RESET: 0x1a, 31 | SET_OPTION: 0x1b, 32 | STMT_FETCH: 0x1c, 33 | DAEMON: 0x1d, // deprecated 34 | BINLOG_DUMP_GTID: 0x1e, 35 | UNKNOWN: 0xff, // bad! 36 | }; 37 | -------------------------------------------------------------------------------- /lib/constants/cursor.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | NO_CURSOR: 0, 5 | READ_ONLY: 1, 6 | FOR_UPDATE: 2, 7 | SCROLLABLE: 3, 8 | }; 9 | -------------------------------------------------------------------------------- /lib/constants/encoding_charset.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // inverse of charset_encodings 4 | // given encoding, get matching mysql charset number 5 | 6 | module.exports = { 7 | big5: 1, 8 | latin2: 2, 9 | dec8: 3, 10 | cp850: 4, 11 | latin1: 5, 12 | hp8: 6, 13 | koi8r: 7, 14 | swe7: 10, 15 | ascii: 11, 16 | eucjp: 12, 17 | sjis: 13, 18 | cp1251: 14, 19 | hebrew: 16, 20 | tis620: 18, 21 | euckr: 19, 22 | latin7: 20, 23 | koi8u: 22, 24 | gb2312: 24, 25 | greek: 25, 26 | cp1250: 26, 27 | gbk: 28, 28 | cp1257: 29, 29 | latin5: 30, 30 | armscii8: 32, 31 | cesu8: 33, 32 | ucs2: 35, 33 | cp866: 36, 34 | keybcs2: 37, 35 | macintosh: 38, 36 | macroman: 39, 37 | cp852: 40, 38 | utf8: 45, 39 | utf8mb4: 45, 40 | utf16: 54, 41 | utf16le: 56, 42 | cp1256: 57, 43 | utf32: 60, 44 | binary: 63, 45 | geostd8: 92, 46 | cp932: 95, 47 | eucjpms: 97, 48 | gb18030: 248, 49 | utf8mb3: 192, 50 | }; 51 | -------------------------------------------------------------------------------- /lib/constants/field_flags.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Manually extracted from mysql-5.5.23/include/mysql_com.h 4 | exports.NOT_NULL = 1; /* Field can't be NULL */ 5 | exports.PRI_KEY = 2; /* Field is part of a primary key */ 6 | exports.UNIQUE_KEY = 4; /* Field is part of a unique key */ 7 | exports.MULTIPLE_KEY = 8; /* Field is part of a key */ 8 | exports.BLOB = 16; /* Field is a blob */ 9 | exports.UNSIGNED = 32; /* Field is unsigned */ 10 | exports.ZEROFILL = 64; /* Field is zerofill */ 11 | exports.BINARY = 128; /* Field is binary */ 12 | 13 | /* The following are only sent to new clients */ 14 | exports.ENUM = 256; /* field is an enum */ 15 | exports.AUTO_INCREMENT = 512; /* field is a autoincrement field */ 16 | exports.TIMESTAMP = 1024; /* Field is a timestamp */ 17 | exports.SET = 2048; /* field is a set */ 18 | exports.NO_DEFAULT_VALUE = 4096; /* Field doesn't have default value */ 19 | exports.ON_UPDATE_NOW = 8192; /* Field is set to NOW on UPDATE */ 20 | exports.NUM = 32768; /* Field is num (for clients) */ 21 | -------------------------------------------------------------------------------- /lib/constants/session_track.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.SYSTEM_VARIABLES = 0; 4 | exports.SCHEMA = 1; 5 | exports.STATE_CHANGE = 2; 6 | exports.STATE_GTIDS = 3; 7 | exports.TRANSACTION_CHARACTERISTICS = 4; 8 | exports.TRANSACTION_STATE = 5; 9 | 10 | exports.FIRST_KEY = exports.SYSTEM_VARIABLES; 11 | exports.LAST_KEY = exports.TRANSACTION_STATE; 12 | -------------------------------------------------------------------------------- /lib/constants/ssl_profiles.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const awsCaBundle = require('aws-ssl-profiles'); 4 | 5 | /** 6 | * @deprecated 7 | * Please, use [**aws-ssl-profiles**](https://github.com/mysqljs/aws-ssl-profiles). 8 | */ 9 | exports['Amazon RDS'] = { 10 | ca: awsCaBundle.ca, 11 | }; 12 | -------------------------------------------------------------------------------- /lib/create_connection.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Connection = require('./connection.js'); 4 | const ConnectionConfig = require('./connection_config.js'); 5 | 6 | function createConnection(opts) { 7 | return new Connection({ config: new ConnectionConfig(opts) }); 8 | } 9 | 10 | module.exports = createConnection; 11 | -------------------------------------------------------------------------------- /lib/create_pool.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Pool = require('./pool.js'); 4 | const PoolConfig = require('./pool_config.js'); 5 | 6 | function createPool(config) { 7 | return new Pool({ config: new PoolConfig(config) }); 8 | } 9 | 10 | module.exports = createPool; 11 | -------------------------------------------------------------------------------- /lib/create_pool_cluster.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const PoolCluster = require('./pool_cluster.js'); 4 | 5 | function createPoolCluster(config) { 6 | return new PoolCluster(config); 7 | } 8 | 9 | module.exports = createPoolCluster; 10 | -------------------------------------------------------------------------------- /lib/packets/auth_next_factor.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, Oracle and/or its affiliates. 2 | 3 | 'use strict'; 4 | 5 | const Packet = require('../packets/packet'); 6 | 7 | class AuthNextFactor { 8 | constructor(opts) { 9 | this.pluginName = opts.pluginName; 10 | this.pluginData = opts.pluginData; 11 | } 12 | 13 | toPacket(encoding) { 14 | const length = 6 + this.pluginName.length + this.pluginData.length; 15 | const buffer = Buffer.allocUnsafe(length); 16 | const packet = new Packet(0, buffer, 0, length); 17 | packet.offset = 4; 18 | packet.writeInt8(0x02); 19 | packet.writeNullTerminatedString(this.pluginName, encoding); 20 | packet.writeBuffer(this.pluginData); 21 | return packet; 22 | } 23 | 24 | static fromPacket(packet, encoding) { 25 | packet.readInt8(); // marker 26 | const name = packet.readNullTerminatedString(encoding); 27 | const data = packet.readBuffer(); 28 | return new AuthNextFactor({ 29 | pluginName: name, 30 | pluginData: data, 31 | }); 32 | } 33 | } 34 | 35 | module.exports = AuthNextFactor; 36 | -------------------------------------------------------------------------------- /lib/packets/auth_switch_request.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest 4 | 5 | const Packet = require('../packets/packet'); 6 | 7 | class AuthSwitchRequest { 8 | constructor(opts) { 9 | this.pluginName = opts.pluginName; 10 | this.pluginData = opts.pluginData; 11 | } 12 | 13 | toPacket() { 14 | const length = 6 + this.pluginName.length + this.pluginData.length; 15 | const buffer = Buffer.allocUnsafe(length); 16 | const packet = new Packet(0, buffer, 0, length); 17 | packet.offset = 4; 18 | packet.writeInt8(0xfe); 19 | // TODO: use server encoding 20 | packet.writeNullTerminatedString(this.pluginName, 'cesu8'); 21 | packet.writeBuffer(this.pluginData); 22 | return packet; 23 | } 24 | 25 | static fromPacket(packet) { 26 | packet.readInt8(); // marker 27 | // assert marker == 0xfe? 28 | // TODO: use server encoding 29 | const name = packet.readNullTerminatedString('cesu8'); 30 | const data = packet.readBuffer(); 31 | return new AuthSwitchRequest({ 32 | pluginName: name, 33 | pluginData: data, 34 | }); 35 | } 36 | } 37 | 38 | module.exports = AuthSwitchRequest; 39 | -------------------------------------------------------------------------------- /lib/packets/auth_switch_request_more_data.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest 4 | 5 | const Packet = require('../packets/packet'); 6 | 7 | class AuthSwitchRequestMoreData { 8 | constructor(data) { 9 | this.data = data; 10 | } 11 | 12 | toPacket() { 13 | const length = 5 + this.data.length; 14 | const buffer = Buffer.allocUnsafe(length); 15 | const packet = new Packet(0, buffer, 0, length); 16 | packet.offset = 4; 17 | packet.writeInt8(0x01); 18 | packet.writeBuffer(this.data); 19 | return packet; 20 | } 21 | 22 | static fromPacket(packet) { 23 | packet.readInt8(); // marker 24 | const data = packet.readBuffer(); 25 | return new AuthSwitchRequestMoreData(data); 26 | } 27 | 28 | static verifyMarker(packet) { 29 | return packet.peekByte() === 0x01; 30 | } 31 | } 32 | 33 | module.exports = AuthSwitchRequestMoreData; 34 | -------------------------------------------------------------------------------- /lib/packets/auth_switch_response.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest 4 | 5 | const Packet = require('../packets/packet'); 6 | 7 | class AuthSwitchResponse { 8 | constructor(data) { 9 | if (!Buffer.isBuffer(data)) { 10 | data = Buffer.from(data); 11 | } 12 | this.data = data; 13 | } 14 | 15 | toPacket() { 16 | const length = 4 + this.data.length; 17 | const buffer = Buffer.allocUnsafe(length); 18 | const packet = new Packet(0, buffer, 0, length); 19 | packet.offset = 4; 20 | packet.writeBuffer(this.data); 21 | return packet; 22 | } 23 | 24 | static fromPacket(packet) { 25 | const data = packet.readBuffer(); 26 | return new AuthSwitchResponse(data); 27 | } 28 | } 29 | 30 | module.exports = AuthSwitchResponse; 31 | -------------------------------------------------------------------------------- /lib/packets/binlog_dump.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // http://dev.mysql.com/doc/internals/en/com-binlog-dump.html#packet-COM_BINLOG_DUMP 4 | 5 | const Packet = require('../packets/packet'); 6 | const CommandCodes = require('../constants/commands'); 7 | 8 | // TODO: add flag to constants 9 | // 0x01 - BINLOG_DUMP_NON_BLOCK 10 | // send EOF instead of blocking 11 | class BinlogDump { 12 | constructor(opts) { 13 | this.binlogPos = opts.binlogPos || 0; 14 | this.serverId = opts.serverId || 0; 15 | this.flags = opts.flags || 0; 16 | this.filename = opts.filename || ''; 17 | } 18 | 19 | toPacket() { 20 | const length = 15 + Buffer.byteLength(this.filename, 'utf8'); // TODO: should be ascii? 21 | const buffer = Buffer.allocUnsafe(length); 22 | const packet = new Packet(0, buffer, 0, length); 23 | packet.offset = 4; 24 | packet.writeInt8(CommandCodes.BINLOG_DUMP); 25 | packet.writeInt32(this.binlogPos); 26 | packet.writeInt16(this.flags); 27 | packet.writeInt32(this.serverId); 28 | packet.writeString(this.filename); 29 | return packet; 30 | } 31 | } 32 | 33 | module.exports = BinlogDump; 34 | -------------------------------------------------------------------------------- /lib/packets/close_statement.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Packet = require('../packets/packet'); 4 | const CommandCodes = require('../constants/commands'); 5 | 6 | class CloseStatement { 7 | constructor(id) { 8 | this.id = id; 9 | } 10 | 11 | // note: no response sent back 12 | toPacket() { 13 | const packet = new Packet(0, Buffer.allocUnsafe(9), 0, 9); 14 | packet.offset = 4; 15 | packet.writeInt8(CommandCodes.STMT_CLOSE); 16 | packet.writeInt32(this.id); 17 | return packet; 18 | } 19 | } 20 | 21 | module.exports = CloseStatement; 22 | -------------------------------------------------------------------------------- /lib/packets/prepare_statement.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Packet = require('../packets/packet'); 4 | const CommandCodes = require('../constants/commands'); 5 | const StringParser = require('../parsers/string.js'); 6 | const CharsetToEncoding = require('../constants/charset_encodings.js'); 7 | 8 | class PrepareStatement { 9 | constructor(sql, charsetNumber) { 10 | this.query = sql; 11 | this.charsetNumber = charsetNumber; 12 | this.encoding = CharsetToEncoding[charsetNumber]; 13 | } 14 | 15 | toPacket() { 16 | const buf = StringParser.encode(this.query, this.encoding); 17 | const length = 5 + buf.length; 18 | const buffer = Buffer.allocUnsafe(length); 19 | const packet = new Packet(0, buffer, 0, length); 20 | packet.offset = 4; 21 | packet.writeInt8(CommandCodes.STMT_PREPARE); 22 | packet.writeBuffer(buf); 23 | return packet; 24 | } 25 | } 26 | 27 | module.exports = PrepareStatement; 28 | -------------------------------------------------------------------------------- /lib/packets/prepared_statement_header.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | class PreparedStatementHeader { 4 | constructor(packet) { 5 | packet.skip(1); // should be 0 6 | this.id = packet.readInt32(); 7 | this.fieldCount = packet.readInt16(); 8 | this.parameterCount = packet.readInt16(); 9 | packet.skip(1); // should be 0 10 | this.warningCount = packet.readInt16(); 11 | } 12 | } 13 | 14 | // TODO: toPacket 15 | 16 | module.exports = PreparedStatementHeader; 17 | -------------------------------------------------------------------------------- /lib/packets/query.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Packet = require('../packets/packet.js'); 4 | const CommandCode = require('../constants/commands.js'); 5 | const StringParser = require('../parsers/string.js'); 6 | const CharsetToEncoding = require('../constants/charset_encodings.js'); 7 | 8 | class Query { 9 | constructor(sql, charsetNumber) { 10 | this.query = sql; 11 | this.charsetNumber = charsetNumber; 12 | this.encoding = CharsetToEncoding[charsetNumber]; 13 | } 14 | 15 | toPacket() { 16 | const buf = StringParser.encode(this.query, this.encoding); 17 | const length = 5 + buf.length; 18 | const buffer = Buffer.allocUnsafe(length); 19 | const packet = new Packet(0, buffer, 0, length); 20 | packet.offset = 4; 21 | packet.writeInt8(CommandCode.QUERY); 22 | packet.writeBuffer(buf); 23 | return packet; 24 | } 25 | } 26 | 27 | module.exports = Query; 28 | -------------------------------------------------------------------------------- /lib/packets/ssl_request.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const ClientConstants = require('../constants/client'); 4 | const Packet = require('../packets/packet'); 5 | 6 | class SSLRequest { 7 | constructor(flags, charset) { 8 | this.clientFlags = flags | ClientConstants.SSL; 9 | this.charset = charset; 10 | } 11 | 12 | toPacket() { 13 | const length = 36; 14 | const buffer = Buffer.allocUnsafe(length); 15 | const packet = new Packet(0, buffer, 0, length); 16 | buffer.fill(0); 17 | packet.offset = 4; 18 | packet.writeInt32(this.clientFlags); 19 | packet.writeInt32(0); // max packet size. todo: move to config 20 | packet.writeInt8(this.charset); 21 | return packet; 22 | } 23 | } 24 | 25 | module.exports = SSLRequest; 26 | -------------------------------------------------------------------------------- /lib/pool.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const BasePool = require('./base/pool.js'); 4 | 5 | class Pool extends BasePool { 6 | promise(promiseImpl) { 7 | const PromisePool = require('./promise/pool.js'); 8 | return new PromisePool(this, promiseImpl); 9 | } 10 | } 11 | 12 | module.exports = Pool; 13 | -------------------------------------------------------------------------------- /lib/pool_config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const ConnectionConfig = require('./connection_config.js'); 4 | 5 | class PoolConfig { 6 | constructor(options) { 7 | if (typeof options === 'string') { 8 | options = ConnectionConfig.parseUrl(options); 9 | } 10 | this.connectionConfig = new ConnectionConfig(options); 11 | this.waitForConnections = 12 | options.waitForConnections === undefined 13 | ? true 14 | : Boolean(options.waitForConnections); 15 | this.connectionLimit = isNaN(options.connectionLimit) 16 | ? 10 17 | : Number(options.connectionLimit); 18 | this.maxIdle = isNaN(options.maxIdle) 19 | ? this.connectionLimit 20 | : Number(options.maxIdle); 21 | this.idleTimeout = isNaN(options.idleTimeout) 22 | ? 60000 23 | : Number(options.idleTimeout); 24 | this.queueLimit = isNaN(options.queueLimit) 25 | ? 0 26 | : Number(options.queueLimit); 27 | } 28 | } 29 | 30 | module.exports = PoolConfig; 31 | -------------------------------------------------------------------------------- /lib/pool_connection.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const BasePoolConnection = require('./base/pool_connection.js'); 4 | 5 | class PoolConnection extends BasePoolConnection { 6 | promise(promiseImpl) { 7 | const PromisePoolConnection = require('./promise/pool_connection.js'); 8 | return new PromisePoolConnection(this, promiseImpl); 9 | } 10 | } 11 | 12 | module.exports = PoolConnection; 13 | -------------------------------------------------------------------------------- /lib/promise/inherit_events.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function inheritEvents(source, target, events) { 4 | const listeners = {}; 5 | target 6 | .on('newListener', (eventName) => { 7 | if (events.indexOf(eventName) >= 0 && !target.listenerCount(eventName)) { 8 | source.on( 9 | eventName, 10 | (listeners[eventName] = function () { 11 | const args = [].slice.call(arguments); 12 | args.unshift(eventName); 13 | 14 | target.emit.apply(target, args); 15 | }) 16 | ); 17 | } 18 | }) 19 | .on('removeListener', (eventName) => { 20 | if (events.indexOf(eventName) >= 0 && !target.listenerCount(eventName)) { 21 | source.removeListener(eventName, listeners[eventName]); 22 | delete listeners[eventName]; 23 | } 24 | }); 25 | } 26 | 27 | module.exports = inheritEvents; 28 | -------------------------------------------------------------------------------- /lib/promise/make_done_cb.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function makeDoneCb(resolve, reject, localErr) { 4 | return function (err, rows, fields) { 5 | if (err) { 6 | localErr.message = err.message; 7 | localErr.code = err.code; 8 | localErr.errno = err.errno; 9 | localErr.sql = err.sql; 10 | localErr.sqlState = err.sqlState; 11 | localErr.sqlMessage = err.sqlMessage; 12 | reject(localErr); 13 | } else { 14 | resolve([rows, fields]); 15 | } 16 | }; 17 | } 18 | 19 | module.exports = makeDoneCb; 20 | -------------------------------------------------------------------------------- /lib/promise/pool_connection.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const PromiseConnection = require('./connection.js'); 4 | const BasePoolConnection = require('../base/pool_connection.js'); 5 | 6 | class PromisePoolConnection extends PromiseConnection { 7 | constructor(connection, promiseImpl) { 8 | super(connection, promiseImpl); 9 | } 10 | 11 | destroy() { 12 | return BasePoolConnection.prototype.destroy.apply( 13 | this.connection, 14 | arguments 15 | ); 16 | } 17 | } 18 | 19 | module.exports = PromisePoolConnection; 20 | -------------------------------------------------------------------------------- /lib/promise/prepared_statement_info.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const makeDoneCb = require('./make_done_cb.js'); 4 | 5 | class PromisePreparedStatementInfo { 6 | constructor(statement, promiseImpl) { 7 | this.statement = statement; 8 | this.Promise = promiseImpl; 9 | } 10 | 11 | execute(parameters) { 12 | const s = this.statement; 13 | const localErr = new Error(); 14 | return new this.Promise((resolve, reject) => { 15 | const done = makeDoneCb(resolve, reject, localErr); 16 | if (parameters) { 17 | s.execute(parameters, done); 18 | } else { 19 | s.execute(done); 20 | } 21 | }); 22 | } 23 | 24 | close() { 25 | return new this.Promise((resolve) => { 26 | this.statement.close(); 27 | resolve(); 28 | }); 29 | } 30 | } 31 | 32 | module.exports = PromisePreparedStatementInfo; 33 | -------------------------------------------------------------------------------- /lib/results_stream.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Readable = require('stream').Readable; 4 | 5 | // copy-paste from https://github.com/mysqljs/mysql/blob/master/lib/protocol/sequences/Query.js 6 | module.exports = function (command, connectionStream) { 7 | command.stream = function (options) { 8 | let stream; 9 | 10 | options = options || {}; 11 | options.objectMode = true; 12 | (stream = new Readable(options)), 13 | (stream._read = function () { 14 | connectionStream.resume(); 15 | }); 16 | 17 | this.on('result', (row, i) => { 18 | if (!stream.push(row)) { 19 | connectionStream.pause(); 20 | } 21 | stream.emit('result', row, i); // replicate old emitter 22 | }); 23 | 24 | this.on('error', (err) => { 25 | stream.emit('error', err); // Pass on any errors 26 | }); 27 | 28 | this.on('end', () => { 29 | stream.push(null); // pushing null, indicating EOF 30 | }); 31 | 32 | this.on('fields', (fields, i) => { 33 | stream.emit('fields', fields, i); // replicate old emitter 34 | }); 35 | 36 | return stream; 37 | }; 38 | }; 39 | -------------------------------------------------------------------------------- /lib/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const net = require('net'); 4 | const EventEmitter = require('events').EventEmitter; 5 | 6 | const Connection = require('./connection'); 7 | const ConnectionConfig = require('./connection_config'); 8 | 9 | // TODO: inherit Server from net.Server 10 | class Server extends EventEmitter { 11 | constructor() { 12 | super(); 13 | this.connections = []; 14 | this._server = net.createServer(this._handleConnection.bind(this)); 15 | } 16 | 17 | _handleConnection(socket) { 18 | const connectionConfig = new ConnectionConfig({ 19 | stream: socket, 20 | isServer: true, 21 | }); 22 | const connection = new Connection({ config: connectionConfig }); 23 | this.emit('connection', connection); 24 | } 25 | 26 | listen(port) { 27 | this._port = port; 28 | this._server.listen.apply(this._server, arguments); 29 | return this; 30 | } 31 | 32 | close(cb) { 33 | this._server.close(cb); 34 | } 35 | } 36 | 37 | module.exports = Server; 38 | -------------------------------------------------------------------------------- /tea.yaml: -------------------------------------------------------------------------------- 1 | # https://tea.xyz/what-is-this-file 2 | --- 3 | version: 1.0.0 4 | codeOwners: 5 | - '0xE29b117AD9088c71DC0BC48CA84Ff7328Ab3bfd1' 6 | - '0xCd4AB81DBe170a88717F952d28a3e6319E9Ce2E2' 7 | quorum: 1 8 | -------------------------------------------------------------------------------- /test/esm/integration/parsers/json-parse.test.mjs: -------------------------------------------------------------------------------- 1 | import { test, describe, assert } from 'poku'; 2 | import { createRequire } from 'node:module'; 3 | 4 | const require = createRequire(import.meta.url); 5 | const { 6 | createConnection, 7 | describeOptions, 8 | } = require('../../../common.test.cjs'); 9 | 10 | describe('JSON Parser', describeOptions); 11 | 12 | const connection = createConnection().promise(); 13 | 14 | Promise.all([ 15 | test(async () => { 16 | const [result] = await connection.query( 17 | `SELECT CAST('{"test": true}' AS JSON) AS json_result` 18 | ); 19 | 20 | assert.deepStrictEqual( 21 | result[0].json_result, 22 | { test: true }, 23 | 'Ensure JSON return parsed (query)' 24 | ); 25 | }), 26 | test(async () => { 27 | const [result] = await connection.execute( 28 | `SELECT CAST('{"test": true}' AS JSON) AS json_result` 29 | ); 30 | 31 | assert.deepStrictEqual( 32 | result[0].json_result, 33 | { test: true }, 34 | 'Ensure JSON return parsed (execute)' 35 | ); 36 | }), 37 | ]).then(async () => { 38 | await connection.end(); 39 | }); 40 | -------------------------------------------------------------------------------- /test/esm/integration/parsers/json-string.test.mjs: -------------------------------------------------------------------------------- 1 | import { test, describe, assert } from 'poku'; 2 | import { createRequire } from 'node:module'; 3 | 4 | const require = createRequire(import.meta.url); 5 | const { 6 | createConnection, 7 | describeOptions, 8 | } = require('../../../common.test.cjs'); 9 | 10 | describe('JSON String', describeOptions); 11 | 12 | const connection = createConnection({ 13 | jsonStrings: true, 14 | }).promise(); 15 | 16 | Promise.all([ 17 | test(async () => { 18 | const [result] = await connection.query( 19 | `SELECT CAST('{"test": true}' AS JSON) AS json_result` 20 | ); 21 | 22 | assert.deepStrictEqual( 23 | result[0].json_result, 24 | '{"test": true}', 25 | 'Ensure JSON return as string (query)' 26 | ); 27 | }), 28 | test(async () => { 29 | const [result] = await connection.execute( 30 | `SELECT CAST('{"test": true}' AS JSON) AS json_result` 31 | ); 32 | 33 | assert.deepStrictEqual( 34 | result[0].json_result, 35 | '{"test": true}', 36 | 'Ensure JSON return as string (execute)' 37 | ); 38 | }), 39 | ]).then(async () => { 40 | await connection.end(); 41 | }); 42 | -------------------------------------------------------------------------------- /test/esm/unit/check-extensions.test.mjs: -------------------------------------------------------------------------------- 1 | import { EOL } from 'node:os'; 2 | import { listFiles, test, assert } from 'poku'; 3 | 4 | const invalidFiles = []; 5 | const message = [ 6 | 'Check for invalid file types found in restricted directories', 7 | ]; 8 | 9 | const checkExtensions = async ( 10 | dirs, 11 | allowedExtensions, 12 | ignoreList = /\.DS_Store/ 13 | ) => { 14 | for (const dir of dirs) { 15 | const files = await listFiles(dir, { filter: /\./ }); 16 | 17 | for (const file of files) { 18 | if (!ignoreList.test(file) && !allowedExtensions.test(file)) { 19 | invalidFiles.push(file); 20 | message.push(`${EOL}${String(allowedExtensions)}`); 21 | message.push(`- ${file}`); 22 | } 23 | } 24 | } 25 | }; 26 | 27 | test(async () => { 28 | await checkExtensions(['test/unit', 'test/integration'], /\.test\.cjs$/); 29 | await checkExtensions(['test/esm'], /\.test\.mjs$/); 30 | await checkExtensions(['test/tsc-build'], /(\.test\.ts|tsconfig\.json)$/); 31 | 32 | assert.deepStrictEqual( 33 | invalidFiles.length, 34 | 0, 35 | Array.from(new Set(message)).join(EOL) 36 | ); 37 | }); 38 | -------------------------------------------------------------------------------- /test/esm/unit/parsers/timezone-binary-sanitization.test.mjs: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | import { describe, test, assert } from 'poku'; 3 | import { createRequire } from 'node:module'; 4 | 5 | const require = createRequire(import.meta.url); 6 | const { 7 | createConnection, 8 | describeOptions, 9 | } = require('../../../common.test.cjs'); 10 | 11 | const connection = createConnection().promise(); 12 | 13 | describe('Binary Parser: timezone Sanitization', describeOptions); 14 | 15 | Promise.all([ 16 | test(async () => { 17 | process.env.TEST_ENV_VALUE = 'secure'; 18 | await connection.execute({ 19 | sql: 'SELECT NOW()', 20 | timezone: `'); process.env.TEST_ENV_VALUE = "not so much"; //`, 21 | }); 22 | 23 | assert.strictEqual( 24 | process.env.TEST_ENV_VALUE, 25 | 'secure', 26 | 'Timezone sanitization failed - code injection possible' 27 | ); 28 | }), 29 | ]).then(async () => { 30 | await connection.end(); 31 | }); 32 | -------------------------------------------------------------------------------- /test/esm/unit/parsers/timezone-text-sanitization.test.mjs: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | import { describe, test, assert } from 'poku'; 3 | import { createRequire } from 'node:module'; 4 | 5 | const require = createRequire(import.meta.url); 6 | const { 7 | createConnection, 8 | describeOptions, 9 | } = require('../../../common.test.cjs'); 10 | 11 | const connection = createConnection().promise(); 12 | 13 | describe('Text Parser: timezone Sanitization', describeOptions); 14 | 15 | Promise.all([ 16 | test(async () => { 17 | process.env.TEST_ENV_VALUE = 'secure'; 18 | await connection.query({ 19 | sql: 'SELECT NOW()', 20 | timezone: `'); process.env.TEST_ENV_VALUE = "not so much"; //`, 21 | }); 22 | 23 | assert.strictEqual( 24 | process.env.TEST_ENV_VALUE, 25 | 'secure', 26 | 'Timezone sanitization failed - code injection possible' 27 | ); 28 | }), 29 | ]).then(async () => { 30 | await connection.end(); 31 | }); 32 | -------------------------------------------------------------------------------- /test/fixtures/custom-conf/config-file.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | ssl-ca=/certs/ca.pem 3 | ssl-cert=/certs/server-cert.pem 4 | ssl-key=/certs/server-key.pem -------------------------------------------------------------------------------- /test/fixtures/data.csv: -------------------------------------------------------------------------------- 1 | 1,Hello World 2 | 2,This is a test 3 | 3,For loading data from a file 4 | 4,中文内容 -------------------------------------------------------------------------------- /test/fixtures/ssl/certs/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICsjCCAZoCCQDe1QK5Efu90jANBgkqhkiG9w0BAQsFADAbMQswCQYDVQQGEwJB 3 | VTEMMAoGA1UECAwDVklDMB4XDTE5MDkyOTEzMDI1OFoXDTI5MDgwNzEzMDI1OFow 4 | GzELMAkGA1UEBhMCQVUxDDAKBgNVBAgMA1ZJQzCCASIwDQYJKoZIhvcNAQEBBQAD 5 | ggEPADCCAQoCggEBAMKchojHs540/esAhMmvt5qJWpelWKG2gsKkKTeBc50sD2XR 6 | 66Yh7+d61bDYE44xjk0t4BK/6l5lYLNtX9q8Xxx7lmSkWVb96f0pVxV+3gvdPTH2 7 | 1qpRDS5lXm+o0WfG5sF/yaQJRn+UQPo/vsAtglfLm1QDn+Gwbq7ur+P877WYEZ/o 8 | K1lDwsFBqBjHu9LkywVquSajtDP4jhFRLFIR3tgTAQ1D4BxaKHFetierfrFXCwUV 9 | osnXoOArqHHE6UyUKWNUPAWFOeNEMELMU6lQnEkg0SoMBgIvjifGhT7BCa8+vP71 10 | UO85nFMsADbTvJ6ziyasKnXnwbppB3RnEj1JkX0CAwEAATANBgkqhkiG9w0BAQsF 11 | AAOCAQEAqCH1UN4wN6rMQw2DtdFb0XBKGb6TpHj+rGpsNimmAxYMhLb/09ua3Y33 12 | OfRudl0Q5ZPZ0KQSQU/WoETyei44OLaSqfTPww6L53Mbf+qyla4e602b9/nWNe8n 13 | y0n9nL2s3u6rhCvFXxZiu813blw1GPd7/B5mfu+QEA/UhkiASMA5msr7fNIMzke9 14 | 5rUYjMBzvSuy/vYbiTrXmKpAu5h4Z14qO8EDZy6gMzi0VhsUwur3I/ApOMt18BKx 15 | rOagdnBFQ9XAde7wmkO7ODr3cj1yA7GmIMTWGwCaJh5F/RlsfCdT2jlWPXQ2T8Fn 16 | PYufwpqtHrvN2qw7bU7SiV5UuX1I3A== 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /test/fixtures/ssl/certs/mkcerts.sh: -------------------------------------------------------------------------------- 1 | # from https://dev.mysql.com/doc/refman/8.0/en/creating-ssl-files-using-openssl.html 2 | 3 | # Create CA certificate 4 | openssl genrsa 2048 > ca-key.pem 5 | openssl req -new -x509 -nodes -days 3600 \ 6 | -key ca-key.pem -out ca.pem 7 | 8 | # Create server certificate, remove passphrase, and sign it 9 | # server-cert.pem = public key, server-key.pem = private key 10 | openssl req -newkey rsa:2048 -days 3600 \ 11 | -nodes -keyout server-key.pem -out server-req.pem 12 | openssl rsa -in server-key.pem -out server-key.pem 13 | openssl x509 -req -in server-req.pem -days 3600 \ 14 | -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem 15 | 16 | # Create client certificate, remove passphrase, and sign it 17 | # client-cert.pem = public key, client-key.pem = private key 18 | openssl req -newkey rsa:2048 -days 3600 \ 19 | -nodes -keyout client-key.pem -out client-req.pem 20 | openssl rsa -in client-key.pem -out client-key.pem 21 | openssl x509 -req -in client-req.pem -days 3600 \ 22 | -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem -------------------------------------------------------------------------------- /test/fixtures/ssl/certs/server-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICqjCCAZICAQEwDQYJKoZIhvcNAQEFBQAwGzELMAkGA1UEBhMCQVUxDDAKBgNV 3 | BAgMA1ZJQzAeFw0xOTA5MjkxMzAzMDdaFw0yOTA4MDcxMzAzMDdaMBsxCzAJBgNV 4 | BAYTAkFVMQwwCgYDVQQIDANWSUMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 5 | AoIBAQC2NaLE0M9LNghfK0CK8WP4TsDP4oGtX+SxfF2NAT6BLNEaM/k7p8htbfoP 6 | zv6YBSKKO9vgcKPsC19BbHuf1bE3HK0le/OLtcE9sI7DgfdFOgcHV2/LF+2EGLdP 7 | Ccvde/Jtqsfo6RaQB8SF7tQ9FNc49UdHGry9CfNUVmi/HHyqKAoYGTFvkwsDvI6R 8 | UfBev6Q6gpAxVkD560sholY8IWxYwI2vqzxYKKYfyuJAcHeSLPON3b+E9XftP8hL 9 | CMXTBjtRKrxoFT5fVxg8yFWC/7bMosQD10NbqJpZAPxPBIf/3DDqADGNcA8FEMPN 10 | FxeAPmledv3fF+JPF/zrKI+qR1zfAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAHB3 11 | D33d8i4j813Aut1Pxm7Ntk0JNDDq1smIDbxnY9MiOpVAEJ3nQkgbmN/vy/MhFE7m 12 | xnARgaiCOx7gYQDtTwKEAuSTyKJ5xsaS4O55ClPUEkzA8EiXyxgu1MiJQgZk7k8h 13 | uHaKjhX4dIRMDNcGWbrZBEBJMlbrHLco6tg2DwTSuF/nNwmZ4YU4xWsz8/aT+uSc 14 | qMPtWrOPRme6zfSKG/SPYreV1GA73Ema+Is9yE7buwPri+IWnzVdPStkEI8yn1S9 15 | uYrZd1i630lcUFiYq+c9ETDkNgX3ldNH2wdsbJI1nkFh6SMi4y8DseyFo7HWMC3w 16 | suH0xMMEPpjyNeVfsMw= 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /test/fixtures/ssl/certs/server-req.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICYDCCAUgCAQAwGzELMAkGA1UEBhMCQVUxDDAKBgNVBAgMA1ZJQzCCASIwDQYJ 3 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBALY1osTQz0s2CF8rQIrxY/hOwM/iga1f 4 | 5LF8XY0BPoEs0Roz+TunyG1t+g/O/pgFIoo72+Bwo+wLX0Fse5/VsTccrSV784u1 5 | wT2wjsOB90U6BwdXb8sX7YQYt08Jy9178m2qx+jpFpAHxIXu1D0U1zj1R0cavL0J 6 | 81RWaL8cfKooChgZMW+TCwO8jpFR8F6/pDqCkDFWQPnrSyGiVjwhbFjAja+rPFgo 7 | ph/K4kBwd5Is843dv4T1d+0/yEsIxdMGO1EqvGgVPl9XGDzIVYL/tsyixAPXQ1uo 8 | mlkA/E8Eh//cMOoAMY1wDwUQw80XF4A+aV52/d8X4k8X/Osoj6pHXN8CAwEAAaAA 9 | MA0GCSqGSIb3DQEBCwUAA4IBAQBVpcCRFnRT5IARzXdhGSxo+P9T8IxDqYltnvni 10 | fs2yLR9E8EEpypY11qzN/0HX42av0RTTrcCQvR+Bfud1TPLGYKA0oUhKlX8kN4XC 11 | E29QGS5RMd7UZLByaGSlKiHSzRuzAt1np4GYUEDoAX3UMxkf3gAgErJEBooSoGmK 12 | qAew16W68dOqzklUiNN9AzmCzbkpjveYtYYC+k5+oBnuU4o+0/rkY6fKI4WpMQ3K 13 | tbYIv51s9wa3vqkdzEY8pZWkfnGRAj+UxRg7yHM44ec2xMxcnyjWZZKEy6z32BoF 14 | rm794RVdobl5Lj6r5lZqpeMvrr9p3QOG5kxL5Q+bIrxJv7Fj 15 | -----END CERTIFICATE REQUEST----- 16 | -------------------------------------------------------------------------------- /test/fixtures/ssl/client-flags.sh: -------------------------------------------------------------------------------- 1 | mysql --ssl-key=certs/client-key.pem --ssl-cert=certs/client-cert.pem -h 127.0.0.1 -P 3307 2 | -------------------------------------------------------------------------------- /test/integration/config/test-connect-timeout.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const portfinder = require('portfinder'); 3 | const mysql = require('../../../index.js'); 4 | const assert = require('node:assert'); 5 | const process = require('node:process'); 6 | 7 | // The process is not terminated in Deno 8 | if (typeof Deno !== 'undefined') process.exit(0); 9 | 10 | console.log('test connect timeout'); 11 | 12 | portfinder.getPort((err, port) => { 13 | const server = mysql.createServer(); 14 | server.on('connection', () => { 15 | // Let connection time out 16 | }); 17 | 18 | server.listen(port); 19 | 20 | const connection = mysql.createConnection({ 21 | host: 'localhost', 22 | port: port, 23 | connectTimeout: 1000, 24 | }); 25 | 26 | connection.on('error', (err) => { 27 | assert.equal(err.code, 'ETIMEDOUT'); 28 | connection.destroy(); 29 | server._server.close(); 30 | console.log('ok'); 31 | }); 32 | }); 33 | 34 | process.on('uncaughtException', (err) => { 35 | assert.equal( 36 | err.message, 37 | 'Connection lost: The server closed the connection.' 38 | ); 39 | assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); 40 | }); 41 | -------------------------------------------------------------------------------- /test/integration/config/test-typecast-global-false.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const connection = common.createConnection({ 5 | typeCast: false, 6 | }); 7 | 8 | const { assert } = require('poku'); 9 | 10 | const COL_1_VALUE = 'col v1'; 11 | const COL_2_VALUE = 'col v2'; 12 | 13 | function executeTests(res) { 14 | assert.equal(res[0].v1.toString('ascii'), COL_1_VALUE); 15 | assert.equal(res[0].n1, null); 16 | assert.equal(res[0].v2.toString('ascii'), COL_2_VALUE); 17 | } 18 | 19 | connection.query( 20 | 'CREATE TEMPORARY TABLE binpar_null_test (v1 VARCHAR(16) NOT NULL, n1 VARCHAR(16), v2 VARCHAR(16) NOT NULL)' 21 | ); 22 | connection.query( 23 | `INSERT INTO binpar_null_test (v1, n1, v2) VALUES ("${COL_1_VALUE}", NULL, "${COL_2_VALUE}")`, 24 | (err) => { 25 | if (err) throw err; 26 | } 27 | ); 28 | 29 | connection.execute('SELECT * FROM binpar_null_test', (err, res) => { 30 | if (err) throw err; 31 | executeTests(res); 32 | connection.end(); 33 | }); 34 | -------------------------------------------------------------------------------- /test/integration/config/test-typecast-global-option.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | 6 | const typeCastWrapper = function (stringMethod) { 7 | return function (field, next) { 8 | if (field.type === 'VAR_STRING') { 9 | return field.string()[stringMethod](); 10 | } 11 | return next(); 12 | }; 13 | }; 14 | 15 | const connection = common.createConnection({ 16 | typeCast: typeCastWrapper('toUpperCase'), 17 | }); 18 | 19 | // query option override global typeCast 20 | connection.query( 21 | { 22 | sql: 'select "FOOBAR" as foo', 23 | typeCast: typeCastWrapper('toLowerCase'), 24 | }, 25 | (err, res) => { 26 | assert.ifError(err); 27 | assert.equal(res[0].foo, 'foobar'); 28 | } 29 | ); 30 | 31 | // global typecast works 32 | connection.query( 33 | { 34 | sql: 'select "foobar" as foo', 35 | }, 36 | (err, res) => { 37 | assert.ifError(err); 38 | assert.equal(res[0].foo, 'FOOBAR'); 39 | } 40 | ); 41 | 42 | connection.end(); 43 | -------------------------------------------------------------------------------- /test/integration/connection/encoding/test-non-bmp-chars.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | if (`${process.env.MYSQL_CONNECTION_URL}`.includes('pscale_pw_')) { 8 | console.log('skipping test for planetscale'); 9 | process.exit(0); 10 | } 11 | 12 | // 4 bytes in utf8 13 | const pileOfPoo = '💩'; 14 | 15 | const connection = common.createConnection({ charset: 'UTF8_GENERAL_CI' }); 16 | connection.query('select "💩"', (err, rows, fields) => { 17 | assert.ifError(err); 18 | assert.equal(fields[0].name, pileOfPoo); 19 | assert.equal(rows[0][fields[0].name], pileOfPoo); 20 | connection.end(); 21 | }); 22 | 23 | const connection2 = common.createConnection({ charset: 'UTF8MB4_GENERAL_CI' }); 24 | connection2.query('select "💩"', (err, rows, fields) => { 25 | assert.ifError(err); 26 | assert.equal(fields[0].name, '?'); 27 | assert.equal(rows[0]['?'], pileOfPoo); 28 | connection2.end(); 29 | }); 30 | -------------------------------------------------------------------------------- /test/integration/connection/encoding/test-track-encodings.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | 6 | const connection = common.createConnection({ charset: 'UTF8MB4_GENERAL_CI' }); 7 | const text = 'привет, мир'; 8 | 9 | connection.query('SET character_set_client=koi8r', (err) => { 10 | assert.ifError(err); 11 | connection.query(`SELECT ? as result`, [text], (err, rows) => { 12 | assert.ifError(err); 13 | assert.equal(rows[0].result, text); 14 | connection.query('SET character_set_client=cp1251', (err) => { 15 | assert.ifError(err); 16 | connection.query(`SELECT ? as result`, [text], (err, rows) => { 17 | assert.ifError(err); 18 | assert.equal(rows[0].result, text); 19 | connection.end(); 20 | }); 21 | }); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/integration/connection/test-buffer-params.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const connection = common.createConnection(); 5 | const { assert } = require('poku'); 6 | const { Buffer } = require('node:buffer'); 7 | const process = require('node:process'); 8 | 9 | let rows = undefined; 10 | let rows1 = undefined; 11 | 12 | const buf = Buffer.from([ 13 | 0x80, 0x90, 1, 2, 3, 4, 5, 6, 7, 8, 9, 100, 100, 255, 255, 14 | ]); 15 | connection.execute('SELECT HEX(?) as buf', [buf], (err, _rows) => { 16 | if (err) { 17 | throw err; 18 | } 19 | rows = _rows; 20 | }); 21 | 22 | connection.query('SELECT HEX(?) as buf', [buf], (err, _rows) => { 23 | if (err) { 24 | throw err; 25 | } 26 | rows1 = _rows; 27 | connection.end(); 28 | }); 29 | 30 | process.on('exit', () => { 31 | assert.deepEqual(rows, [{ buf: buf.toString('hex').toUpperCase() }]); 32 | assert.deepEqual(rows1, [{ buf: buf.toString('hex').toUpperCase() }]); 33 | }); 34 | -------------------------------------------------------------------------------- /test/integration/connection/test-connect-after-connection-error.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const mysql = require('../../../index.js'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | // The process is not terminated in Deno 8 | if (typeof Deno !== 'undefined') process.exit(0); 9 | 10 | const ERROR_TEXT = 'Connection lost: The server closed the connection.'; 11 | 12 | const portfinder = require('portfinder'); 13 | portfinder.getPort((err, port) => { 14 | const server = mysql.createServer(); 15 | let serverConnection; 16 | server.listen(port); 17 | server.on('connection', (conn) => { 18 | conn.serverHandshake({ 19 | serverVersion: '5.6.10', 20 | capabilityFlags: 2181036031, 21 | }); 22 | serverConnection = conn; 23 | }); 24 | 25 | const clientConnection = mysql.createConnection({ 26 | host: 'localhost', 27 | port: port, 28 | user: 'testuser', 29 | database: 'testdatabase', 30 | password: 'testpassword', 31 | }); 32 | 33 | clientConnection.on('connect', () => { 34 | serverConnection.close(); 35 | }); 36 | 37 | clientConnection.once('error', () => { 38 | clientConnection.connect((err) => { 39 | assert.equal(err.message, ERROR_TEXT); 40 | clientConnection.close(); 41 | server._server.close(); 42 | }); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /test/integration/connection/test-connect-after-connection.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let connection2; 10 | 11 | connection.once('connect', () => { 12 | connection.connect((err, _connection) => { 13 | if (err) { 14 | throw err; 15 | } 16 | connection2 = _connection; 17 | connection.end(); 18 | }); 19 | }); 20 | 21 | process.on('exit', () => { 22 | assert.equal(connection, connection2); 23 | }); 24 | -------------------------------------------------------------------------------- /test/integration/connection/test-connect-connection-closed-error.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const mysql = require('../../../index.js'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | const portfinder = require('portfinder'); 7 | 8 | // The process is not terminated in Deno 9 | if (typeof Deno !== 'undefined') process.exit(0); 10 | 11 | const ERROR_TEXT = 'Connection lost: The server closed the connection.'; 12 | 13 | portfinder.getPort((err, port) => { 14 | const server = mysql.createServer(); 15 | server.listen(port); 16 | server.on('connection', (conn) => { 17 | conn.close(); 18 | }); 19 | 20 | const connection = mysql.createConnection({ 21 | host: 'localhost', 22 | port: port, 23 | user: 'testuser', 24 | database: 'testdatabase', 25 | password: 'testpassword', 26 | }); 27 | 28 | connection.query('select 1', (err) => { 29 | assert.equal(err.message, ERROR_TEXT); 30 | server._server.close(); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/integration/connection/test-connect-time-error.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const mysql = require('../../../index.js'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | const portfinder = require('portfinder'); 7 | 8 | // The process is not terminated in Deno 9 | if (typeof Deno !== 'undefined') process.exit(0); 10 | 11 | const ERROR_TEXT = 'test error'; 12 | 13 | portfinder.getPort((err, port) => { 14 | const server = mysql.createServer(); 15 | server.listen(port); 16 | server.on('connection', (conn) => { 17 | conn.writeError(new Error(ERROR_TEXT)); 18 | conn.close(); 19 | }); 20 | 21 | const connection = mysql.createConnection({ 22 | host: 'localhost', 23 | port: port, 24 | user: 'testuser', 25 | database: 'testdatabase', 26 | password: 'testpassword', 27 | }); 28 | 29 | connection.query('select 1+1', (err) => { 30 | assert.equal(err.message, ERROR_TEXT); 31 | }); 32 | 33 | connection.query('select 1+2', (err) => { 34 | assert.equal(err.message, ERROR_TEXT); 35 | connection.close(); 36 | server._server.close(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /test/integration/connection/test-connect-with-uri.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | if (process.env.MYSQL_CONNECTION_URL) { 8 | console.log( 9 | 'skipping test when mysql server is configured using MYSQL_CONNECTION_URL' 10 | ); 11 | process.exit(0); 12 | } 13 | 14 | const connection = common.createConnectionWithURI(); 15 | 16 | let rows = undefined; 17 | let fields = undefined; 18 | connection.query('SELECT 1', (err, _rows, _fields) => { 19 | if (err) { 20 | throw err; 21 | } 22 | 23 | rows = _rows; 24 | fields = _fields; 25 | connection.end(); 26 | }); 27 | 28 | process.on('exit', () => { 29 | assert.deepEqual(rows, [{ 1: 1 }]); 30 | assert.equal(fields[0].name, '1'); 31 | }); 32 | -------------------------------------------------------------------------------- /test/integration/connection/test-connection-reset-while-closing.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('node:assert'); 4 | const common = require('../../common.test.cjs'); 5 | const process = require('node:process'); 6 | 7 | const error = new Error('read ECONNRESET'); 8 | error.code = 'ECONNRESET'; 9 | error.errno = -54; 10 | error.syscall = 'read'; 11 | 12 | const connection = common.createConnection(); 13 | 14 | // Test that we ignore a ECONNRESET error if the connection 15 | // is already closing, we close and then emit the error 16 | connection.query(`select 1 as "1"`, (err, rows) => { 17 | assert.equal(rows[0]['1'], 1); 18 | connection.close(); 19 | connection.stream.emit('error', error); 20 | }); 21 | 22 | process.on('uncaughtException', (err) => { 23 | assert.notEqual(err.code, 'ECONNRESET'); 24 | }); 25 | -------------------------------------------------------------------------------- /test/integration/connection/test-custom-date-parameter.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection({ timezone: 'Z' }); 8 | 9 | let rows = undefined; 10 | 11 | // eslint-disable-next-line no-global-assign 12 | Date = (function () { 13 | const NativeDate = Date; 14 | function CustomDate(str) { 15 | return new NativeDate(str); 16 | } 17 | CustomDate.now = Date.now; 18 | return CustomDate; 19 | })(); 20 | 21 | connection.query("set time_zone = '+00:00'"); 22 | connection.execute( 23 | 'SELECT UNIX_TIMESTAMP(?) t', 24 | [new Date('1990-08-08 UTC')], 25 | (err, _rows) => { 26 | if (err) { 27 | throw err; 28 | } 29 | rows = _rows; 30 | connection.end(); 31 | } 32 | ); 33 | 34 | process.on('exit', () => { 35 | assert.equal(rows[0].t, 650073600); 36 | }); 37 | -------------------------------------------------------------------------------- /test/integration/connection/test-date-parameter.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection({ timezone: 'Z' }); 8 | 9 | let rows = undefined; 10 | 11 | connection.query("set time_zone = '+00:00'"); 12 | connection.execute( 13 | 'SELECT UNIX_TIMESTAMP(?) t', 14 | [new Date('1990-01-01 UTC')], 15 | (err, _rows) => { 16 | if (err) { 17 | throw err; 18 | } 19 | rows = _rows; 20 | connection.end(); 21 | } 22 | ); 23 | 24 | process.on('exit', () => { 25 | assert.deepEqual(rows, [{ t: 631152000 }]); 26 | }); 27 | -------------------------------------------------------------------------------- /test/integration/connection/test-decimals-as-numbers.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | 6 | const connection1 = common.createConnection({ 7 | decimalNumbers: false, 8 | }); 9 | const connection2 = common.createConnection({ 10 | decimalNumbers: true, 11 | }); 12 | 13 | const largeDecimal = 900719.547409; 14 | const largeDecimalExpected = '900719.547409000000000000000000000000'; 15 | const largeMoneyValue = 900719925474.99; 16 | 17 | connection1.query('CREATE TEMPORARY TABLE t1 (d1 DECIMAL(65, 30))'); 18 | connection1.query('INSERT INTO t1 set d1=?', [largeDecimal]); 19 | 20 | connection2.query('CREATE TEMPORARY TABLE t2 (d1 DECIMAL(14, 2))'); 21 | connection2.query('INSERT INTO t2 set d1=?', [largeMoneyValue]); 22 | 23 | connection1.execute('select d1 from t1', (err, _rows) => { 24 | if (err) { 25 | throw err; 26 | } 27 | assert.equal(_rows[0].d1.constructor, String); 28 | assert.equal(_rows[0].d1, largeDecimalExpected); 29 | connection1.end(); 30 | }); 31 | 32 | connection2.query('select d1 from t2', (err, _rows) => { 33 | if (err) { 34 | throw err; 35 | } 36 | assert.equal(_rows[0].d1.constructor, Number); 37 | assert.equal(_rows[0].d1, largeMoneyValue); 38 | connection2.end(); 39 | }); 40 | -------------------------------------------------------------------------------- /test/integration/connection/test-error-events.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | let callCount = 0; 8 | let exceptionCount = 0; 9 | 10 | process.on('uncaughtException', (err) => { 11 | assert.ifError(err); 12 | exceptionCount++; 13 | }); 14 | 15 | const connection1 = common.createConnection({ 16 | password: 'lol', 17 | }); 18 | 19 | // error will NOT bubble up to process level if `on` is used 20 | connection1.on('error', () => { 21 | callCount++; 22 | }); 23 | 24 | const connection2 = common.createConnection({ 25 | password: 'lol', 26 | }); 27 | 28 | // error will bubble up to process level if `once` is used 29 | connection2.once('error', () => { 30 | callCount++; 31 | }); 32 | 33 | process.on('exit', () => { 34 | assert.equal(callCount, 2); 35 | assert.equal(exceptionCount, 0); 36 | }); 37 | -------------------------------------------------------------------------------- /test/integration/connection/test-execute-and-unprepare.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const connection = common.createConnection(); 5 | 6 | const max = 500; 7 | function exec(i) { 8 | const query = `select 1+${i}`; 9 | connection.execute(query, (err) => { 10 | connection.unprepare(query); 11 | if (err) { 12 | throw err; 13 | } 14 | if (i > max) { 15 | connection.end(); 16 | } else { 17 | exec(i + 1); 18 | } 19 | }); 20 | } 21 | connection.query('SET GLOBAL max_prepared_stmt_count=10', (err) => { 22 | if (err) { 23 | throw err; 24 | } 25 | exec(1); 26 | }); 27 | -------------------------------------------------------------------------------- /test/integration/connection/test-execute-bind-boolean.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let rows; 10 | connection.execute( 11 | 'SELECT ? AS trueValue, ? AS falseValue', 12 | [true, false], 13 | (err, _rows) => { 14 | if (err) { 15 | throw err; 16 | } 17 | rows = _rows; 18 | connection.end(); 19 | } 20 | ); 21 | 22 | process.on('exit', () => { 23 | assert.deepEqual(rows, [{ trueValue: 1, falseValue: 0 }]); 24 | }); 25 | -------------------------------------------------------------------------------- /test/integration/connection/test-execute-bind-date.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | const date = new Date(2018, 2, 10, 15, 12, 34, 1234); 9 | 10 | let rows; 11 | connection.execute( 12 | 'SELECT CAST(? AS DATETIME(6)) AS result', 13 | [date], 14 | (err, _rows) => { 15 | if (err) { 16 | throw err; 17 | } 18 | rows = _rows; 19 | connection.end(); 20 | } 21 | ); 22 | 23 | process.on('exit', () => { 24 | assert.deepEqual(rows, [{ result: date }]); 25 | }); 26 | -------------------------------------------------------------------------------- /test/integration/connection/test-execute-bind-function.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let error = null; 10 | 11 | try { 12 | connection.execute('SELECT ? AS result', [function () {}], () => {}); 13 | } catch (err) { 14 | error = err; 15 | connection.end(); 16 | } 17 | 18 | process.on('exit', () => { 19 | assert.equal(error.name, 'TypeError'); 20 | if (!error.message.match(/function/)) { 21 | assert.fail("Expected error.message to contain 'function'"); 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /test/integration/connection/test-execute-bind-json.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | const table = 'jsontable'; 9 | const testJson = [{ a: 1, b: true, c: ['foo'] }]; 10 | 11 | let rows; 12 | connection.query(`CREATE TEMPORARY TABLE ${table} (data JSON)`); 13 | connection.query( 14 | `INSERT INTO ${table} (data) VALUES ('${JSON.stringify(testJson)}')` 15 | ); 16 | connection.execute(`SELECT * from ${table}`, (err, _rows) => { 17 | if (err) { 18 | throw err; 19 | } 20 | rows = _rows; 21 | connection.end(); 22 | }); 23 | 24 | process.on('exit', () => { 25 | assert.deepEqual(rows, [{ data: testJson }]); 26 | }); 27 | -------------------------------------------------------------------------------- /test/integration/connection/test-execute-bind-null.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let rows; 10 | connection.execute( 11 | 'SELECT ? AS firstValue, ? AS nullValue, ? AS lastValue', 12 | ['foo', null, 'bar'], 13 | (err, _rows) => { 14 | if (err) { 15 | throw err; 16 | } 17 | rows = _rows; 18 | connection.end(); 19 | } 20 | ); 21 | 22 | process.on('exit', () => { 23 | assert.deepEqual(rows, [ 24 | { firstValue: 'foo', nullValue: null, lastValue: 'bar' }, 25 | ]); 26 | }); 27 | -------------------------------------------------------------------------------- /test/integration/connection/test-execute-bind-number.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let rows; 10 | connection.execute( 11 | 'SELECT ? AS zeroValue, ? AS positiveValue, ? AS negativeValue, ? AS decimalValue', 12 | [0, 123, -123, 1.25], 13 | (err, _rows) => { 14 | if (err) { 15 | throw err; 16 | } 17 | rows = _rows; 18 | connection.end(); 19 | } 20 | ); 21 | 22 | process.on('exit', () => { 23 | assert.deepEqual(rows, [ 24 | { 25 | zeroValue: 0, 26 | positiveValue: 123, 27 | negativeValue: -123, 28 | decimalValue: 1.25, 29 | }, 30 | ]); 31 | }); 32 | -------------------------------------------------------------------------------- /test/integration/connection/test-execute-bind-undefined.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let error = null; 10 | 11 | try { 12 | connection.execute('SELECT ? AS result', [undefined], () => {}); 13 | } catch (err) { 14 | error = err; 15 | connection.end(); 16 | } 17 | 18 | process.on('exit', () => { 19 | assert.equal(error.name, 'TypeError'); 20 | if (!error.message.match(/undefined/)) { 21 | assert.fail("Expected error.message to contain 'undefined'"); 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /test/integration/connection/test-execute-cached.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let rows = undefined; 10 | let rows1 = undefined; 11 | let rows2 = undefined; 12 | 13 | const q = 'select 1 + ? as test'; 14 | const key = `undefined/undefined/undefined${q}`; 15 | 16 | connection.execute(q, [123], (err, _rows) => { 17 | if (err) { 18 | throw err; 19 | } 20 | rows = _rows; 21 | connection.execute(q, [124], (err, _rows) => { 22 | if (err) { 23 | throw err; 24 | } 25 | rows1 = _rows; 26 | connection.execute(q, [125], (err, _rows) => { 27 | if (err) { 28 | throw err; 29 | } 30 | rows2 = _rows; 31 | assert(connection._statements.size === 1); 32 | assert(connection._statements.get(key).query === q); 33 | assert(connection._statements.get(key).parameters.length === 1); 34 | connection.end(); 35 | }); 36 | }); 37 | }); 38 | 39 | process.on('exit', () => { 40 | assert.deepEqual(rows, [{ test: 124 }]); 41 | assert.deepEqual(rows1, [{ test: 125 }]); 42 | assert.deepEqual(rows2, [{ test: 126 }]); 43 | }); 44 | -------------------------------------------------------------------------------- /test/integration/connection/test-execute-newdecimal.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | connection.query('CREATE TEMPORARY TABLE t (f DECIMAL(19,4))'); 10 | connection.query('INSERT INTO t VALUES(12345.67)'); 11 | 12 | let rows, fields; 13 | connection.execute('SELECT f FROM t', (err, _rows, _fields) => { 14 | if (err) { 15 | throw err; 16 | } 17 | rows = _rows; 18 | fields = _fields; 19 | connection.end(); 20 | }); 21 | 22 | process.on('exit', () => { 23 | assert.deepEqual(rows, [{ f: '12345.6700' }]); 24 | assert.equal(fields[0].name, 'f'); 25 | }); 26 | -------------------------------------------------------------------------------- /test/integration/connection/test-execute-null-bitmap.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const connection = common.createConnection(); 5 | const { assert } = require('poku'); 6 | 7 | const params = [1, 2]; 8 | let query = 'select ? + ?'; 9 | 10 | function dotest() { 11 | connection.execute(`${query} as t`, params, (err, _rows) => { 12 | assert.equal(err, null); 13 | if (params.length < 50) { 14 | assert.equal( 15 | _rows[0].t, 16 | params.reduce((x, y) => x + y) 17 | ); 18 | query += ' + ?'; 19 | params.push(params.length); 20 | dotest(); 21 | } else { 22 | connection.end(); 23 | } 24 | }); 25 | } 26 | 27 | connection.query('SET GLOBAL max_prepared_stmt_count=300', dotest); 28 | -------------------------------------------------------------------------------- /test/integration/connection/test-execute-order.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | const order = []; 10 | connection.execute('select 1+2', (err) => { 11 | assert.ifError(err); 12 | order.push(0); 13 | }); 14 | connection.execute('select 2+2', (err) => { 15 | assert.ifError(err); 16 | order.push(1); 17 | }); 18 | connection.query('select 1+1', (err) => { 19 | assert.ifError(err); 20 | order.push(2); 21 | connection.end(); 22 | }); 23 | 24 | process.on('exit', () => { 25 | assert.deepEqual(order, [0, 1, 2]); 26 | }); 27 | -------------------------------------------------------------------------------- /test/integration/connection/test-execute-signed.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let rows = undefined; 10 | 11 | connection.query( 12 | [ 13 | 'CREATE TEMPORARY TABLE `test_table` (', 14 | '`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', 15 | '`num` int(15),', 16 | '`l` long,', 17 | 'PRIMARY KEY (`id`)', 18 | ') ENGINE=InnoDB DEFAULT CHARSET=utf8', 19 | ].join('\n') 20 | ); 21 | 22 | connection.query('insert into test_table(num,l) values(?, 3)', [1]); 23 | connection.query('insert into test_table(num,l) values(3-?, -10)', [5]); 24 | connection.query( 25 | 'insert into test_table(num,l) values(4+?, 4000000-?)', 26 | [-5, 8000000] 27 | ); 28 | 29 | connection.execute('SELECT * from test_table', [], (err, _rows) => { 30 | if (err) { 31 | throw err; 32 | } 33 | rows = _rows; 34 | connection.end(); 35 | }); 36 | 37 | process.on('exit', () => { 38 | assert.deepEqual(rows, [ 39 | { id: 1, num: 1, l: 3 }, 40 | { id: 2, num: -2, l: -10 }, 41 | { id: 3, num: -1, l: -4000000 }, 42 | ]); 43 | }); 44 | -------------------------------------------------------------------------------- /test/integration/connection/test-insert-json.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Created by Elijah Melton on 2023.05.03 5 | * issue#1924: https://github.com/sidorares/node-mysql2/issues/1924 6 | */ 7 | 8 | const common = require('../../common.test.cjs'); 9 | const { assert } = require('poku'); 10 | const process = require('node:process'); 11 | 12 | const connection = common.createConnection(); 13 | 14 | let result; 15 | let errorCodeInvalidJSON; 16 | let errorNumInvalidJSON; 17 | 18 | connection.query('CREATE TEMPORARY TABLE json_test (data JSON)'); 19 | connection.query('INSERT INTO json_test VALUES (?)', ['{"k": "v"'], (err) => { 20 | errorCodeInvalidJSON = err.code; 21 | errorNumInvalidJSON = err.errno; 22 | }); 23 | 24 | connection.query('INSERT INTO json_test VALUES (?)', ['{"k": "v"}'], (err) => { 25 | if (err) throw err; 26 | }); 27 | 28 | connection.query('SELECT * FROM json_test;', [], (err, res) => { 29 | if (err) throw err; 30 | result = res; 31 | connection.end(); 32 | }); 33 | 34 | process.on('exit', () => { 35 | assert.equal(errorCodeInvalidJSON, 'ER_INVALID_JSON_TEXT'); 36 | assert.equal(errorNumInvalidJSON, 3140); 37 | assert.equal(result[0].data.k, 'v'); 38 | }); 39 | -------------------------------------------------------------------------------- /test/integration/connection/test-insert-results.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | // common.useTestDb(connection); 10 | 11 | const table = 'insert_test'; 12 | // const text = "本日は晴天なり"; 13 | const text = ' test test test '; 14 | connection.query( 15 | [ 16 | `CREATE TEMPORARY TABLE \`${table}\` (`, 17 | '`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', 18 | '`title` varchar(255),', 19 | 'PRIMARY KEY (`id`)', 20 | ') ENGINE=InnoDB DEFAULT CHARSET=utf8', 21 | ].join('\n') 22 | ); 23 | 24 | let result, result2; 25 | connection.query(`INSERT INTO ${table} SET title="${text}"`, (err, _result) => { 26 | if (err) { 27 | throw err; 28 | } 29 | result = _result; 30 | connection.query( 31 | `SELECT * FROM ${table} WHERE id = ${result.insertId}`, 32 | (err, _result2) => { 33 | result2 = _result2; 34 | connection.end(); 35 | } 36 | ); 37 | }); 38 | 39 | process.on('exit', () => { 40 | assert.strictEqual(result.insertId, 1); 41 | assert.strictEqual(result2.length, 1); 42 | // TODO: type conversions 43 | assert.equal(result2[0].id, String(result.insertId)); 44 | assert.equal(result2[0].title, text); 45 | }); 46 | -------------------------------------------------------------------------------- /test/integration/connection/test-null-buffer.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let rowsTextProtocol; 10 | let rowsBinaryProtocol; 11 | 12 | connection.query('CREATE TEMPORARY TABLE binary_table (stuff BINARY(16));'); 13 | connection.query('INSERT INTO binary_table VALUES(null)'); 14 | 15 | connection.query('SELECT * from binary_table', (err, _rows) => { 16 | if (err) { 17 | throw err; 18 | } 19 | rowsTextProtocol = _rows; 20 | connection.execute('SELECT * from binary_table', (err, _rows) => { 21 | if (err) { 22 | throw err; 23 | } 24 | rowsBinaryProtocol = _rows; 25 | connection.end(); 26 | }); 27 | }); 28 | 29 | process.on('exit', () => { 30 | assert.deepEqual(rowsTextProtocol[0], { stuff: null }); 31 | assert.deepEqual(rowsBinaryProtocol[0], { stuff: null }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/integration/connection/test-null-double.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let rows; 10 | 11 | connection.query('CREATE TEMPORARY TABLE t (i int)'); 12 | connection.query('INSERT INTO t VALUES(null)'); 13 | connection.query('INSERT INTO t VALUES(123)'); 14 | 15 | connection.query('SELECT * from t', (err, _rows) => { 16 | if (err) { 17 | throw err; 18 | } 19 | rows = _rows; 20 | connection.end(); 21 | }); 22 | 23 | process.on('exit', () => { 24 | assert.deepEqual(rows[0], { i: null }); 25 | assert.deepEqual(rows[1], { i: 123 }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/integration/connection/test-null-int.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let rows; 10 | 11 | connection.query('CREATE TEMPORARY TABLE t (i int)'); 12 | connection.query('INSERT INTO t VALUES(null)'); 13 | connection.query('INSERT INTO t VALUES(123)'); 14 | 15 | connection.query('SELECT * from t', (err, _rows) => { 16 | if (err) { 17 | throw err; 18 | } 19 | rows = _rows; 20 | connection.end(); 21 | }); 22 | 23 | process.on('exit', () => { 24 | assert.deepEqual(rows[0], { i: null }); 25 | assert.deepEqual(rows[1], { i: 123 }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/integration/connection/test-null.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let rows, rows1; 10 | let fields1; 11 | 12 | connection.query('CREATE TEMPORARY TABLE t (i int)'); 13 | connection.query('INSERT INTO t VALUES(null)'); 14 | connection.query('SELECT cast(NULL AS CHAR) as cast_result', (err, _rows) => { 15 | if (err) { 16 | throw err; 17 | } 18 | rows = _rows; 19 | }); 20 | connection.query('SELECT * from t', (err, _rows, _fields) => { 21 | if (err) { 22 | throw err; 23 | } 24 | rows1 = _rows; 25 | fields1 = _fields; 26 | connection.end(); 27 | }); 28 | 29 | process.on('exit', () => { 30 | assert.deepEqual(rows, [{ cast_result: null }]); 31 | // assert.equal(fields[0].columnType, 253); // depeding on the server type could be 253 or 3, disabling this check for now 32 | assert.deepEqual(rows1, [{ i: null }]); 33 | assert.equal(fields1[0].columnType, 3); 34 | }); 35 | -------------------------------------------------------------------------------- /test/integration/connection/test-parameters-questionmark.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | 6 | const pool = common.createPool(); 7 | pool.config.connectionLimit = 1; 8 | 9 | pool.query( 10 | [ 11 | 'CREATE TEMPORARY TABLE `test_table` (', 12 | '`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', 13 | '`str` varchar(64),', 14 | 'PRIMARY KEY (`id`)', 15 | ') ENGINE=InnoDB DEFAULT CHARSET=utf8', 16 | ].join('\n') 17 | ); 18 | pool.query('insert into test_table(str) values(?)', ['abc?']); 19 | pool.query('UPDATE test_table SET str = ? WHERE id = ?', [ 20 | 'should not change ?', 21 | 1, 22 | ]); 23 | pool.query('SELECT str FROM test_table WHERE id = ?', [1], (err, rows) => { 24 | pool.end(); 25 | if (err) { 26 | throw err; 27 | } 28 | assert.deepEqual(rows, [{ str: 'should not change ?' }]); 29 | }); 30 | -------------------------------------------------------------------------------- /test/integration/connection/test-prepare-and-close.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | const max = 500; 10 | const start = process.hrtime(); 11 | function prepare(i) { 12 | connection.prepare(`select 1+${i}`, (err, stmt) => { 13 | assert.ifError(err); 14 | stmt.close(); 15 | if (!err) { 16 | if (i > max) { 17 | const end = process.hrtime(start); 18 | const ns = end[0] * 1e9 + end[1]; 19 | console.log(`${(max * 1e9) / ns} prepares/sec`); 20 | connection.end(); 21 | return; 22 | } 23 | setTimeout(() => { 24 | prepare(i + 1); 25 | }, 2); 26 | return; 27 | } 28 | assert(0, 'Error in prepare!'); 29 | }); 30 | } 31 | connection.query('SET GLOBAL max_prepared_stmt_count=10', (err) => { 32 | assert.ifError(err); 33 | prepare(1); 34 | }); 35 | -------------------------------------------------------------------------------- /test/integration/connection/test-prepare-simple.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let _stmt1, _stmt2, _stmt3; 10 | const query1 = 'select 1 + ? + ? as test'; 11 | const query2 = 'select 1 + 1'; // no parameters 12 | const query3 = 'create temporary table aaa(i int);'; // no parameters, no result columns 13 | 14 | connection.prepare(query1, (err1, stmt1) => { 15 | assert.ifError(err1); 16 | _stmt1 = stmt1; 17 | _stmt1.close(); 18 | connection.prepare(query2, (err2, stmt2) => { 19 | assert.ifError(err2); 20 | _stmt2 = stmt2; 21 | connection.prepare(query3, (err3, stmt3) => { 22 | assert.ifError(err3); 23 | _stmt3 = stmt3; 24 | _stmt2.close(); 25 | _stmt3.close(); 26 | connection.end(); 27 | }); 28 | }); 29 | }); 30 | 31 | process.on('exit', () => { 32 | assert.equal(_stmt1.query, query1); 33 | assert(_stmt1.id >= 0); 34 | assert.equal(_stmt1.columns.length, 1); 35 | assert.equal(_stmt1.parameters.length, 2); 36 | }); 37 | -------------------------------------------------------------------------------- /test/integration/connection/test-prepare-then-execute.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let _stmt = null; 10 | let _columns = null; 11 | let _rows = null; 12 | 13 | connection.prepare('select 1 + ? + ? as test', (err, stmt) => { 14 | if (err) { 15 | throw err; 16 | } 17 | _stmt = stmt; 18 | stmt.execute([111, 123], (err, rows, columns) => { 19 | if (err) { 20 | throw err; 21 | } 22 | _columns = columns; 23 | _rows = rows; 24 | connection.end(); 25 | }); 26 | }); 27 | 28 | process.on('exit', () => { 29 | assert.equal(_stmt.columns.length, 1); 30 | assert.equal(_stmt.parameters.length, 2); 31 | assert.deepEqual(_rows, [{ test: 235 }]); 32 | assert.equal(_columns[0].name, 'test'); 33 | }); 34 | -------------------------------------------------------------------------------- /test/integration/connection/test-query-zero.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let rows; 10 | connection.query('SELECT ? AS result', 0, (err, _rows) => { 11 | if (err) { 12 | throw err; 13 | } 14 | rows = _rows; 15 | connection.end(); 16 | }); 17 | 18 | process.on('exit', () => { 19 | assert.deepEqual(rows, [{ result: 0 }]); 20 | }); 21 | -------------------------------------------------------------------------------- /test/integration/connection/test-select-1.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('poku'); 4 | const common = require('../../common.test.cjs'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | connection.query('SELECT 1 as result', (err, rows, fields) => { 10 | assert.ifError(err); 11 | assert.deepEqual(rows, [{ result: 1 }]); 12 | assert.equal(fields[0].name, 'result'); 13 | 14 | connection.execute('SELECT 1 as result', (err, rows, fields) => { 15 | assert.ifError(err); 16 | assert.deepEqual(rows, [{ result: 1 }]); 17 | assert.equal(fields[0].name, 'result'); 18 | 19 | connection.end((err) => { 20 | assert.ifError(err); 21 | process.exit(0); 22 | }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /test/integration/connection/test-select-empty-string.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let rows, fields; 10 | connection.query('SELECT ""', (err, _rows, _fields) => { 11 | if (err) { 12 | throw err; 13 | } 14 | 15 | rows = _rows; 16 | fields = _fields; 17 | connection.end(); 18 | }); 19 | 20 | process.on('exit', () => { 21 | assert.deepEqual(rows, [{ [fields[0].name]: '' }]); 22 | }); 23 | -------------------------------------------------------------------------------- /test/integration/connection/test-select-json.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Created by Alexander Panko on 2016.09.23 18:02 5 | * issue#409: https://github.com/sidorares/node-mysql2/issues/409 6 | */ 7 | const common = require('../../common.test.cjs'); 8 | const { assert } = require('poku'); 9 | const process = require('node:process'); 10 | 11 | const connection = common.createConnection(); 12 | 13 | let textFetchedRows = undefined; 14 | let binaryFetchedRows = undefined; 15 | 16 | const face = '\uD83D\uDE02'; 17 | 18 | connection.query('CREATE TEMPORARY TABLE json_test (json_test JSON)'); 19 | connection.query('INSERT INTO json_test VALUES (?)', JSON.stringify(face)); 20 | connection.query('SELECT * FROM json_test', (err, _rows) => { 21 | if (err) { 22 | throw err; 23 | } 24 | textFetchedRows = _rows; 25 | connection.execute('SELECT * FROM json_test', (err, _rows) => { 26 | if (err) { 27 | throw err; 28 | } 29 | binaryFetchedRows = _rows; 30 | connection.end(); 31 | }); 32 | }); 33 | 34 | process.on('exit', () => { 35 | assert.equal(textFetchedRows[0].json_test, face); 36 | assert.equal(binaryFetchedRows[0].json_test, face); 37 | }); 38 | -------------------------------------------------------------------------------- /test/integration/connection/test-select-negative.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let rows = undefined; 10 | let rows1 = undefined; 11 | 12 | connection.execute('SELECT -1 v', [], (err, _rows) => { 13 | if (err) { 14 | throw err; 15 | } 16 | rows = _rows; 17 | }); 18 | 19 | connection.query('SELECT -1 v', (err, _rows) => { 20 | if (err) { 21 | throw err; 22 | } 23 | rows1 = _rows; 24 | connection.end(); 25 | }); 26 | 27 | process.on('exit', () => { 28 | assert.deepEqual(rows, [{ v: -1 }]); 29 | assert.deepEqual(rows1, [{ v: -1 }]); 30 | }); 31 | -------------------------------------------------------------------------------- /test/integration/connection/test-select-ssl.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('poku'); 4 | const common = require('../../common.test.cjs'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | connection.query(`SHOW STATUS LIKE 'Ssl_cipher'`, (err, rows) => { 10 | assert.ifError(err); 11 | if (process.env.MYSQL_USE_TLS === '1') { 12 | assert.equal(rows[0].Value.length > 0, true); 13 | } else { 14 | assert.deepEqual(rows, [{ Variable_name: 'Ssl_cipher', Value: '' }]); 15 | } 16 | 17 | connection.execute(`SHOW STATUS LIKE 'Ssl_cipher'`, (err, rows) => { 18 | assert.ifError(err); 19 | if (process.env.MYSQL_USE_TLS === '1') { 20 | assert.equal(rows[0].Value.length > 0, true); 21 | } else { 22 | assert.deepEqual(rows, [{ Variable_name: 'Ssl_cipher', Value: '' }]); 23 | } 24 | 25 | connection.end((err) => { 26 | assert.ifError(err); 27 | process.exit(0); 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/integration/connection/test-select-utf8.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let rows = undefined; 10 | const multibyteText = '本日は晴天なり'; 11 | connection.query(`SELECT '${multibyteText}' as result`, (err, _rows) => { 12 | if (err) { 13 | throw err; 14 | } 15 | rows = _rows; 16 | connection.end(); 17 | }); 18 | 19 | process.on('exit', () => { 20 | assert.equal(rows[0].result, multibyteText); 21 | }); 22 | -------------------------------------------------------------------------------- /test/integration/connection/test-server-listen.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('poku'); 4 | const mysql = require('../../../index.js'); 5 | 6 | // Verifies that the Server.listen can be called with any combination of 7 | // pararameters valid for net.Server.listen. 8 | 9 | function testListen(argsDescription, listenCaller) { 10 | const server = mysql.createServer(); 11 | let listenCallbackFired = false; 12 | 13 | listenCaller(server, () => { 14 | listenCallbackFired = true; 15 | }); 16 | setTimeout(() => { 17 | assert.ok( 18 | listenCallbackFired, 19 | `Callback for call with ${argsDescription} did not fire` 20 | ); 21 | server._server.close(); 22 | }, 100); 23 | } 24 | 25 | testListen('port', (server, callback) => { 26 | server.listen(0, callback); 27 | }); 28 | 29 | testListen('port, host', (server, callback) => { 30 | server.listen(0, '127.0.0.1', callback); 31 | }); 32 | 33 | testListen('port, host, backlog', (server, callback) => { 34 | server.listen(0, '127.0.0.1', 50, callback); 35 | }); 36 | -------------------------------------------------------------------------------- /test/integration/connection/test-signed-tinyint.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let rows = undefined; 10 | 11 | connection.query( 12 | 'CREATE TEMPORARY TABLE signed_ints (b11 tinyint NOT NULL, b12 tinyint NOT NULL, b21 smallint NOT NULL)' 13 | ); 14 | connection.query('INSERT INTO signed_ints values (-3, -120, 500)'); 15 | connection.query('INSERT INTO signed_ints values (3, -110, -500)'); 16 | 17 | connection.execute('SELECT * from signed_ints', [5], (err, _rows) => { 18 | if (err) { 19 | throw err; 20 | } 21 | rows = _rows; 22 | connection.end(); 23 | }); 24 | 25 | process.on('exit', () => { 26 | assert.deepEqual(rows, [ 27 | { b11: -3, b12: -120, b21: 500 }, 28 | { b11: 3, b12: -110, b21: -500 }, 29 | ]); 30 | }); 31 | -------------------------------------------------------------------------------- /test/integration/connection/test-then-on-query.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | let error = true; 10 | 11 | const q = connection.query('SELECT 1'); 12 | try { 13 | if (q.then) q.then(); 14 | } catch (err) { 15 | error = false; 16 | } 17 | q.on('end', () => { 18 | connection.end(); 19 | }); 20 | 21 | process.on('exit', () => { 22 | assert.equal(error, false); 23 | }); 24 | -------------------------------------------------------------------------------- /test/integration/connection/test-track-state-change.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | if (`${process.env.MYSQL_CONNECTION_URL}`.includes('pscale_pw_')) { 8 | console.log('skipping test for planetscale'); 9 | process.exit(0); 10 | } 11 | 12 | const connection = common.createConnection(); 13 | 14 | let result1, result2; 15 | 16 | connection.query('SET NAMES koi8r', (err, _ok) => { 17 | assert.ifError(err); 18 | result1 = _ok; 19 | }); 20 | 21 | connection.query('USE mysql', (err, _ok) => { 22 | assert.ifError(err); 23 | result2 = _ok; 24 | connection.end(); 25 | }); 26 | 27 | process.on('exit', () => { 28 | assert.deepEqual(result1.stateChanges.systemVariables, { 29 | character_set_connection: 'koi8r', 30 | character_set_client: 'koi8r', 31 | character_set_results: 'koi8r', 32 | }); 33 | assert.deepEqual(result2.stateChanges.schema, 'mysql'); 34 | }); 35 | -------------------------------------------------------------------------------- /test/integration/connection/test-transaction-commit.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const connection = common.createConnection(); 5 | const { assert } = require('poku'); 6 | 7 | common.useTestDb(connection); 8 | 9 | const table = 'transaction_test'; 10 | connection.query( 11 | [ 12 | `CREATE TEMPORARY TABLE \`${table}\` (`, 13 | '`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', 14 | '`title` varchar(255),', 15 | 'PRIMARY KEY (`id`)', 16 | ') ENGINE=InnoDB DEFAULT CHARSET=utf8', 17 | ].join('\n') 18 | ); 19 | 20 | connection.beginTransaction((err) => { 21 | assert.ifError(err); 22 | 23 | const row = { 24 | id: 1, 25 | title: 'Test row', 26 | }; 27 | 28 | connection.query(`INSERT INTO ${table} SET ?`, row, (err) => { 29 | assert.ifError(err); 30 | 31 | connection.commit((err) => { 32 | assert.ifError(err); 33 | 34 | connection.query(`SELECT * FROM ${table}`, (err, rows) => { 35 | assert.ifError(err); 36 | connection.end(); 37 | assert.equal(rows.length, 1); 38 | }); 39 | }); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /test/integration/connection/test-transaction-rollback.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | 6 | const connection = common.createConnection(); 7 | 8 | common.useTestDb(connection); 9 | 10 | const table = 'transaction_test'; 11 | connection.query( 12 | [ 13 | `CREATE TEMPORARY TABLE \`${table}\` (`, 14 | '`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', 15 | '`title` varchar(255),', 16 | 'PRIMARY KEY (`id`)', 17 | ') ENGINE=InnoDB DEFAULT CHARSET=utf8', 18 | ].join('\n') 19 | ); 20 | 21 | connection.beginTransaction((err) => { 22 | assert.ifError(err); 23 | 24 | const row = { 25 | id: 1, 26 | title: 'Test row', 27 | }; 28 | 29 | connection.query(`INSERT INTO ${table} SET ?`, row, (err) => { 30 | assert.ifError(err); 31 | 32 | connection.rollback((err) => { 33 | assert.ifError(err); 34 | 35 | connection.query(`SELECT * FROM ${table}`, (err, rows) => { 36 | assert.ifError(err); 37 | connection.end(); 38 | assert.equal(rows.length, 0); 39 | }); 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /test/integration/connection/test-type-cast-null-fields-execute.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | common.useTestDb(connection); 10 | 11 | const table = 'insert_test'; 12 | connection.execute( 13 | [ 14 | `CREATE TEMPORARY TABLE \`${table}\` (`, 15 | '`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', 16 | '`date` DATETIME NULL,', 17 | '`number` INT NULL,', 18 | 'PRIMARY KEY (`id`)', 19 | ') ENGINE=InnoDB DEFAULT CHARSET=utf8', 20 | ].join('\n'), 21 | (err) => { 22 | if (err) throw err; 23 | } 24 | ); 25 | 26 | connection.execute( 27 | `INSERT INTO ${table} (date, number) VALUES (?, ?)`, 28 | [null, null], 29 | (err) => { 30 | if (err) throw err; 31 | } 32 | ); 33 | 34 | let results; 35 | connection.execute(`SELECT * FROM ${table}`, (err, _results) => { 36 | if (err) { 37 | throw err; 38 | } 39 | 40 | results = _results; 41 | connection.end(); 42 | }); 43 | 44 | process.on('exit', () => { 45 | assert.strictEqual(results[0].date, null); 46 | assert.strictEqual(results[0].number, null); 47 | }); 48 | -------------------------------------------------------------------------------- /test/integration/connection/test-type-cast-null-fields.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | const process = require('node:process'); 6 | 7 | const connection = common.createConnection(); 8 | 9 | common.useTestDb(connection); 10 | 11 | const table = 'insert_test'; 12 | connection.query( 13 | [ 14 | `CREATE TEMPORARY TABLE \`${table}\` (`, 15 | '`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', 16 | '`date` DATETIME NULL,', 17 | '`number` INT NULL,', 18 | 'PRIMARY KEY (`id`)', 19 | ') ENGINE=InnoDB DEFAULT CHARSET=utf8', 20 | ].join('\n') 21 | ); 22 | 23 | connection.query(`INSERT INTO ${table} SET ?`, { 24 | date: null, 25 | number: null, 26 | }); 27 | 28 | let results; 29 | connection.query(`SELECT * FROM ${table}`, (err, _results) => { 30 | if (err) { 31 | throw err; 32 | } 33 | 34 | results = _results; 35 | connection.end(); 36 | }); 37 | 38 | process.on('exit', () => { 39 | assert.strictEqual(results[0].date, null); 40 | assert.strictEqual(results[0].number, null); 41 | }); 42 | -------------------------------------------------------------------------------- /test/integration/connection/test-typecast-overwriting-execute.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('poku'); 4 | const common = require('../../common.test.cjs'); 5 | 6 | const connection = common.createConnection({ 7 | typeCast: function (field, next) { 8 | assert.equal('number', typeof field.length); 9 | if (field.type === 'VAR_STRING') { 10 | return field.string().toUpperCase(); 11 | } 12 | return next(); 13 | }, 14 | }); 15 | 16 | connection.execute( 17 | { 18 | sql: 'select "foo uppercase" as foo', 19 | }, 20 | (err, res) => { 21 | assert.ifError(err); 22 | assert.equal(res[0].foo, 'FOO UPPERCASE'); 23 | } 24 | ); 25 | 26 | connection.execute( 27 | { 28 | sql: 'select "foo lowercase" as foo', 29 | typeCast: function (field, next) { 30 | assert.equal('number', typeof field.length); 31 | if (field.type === 'VAR_STRING') { 32 | return field.string().toLowerCase(); 33 | } 34 | return next(); 35 | }, 36 | }, 37 | (err, res) => { 38 | assert.ifError(err); 39 | assert.equal(res[0].foo, 'foo lowercase'); 40 | } 41 | ); 42 | 43 | connection.end(); 44 | -------------------------------------------------------------------------------- /test/integration/connection/test-typecast-overwriting.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('poku'); 4 | const common = require('../../common.test.cjs'); 5 | 6 | const connection = common.createConnection({ 7 | typeCast: function (field, next) { 8 | assert.equal('number', typeof field.length); 9 | if (field.type === 'VAR_STRING') { 10 | return field.string().toUpperCase(); 11 | } 12 | return next(); 13 | }, 14 | }); 15 | 16 | connection.query( 17 | { 18 | sql: 'select "foo uppercase" as foo', 19 | }, 20 | (err, res) => { 21 | assert.ifError(err); 22 | assert.equal(res[0].foo, 'FOO UPPERCASE'); 23 | } 24 | ); 25 | 26 | connection.query( 27 | { 28 | sql: 'select "foo lowercase" as foo', 29 | typeCast: function (field, next) { 30 | assert.equal('number', typeof field.length); 31 | if (field.type === 'VAR_STRING') { 32 | return field.string().toLowerCase(); 33 | } 34 | return next(); 35 | }, 36 | }, 37 | (err, res) => { 38 | assert.ifError(err); 39 | assert.equal(res[0].foo, 'foo lowercase'); 40 | } 41 | ); 42 | 43 | connection.end(); 44 | -------------------------------------------------------------------------------- /test/integration/regressions/test-#485.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const config = require('../../common.test.cjs').config; 4 | const { assert } = require('poku'); 5 | const createPoolPromise = require('../../../promise.js').createPool; 6 | const PoolConnection = require('../../../lib/pool_connection.js'); 7 | const process = require('node:process'); 8 | 9 | function createPool(args) { 10 | if (!args && process.env.MYSQL_CONNECTION_URL) { 11 | return createPoolPromise({ uri: process.env.MYSQL_CONNECTION_URL }); 12 | } 13 | return createPoolPromise({ ...config, ...args }); 14 | } 15 | 16 | // stub 17 | const release = PoolConnection.prototype.release; 18 | let releaseCalls = 0; 19 | PoolConnection.prototype.release = function () { 20 | releaseCalls++; 21 | }; 22 | 23 | function testPoolPromiseExecuteLeak() { 24 | const pool = createPool(); 25 | pool 26 | .execute('select 1+2 as ttt') 27 | .then((result) => { 28 | assert.equal(result[0][0].ttt, 3); 29 | return pool.end(); 30 | }) 31 | .catch((err) => { 32 | assert.ifError(err); 33 | }); 34 | } 35 | 36 | testPoolPromiseExecuteLeak(); 37 | 38 | process.on('exit', () => { 39 | PoolConnection.prototype.release = release; 40 | assert.equal(releaseCalls, 1, 'PoolConnection.release was not called'); 41 | }); 42 | -------------------------------------------------------------------------------- /test/integration/test-pool-end.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { createPool } = require('../common.test.cjs'); 4 | const { assert } = require('poku'); 5 | 6 | const pool = createPool(); 7 | 8 | pool.getConnection((err, conn) => { 9 | assert.ifError(err); 10 | 11 | assert(pool._allConnections.length === 1); 12 | assert(pool._freeConnections.length === 0); 13 | 14 | // emit the end event, so the connection gets removed from the pool 15 | conn.stream.emit('end'); 16 | 17 | assert(pool._allConnections.length === 0); 18 | assert(pool._freeConnections.length === 0); 19 | 20 | // As the connection has not really ended we need to do this ourselves 21 | conn.destroy(); 22 | }); 23 | -------------------------------------------------------------------------------- /test/tsc-build/helpers.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql, mysqlp } from './index.test.js'; 2 | 3 | export const isResultSetHeader = ( 4 | data: unknown 5 | ): data is mysql.ResultSetHeader | mysqlp.ResultSetHeader => { 6 | if (!data || typeof data !== 'object') return false; 7 | 8 | const keys = [ 9 | 'fieldCount', 10 | 'affectedRows', 11 | 'insertId', 12 | 'info', 13 | 'serverStatus', 14 | 'warningStatus', 15 | ]; 16 | 17 | return keys.every((key) => key in data); 18 | }; 19 | 20 | export const isOkPacket = ( 21 | data: unknown 22 | ): data is mysql.OkPacket | mysqlp.OkPacket => { 23 | if (!data || typeof data !== 'object') return false; 24 | 25 | const keys = [ 26 | 'fieldCount', 27 | 'affectedRows', 28 | 'changedRows', 29 | 'insertId', 30 | 'serverStatus', 31 | 'warningCount', 32 | 'message', 33 | 'protocol41', 34 | ]; 35 | 36 | return keys.every((key) => key in data); 37 | }; 38 | -------------------------------------------------------------------------------- /test/tsc-build/index.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This tests doesn't execute the scripts or connect in any database. 3 | * It only compiles all typings in the project and ensures that the compilation will be successful. 4 | * To test it, run: npm run test:tsc-build 5 | * 6 | * The purpose of this test is to prevent changes that break the typings in new PRs 7 | * 8 | * Contributions: 9 | * 10 | * For mysql build tests: './mysql/...' 11 | * For mysql/promise build tests: './promise/...' 12 | */ 13 | 14 | import mysql from '../../index.js'; 15 | import mysqlp from '../../promise.js'; 16 | 17 | export { mysql, mysqlp }; 18 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/baseConnection.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../index.test.js'; 2 | 3 | export const access: mysql.ConnectionOptions = { 4 | host: '', 5 | user: '', 6 | password: '', 7 | database: '', 8 | }; 9 | 10 | export const uriAccess = `mysql://${access.host}:${access.password}@${access.host}:${access.port}/${access.database}`; 11 | 12 | /** The SQL for the query */ 13 | export const sql = 'SELECT * FROM `table`'; 14 | 15 | /** The SQL for the query with prepared statements */ 16 | export const sqlPS = 'SELECT * FROM `table` WHERE `id` = ?'; 17 | 18 | /** The values for the query with prepared statements */ 19 | export const values = [1]; 20 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/constants/CharsetToEncoding.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../index.test.js'; 2 | 3 | const charsetToEncoding: string[] = mysql.CharsetToEncoding; 4 | const utf8: string = charsetToEncoding[0]; 5 | 6 | console.log(utf8, charsetToEncoding); 7 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/constants/Charsets.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../index.test.js'; 2 | 3 | const BIG5_CHINESE_CI: number = mysql.Charsets.BIG5_CHINESE_CI; 4 | const BIG5: number = mysql.Charsets.BIG5; 5 | 6 | console.log(BIG5_CHINESE_CI, BIG5); 7 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/constants/Types.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../index.test.js'; 2 | 3 | const BLOB: number = mysql.Types.BLOB; 4 | const DECIMAL: string = mysql.Types[0x00]; 5 | const DOUBLE: string = mysql.Types[5]; 6 | 7 | console.log(BLOB, DECIMAL, DOUBLE); 8 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createConnection/callbacks/execute.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../../index.test.js'; 2 | import { access, sql, sqlPS, values } from '../../baseConnection.test.js'; 3 | 4 | { 5 | const db = mysql.createConnection(access); 6 | 7 | /** Overload: execute(sql, () => {}}) */ 8 | db.execute(sql, (err, result, fields) => { 9 | console.log(err, result, fields); 10 | }); 11 | 12 | /** Overload: execute(sql, values, () => {}}) */ 13 | db.execute(sqlPS, values, (err, result, fields) => { 14 | console.log(err, result, fields); 15 | }); 16 | 17 | /** Overload: execute(QueryOptions, () => {}}) I */ 18 | db.execute({ sql }, (err, result, fields) => { 19 | console.log(err, result, fields); 20 | }); 21 | 22 | /** Overload: execute(QueryOptions, () => {}}) II */ 23 | db.execute({ sql: sqlPS, values }, (err, result, fields) => { 24 | console.log(err, result, fields); 25 | }); 26 | 27 | /** Overload: execute(QueryOptions, values, () => {}}) */ 28 | db.execute({ sql: sqlPS }, values, (err, result, fields) => { 29 | console.log(err, result, fields); 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createConnection/callbacks/query.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../../index.test.js'; 2 | import { access, sql, sqlPS, values } from '../../baseConnection.test.js'; 3 | 4 | { 5 | const db = mysql.createConnection(access); 6 | 7 | /** Overload: query(sql, () => {}}) */ 8 | db.query(sql, (err, result, fields) => { 9 | console.log(err, result, fields); 10 | }); 11 | 12 | /** Overload: query(sql, values, () => {}}) */ 13 | db.query(sqlPS, values, (err, result, fields) => { 14 | console.log(err, result, fields); 15 | }); 16 | 17 | /** Overload: query(QueryOptions, () => {}}) I */ 18 | db.query({ sql }, (err, result, fields) => { 19 | console.log(err, result, fields); 20 | }); 21 | 22 | /** Overload: query(QueryOptions, () => {}}) II */ 23 | db.query({ sql: sqlPS, values }, (err, result, fields) => { 24 | console.log(err, result, fields); 25 | }); 26 | 27 | /** Overload: query(QueryOptions, values, () => {}}) */ 28 | db.query({ sql: sqlPS }, values, (err, result, fields) => { 29 | console.log(err, result, fields); 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createConnection/promise/execute.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../../index.test.js'; 2 | import { access, sql, sqlPS, values } from '../../baseConnection.test.js'; 3 | 4 | (async () => { 5 | const db = mysql.createConnection(access).promise(); 6 | 7 | { 8 | /** Overload: execute(sql) */ 9 | const [results, fields] = await db.execute(sql); 10 | console.log(results, fields); 11 | } 12 | 13 | { 14 | /** Overload: execute(sql, values) */ 15 | const [results, fields] = await db.execute(sqlPS, values); 16 | console.log(results, fields); 17 | } 18 | 19 | { 20 | /** Overload: execute(QueryOptions) I */ 21 | const [results, fields] = await db.execute({ sql }); 22 | console.log(results, fields); 23 | } 24 | 25 | { 26 | /** Overload: execute(QueryOptions) II */ 27 | const [results, fields] = await db.execute({ sql: sqlPS, values }); 28 | console.log(results, fields); 29 | } 30 | 31 | { 32 | /** Overload: execute(QueryOptions, values) */ 33 | const [results, fields] = await db.execute({ sql: sqlPS }, values); 34 | console.log(results, fields); 35 | } 36 | 37 | await db.end(); 38 | })(); 39 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createConnection/promise/query.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../../index.test.js'; 2 | import { access, sql, sqlPS, values } from '../../baseConnection.test.js'; 3 | 4 | (async () => { 5 | const db = mysql.createConnection(access).promise(); 6 | 7 | { 8 | /** Overload: query(sql) */ 9 | const [results, fields] = await db.query(sql); 10 | console.log(results, fields); 11 | } 12 | 13 | { 14 | /** Overload: query(sql, values) */ 15 | const [results, fields] = await db.query(sqlPS, values); 16 | console.log(results, fields); 17 | } 18 | 19 | { 20 | /** Overload: query(QueryOptions) I */ 21 | const [results, fields] = await db.query({ sql }); 22 | console.log(results, fields); 23 | } 24 | 25 | { 26 | /** Overload: query(QueryOptions) II */ 27 | const [results, fields] = await db.query({ sql: sqlPS, values }); 28 | console.log(results, fields); 29 | } 30 | 31 | { 32 | /** Overload: query(QueryOptions, values) */ 33 | const [results, fields] = await db.query({ sql: sqlPS }, values); 34 | console.log(results, fields); 35 | } 36 | 37 | await db.end(); 38 | })(); 39 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createPool/callbacks/connection.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../../index.test.js'; 2 | import { access } from '../../baseConnection.test.js'; 3 | 4 | const pool = mysql.createPool(access); 5 | 6 | pool.getConnection((_err, conn) => { 7 | conn.connection; 8 | 9 | try { 10 | // @ts-expect-error: The pool can't be a connection itself 11 | pool.connection; 12 | } catch (err) { 13 | console.log('This error is expected', err); 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createPool/callbacks/createPool.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../../index.test.js'; 2 | import { uriAccess, access } from '../../baseConnection.test.js'; 3 | 4 | (() => { 5 | let uriPool: mysql.Pool | null = null; 6 | let pool: mysql.Pool | null = null; 7 | 8 | if (uriPool === null || pool === null) return; 9 | 10 | uriPool = mysql.createPool(uriAccess); 11 | pool = mysql.createPool(access); 12 | })(); 13 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createPool/callbacks/getConnection.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../../index.test.js'; 2 | import { access } from '../../baseConnection.test.js'; 3 | 4 | const pool = mysql.createPool(access); 5 | 6 | pool.getConnection((_err, conn) => { 7 | try { 8 | // @ts-expect-error: The connection can't get another connection 9 | conn.getConnection(); 10 | } catch (err) { 11 | console.log('This error is expected', err); 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createPool/callbacks/release.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../../index.test.js'; 2 | import { access } from '../../baseConnection.test.js'; 3 | 4 | const pool = mysql.createPool(access); 5 | 6 | pool.getConnection((_err, conn) => { 7 | conn.release(); 8 | 9 | try { 10 | // @ts-expect-error: The pool isn't a connection itself, so it doesn't have the connection methods 11 | pool.release(); 12 | } catch (err) { 13 | console.log('This error is expected', err); 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createPool/callbacks/releaseConnection.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../../index.test.js'; 2 | import { access } from '../../baseConnection.test.js'; 3 | 4 | const pool = mysql.createPool(access); 5 | 6 | pool.getConnection((_err, conn) => { 7 | pool.releaseConnection(conn); 8 | }); 9 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createPool/promise/connection.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../../index.test.js'; 2 | import { access } from '../../baseConnection.test.js'; 3 | 4 | (async () => { 5 | const pool = mysql.createPool(access); 6 | const conn = await pool.promise().getConnection(); 7 | 8 | conn.connection; 9 | 10 | try { 11 | // @ts-expect-error: The pool can't be a connection itself 12 | pool.connection; 13 | } catch (err) { 14 | console.log('This error is expected', err); 15 | } 16 | })(); 17 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createPool/promise/getConnection.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../../index.test.js'; 2 | import { access } from '../../baseConnection.test.js'; 3 | 4 | (async () => { 5 | const pool = mysql.createPool(access); 6 | const conn = await pool.promise().getConnection(); 7 | 8 | try { 9 | // @ts-expect-error: The connection can't get another connection 10 | conn.getConnection(); 11 | } catch (err) { 12 | console.log('This error is expected', err); 13 | } 14 | })(); 15 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createPool/promise/promise.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql, mysqlp } from '../../../index.test.js'; 2 | import { access } from '../../baseConnection.test.js'; 3 | 4 | (async () => { 5 | let pool: mysql.Pool | null = null; 6 | let promisePool: mysqlp.Pool | null = null; 7 | let conn: mysqlp.PoolConnection | null = null; 8 | 9 | if (pool === null) return; 10 | 11 | pool = mysql.createPool(access); 12 | promisePool = pool.promise(); 13 | conn = await promisePool.getConnection(); 14 | 15 | conn.release(); 16 | })(); 17 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createPool/promise/release.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../../index.test.js'; 2 | import { access } from '../../baseConnection.test.js'; 3 | 4 | (async () => { 5 | const pool = mysql.createPool(access); 6 | const conn = await pool.promise().getConnection(); 7 | 8 | conn.release(); 9 | 10 | try { 11 | // @ts-expect-error: The pool isn't a connection itself, so it doesn't have the connection methods 12 | pool.release(); 13 | } catch (err) { 14 | console.log('This error is expected', err); 15 | } 16 | })(); 17 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createPool/promise/releaseConnection.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../../index.test.js'; 2 | import { access } from '../../baseConnection.test.js'; 3 | 4 | (async () => { 5 | const pool = mysql.createPool(access); 6 | const conn = await pool.promise().getConnection(); 7 | 8 | pool.releaseConnection(conn); 9 | })(); 10 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createPoolCluster/add.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../index.test.js'; 2 | import { access, uriAccess } from '../baseConnection.test.js'; 3 | 4 | const poolCluster = mysql.createPoolCluster(); 5 | 6 | // Overload: poolCluster.add(group, connectionUri); 7 | poolCluster.add('cluster1', uriAccess); 8 | // Overload: poolCluster.add(group, config); 9 | poolCluster.add('cluster2', access); 10 | // Overload: poolCluster.add(config); 11 | poolCluster.add(access); 12 | 13 | // @ts-expect-error: The option to pass only `URI` doesn't exists 14 | poolCluster.add(uriAccess); 15 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/createPoolCluster/remove.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../index.test.js'; 2 | 3 | const poolCluster = mysql.createPoolCluster(); 4 | 5 | // Overload: poolCluster.add(group, connectionUri); 6 | poolCluster.remove('cluster1'); 7 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/parsers/clearParserCache.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../index.test.js'; 2 | 3 | mysql.clearParserCache(); 4 | -------------------------------------------------------------------------------- /test/tsc-build/mysql/parsers/setMaxParserCache.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql } from '../../index.test.js'; 2 | 3 | mysql.setMaxParserCache(1000); 4 | 5 | // @ts-expect-error: The `max` param is required 6 | mysql.setMaxParserCache(); 7 | -------------------------------------------------------------------------------- /test/tsc-build/promise/baseConnection.test.ts: -------------------------------------------------------------------------------- 1 | import { mysqlp as mysql } from '../index.test.js'; 2 | 3 | export const access: mysql.ConnectionOptions = { 4 | host: '', 5 | user: '', 6 | password: '', 7 | database: '', 8 | }; 9 | 10 | export const uriAccess = `mysql://${access.host}:${access.password}@${access.host}:${access.port}/${access.database}`; 11 | 12 | /** The SQL for the query */ 13 | export const sql = 'SELECT * FROM `table`'; 14 | 15 | /** The SQL for the query with prepared statements */ 16 | export const sqlPS = 'SELECT * FROM `table` WHERE `id` = ?'; 17 | 18 | /** The values for the query with prepared statements */ 19 | export const values = [1]; 20 | -------------------------------------------------------------------------------- /test/tsc-build/promise/constants/CharsetToEncoding.test.ts: -------------------------------------------------------------------------------- 1 | import { mysqlp as mysql } from '../../index.test.js'; 2 | 3 | const charsetToEncoding: string[] = mysql.CharsetToEncoding; 4 | const utf8: string = charsetToEncoding[0]; 5 | 6 | console.log(utf8, charsetToEncoding); 7 | -------------------------------------------------------------------------------- /test/tsc-build/promise/constants/Charsets.test.ts: -------------------------------------------------------------------------------- 1 | import { mysqlp as mysql } from '../../index.test.js'; 2 | 3 | const BIG5_CHINESE_CI: number = mysql.Charsets.BIG5_CHINESE_CI; 4 | const BIG5: number = mysql.Charsets.BIG5; 5 | 6 | console.log(BIG5_CHINESE_CI, BIG5); 7 | -------------------------------------------------------------------------------- /test/tsc-build/promise/constants/Types.test.ts: -------------------------------------------------------------------------------- 1 | import { mysqlp as mysql } from '../../index.test.js'; 2 | 3 | const BLOB: number = mysql.Types.BLOB; 4 | const DECIMAL: string = mysql.Types[0x00]; 5 | const DOUBLE: string = mysql.Types[5]; 6 | 7 | console.log(BLOB, DECIMAL, DOUBLE); 8 | -------------------------------------------------------------------------------- /test/tsc-build/promise/createConnection/execute.test.ts: -------------------------------------------------------------------------------- 1 | import { mysqlp as mysql } from '../../index.test.js'; 2 | import { access, sql, sqlPS, values } from '../baseConnection.test.js'; 3 | 4 | (async () => { 5 | const db = await mysql.createConnection(access); 6 | 7 | { 8 | /** Overload: execute(sql) */ 9 | const [results, fields] = await db.execute(sql); 10 | console.log(results, fields); 11 | } 12 | 13 | { 14 | /** Overload: execute(sql, values) */ 15 | const [results, fields] = await db.execute(sqlPS, values); 16 | console.log(results, fields); 17 | } 18 | 19 | { 20 | /** Overload: execute(QueryOptions) I */ 21 | const [results, fields] = await db.execute({ sql }); 22 | console.log(results, fields); 23 | } 24 | 25 | { 26 | /** Overload: execute(QueryOptions) II */ 27 | const [results, fields] = await db.execute({ sql: sqlPS, values }); 28 | console.log(results, fields); 29 | } 30 | 31 | { 32 | /** Overload: execute(QueryOptions, values) */ 33 | const [results, fields] = await db.execute({ sql: sqlPS }, values); 34 | console.log(results, fields); 35 | } 36 | 37 | await db.end(); 38 | })(); 39 | -------------------------------------------------------------------------------- /test/tsc-build/promise/createConnection/query.test.ts: -------------------------------------------------------------------------------- 1 | import { mysqlp as mysql } from '../../index.test.js'; 2 | import { access, sql, sqlPS, values } from '../baseConnection.test.js'; 3 | 4 | (async () => { 5 | const db = await mysql.createConnection(access); 6 | 7 | { 8 | /** Overload: query(sql) */ 9 | const [results, fields] = await db.query(sql); 10 | console.log(results, fields); 11 | } 12 | 13 | { 14 | /** Overload: query(sql, values) */ 15 | const [results, fields] = await db.query(sqlPS, values); 16 | console.log(results, fields); 17 | } 18 | 19 | { 20 | /** Overload: query(QueryOptions) I */ 21 | const [results, fields] = await db.query({ sql }); 22 | console.log(results, fields); 23 | } 24 | 25 | { 26 | /** Overload: query(QueryOptions) II */ 27 | const [results, fields] = await db.query({ sql: sqlPS, values }); 28 | console.log(results, fields); 29 | } 30 | 31 | { 32 | /** Overload: query(QueryOptions, values) */ 33 | const [results, fields] = await db.query({ sql: sqlPS }, values); 34 | console.log(results, fields); 35 | } 36 | 37 | await db.end(); 38 | })(); 39 | -------------------------------------------------------------------------------- /test/tsc-build/promise/createPool/connection.test.ts: -------------------------------------------------------------------------------- 1 | import { mysqlp as mysql } from '../../index.test.js'; 2 | import { access } from '../baseConnection.test.js'; 3 | 4 | (async () => { 5 | const pool = mysql.createPool(access); 6 | const conn = await pool.getConnection(); 7 | 8 | conn.connection; 9 | 10 | try { 11 | // @ts-expect-error: The pool can't be a connection itself 12 | pool.connection; 13 | } catch (err) { 14 | console.log('This error is expected', err); 15 | } 16 | })(); 17 | -------------------------------------------------------------------------------- /test/tsc-build/promise/createPool/createPool.test.ts: -------------------------------------------------------------------------------- 1 | import { mysqlp as mysql } from '../../index.test.js'; 2 | import { uriAccess, access } from '../baseConnection.test.js'; 3 | 4 | (() => { 5 | let uriPool: mysql.Pool | null = null; 6 | let pool: mysql.Pool | null = null; 7 | 8 | if (uriPool === null || pool === null) return; 9 | 10 | uriPool = mysql.createPool(uriAccess); 11 | pool = mysql.createPool(access); 12 | })(); 13 | -------------------------------------------------------------------------------- /test/tsc-build/promise/createPool/getConnection.test.ts: -------------------------------------------------------------------------------- 1 | import { mysqlp as mysql } from '../../index.test.js'; 2 | import { access } from '../baseConnection.test.js'; 3 | 4 | (async () => { 5 | const pool = mysql.createPool(access); 6 | const conn = await pool.getConnection(); 7 | 8 | conn.connection; 9 | 10 | try { 11 | // @ts-expect-error: The connection can't get another connection 12 | conn.getConnection(); 13 | } catch (err) { 14 | console.log('This error is expected', err); 15 | } 16 | })(); 17 | -------------------------------------------------------------------------------- /test/tsc-build/promise/createPool/release.test.ts: -------------------------------------------------------------------------------- 1 | import { mysqlp as mysql } from '../../index.test.js'; 2 | import { access } from '../baseConnection.test.js'; 3 | 4 | (async () => { 5 | const pool = mysql.createPool(access); 6 | const conn = await pool.getConnection(); 7 | 8 | conn.release(); 9 | 10 | try { 11 | // @ts-expect-error: The pool isn't a connection itself, so it doesn't have the connection methods 12 | pool.release(); 13 | } catch (err) { 14 | console.log('This error is expected', err); 15 | } 16 | })(); 17 | -------------------------------------------------------------------------------- /test/tsc-build/promise/createPool/releaseConnection.test.ts: -------------------------------------------------------------------------------- 1 | import { mysqlp as mysql } from '../../index.test.js'; 2 | import { access } from '../baseConnection.test.js'; 3 | 4 | (async () => { 5 | const pool = mysql.createPool(access); 6 | const conn = await pool.getConnection(); 7 | 8 | pool.releaseConnection(conn); 9 | })(); 10 | -------------------------------------------------------------------------------- /test/tsc-build/promise/createPoolCluster/add.test.ts: -------------------------------------------------------------------------------- 1 | import { mysqlp as mysql } from '../../index.test.js'; 2 | import { access, uriAccess } from '../baseConnection.test.js'; 3 | 4 | const poolCluster = mysql.createPoolCluster(); 5 | 6 | // Overload: poolCluster.add(group, connectionUri); 7 | poolCluster.add('cluster1', uriAccess); 8 | // Overload: poolCluster.add(group, config); 9 | poolCluster.add('cluster2', access); 10 | // Overload: poolCluster.add(config); 11 | poolCluster.add(access); 12 | 13 | // @ts-expect-error: The option to pass only `URI` doesn't exists 14 | poolCluster.add(uriAccess); 15 | -------------------------------------------------------------------------------- /test/tsc-build/promise/parsers/clearParserCache.test.ts: -------------------------------------------------------------------------------- 1 | import { mysqlp as mysql } from '../../index.test.js'; 2 | 3 | mysql.clearParserCache(); 4 | -------------------------------------------------------------------------------- /test/tsc-build/promise/parsers/setMaxParserCache.test.ts: -------------------------------------------------------------------------------- 1 | import { mysqlp as mysql } from '../../index.test.js'; 2 | 3 | mysql.setMaxParserCache(1000); 4 | 5 | // @ts-expect-error: The `max` param is required 6 | mysql.setMaxParserCache(); 7 | -------------------------------------------------------------------------------- /test/tsc-build/strict-checks/enableKeepAlive-and-keepAliveInitialDelay.test.ts: -------------------------------------------------------------------------------- 1 | import { mysql, mysqlp } from '../index.test.js'; 2 | 3 | // Callback 4 | (() => { 5 | const poolOptions: mysql.PoolOptions = { 6 | enableKeepAlive: true, 7 | keepAliveInitialDelay: 0, 8 | }; 9 | 10 | const connectionOptions: mysql.ConnectionOptions = { 11 | enableKeepAlive: true, 12 | keepAliveInitialDelay: 0, 13 | }; 14 | 15 | mysql.createConnection(connectionOptions); 16 | mysql.createPool(poolOptions); 17 | mysql.createPoolCluster().add(poolOptions); 18 | })(); 19 | 20 | // Promise 21 | (() => { 22 | const poolOptions: mysqlp.PoolOptions = { 23 | enableKeepAlive: true, 24 | keepAliveInitialDelay: 0, 25 | }; 26 | 27 | const connectionOptions: mysqlp.ConnectionOptions = { 28 | enableKeepAlive: true, 29 | keepAliveInitialDelay: 0, 30 | }; 31 | 32 | mysqlp.createConnection(connectionOptions); 33 | mysqlp.createPool(poolOptions); 34 | mysqlp.createPoolCluster().add(poolOptions); 35 | })(); 36 | -------------------------------------------------------------------------------- /test/tsc-build/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "index.test.ts", 4 | "helpers.test.ts", 5 | "mysql", 6 | "promise", 7 | "strict-checks" 8 | ], 9 | "compilerOptions": { 10 | "target": "ES2016", 11 | "module": "CommonJS", 12 | "moduleResolution": "Node", 13 | "esModuleInterop": true, 14 | "allowSyntheticDefaultImports": true, 15 | "strict": true, 16 | "alwaysStrict": true, 17 | "noImplicitAny": true, 18 | "strictFunctionTypes": false, 19 | "skipLibCheck": false, 20 | "noEmitOnError": true, 21 | "noEmit": true, 22 | "noUnusedParameters": true, 23 | "isolatedModules": true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/unit/commands/test-query.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('poku'); 4 | const Query = require('../../../lib/commands/query.js'); 5 | 6 | const testError = new Error('something happened'); 7 | const testQuery = new Query({}, (err, res) => { 8 | assert.equal(err, testError); 9 | assert.equal(res, null); 10 | }); 11 | 12 | testQuery._rowParser = new (class FailingRowParser { 13 | next() { 14 | throw testError; 15 | } 16 | })(); 17 | 18 | testQuery.row({ 19 | isEOF: () => false, 20 | }); 21 | -------------------------------------------------------------------------------- /test/unit/commands/test-quit.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('poku'); 4 | const Quit = require('../../../lib/commands/quit.js'); 5 | 6 | const testCallback = (err) => console.info(err.message); 7 | const testQuit = new Quit(testCallback); 8 | 9 | assert.strictEqual(testQuit.onResult, testCallback); 10 | -------------------------------------------------------------------------------- /test/unit/packets/test-datetime.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('poku'); 4 | const packets = require('../../../lib/packets/index.js'); 5 | const { Buffer } = require('node:buffer'); 6 | 7 | let buf = Buffer.from('0a000004000007dd070116010203', 'hex'); 8 | 9 | let packet = new packets.Packet(4, buf, 0, buf.length); 10 | packet.readInt16(); // unused 11 | let d = packet.readDateTime('Z'); 12 | 13 | assert.equal(+d, 1358816523000); 14 | 15 | buf = Buffer.from( 16 | '18000006000004666f6f310be00702090f01095d7f06000462617231', 17 | 'hex' 18 | ); 19 | packet = new packets.Packet(6, buf, 0, buf.length); 20 | 21 | packet.readInt16(); // ignore 22 | const s = packet.readLengthCodedString('cesu8'); 23 | assert.equal(s, 'foo1'); 24 | d = packet.readDateTime('Z'); 25 | assert.equal(+d, 1455030069425); 26 | 27 | const s1 = packet.readLengthCodedString('cesu8'); 28 | assert.equal(s1, 'bar1'); 29 | assert.equal(packet.offset, packet.end); 30 | -------------------------------------------------------------------------------- /test/unit/packets/test-ok-autoinc.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('poku'); 4 | const packets = require('../../../lib/packets/index.js'); 5 | 6 | const packet = packets.OK.toPacket({ affectedRows: 0, insertId: 1 }); 7 | 8 | // 5 bytes for an OK packet, plus one byte to store affectedRows plus one byte to store the insertId 9 | assert.equal( 10 | packet.length(), 11 | 11, 12 | `${ 13 | 'OK packets with 0 affectedRows and a minimal insertId should be ' + 14 | '11 bytes long, got ' 15 | }${packet.length()} byte(s)` 16 | ); 17 | -------------------------------------------------------------------------------- /test/unit/packets/test-ok-sessiontrack.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('poku'); 4 | const Packet = require('../../../lib/packets/packet.js'); 5 | const ResultSetHeader = require('../../../lib/packets/resultset_header.js'); 6 | const clientConstants = require('../../../lib/constants/client.js'); 7 | const { Buffer } = require('node:buffer'); 8 | 9 | const mockConnection = { 10 | config: {}, 11 | serverEncoding: 'utf8', 12 | _handshakePacket: { 13 | capabilityFlags: 14 | clientConstants.PROTOCOL_41 + clientConstants.SESSION_TRACK, 15 | }, 16 | }; 17 | 18 | const mkpacket = (str) => { 19 | const buf = Buffer.from(str.split(/[ \n]+/).join(''), 'hex'); 20 | return new Packet(0, buf, 0, buf.length); 21 | }; 22 | 23 | // regression examples from https://github.com/sidorares/node-mysql2/issues/989 24 | 25 | assert.doesNotThrow(() => { 26 | const packet = mkpacket( 27 | `1b 00 00 01 28 | 00 29 | 01 fe 65 96 fc 02 00 00 00 00 03 40 00 00 00 0a 14 08 fe 60 63 9b 05 00 00 00 30 | ` 31 | ); 32 | new ResultSetHeader(packet, mockConnection); 33 | }); 34 | 35 | assert.doesNotThrow(() => { 36 | const packet = mkpacket( 37 | `13 00 00 01 00 01 00 02 40 00 00 00 0a 14 08 fe 18 25 e7 06 00 00 00` 38 | ); 39 | new ResultSetHeader(packet, mockConnection); 40 | }); 41 | -------------------------------------------------------------------------------- /test/unit/packets/test-time.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('poku'); 4 | const packets = require('../../../lib/packets/index.js'); 5 | const { Buffer } = require('node:buffer'); 6 | 7 | [ 8 | ['01:23:45', '0b000004000008000000000001172d'], // CONVERT('01:23:45', TIME) 9 | ['01:23:45.123456', '0f00000400000c000000000001172d40e20100'], // DATE_ADD(CONVERT('01:23:45', TIME), INTERVAL 0.123456 SECOND) 10 | ['-01:23:44.876544', '0f00000400000c010000000001172c00600d00'], // DATE_ADD(CONVERT('-01:23:45', TIME), INTERVAL 0.123456 SECOND) 11 | ['-81:23:44.876544', '0f00000400000c010300000009172c00600d00'], // DATE_ADD(CONVERT('-81:23:45', TIME), INTERVAL 0.123456 SECOND) 12 | ['81:23:45', '0b000004000008000300000009172d'], // CONVERT('81:23:45', TIME) 13 | ['123:23:45.123456', '0f00000400000c000500000003172d40e20100'], // DATE_ADD(CONVERT('123:23:45', TIME), INTERVAL 0.123456 SECOND) 14 | ['-121:23:45', '0b000004000008010500000001172d'], // CONVERT('-121:23:45', TIME) 15 | ['-01:23:44.88', '0f00000400000c010000000001172c806d0d00'], //DATE_ADD(CONVERT('-01:23:45', TIME), INTERVAL 0.12 SECOND) 16 | ].forEach(([expected, buffer]) => { 17 | const buf = Buffer.from(buffer, 'hex'); 18 | const packet = new packets.Packet(4, buf, 0, buf.length); 19 | packet.readInt16(); // unused 20 | const d = packet.readTimeString(false); 21 | assert.equal(d, expected); 22 | }); 23 | -------------------------------------------------------------------------------- /test/unit/parsers/test-text-parser.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('poku'); 4 | const common = require('../../common.test.cjs'); 5 | 6 | const typeCastWrapper = function (...args) { 7 | return function (field, next) { 8 | if (field.type === 'JSON') { 9 | return JSON.parse(field.string(...args)); 10 | } 11 | 12 | return next(); 13 | }; 14 | }; 15 | 16 | const connection = common.createConnection(); 17 | connection.query('CREATE TEMPORARY TABLE t (i JSON)'); 18 | connection.query('INSERT INTO t values(\'{ "test": "😀" }\')'); 19 | 20 | // JSON without encoding options - should result in unexpected behaviors 21 | connection.query( 22 | { 23 | sql: 'SELECT * FROM t', 24 | typeCast: typeCastWrapper(), 25 | }, 26 | (err, rows) => { 27 | assert.ifError(err); 28 | assert.notEqual(rows[0].i.test, '😀'); 29 | } 30 | ); 31 | 32 | // JSON with encoding explicitly set to utf8 33 | connection.query( 34 | { 35 | sql: 'SELECT * FROM t', 36 | typeCast: typeCastWrapper('utf8'), 37 | }, 38 | (err, rows) => { 39 | assert.ifError(err); 40 | assert.equal(rows[0].i.test, '😀'); 41 | } 42 | ); 43 | 44 | connection.end(); 45 | -------------------------------------------------------------------------------- /test/unit/pool-cluster/test-connection-order.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('poku'); 4 | const common = require('../../common.test.cjs'); 5 | const process = require('node:process'); 6 | 7 | // TODO: config poolCluster to work with MYSQL_CONNECTION_URL run 8 | if (`${process.env.MYSQL_CONNECTION_URL}`.includes('pscale_pw_')) { 9 | console.log('skipping test for planetscale'); 10 | process.exit(0); 11 | } 12 | 13 | const cluster = common.createPoolCluster(); 14 | 15 | const order = []; 16 | 17 | const poolConfig = common.getConfig(); 18 | cluster.add('SLAVE1', poolConfig); 19 | cluster.add('SLAVE2', poolConfig); 20 | 21 | const done = function () { 22 | assert.deepEqual(order, ['SLAVE1', 'SLAVE1', 'SLAVE1', 'SLAVE1', 'SLAVE1']); 23 | cluster.end(); 24 | console.log('done'); 25 | }; 26 | 27 | const pool = cluster.of('SLAVE*', 'ORDER'); 28 | 29 | console.log('test pool cluster connection ORDER'); 30 | 31 | let count = 0; 32 | 33 | function getConnection(i) { 34 | pool.getConnection((err, conn) => { 35 | assert.ifError(err); 36 | order[i] = conn._clusterId; 37 | conn.release(); 38 | 39 | count += 1; 40 | 41 | if (count <= 4) { 42 | getConnection(count); 43 | } else { 44 | done(); 45 | } 46 | }); 47 | } 48 | 49 | getConnection(0); 50 | -------------------------------------------------------------------------------- /test/unit/pool-cluster/test-connection-rr.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('poku'); 4 | const common = require('../../common.test.cjs'); 5 | const process = require('node:process'); 6 | 7 | // TODO: config poolCluster to work with MYSQL_CONNECTION_URL run 8 | if (`${process.env.MYSQL_CONNECTION_URL}`.includes('pscale_pw_')) { 9 | console.log('skipping test for planetscale'); 10 | process.exit(0); 11 | } 12 | 13 | const cluster = common.createPoolCluster(); 14 | 15 | const order = []; 16 | 17 | const poolConfig = common.getConfig(); 18 | cluster.add('SLAVE1', poolConfig); 19 | cluster.add('SLAVE2', poolConfig); 20 | 21 | const done = function () { 22 | assert.deepEqual(order, ['SLAVE1', 'SLAVE2', 'SLAVE1', 'SLAVE2', 'SLAVE1']); 23 | cluster.end(); 24 | console.log('done'); 25 | }; 26 | 27 | const pool = cluster.of('SLAVE*', 'RR'); 28 | 29 | console.log('test pool cluster connection RR'); 30 | 31 | let count = 0; 32 | 33 | function getConnection(i) { 34 | pool.getConnection((err, conn) => { 35 | assert.ifError(err); 36 | order[i] = conn._clusterId; 37 | conn.release(); 38 | 39 | count += 1; 40 | 41 | if (count <= 4) { 42 | getConnection(count); 43 | } else { 44 | done(); 45 | } 46 | }); 47 | } 48 | 49 | getConnection(0); 50 | -------------------------------------------------------------------------------- /test/unit/pool-cluster/test-query.test.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('poku'); 4 | const common = require('../../common.test.cjs'); 5 | const process = require('node:process'); 6 | 7 | // TODO: config poolCluster to work with MYSQL_CONNECTION_URL run 8 | if (`${process.env.MYSQL_CONNECTION_URL}`.includes('pscale_pw_')) { 9 | console.log('skipping test for planetscale'); 10 | process.exit(0); 11 | } 12 | 13 | const cluster = common.createPoolCluster(); 14 | const poolConfig = common.getConfig(); 15 | 16 | cluster.add('MASTER', poolConfig); 17 | cluster.add('SLAVE1', poolConfig); 18 | cluster.add('SLAVE2', poolConfig); 19 | 20 | const connection = cluster.of('*'); 21 | 22 | console.log('test pool cluster connection query'); 23 | 24 | connection.query('SELECT 1', (err, rows) => { 25 | assert.ifError(err); 26 | assert.equal(rows.length, 1); 27 | assert.equal(rows[0]['1'], 1); 28 | assert.deepEqual(cluster._serviceableNodeIds, ['MASTER', 'SLAVE1', 'SLAVE2']); 29 | 30 | cluster.end(); 31 | console.log('done'); 32 | }); 33 | -------------------------------------------------------------------------------- /tools/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-console": "off" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tools/create-db.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const conn = require('../test/common.test.cjs').createConnection({ 4 | database: 'mysql', 5 | }); 6 | conn.query('CREATE DATABASE IF NOT EXISTS test', (err) => { 7 | if (err) { 8 | console.log(err); 9 | return process.exit(-1); 10 | } 11 | 12 | conn.end(); 13 | }); 14 | -------------------------------------------------------------------------------- /tools/wait-up.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('../test/common.test.cjs').waitDatabaseReady(() => { 4 | console.log('ready!'); 5 | }); 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["index.d.ts", "promise.d.ts", "typings"], 3 | "exclude": ["node_modules", "test/tsc-build"], 4 | "compilerOptions": { 5 | "target": "es2016", 6 | "alwaysStrict": true, 7 | "noUnusedLocals": true, 8 | "module": "commonjs", 9 | "declaration": true, 10 | "strict": true, 11 | "noImplicitAny": true, 12 | "moduleResolution": "node", 13 | "removeComments": false, 14 | "noUnusedParameters": true, 15 | "isolatedModules": true 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /typings/mysql/LICENSE.txt: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2016, Felix Frederick Becker 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /typings/mysql/info.txt: -------------------------------------------------------------------------------- 1 | temporary workaround, see https://github.com/sidorares/node-mysql2/issues/1210 2 | -------------------------------------------------------------------------------- /typings/mysql/lib/Auth.d.ts: -------------------------------------------------------------------------------- 1 | import { RsaPublicKey, RsaPrivateKey, KeyLike } from 'crypto'; 2 | import { Connection } from './Connection.js'; 3 | 4 | export type AuthPlugin = (pluginMetadata: { 5 | connection: Connection; 6 | command: string; 7 | }) => ( 8 | pluginData: Buffer 9 | ) => Promise | string | Buffer | Promise | null; 10 | 11 | type AuthPluginDefinition = (pluginOptions?: T) => AuthPlugin; 12 | 13 | export const authPlugins: { 14 | caching_sha2_password: AuthPluginDefinition<{ 15 | overrideIsSecure?: boolean; 16 | serverPublicKey?: RsaPublicKey | RsaPrivateKey | KeyLike; 17 | onServerPublicKey?: (data: Buffer) => void; 18 | }>; 19 | mysql_clear_password: AuthPluginDefinition<{ 20 | password?: string; 21 | }>; 22 | mysql_native_password: AuthPluginDefinition<{ 23 | password?: string; 24 | passwordSha1?: string; 25 | }>; 26 | sha256_password: AuthPluginDefinition<{ 27 | serverPublicKey?: RsaPublicKey | RsaPrivateKey | KeyLike; 28 | onServerPublicKey?: (data: Buffer) => void; 29 | }>; 30 | }; 31 | -------------------------------------------------------------------------------- /typings/mysql/lib/PoolConnection.d.ts: -------------------------------------------------------------------------------- 1 | import { Connection } from './Connection.js'; 2 | import { Pool as PromisePool } from '../../../promise.js'; 3 | 4 | declare class PoolConnection extends Connection { 5 | connection: Connection; 6 | release(): void; 7 | promise(promiseImpl?: PromiseConstructor): PromisePool; 8 | } 9 | 10 | export { PoolConnection }; 11 | -------------------------------------------------------------------------------- /typings/mysql/lib/Server.d.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from 'events'; 2 | import { Connection } from './Connection.js'; 3 | 4 | declare class Server extends EventEmitter { 5 | connections: Array; 6 | 7 | listen(port: number): Server; 8 | close(callback: (error: Error, count: number) => any): void; 9 | } 10 | 11 | export { Server }; 12 | -------------------------------------------------------------------------------- /typings/mysql/lib/constants/CharsetToEncoding.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Constant `CharsetToEncoding`. 3 | * 4 | * Please note that `CharsetToEncoding` can only be accessed from the `mysql` object and not imported directly. 5 | */ 6 | declare const CharsetToEncoding: string[]; 7 | 8 | export { CharsetToEncoding }; 9 | -------------------------------------------------------------------------------- /typings/mysql/lib/constants/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Types } from './Types.js'; 2 | import { Charsets } from './Charsets.js'; 3 | import { CharsetToEncoding } from './CharsetToEncoding.js'; 4 | 5 | export { Types, Charsets, CharsetToEncoding }; 6 | -------------------------------------------------------------------------------- /typings/mysql/lib/parsers/ParserCache.d.ts: -------------------------------------------------------------------------------- 1 | declare function setMaxParserCache(max: number): void; 2 | declare function clearParserCache(): void; 3 | 4 | export { setMaxParserCache, clearParserCache }; 5 | -------------------------------------------------------------------------------- /typings/mysql/lib/parsers/index.d.ts: -------------------------------------------------------------------------------- 1 | import { setMaxParserCache, clearParserCache } from './ParserCache.js'; 2 | import { 3 | TypeCast, 4 | Field as TypeCastField, 5 | Geometry as TypeCastGeometry, 6 | Next as TypeCastNext, 7 | Type as TypeCastType, 8 | } from './typeCast.js'; 9 | 10 | export { 11 | setMaxParserCache, 12 | clearParserCache, 13 | TypeCast, 14 | TypeCastField, 15 | TypeCastGeometry, 16 | TypeCastNext, 17 | TypeCastType, 18 | }; 19 | -------------------------------------------------------------------------------- /typings/mysql/lib/parsers/typeCast.d.ts: -------------------------------------------------------------------------------- 1 | export type Geometry = { 2 | x: number; 3 | y: number; 4 | }; 5 | 6 | export type Type = { 7 | type: 8 | | 'DECIMAL' 9 | | 'TINY' 10 | | 'SHORT' 11 | | 'LONG' 12 | | 'FLOAT' 13 | | 'DOUBLE' 14 | | 'NULL' 15 | | 'TIMESTAMP' 16 | | 'TIMESTAMP2' 17 | | 'LONGLONG' 18 | | 'INT24' 19 | | 'DATE' 20 | | 'TIME' 21 | | 'TIME2' 22 | | 'DATETIME' 23 | | 'DATETIME2' 24 | | 'YEAR' 25 | | 'NEWDATE' 26 | | 'VARCHAR' 27 | | 'BIT' 28 | | 'VECTOR' 29 | | 'JSON' 30 | | 'NEWDECIMAL' 31 | | 'ENUM' 32 | | 'SET' 33 | | 'TINY_BLOB' 34 | | 'MEDIUM_BLOB' 35 | | 'LONG_BLOB' 36 | | 'BLOB' 37 | | 'VAR_STRING' 38 | | 'STRING' 39 | | 'GEOMETRY'; 40 | }; 41 | 42 | export type Field = Type & { 43 | length: number; 44 | db: string; 45 | table: string; 46 | name: string; 47 | string: (encoding?: BufferEncoding | string | undefined) => string | null; 48 | buffer: () => Buffer | null; 49 | geometry: () => Geometry | Geometry[] | null; 50 | }; 51 | 52 | export type Next = () => unknown; 53 | 54 | export type TypeCast = ((field: Field, next: Next) => any) | boolean; 55 | -------------------------------------------------------------------------------- /typings/mysql/lib/protocol/packets/Field.d.ts: -------------------------------------------------------------------------------- 1 | // TODO (major version): remove workaround for `Field` compatibility. 2 | import { TypeCastField } from '../../../lib/parsers/index.js'; 3 | 4 | /** 5 | * @deprecated 6 | * `Field` is deprecated and might be removed in the future major release. Please use `TypeCastField` type instead. 7 | */ 8 | declare interface Field extends TypeCastField {} 9 | 10 | export { Field }; 11 | -------------------------------------------------------------------------------- /typings/mysql/lib/protocol/packets/FieldPacket.d.ts: -------------------------------------------------------------------------------- 1 | declare interface FieldPacket { 2 | constructor: { 3 | name: 'FieldPacket'; 4 | }; 5 | catalog: string; 6 | charsetNr?: number; 7 | db?: string; 8 | schema?: string; 9 | characterSet?: number; 10 | decimals: number; 11 | default?: any; 12 | flags: number | string[]; 13 | length?: number; 14 | name: string; 15 | orgName: string; 16 | orgTable: string; 17 | protocol41?: boolean; 18 | table: string; 19 | type?: number; 20 | columnType?: number; 21 | zerofill?: boolean; 22 | typeName?: string; 23 | encoding?: string; 24 | columnLength?: number; 25 | } 26 | 27 | export { FieldPacket }; 28 | -------------------------------------------------------------------------------- /typings/mysql/lib/protocol/packets/OkPacket.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @deprecated 3 | * `OkPacket` is deprecated and might be removed in the future major release. Please use `ResultSetHeader` instead. 4 | */ 5 | declare interface OkPacket { 6 | constructor: { 7 | name: 'OkPacket'; 8 | }; 9 | fieldCount: number; 10 | affectedRows: number; 11 | /** 12 | * @deprecated 13 | * `changedRows` is deprecated and might be removed in the future major release. Please use `affectedRows` property instead. 14 | */ 15 | changedRows: number; 16 | insertId: number; 17 | serverStatus: number; 18 | warningCount: number; 19 | message: string; 20 | protocol41: boolean; 21 | } 22 | 23 | export { OkPacket }; 24 | -------------------------------------------------------------------------------- /typings/mysql/lib/protocol/packets/ProcedurePacket.d.ts: -------------------------------------------------------------------------------- 1 | import { OkPacket } from './OkPacket.js'; 2 | import { ResultSetHeader } from './ResultSetHeader.js'; 3 | import { RowDataPacket } from './RowDataPacket.js'; 4 | 5 | declare type ProcedureCallPacket< 6 | T = [RowDataPacket[], ResultSetHeader] | ResultSetHeader, 7 | > = T extends RowDataPacket[] 8 | ? [T, ResultSetHeader] 9 | : T extends ResultSetHeader | OkPacket 10 | ? ResultSetHeader 11 | : [RowDataPacket[], ResultSetHeader] | ResultSetHeader; 12 | 13 | export { ProcedureCallPacket }; 14 | -------------------------------------------------------------------------------- /typings/mysql/lib/protocol/packets/ResultSetHeader.d.ts: -------------------------------------------------------------------------------- 1 | declare interface ResultSetHeader { 2 | constructor: { 3 | name: 'ResultSetHeader'; 4 | }; 5 | affectedRows: number; 6 | fieldCount: number; 7 | info: string; 8 | insertId: number; 9 | serverStatus: number; 10 | warningStatus: number; 11 | /** 12 | * @deprecated 13 | * `changedRows` is deprecated and might be removed in the future major release. Please use `affectedRows` property instead. 14 | */ 15 | changedRows: number; 16 | } 17 | 18 | export { ResultSetHeader }; 19 | -------------------------------------------------------------------------------- /typings/mysql/lib/protocol/packets/RowDataPacket.d.ts: -------------------------------------------------------------------------------- 1 | declare interface RowDataPacket { 2 | constructor: { 3 | name: 'RowDataPacket'; 4 | }; 5 | [column: string]: any; 6 | [column: number]: any; 7 | } 8 | 9 | export { RowDataPacket }; 10 | -------------------------------------------------------------------------------- /typings/mysql/lib/protocol/packets/index.d.ts: -------------------------------------------------------------------------------- 1 | import { OkPacket } from './OkPacket.js'; 2 | import { RowDataPacket } from './RowDataPacket.js'; 3 | import { FieldPacket } from './FieldPacket.js'; 4 | import { Field } from './Field.js'; 5 | import { ProcedureCallPacket } from './ProcedurePacket.js'; 6 | import { ResultSetHeader } from './ResultSetHeader.js'; 7 | import { OkPacketParams } from './params/OkPacketParams.js'; 8 | import { ErrorPacketParams } from './params/ErrorPacketParams.js'; 9 | 10 | export type QueryResult = 11 | | OkPacket 12 | | ResultSetHeader 13 | | ResultSetHeader[] 14 | | RowDataPacket[] 15 | | RowDataPacket[][] 16 | | OkPacket[] 17 | | ProcedureCallPacket; 18 | 19 | export { 20 | OkPacket, 21 | RowDataPacket, 22 | FieldPacket, 23 | Field, 24 | ProcedureCallPacket, 25 | ResultSetHeader, 26 | OkPacketParams, 27 | ErrorPacketParams, 28 | }; 29 | -------------------------------------------------------------------------------- /typings/mysql/lib/protocol/packets/params/ErrorPacketParams.d.ts: -------------------------------------------------------------------------------- 1 | declare interface ErrorPacketParams { 2 | message?: string; 3 | code?: number | string; 4 | } 5 | 6 | export { ErrorPacketParams }; 7 | -------------------------------------------------------------------------------- /typings/mysql/lib/protocol/packets/params/OkPacketParams.d.ts: -------------------------------------------------------------------------------- 1 | declare interface OkPacketParams { 2 | affectedRows?: number; 3 | insertId?: number; 4 | serverStatus?: number; 5 | warningCount?: number; 6 | message?: string; 7 | } 8 | 9 | export { OkPacketParams }; 10 | -------------------------------------------------------------------------------- /typings/mysql/lib/protocol/sequences/ExecutableBase.d.ts: -------------------------------------------------------------------------------- 1 | import { FieldPacket, QueryResult } from '../packets/index.js'; 2 | import { 3 | Query, 4 | QueryError, 5 | QueryOptions, 6 | QueryableConstructor, 7 | } from './Query.js'; 8 | 9 | export declare function ExecutableBase( 10 | Base?: T 11 | ): { 12 | new (...args: any[]): { 13 | execute( 14 | sql: string, 15 | callback?: 16 | | ((err: QueryError | null, result: T, fields: FieldPacket[]) => any) 17 | | undefined 18 | ): Query; 19 | execute( 20 | sql: string, 21 | values: any, 22 | callback?: 23 | | ((err: QueryError | null, result: T, fields: FieldPacket[]) => any) 24 | | undefined 25 | ): Query; 26 | execute( 27 | options: QueryOptions, 28 | callback?: 29 | | ((err: QueryError | null, result: T, fields?: FieldPacket[]) => any) 30 | | undefined 31 | ): Query; 32 | execute( 33 | options: QueryOptions, 34 | values: any, 35 | callback?: 36 | | ((err: QueryError | null, result: T, fields: FieldPacket[]) => any) 37 | | undefined 38 | ): Query; 39 | }; 40 | } & T; 41 | -------------------------------------------------------------------------------- /typings/mysql/lib/protocol/sequences/QueryableBase.d.ts: -------------------------------------------------------------------------------- 1 | import { FieldPacket, QueryResult } from '../packets/index.js'; 2 | import { 3 | Query, 4 | QueryError, 5 | QueryOptions, 6 | QueryableConstructor, 7 | } from './Query.js'; 8 | 9 | export declare function QueryableBase( 10 | Base?: T 11 | ): { 12 | new (...args: any[]): { 13 | query( 14 | sql: string, 15 | callback?: 16 | | ((err: QueryError | null, result: T, fields: FieldPacket[]) => any) 17 | | undefined 18 | ): Query; 19 | query( 20 | sql: string, 21 | values: any, 22 | callback?: 23 | | ((err: QueryError | null, result: T, fields: FieldPacket[]) => any) 24 | | undefined 25 | ): Query; 26 | query( 27 | options: QueryOptions, 28 | callback?: 29 | | ((err: QueryError | null, result: T, fields?: FieldPacket[]) => any) 30 | | undefined 31 | ): Query; 32 | query( 33 | options: QueryOptions, 34 | values: any, 35 | callback?: 36 | | ((err: QueryError | null, result: T, fields: FieldPacket[]) => any) 37 | | undefined 38 | ): Query; 39 | }; 40 | } & T; 41 | -------------------------------------------------------------------------------- /typings/mysql/lib/protocol/sequences/Sequence.d.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from 'events'; 2 | 3 | declare class Sequence extends EventEmitter {} 4 | 5 | export { Sequence }; 6 | -------------------------------------------------------------------------------- /typings/mysql/lib/protocol/sequences/promise/ExecutableBase.d.ts: -------------------------------------------------------------------------------- 1 | import { FieldPacket, QueryResult } from '../../packets/index.js'; 2 | import { QueryOptions, QueryableConstructor } from '../Query.js'; 3 | 4 | export declare function ExecutableBase( 5 | Base?: T 6 | ): { 7 | new (...args: any[]): { 8 | execute(sql: string): Promise<[T, FieldPacket[]]>; 9 | execute( 10 | sql: string, 11 | values: any 12 | ): Promise<[T, FieldPacket[]]>; 13 | execute( 14 | options: QueryOptions 15 | ): Promise<[T, FieldPacket[]]>; 16 | execute( 17 | options: QueryOptions, 18 | values: any 19 | ): Promise<[T, FieldPacket[]]>; 20 | }; 21 | } & T; 22 | -------------------------------------------------------------------------------- /typings/mysql/lib/protocol/sequences/promise/QueryableBase.d.ts: -------------------------------------------------------------------------------- 1 | import { FieldPacket, QueryResult } from '../../packets/index.js'; 2 | import { QueryOptions, QueryableConstructor } from '../Query.js'; 3 | 4 | export declare function QueryableBase( 5 | Base?: T 6 | ): { 7 | new (...args: any[]): { 8 | query(sql: string): Promise<[T, FieldPacket[]]>; 9 | query( 10 | sql: string, 11 | values: any 12 | ): Promise<[T, FieldPacket[]]>; 13 | query( 14 | options: QueryOptions 15 | ): Promise<[T, FieldPacket[]]>; 16 | query( 17 | options: QueryOptions, 18 | values: any 19 | ): Promise<[T, FieldPacket[]]>; 20 | }; 21 | } & T; 22 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | i18n/**/docusaurus-theme-classic/navbar.json 11 | i18n/**/code.json 12 | 13 | # Misc 14 | .DS_Store 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | -------------------------------------------------------------------------------- /website/.prettierignore: -------------------------------------------------------------------------------- 1 | /build 2 | /.docusaurus 3 | /.cache-loader 4 | # /**/*.mdx 5 | -------------------------------------------------------------------------------- /website/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": true, 6 | "quoteProps": "as-needed", 7 | "jsxSingleQuote": true, 8 | "trailingComma": "es5", 9 | "bracketSpacing": true, 10 | "bracketSameLine": false, 11 | "arrowParens": "always", 12 | "proseWrap": "preserve", 13 | "htmlWhitespaceSensitivity": "css", 14 | "endOfLine": "auto", 15 | "embeddedLanguageFormatting": "auto", 16 | "singleAttributePerLine": false 17 | } 18 | -------------------------------------------------------------------------------- /website/.purc.json: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": { 3 | "eslint": { 4 | "target": "minor" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This [website](https://sidorares.github.io/node-mysql2/docs) is built using [Docusaurus 3](https://docusaurus.io/), a modern static website generator. 4 | 5 | # Contributing 6 | 7 | Want to improve something in **MySQL2 Documentation Website**? 8 | Please visit the [Website Contributing Guidelines](https://sidorares.github.io/node-mysql2/docs/contributing/website) for detailed instruction on how to get started. 9 | -------------------------------------------------------------------------------- /website/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /website/docs/acknowledgements.mdx: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | 3 | [mysql-native]: https://github.com/sidorares/nodejs-mysql-native 4 | [sidorares]: https://github.com/sidorares 5 | [node-mysql]: https://github.com/mysqljs/mysql 6 | [TooTallNate]: https://gist.github.com/TooTallNate 7 | [starttls.js]: https://gist.github.com/TooTallNate/848444 8 | [node-mariasql]: https://github.com/mscdex/node-mariasql 9 | [contributors]: https://github.com/sidorares/node-mysql2/graphs/contributors 10 | 11 | - Internal protocol is written by [@sidorares][sidorares] [MySQL-Native][mysql-native]. 12 | - Constants, SQL parameters interpolation, Pooling, `ConnectionConfig` class taken from [Node MySQL][node-mysql]. 13 | - SSL upgrade code based on [@TooTallNate][TooTallNate] [code][starttls.js]. 14 | - Secure connection / compressed connection api flags compatible to [MariaSQL][node-mariasql] client. 15 | - [Contributors][contributors]. 16 | -------------------------------------------------------------------------------- /website/docs/api-and-configurations.mdx: -------------------------------------------------------------------------------- 1 | # API and Configuration 2 | 3 | [node-mysql]: https://github.com/mysqljs/mysql 4 | 5 | MySQL2 is mostly API compatible with [Node MySQL][node-mysql]. 6 | 7 | One known incompatibility is that `DECIMAL` values are returned as strings whereas in [Node MySQL][node-mysql] they are returned as numbers. This includes the result of `SUM()` and `AVG()` functions when applied to `INTEGER` arguments. This is done deliberately to avoid loss of precision - see https://github.com/sidorares/node-mysql2/issues/935. 8 | 9 | :::info 10 | If you find any other incompatibility with [Node MySQL][node-mysql], Please report via Issue tracker. We will fix reported incompatibility on priority basis. 11 | ::: 12 | -------------------------------------------------------------------------------- /website/docs/contributing/00-index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /contributing 3 | title: MySQL2 4 | --- 5 | 6 | import { PageTitle } from '@site/src/components/PageTitle'; 7 | 8 | 9 | 10 | # Contributing 11 | 12 | Want to improve something in **MySQL2**? 13 | Please check [Contributing.md](https://github.com/sidorares/node-mysql2/blob/master/Contributing.md) for detailed instruction on how to get started. 14 | -------------------------------------------------------------------------------- /website/docs/examples/00-index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /examples 3 | title: Introduction 4 | --- 5 | 6 | import Tabs from '@theme/Tabs'; 7 | import TabItem from '@theme/TabItem'; 8 | import { PageTitle } from '@site/src/components/PageTitle'; 9 | 10 | 11 | 12 | # Examples 13 | 14 | :::tip 15 | To explore the examples, please use the **sidebar navigation** on desktop or access the **menu** on mobile devices. 16 | ::: 17 | 18 | ## Examples using MySQL server API 19 | 20 | - [MySQL-pg-proxy](https://github.com/sidorares/mysql-pg-proxy) - MySQL to Postgres proxy server. 21 | - [MySQLite.js](https://github.com/sidorares/mysqlite.js) - MySQL server with JS-only (emscripten compiled) sqlite backend. 22 | - [SQL-engine](https://github.com/eugeneware/sql-engine) - MySQL server with LevelDB backend. 23 | - [MySQL-osquery-proxy](https://github.com/sidorares/mysql-osquery-proxy) - Connect to [facebook osquery](https://osquery.io/) using MySQL client 24 | - [PlyQL](https://github.com/implydata/plyql) - Connect to [Druid](https://druid.io/) using MySQL client 25 | -------------------------------------------------------------------------------- /website/docs/examples/binlog-watcher.mdx: -------------------------------------------------------------------------------- 1 | import Tabs from '@theme/Tabs'; 2 | import TabItem from '@theme/TabItem'; 3 | 4 | # Binlog Watcher 5 | 6 | 7 | 8 | 9 | ```js 10 | 'use strict'; 11 | 12 | const mysql = require('mysql2'); 13 | const through2 = require('through2'); 14 | 15 | const binlogStream = mysql.createBinlogStream({ 16 | serverId: 123, // slave ID, first field in "show slave hosts" sql response 17 | // you can also specify slave host, username, password and port 18 | masterId: 0, 19 | filename: 'mysql-bin.000007', 20 | binlogPos: 120, 21 | flags: 1, // 1 = "non-blocking mode" 22 | }); 23 | 24 | binlogStream.pipe( 25 | through2.obj((obj, enc, next) => { 26 | console.log(obj); 27 | next(); 28 | }) 29 | ); 30 | ``` 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /website/docs/examples/connections/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Connections", 3 | "position": 1 4 | } 5 | -------------------------------------------------------------------------------- /website/docs/examples/promise-wrapper/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Promise Wrapper" 3 | } 4 | -------------------------------------------------------------------------------- /website/docs/examples/queries/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Queries", 3 | "position": 2 4 | } 5 | -------------------------------------------------------------------------------- /website/docs/examples/queries/prepared-statements/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Prepared Statements", 3 | "position": 2 4 | } 5 | -------------------------------------------------------------------------------- /website/docs/examples/queries/prepared-statements/index.mdx: -------------------------------------------------------------------------------- 1 | # Prepared Statements 2 | 3 | MySQL2 provides `execute` helper which will prepare and query the statement. 4 | You can also manually prepare / unprepare statement with `prepare` / `unprepare` methods. 5 | 6 | See detailed documentaion in [Prepared Statements](/docs/documentation/prepared-statements). 7 | 8 | :::tip 9 | If you execute same statement again, it will be picked form a **LRU cache** which will save query preparation time and give better performance. 10 | ::: 11 | 12 |
13 | 14 | Usage examples: 15 | 16 | - [x] [**INSERT**](/docs/examples/queries/prepared-statements/insert) 17 | - [x] [**SELECT**](/docs/examples/queries/prepared-statements/select) 18 | - [x] [**UPDATE**](/docs/examples/queries/prepared-statements/update) 19 | - [x] [**DELETE**](/docs/examples/queries/prepared-statements/delete) 20 | -------------------------------------------------------------------------------- /website/docs/examples/queries/simple-queries/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Simple Queries", 3 | "position": 1 4 | } 5 | -------------------------------------------------------------------------------- /website/docs/examples/queries/simple-queries/index.mdx: -------------------------------------------------------------------------------- 1 | # Simple Queries 2 | 3 | :::info 4 | For **Prepared Statements** or **Placeholders** / **Parameters** examples, please see [here](/docs/examples/queries/prepared-statements). 5 | ::: 6 | 7 |
8 | 9 | Usage examples: 10 | 11 | - [x] [**INSERT**](/docs/examples/queries/simple-queries/insert) 12 | - [x] [**SELECT**](/docs/examples/queries/simple-queries/select) 13 | - [x] [**UPDATE**](/docs/examples/queries/simple-queries/update) 14 | - [x] [**DELETE**](/docs/examples/queries/simple-queries/delete) 15 | -------------------------------------------------------------------------------- /website/docs/examples/tests/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Tests" 3 | } 4 | -------------------------------------------------------------------------------- /website/docs/examples/tests/pool.mdx: -------------------------------------------------------------------------------- 1 | import Tabs from '@theme/Tabs'; 2 | import TabItem from '@theme/TabItem'; 3 | 4 | # Pool 5 | 6 | 7 | 8 | 9 | ```js 10 | 'use strict'; 11 | 12 | const pool = require('mysql2').createPool({ 13 | host: 'localhost', 14 | user: 'root', 15 | database: 'test', 16 | password: 'root', 17 | }); 18 | 19 | setInterval(() => { 20 | for (let i = 0; i < 5; ++i) { 21 | pool.query((err, rows, fields) => { 22 | console.log(rows, fields); 23 | // Connection is automatically released once query resolves 24 | }); 25 | } 26 | }, 1000); 27 | 28 | setInterval(() => { 29 | for (let i = 0; i < 5; ++i) { 30 | pool.getConnection((err, db) => { 31 | db.query('select sleep(0.5) as qqq', (err, rows, fields) => { 32 | console.log(rows, fields); 33 | db.release(); 34 | }); 35 | }); 36 | } 37 | }, 1000); 38 | ``` 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /website/docs/examples/typescript/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "TypeScript" 3 | } 4 | -------------------------------------------------------------------------------- /website/docs/examples/typescript/procedure-call/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Procedure Call" 3 | } 4 | -------------------------------------------------------------------------------- /website/docs/examples/typescript/row-data/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Row Data" 3 | } 4 | -------------------------------------------------------------------------------- /website/docs/faq/00-index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /faq 3 | title: Introduction 4 | --- 5 | 6 | import { PageTitle } from '@site/src/components/PageTitle'; 7 | 8 | 9 | 10 | # Frequently Asked Questions 11 | 12 | This section provides answers to commonly asked questions about [MySQL2](https://github.com/sidorares/node-mysql2/discussions). 13 | 14 | :::tip 15 | To explore the FAQs, please use the **sidebar navigation** on desktop or access the **menu** on mobile devices. 16 | ::: 17 | -------------------------------------------------------------------------------- /website/docs/history-and-why-mysq2.mdx: -------------------------------------------------------------------------------- 1 | # History and Why MySQL2 2 | 3 | [node-mysql]: https://github.com/mysqljs/mysql 4 | [mysql-native]: https://github.com/sidorares/nodejs-mysql-native 5 | [mysqljs]: https://github.com/mysqljs 6 | 7 | MySQL2 project is a continuation of [MySQL-Native][mysql-native]. Protocol parser code was rewritten from scratch and api changed to match popular [Node MySQL][node-mysql]. MySQL2 team is working together with [Node MySQL][node-mysql] team to factor out shared code and move it under [mysqljs][mysqljs] organization. 8 | 9 | MySQL2 is mostly API compatible with [Node MySQL][node-mysql] and supports majority of features. MySQL2 also offers these additional features: 10 | 11 | - Faster / Better Performance 12 | - [Prepared Statements](/docs/documentation/prepared-statements) 13 | - MySQL Binary Log Protocol 14 | - [MySQL Server](/docs/documentation/mysql-server) 15 | - Extended support for Encoding and Collation 16 | - [Promise Wrapper](/docs/documentation/promise-wrapper) 17 | - Compression 18 | - SSL and [Authentication Switch](/docs/documentation/authentication-switch) 19 | - [Custom Streams](/docs/documentation/extras#connecting-using-custom-stream) 20 | - [Pooling](/docs/#using-connection-pools) 21 | -------------------------------------------------------------------------------- /website/helpers/extract-method-content.ts: -------------------------------------------------------------------------------- 1 | export type MethodType = 'class' | 'interface' | 'type' | 'function' | 'const'; 2 | 3 | export const extractMethodContent = ( 4 | text: string, 5 | methodName: string, 6 | type: MethodType 7 | ): string => { 8 | const lines = text.split('\n'); 9 | const startPattern = `${type} ${methodName}`; 10 | 11 | let insideSegment = false; 12 | let depth = 0; 13 | let extractedCode = ''; 14 | 15 | for (const line of lines) { 16 | if (line.includes(startPattern)) insideSegment = true; 17 | 18 | if (insideSegment) { 19 | if (line.includes('{')) depth++; 20 | 21 | extractedCode += `${line}\n`; 22 | 23 | if (line.includes('}')) { 24 | depth--; 25 | 26 | if (depth === 0) break; 27 | } 28 | } 29 | } 30 | 31 | return extractedCode.trim() || text; 32 | }; 33 | -------------------------------------------------------------------------------- /website/i18n/pt-BR/docusaurus-plugin-content-docs/current.json: -------------------------------------------------------------------------------- 1 | { 2 | "sidebar.docs.category.Documentation": { 3 | "message": "Documentação" 4 | }, 5 | "sidebar.docs.category.Examples": { 6 | "message": "Exemplos" 7 | }, 8 | "sidebar.docs.category.Contributing": { 9 | "message": "Contribuições" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /website/i18n/pt-BR/docusaurus-plugin-content-docs/current/acknowledgements.mdx: -------------------------------------------------------------------------------- 1 | # Agradecimentos 2 | 3 | - O protocolo interno é escrito por @sidorares [MySQL-Native](https://github.com/sidorares/nodejs-mysql-native) 4 | - _Constants_, interpolação de parâmetros SQL, _Pooling_ e a classe `ConnectionConfig` foram retirados do [node-mysql](https://github.com/mysqljs/mysql) 5 | - O Código de atualização SSL é baseado no [código](https://gist.github.com/TooTallNate/848444) feito por @TooTallNate 6 | - _Flags_ de API de conexão segura / comprimida compatíveis com o cliente [MariaSQL](https://github.com/mscdex/node-mariasql/). 7 | - [Contribuidores](https://github.com/sidorares/node-mysql2/graphs/contributors) 8 | -------------------------------------------------------------------------------- /website/i18n/pt-BR/docusaurus-plugin-content-docs/current/api-and-configurations.mdx: -------------------------------------------------------------------------------- 1 | # API e Configuração 2 | 3 | O MySQL2 é maioritariamente compatível com a API do [Node MySQL][node-mysql]. 4 | 5 | Uma incompatibilidade conhecida é que os valores em `DECIMAL` são retornados como _strings_, enquanto no [Node MySQL][node-mysql] eles são retornados como números. Isso inclui o resultado das funções `SUM()` e `AVG()` quando aplicadas a argumentos `INTEGER`. Isso é feito deliberadamente para evitar a perda de precisão - veja https://github.com/sidorares/node-mysql2/issues/935. 6 | 7 | :::info 8 | Se você encontrar qualquer outra incompatibilidade com o [Node MySQL][node-mysql], por favor, reporte através do acompanhamento de _Issues_. Nós corrigiremos a incompatibilidade relatada como uma prioridade. 9 | ::: 10 | 11 | [node-mysql]: https://github.com/mysqljs/mysql 12 | -------------------------------------------------------------------------------- /website/i18n/pt-BR/docusaurus-plugin-content-docs/current/contributing/00-index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /contributing 3 | title: MySQL2 4 | --- 5 | 6 | import { PageTitle } from '@site/src/components/PageTitle'; 7 | 8 | 9 | 10 | # Contribuições 11 | 12 | Quer melhorar algo no **MySQL2**? 13 | Consulte o arquivo [Contributing.md](https://github.com/sidorares/node-mysql2/blob/master/Contributing.md) para instruções detalhadas sobre como começar. 14 | -------------------------------------------------------------------------------- /website/i18n/zh-CN/docusaurus-plugin-content-docs/current.json: -------------------------------------------------------------------------------- 1 | { 2 | "sidebar.docs.category.Documentation": { 3 | "message": "文档" 4 | }, 5 | "sidebar.docs.category.Examples": { 6 | "message": "示例" 7 | }, 8 | "sidebar.docs.category.Contributing": { 9 | "message": "贡献" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /website/i18n/zh-CN/docusaurus-plugin-content-docs/current/acknowledgements.mdx: -------------------------------------------------------------------------------- 1 | # 鸣谢 2 | 3 | - 内部协议由@sidorares编写 [MySQL-Native](https://github.com/sidorares/nodejs-mysql-native) 4 | - 常量、SQL参数插值、连接池、`ConnectionConfig` 类取自[node-mysql](https://github.com/mysqljs/mysql) 5 | - 基于@TooTallNate的SSL代码升级[代码地址](https://gist.github.com/TooTallNate/848444) 6 | - 与[MariaSQL](https://github.com/mscdex/node-mariasql/)客户端兼容安全连接/压缩连接 API。 7 | - [贡献者](https://github.com/sidorares/node-mysql2/graphs/contributors) 8 | -------------------------------------------------------------------------------- /website/i18n/zh-CN/docusaurus-plugin-content-docs/current/api-and-configurations.mdx: -------------------------------------------------------------------------------- 1 | # API配置项 2 | 3 | MySQL2大部分的API与 [Node MySQL][node-mysql] 基本上相同,你应该查看他们的API文档来知道更多的API选项。 4 | 5 | One known incompatibility is that `DECIMAL` values are returned as strings whereas in [Node MySQL][node-mysql] they are returned as numbers. This includes the result of `SUM()` and `AVG()` functions when applied to `INTEGER` arguments. This is done deliberately to avoid loss of precision - see https://github.com/sidorares/node-mysql2/issues/935. 6 | 7 | :::info 8 | 如果您发现与 [Node MySQL][node-mysql] 的任何不兼容问题,请通过`issue`报告。 我们将优先修复报告的不兼容问题。 9 | ::: 10 | 11 | [node-mysql]: https://github.com/mysqljs/mysql 12 | -------------------------------------------------------------------------------- /website/i18n/zh-CN/docusaurus-plugin-content-docs/current/contributing/00-index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /contributing 3 | title: MySQL2 4 | --- 5 | 6 | import { PageTitle } from '@site/src/components/PageTitle'; 7 | 8 | 9 | 10 | # 贡献 11 | 12 | 如果要为`node-mysql2`做些贡献.请查阅 [Contributing.md](https://github.com/sidorares/node-mysql2/blob/master/Contributing.md) 来获得更多详细信息。 13 | -------------------------------------------------------------------------------- /website/i18n/zh-CN/docusaurus-plugin-content-docs/current/history-and-why-mysq2.mdx: -------------------------------------------------------------------------------- 1 | # MySQL2的历史以及选择原因 2 | 3 | MySQL2 项目是 [MySQL-Native][mysql-native] 的延续。 协议解析器代码从头开始重写,api 更改为匹配流行的 [mysqljs/mysql][node-mysql]。 MySQL2 团队正在与 [mysqljs/mysql][node-mysql] 团队合作,将共享代码分解并移至 [mysqljs][node-mysql] 组织下。 4 | 5 | MySQL2 大部分 API 与 [mysqljs][node-mysql] 兼容,并支持大部分功能。 MySQL2 还提供了更多的附加功能: 6 | 7 | - 更快、更好的性能 8 | - [支持预处理](/docs/documentation/prepared-statements) 9 | - MySQL二进制日志协议 10 | - [MySQL Server](/docs/documentation/mysql-server) 11 | - 对编码和排序规则有很好的支持 12 | - [Promise封装](/docs/documentation/promise-wrapper) 13 | - 支持压缩 14 | - SSL 和 [Authentication Switch](/docs/documentation/authentication-switch) 15 | - [自定义流](/docs/documentation/extras#connecting-using-custom-stream) 16 | - [连接池](/docs/#using-connection-pools) 17 | 18 | [node-mysql]: https://github.com/mysqljs/mysql 19 | [mysql-native]: https://github.com/sidorares/nodejs-mysql-native 20 | -------------------------------------------------------------------------------- /website/plugins/locale.ts: -------------------------------------------------------------------------------- 1 | import type { Plugin } from '@docusaurus/types'; 2 | 3 | export const navbarLocalePlugin = (): Plugin => ({ 4 | name: 'navbar-locale-plugin', 5 | contentLoaded({ actions }) { 6 | const { setGlobalData } = actions; 7 | setGlobalData({ currentLocale: process.env.LOCALE }); 8 | }, 9 | }); 10 | 11 | export const useLocale = 12 | typeof process.env?.LOCALE === 'string' && 13 | process.env.LOCALE.trim().length > 0; 14 | 15 | export const getLocaleURL = (): string => 16 | useLocale ? `/${process.env.LOCALE}/docs` : '/docs'; 17 | -------------------------------------------------------------------------------- /website/sidebars.ts: -------------------------------------------------------------------------------- 1 | import type { SidebarsConfig } from '@docusaurus/plugin-content-docs'; 2 | 3 | const sidebars: SidebarsConfig = { 4 | docs: [ 5 | 'index', 6 | 'history-and-why-mysq2', 7 | 'stability-badges', 8 | { 9 | type: 'category', 10 | label: 'Documentation', 11 | items: [{ type: 'autogenerated', dirName: 'documentation' }], 12 | }, 13 | 'api-and-configurations', 14 | 'acknowledgements', 15 | { 16 | type: 'category', 17 | label: 'Contributing', 18 | items: [{ type: 'autogenerated', dirName: 'contributing' }], 19 | }, 20 | ], 21 | examples: [{ type: 'autogenerated', dirName: 'examples' }], 22 | faq: [{ type: 'autogenerated', dirName: 'faq' }], 23 | }; 24 | 25 | export default sidebars; 26 | -------------------------------------------------------------------------------- /website/src/components/FAQ.tsx: -------------------------------------------------------------------------------- 1 | import type { FC, ReactNode } from 'react'; 2 | import Details from '@theme/Details'; 3 | 4 | export type FAQProps = { 5 | children: ReactNode; 6 | open?: boolean; 7 | title: string; 8 | }; 9 | 10 | /** 11 | * Usage example: 12 | * 13 | * ```mdx 14 | * 15 | * 16 | * > Some markdown (**MDX**) content. 17 | * 18 | * 19 | * ``` 20 | */ 21 | export const FAQ: FC = ({ children, open, title }) => { 22 | return ( 23 |
28 | {title} 29 | 30 | } 31 | > 32 |
{children}
33 |
34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /website/src/components/Loading.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Credits: https://cssloaders.github.io/ 3 | */ 4 | export const Loading = () => ; 5 | -------------------------------------------------------------------------------- /website/src/components/PageTitle.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react'; 2 | import Head from '@docusaurus/Head'; 3 | 4 | export type PageTitleProps = { 5 | title: string; 6 | }; 7 | 8 | /** 9 | * **Force a custom Tab Title:** this component sets a specific title for the browser tab. 10 | * 11 | * Use it to override the default title derived from the document or page content. 12 | * 13 | * ℹ️ Ideal for situations where the tab title needs to be different from the page's main heading or `.mdx` title. 14 | * 15 | * --- 16 | * 17 | * **Usage:** 18 | * 19 | * ```tsx 20 | * 21 | * ``` 22 | */ 23 | export const PageTitle: FC = ({ title }) => { 24 | return ( 25 | 26 | {title} 27 | 28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /website/src/css/_faq.scss: -------------------------------------------------------------------------------- 1 | details { 2 | &.faq { 3 | background-color: var(--faq-background); 4 | border-color: var(--faq-border-color); 5 | 6 | pre { 7 | code { 8 | border: 0.0625rem solid var(--faq-code-border-color); 9 | } 10 | } 11 | } 12 | } 13 | 14 | [data-theme='light'] { 15 | details { 16 | &.faq { 17 | --docusaurus-details-decoration-color: var(--ifm-color-primary); 18 | --faq-background: #f8fcff; 19 | --faq-border-color: var(--ifm-color-primary); 20 | --faq-code-border-color: #add2eb; 21 | 22 | code[class*='language-'], 23 | pre[class*='language-'] { 24 | background-color: #fbfdff !important; 25 | } 26 | } 27 | } 28 | } 29 | 30 | [data-theme='dark'] { 31 | details { 32 | &.faq { 33 | --docusaurus-details-decoration-color: #7230d6; 34 | --faq-background: #151518; 35 | --faq-border-color: #36284b; 36 | --faq-code-border-color: #38225a; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /website/src/css/_loading.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Credits: https://cssloaders.github.io/ 3 | */ 4 | 5 | .loader { 6 | width: 0.8rem; 7 | height: 0.8rem; 8 | border-radius: 50%; 9 | display: block; 10 | margin: 2.375rem 1.1875rem; 11 | position: relative; 12 | color: var(--ifm-color-primary-lightest); 13 | box-sizing: border-box; 14 | animation: animloader 1s linear infinite alternate; 15 | transform: scale(0.5); 16 | } 17 | 18 | @keyframes animloader { 19 | 0% { 20 | box-shadow: 21 | -2.375rem -0.35rem, 22 | -0.875rem 0.35rem, 23 | 0.875rem -0.35rem; 24 | } 25 | 33% { 26 | box-shadow: 27 | -2.375rem 0.35rem, 28 | -0.875rem -0.35rem, 29 | 0.875rem 0.35rem; 30 | } 31 | 66% { 32 | box-shadow: 33 | -2.375rem -0.35rem, 34 | -0.875rem 0.35rem, 35 | 0.875rem -0.35rem; 36 | } 37 | 100% { 38 | box-shadow: 39 | -2.375rem 0.35rem, 40 | -0.875rem -0.35rem, 41 | 0.875rem 0.35rem; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /website/src/css/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin flex($direction: unset, $align: unset, $justify: unset, $wrap: unset) { 2 | display: flex; 3 | 4 | @if ($direction != unset) { 5 | flex-direction: $direction; 6 | } 7 | 8 | @if ($align != unset) { 9 | align-items: $align; 10 | } 11 | 12 | @if ($justify != unset) { 13 | justify-content: $justify; 14 | } 15 | 16 | @if ($wrap != unset) { 17 | flex-wrap: $wrap; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /website/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { Redirect } from '@docusaurus/router'; 2 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 3 | 4 | function Home() { 5 | const { i18n, siteConfig } = useDocusaurusContext(); 6 | const { baseUrl } = siteConfig; 7 | const currentLocale = i18n.currentLocale; 8 | const setLocaleRedirectMap = () => 9 | currentLocale === 'en' || baseUrl.includes(currentLocale) 10 | ? `${baseUrl}docs` 11 | : `${baseUrl}${currentLocale}/docs`; 12 | const redirectUrl = setLocaleRedirectMap(); 13 | 14 | return ; 15 | } 16 | 17 | export default Home; 18 | -------------------------------------------------------------------------------- /website/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidorares/node-mysql2/febd2deaf996593636fa088ab4093ff208e67ada/website/static/.nojekyll -------------------------------------------------------------------------------- /website/static/img/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /website/test/fixtures/external-code-embed/HistoryRecords.txt: -------------------------------------------------------------------------------- 1 | export type HistoryRecords = { 2 | /** **Examples:** 3 | * 4 | * - `3.x` 5 | * - `3.2.x` 6 | * - `3.2.6` 7 | */ 8 | version: string; 9 | /** 10 | * Examples: 11 | * 12 | * --- 13 | * 14 | * - string 15 | * ```plain 16 | * Indicate your changes 17 | * ``` 18 | * 19 | * --- 20 | * 21 | * - JSX 22 | * ```tsx 23 | * <> 24 | * Method Name and your changes 25 | * 26 | * ``` 27 | */ 28 | changes: (string | JSX.Element)[]; 29 | }; -------------------------------------------------------------------------------- /website/test/fixtures/external-code-embed/handleCompressedPacket.txt: -------------------------------------------------------------------------------- 1 | function handleCompressedPacket(packet) { 2 | // eslint-disable-next-line consistent-this, no-invalid-this 3 | const connection = this; 4 | const deflatedLength = packet.readInt24(); 5 | const body = packet.readBuffer(); 6 | 7 | if (deflatedLength !== 0) { 8 | connection.inflateQueue.push(task => { 9 | zlib.inflate(body, (err, data) => { 10 | if (err) { 11 | connection._handleNetworkError(err); 12 | return; 13 | } 14 | connection._bumpCompressedSequenceId(packet.numPackets); 15 | connection._inflatedPacketsParser.execute(data); 16 | task.done(); 17 | }); 18 | }); 19 | } else { 20 | connection.inflateQueue.push(task => { 21 | connection._bumpCompressedSequenceId(packet.numPackets); 22 | connection._inflatedPacketsParser.execute(body); 23 | task.done(); 24 | }); 25 | } 26 | } -------------------------------------------------------------------------------- /website/test/fixtures/external-code-embed/handler.txt: -------------------------------------------------------------------------------- 1 | function handler(packet) { 2 | //console.log(packet.length(), packet.sequenceId); 3 | cc += packet.sequenceId; 4 | count++; 5 | } -------------------------------------------------------------------------------- /website/test/fixtures/external-code-embed/makeSelector.txt: -------------------------------------------------------------------------------- 1 | const makeSelector = { 2 | RR() { 3 | let index = 0; 4 | return clusterIds => clusterIds[index++ % clusterIds.length]; 5 | }, 6 | RANDOM() { 7 | return clusterIds => 8 | clusterIds[Math.floor(Math.random() * clusterIds.length)]; 9 | }, 10 | ORDER() { 11 | return clusterIds => clusterIds[0]; 12 | } 13 | }; -------------------------------------------------------------------------------- /website/test/unit/check-extensions.test.ts: -------------------------------------------------------------------------------- 1 | import { EOL } from 'node:os'; 2 | import { listFiles, test, assert } from 'poku'; 3 | 4 | const invalidFiles: string[] = []; 5 | const message = [ 6 | 'Check for invalid file types found in restricted directories', 7 | ]; 8 | 9 | const checkExtensions = async ( 10 | dirs: string[], 11 | allowedExtensions: RegExp, 12 | ignoreList: RegExp = /\.DS_Store/ 13 | ) => { 14 | for (const dir of dirs) { 15 | const files = await listFiles(dir, { filter: /\./ }); 16 | 17 | for (const file of files) { 18 | if (!(ignoreList.test(file) || allowedExtensions.test(file))) { 19 | invalidFiles.push(file); 20 | message.push(`${EOL}${String(allowedExtensions)}`); 21 | message.push(`- ${file}`); 22 | } 23 | } 24 | } 25 | }; 26 | 27 | test(async () => { 28 | await checkExtensions(['docs', 'i18n'], /\.(mdx|json)$/); 29 | await checkExtensions(['helpers', 'plugins'], /\.ts$/); 30 | await checkExtensions(['test/unit', 'test/utils'], /\.test\.ts$/); 31 | await checkExtensions(['src/components', 'src/pages'], /\.tsx$/); 32 | await checkExtensions(['src/css'], /\.scss$/); 33 | 34 | assert.deepStrictEqual( 35 | invalidFiles.length, 36 | 0, 37 | Array.from(new Set(message)).join(EOL) 38 | ); 39 | }); 40 | -------------------------------------------------------------------------------- /website/test/unit/external-code-embed.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Fixtures generated using './test/utils/gen-expected-extract-results.ts' 3 | */ 4 | 5 | import fs from 'node:fs'; 6 | import path from 'node:path'; 7 | import { assert } from 'poku'; 8 | import { 9 | extractMethodContent, 10 | type MethodType, 11 | } from '@site/helpers/extract-method-content'; 12 | 13 | const resource = fs.readFileSync( 14 | path.resolve('./test/resources/external-code-embed/random-methods.txt'), 15 | 'utf-8' 16 | ); 17 | 18 | const checkResult = (methodName: string, methodType: MethodType) => { 19 | if ( 20 | fs.readFileSync( 21 | path.resolve(`./test/fixtures/external-code-embed/${methodName}.txt`), 22 | 'utf-8' 23 | ) !== extractMethodContent(resource, methodName, methodType) 24 | ) 25 | assert.fail(`${methodName} example failed`); 26 | }; 27 | 28 | // Valid methods 29 | checkResult('QueryOptions', 'interface'); 30 | checkResult('Pool', 'class'); 31 | checkResult('makeSelector', 'const'); 32 | checkResult('handleCompressedPacket', 'function'); 33 | checkResult('HistoryRecords', 'type'); 34 | checkResult('handler', 'function'); 35 | 36 | // Invalid method 37 | if (resource !== extractMethodContent(resource, 'invalidMethod', 'function')) { 38 | assert.fail( 39 | "Invalid method example failed. It should return the original content when it didn't find the requested method." 40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /website/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@docusaurus/tsconfig", 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "isolatedModules": true, 7 | "allowJs": false, 8 | "strict": true, 9 | "alwaysStrict": true, 10 | "strictFunctionTypes": true, 11 | "noUnusedLocals": true 12 | }, 13 | "exclude": ["static", "build", ".docusaurus"] 14 | } 15 | --------------------------------------------------------------------------------