├── .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 | defmysqluserusermax_updatesmax_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 PankoMethod 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 |
--------------------------------------------------------------------------------