diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index b496b5a9..00000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: "CodeQL" - -on: - push: - branches: [ "main" ] - pull_request: - schedule: - - cron: "29 15 * * 6" - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - # with: - # languages: ${{ matrix.language }} - # queries: +security-and-quality - - # - name: Autobuild - # uses: github/codeql-action/autobuild@v2 - - - name: Build - run: | - python setup.py build_ext -if - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 8e0e2947..95a95ac3 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -10,5 +10,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: psf/black@stable - - uses: chartboost/ruff-action@v1 + - run: pipx install ruff + - run: ruff check src/ + - run: ruff format src/ diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index f6a13fd2..cf784c78 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -13,9 +13,9 @@ jobs: PIP_DISABLE_PIP_VERSION_CHECK: 1 strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] include: - - python-version: "3.11" + - python-version: "3.12" mariadb: 1 steps: - if: ${{ matrix.mariadb }} @@ -59,7 +59,7 @@ jobs: run: | pytest --cov=MySQLdb tests - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v5 django-test: name: "Run Django LTS test suite" @@ -68,7 +68,7 @@ jobs: env: PIP_NO_PYTHON_VERSION_WARNING: 1 PIP_DISABLE_PIP_VERSION_CHECK: 1 - DJANGO_VERSION: "3.2.19" + DJANGO_VERSION: "4.2.16" steps: - name: Start MySQL run: | @@ -83,9 +83,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - # Django 3.2.9+ supports Python 3.10 - # https://docs.djangoproject.com/ja/3.2/releases/3.2/ - python-version: "3.10" + python-version: "3.12" cache: "pip" cache-dependency-path: "ci/django-requirements.txt" diff --git a/.github/workflows/windows.yaml b/.github/workflows/windows.yaml index afbfd4c8..f8dbf87a 100644 --- a/.github/workflows/windows.yaml +++ b/.github/workflows/windows.yaml @@ -10,15 +10,14 @@ jobs: build: runs-on: windows-latest env: - CONNECTOR_VERSION: "3.3.8" + CONNECTOR_VERSION: "3.4.1" steps: - - name: Cache Connector id: cache-connector - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: c:/mariadb-connector - key: mariadb-connector-c-${{ env.CONNECTOR_VERSION }}-win + key: mariadb-connector-c-${{ env.CONNECTOR_VERSION }}-win-2 - name: Download and Unzip Connector if: steps.cache-connector.outputs.cache-hit != 'true' @@ -28,15 +27,32 @@ jobs: unzip "mariadb-connector-c-${CONNECTOR_VERSION}-src.zip" -d c:/ mv "c:/mariadb-connector-c-${CONNECTOR_VERSION}-src" c:/mariadb-connector-src - - name: Build Connector + - name: make build directory if: steps.cache-connector.outputs.cache-hit != 'true' shell: cmd working-directory: c:/mariadb-connector-src run: | mkdir build - cd build - cmake -A x64 .. -DCMAKE_BUILD_TYPE=Release -DCLIENT_PLUGIN_DIALOG=static -DCLIENT_PLUGIN_SHA256_PASSWORD=static -DCLIENT_PLUGIN_CACHING_SHA2_PASSWORD=static + + - name: cmake + if: steps.cache-connector.outputs.cache-hit != 'true' + shell: cmd + working-directory: c:/mariadb-connector-src/build + run: | + cmake -A x64 .. -DCMAKE_BUILD_TYPE=Release -DCLIENT_PLUGIN_DIALOG=static -DCLIENT_PLUGIN_SHA256_PASSWORD=static -DCLIENT_PLUGIN_CACHING_SHA2_PASSWORD=static -DDEFAULT_SSL_VERIFY_SERVER_CERT=0 + + - name: cmake build + if: steps.cache-connector.outputs.cache-hit != 'true' + shell: cmd + working-directory: c:/mariadb-connector-src/build + run: | cmake --build . -j 8 --config Release + + - name: cmake install + if: steps.cache-connector.outputs.cache-hit != 'true' + shell: cmd + working-directory: c:/mariadb-connector-src/build + run: | cmake -DCMAKE_INSTALL_PREFIX=c:/mariadb-connector -DCMAKE_INSTALL_COMPONENT=Development -DCMAKE_BUILD_TYPE=Release -P cmake_install.cmake - name: Checkout mysqlclient @@ -63,9 +79,9 @@ jobs: - name: Build wheels working-directory: mysqlclient env: - CIBW_PROJECT_REQUIRES_PYTHON: ">=3.8" + CIBW_PROJECT_REQUIRES_PYTHON: ">=3.9" CIBW_ARCHS: "AMD64" - CIBW_TEST_COMMAND: "python -c \"import MySQLdb; print(MySQLdb.version_info)\" " + CIBW_TEST_COMMAND: 'python -c "import MySQLdb; print(MySQLdb.version_info)" ' run: "python -m cibuildwheel --prerelease-pythons --output-dir dist" - name: Build sdist @@ -75,7 +91,7 @@ jobs: python -m build -s -o dist - name: Upload Wheel - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: win-wheels path: mysqlclient/dist/*.* diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 0b288620..75d7a389 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,9 +1,12 @@ version: 2 +sphinx: + configuration: doc/conf.py + build: os: ubuntu-22.04 tools: - python: "3.11" + python: "3.13" apt_packages: - default-libmysqlclient-dev diff --git a/HISTORY.rst b/HISTORY.rst index 99ff66cd..66470541 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,3 +1,66 @@ +====================== + What's new in 2.2.7 +====================== + +Release: 2025-01-10 + +* Add ``user``, ``host``, ``database``, and ``db`` attributes to ``Connection``. + opentelemetry-instrumentation-(dbapi|mysqlclient) use them. (#753) + +====================== + What's new in 2.2.6 +====================== + +Release: 2024-11-12 + +* MariaDB Connector/C 3.4 and MairaDB 11.4 enabled SSL and CA verification by default. + It affected 2.2.5 windows wheel. This release disables SSL and CA verification by default. (#731) + +* Add ``server_public_key_path`` option. It is needed to connect MySQL server with + ``sha256_password`` or ``caching_sha2_password`` authentication plugin without + secure connection. (#744) + +====================== + What's new in 2.2.5 +====================== + +Release: 2024-10-20 + +* (Windows wheel) Update MariaDB Connector/C to 3.4.1. #726 +* (Windows wheel) Build wheels for Python 3.13. #726 + +====================== + What's new in 2.2.4 +====================== + +Release: 2024-02-09 + +* Support ``ssl=True`` in ``connect()``. (#700) + This makes better compatibility with PyMySQL and mysqlclient==2.2.1 + with libmariadb. See #698 for detail. + + +====================== + What's new in 2.2.3 +====================== + +Release: 2024-02-04 + +* Fix ``Connection.kill()`` method that broken in 2.2.2. (#689) + + +====================== + What's new in 2.2.2 +====================== + +Release: 2024-02-04 + +* Support building with MySQL 8.3 (#688). +* Deprecate ``db.shutdown()`` and ``db.kill()`` methods in docstring. + This is because ``mysql_shutdown()`` and ``mysql_kill()`` were removed in MySQL 8.3. + They will emit DeprecationWarning in the future but not for now. + + ====================== What's new in 2.2.1 ====================== @@ -601,4 +664,3 @@ ursor.fetchXXXDict() methods raise DeprecationWarning cursor.begin() is making a brief reappearence. cursor.callproc() now works, with some limitations. - diff --git a/README.md b/README.md index 451ce799..e679b533 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,15 @@ This project adds Python 3 support and fixed many bugs. **Do Not use Github Issue Tracker to ask help. OSS Maintainer is not free tech support** -When your question looks relating to Python rather than MySQL: +When your question looks relating to Python rather than MySQL/MariaDB: * Python mailing list [python-list](https://mail.python.org/mailman/listinfo/python-list) * Slack [pythondev.slack.com](https://pyslackers.com/web/slack) -Or when you have question about MySQL: +Or when you have question about MySQL/MariaDB: -* [MySQL Community on Slack](https://lefred.be/mysql-community-on-slack/) +* [MySQL Support](https://dev.mysql.com/support/) +* [Getting Help With MariaDB](https://mariadb.com/kb/en/getting-help-with-mariadb/) ## Install diff --git a/ci/test_mysql.py b/ci/test_mysql.py index 9417fc9f..498be7cf 100644 --- a/ci/test_mysql.py +++ b/ci/test_mysql.py @@ -39,3 +39,5 @@ ] DEFAULT_AUTO_FIELD = "django.db.models.AutoField" + +USE_TZ = False diff --git a/doc/requirements.txt b/doc/requirements.txt index 01406623..48319f03 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,2 +1,2 @@ -sphinx~=7.2 -sphinx-rtd-theme~=2.0.0 +sphinx~=8.0 +sphinx-rtd-theme~=3.0.0 diff --git a/doc/user_guide.rst b/doc/user_guide.rst index 5c9577bc..391b162f 100644 --- a/doc/user_guide.rst +++ b/doc/user_guide.rst @@ -8,13 +8,13 @@ MySQLdb User's Guide Introduction ------------ -MySQLdb is an interface to the popular MySQL -database server that provides the Python database API. +MySQLdb is an interface to the popular MySQL or MariaDB +database servers that provides the Python database API. Installation ------------ -The ``README`` file has complete installation instructions. +The `README `_ file has complete installation instructions. MySQLdb._mysql @@ -393,6 +393,21 @@ connect(parameters...) an exception is raised. *This must be a keyword parameter.* + server_public_key_path + specifies path to a RSA public key used by caching sha2 password authentication. + See https://dev.mysql.com/doc/refman/9.0/en/caching-sha2-pluggable-authentication.html + + local_infile + sets ``MYSQL_OPT_LOCAL_INFILE`` in ``mysql_options()`` enabling LOAD LOCAL INFILE from any path; zero disables; + + *This must be a keyword parameter.* + + local_infile_dir + sets ``MYSQL_OPT_LOAD_DATA_LOCAL_DIR`` in ``mysql_options()`` enabling LOAD LOCAL INFILE from any path; + if ``local_infile`` is set to ``True`` then this is ignored; + + *This must be a keyword parameter.* + .. _mysql_ssl_set: http://dev.mysql.com/doc/refman/en/mysql-ssl-set.html diff --git a/pyproject.toml b/pyproject.toml index 0ad7ae58..d786f336 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,18 +1,17 @@ [project] name = "mysqlclient" -# version = "2.2.0dev0" description = "Python interface to MySQL" readme = "README.md" requires-python = ">=3.8" authors = [ {name = "Inada Naoki", email = "songofacandy@gmail.com"} ] -license = {text = "GNU General Public License v2 (GPLv2)"} +license = {text = "GNU General Public License v2 or later (GPLv2+)"} keywords = ["MySQL"] classifiers = [ "Development Status :: 5 - Production/Stable", "Environment :: Other Environment", - "License :: OSI Approved :: GNU General Public License (GPL)", + "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows :: Windows NT/2000", "Operating System :: OS Independent", @@ -27,6 +26,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Database", "Topic :: Database :: Database Engines/Servers", ] diff --git a/setup.py b/setup.py index f7f3d924..9a1d26b8 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ def find_package_name(): """Get available pkg-config package name""" # Ubuntu uses mariadb.pc, but CentOS uses libmariadb.pc - packages = ["mysqlclient", "mariadb", "libmariadb"] + packages = ["mysqlclient", "mariadb", "libmariadb", "perconaserverclient"] for pkg in packages: try: cmd = f"pkg-config --exists {pkg}" @@ -109,6 +109,7 @@ def get_config_win32(options): ] include_dirs = [ os.path.join(connector, "include", "mariadb"), + os.path.join(connector, "include", "mysql"), os.path.join(connector, "include"), ] diff --git a/src/MySQLdb/_mysql.c b/src/MySQLdb/_mysql.c index 0612be26..cd95b641 100644 --- a/src/MySQLdb/_mysql.c +++ b/src/MySQLdb/_mysql.c @@ -36,13 +36,22 @@ PERFORMANCE OF THIS SOFTWARE. #endif #if ((MYSQL_VERSION_ID >= 50555 && MYSQL_VERSION_ID <= 50599) || \ -(MYSQL_VERSION_ID >= 50636 && MYSQL_VERSION_ID <= 50699) || \ -(MYSQL_VERSION_ID >= 50711 && MYSQL_VERSION_ID <= 50799) || \ -(MYSQL_VERSION_ID >= 80000)) && \ -!defined(MARIADB_BASE_VERSION) && !defined(MARIADB_VERSION_ID) + (MYSQL_VERSION_ID >= 50636 && MYSQL_VERSION_ID <= 50699) || \ + (MYSQL_VERSION_ID >= 50711 && MYSQL_VERSION_ID <= 50799) || \ + (MYSQL_VERSION_ID >= 80000)) && \ + !defined(MARIADB_BASE_VERSION) && !defined(MARIADB_VERSION_ID) #define HAVE_ENUM_MYSQL_OPT_SSL_MODE #endif +#if defined(MARIADB_VERSION_ID) && MARIADB_VERSION_ID >= 100403 || \ + !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 50723 +#define HAVE_MYSQL_SERVER_PUBLIC_KEY +#endif + +#if !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 80021 +#define HAVE_MYSQL_OPT_LOCAL_INFILE_DIR +#endif + #define PY_SSIZE_T_CLEAN 1 #include "Python.h" @@ -391,10 +400,10 @@ enum { }; static int -_get_ssl_mode_num(char *ssl_mode) +_get_ssl_mode_num(const char *ssl_mode) { - static char *ssl_mode_list[] = { "DISABLED", "PREFERRED", - "REQUIRED", "VERIFY_CA", "VERIFY_IDENTITY" }; + static const char *ssl_mode_list[] = { + "DISABLED", "PREFERRED", "REQUIRED", "VERIFY_CA", "VERIFY_IDENTITY" }; unsigned int i; for (i=0; i < sizeof(ssl_mode_list)/sizeof(ssl_mode_list[0]); i++) { if (strcmp(ssl_mode, ssl_mode_list[i]) == 0) { @@ -414,7 +423,7 @@ _mysql_ConnectionObject_Initialize( MYSQL *conn = NULL; PyObject *conv = NULL; PyObject *ssl = NULL; - char *ssl_mode = NULL; + const char *ssl_mode = NULL; const char *key = NULL, *cert = NULL, *ca = NULL, *capath = NULL, *cipher = NULL; PyObject *ssl_keepref[5] = {NULL}; @@ -431,25 +440,27 @@ _mysql_ConnectionObject_Initialize( "client_flag", "ssl", "ssl_mode", "local_infile", "read_timeout", "write_timeout", "charset", - "auth_plugin", + "auth_plugin", "server_public_key_path", "local_infile_dir", NULL } ; int connect_timeout = 0; int read_timeout = 0; int write_timeout = 0; int compress = -1, named_pipe = -1, local_infile = -1; - int ssl_mode_num = SSLMODE_DISABLED; + int ssl_mode_num = SSLMODE_PREFERRED; char *init_command=NULL, *read_default_file=NULL, *read_default_group=NULL, *charset=NULL, - *auth_plugin=NULL; + *auth_plugin=NULL, + *server_public_key_path=NULL, + *local_infile_dir=NULL; self->converter = NULL; self->open = false; self->reconnect = false; if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "|ssssisOiiisssiOsiiiss:connect", + "|ssssisOiiisssiOsiiissss:connect", kwlist, &host, &user, &passwd, &db, &port, &unix_socket, &conv, @@ -462,27 +473,56 @@ _mysql_ConnectionObject_Initialize( &read_timeout, &write_timeout, &charset, - &auth_plugin + &auth_plugin, + &server_public_key_path, + &local_infile_dir )) return -1; +#ifndef HAVE_MYSQL_SERVER_PUBLIC_KEY + if (server_public_key_path) { + PyErr_SetString(_mysql_NotSupportedError, "server_public_key_path is not supported"); + return -1; + } +#endif + +#ifndef HAVE_MYSQL_OPT_LOCAL_INFILE_DIR + if (local_infile_dir) { + PyErr_SetString(_mysql_NotSupportedError, "local_infile_dir is not supported"); + return -1; + } +#endif + // For compatibility with PyPy, we need to keep strong reference + // to unicode objects until we use UTF8. #define _stringsuck(d,t,s) {t=PyMapping_GetItemString(s,#d);\ if(t){d=PyUnicode_AsUTF8(t);ssl_keepref[n_ssl_keepref++]=t;}\ PyErr_Clear();} + char ssl_mode_set = 0; if (ssl) { - PyObject *value = NULL; - _stringsuck(ca, value, ssl); - _stringsuck(capath, value, ssl); - _stringsuck(cert, value, ssl); - _stringsuck(key, value, ssl); - _stringsuck(cipher, value, ssl); + if (PyMapping_Check(ssl)) { + PyObject *value = NULL; + _stringsuck(ca, value, ssl); + _stringsuck(capath, value, ssl); + _stringsuck(cert, value, ssl); + _stringsuck(key, value, ssl); + _stringsuck(cipher, value, ssl); + } else if (PyObject_IsTrue(ssl)) { + // Support ssl=True from mysqlclient 2.2.4. + // for compatibility with PyMySQL and mysqlclient==2.2.1&libmariadb. + ssl_mode_num = SSLMODE_REQUIRED; + ssl_mode_set = 1; + } else { + ssl_mode_num = SSLMODE_DISABLED; + ssl_mode_set = 1; + } } if (ssl_mode) { if ((ssl_mode_num = _get_ssl_mode_num(ssl_mode)) <= 0) { PyErr_SetString(_mysql_NotSupportedError, "Unknown ssl_mode specification"); return -1; } + ssl_mode_set = 1; } conn = mysql_init(&(self->connection)); @@ -524,25 +564,41 @@ _mysql_ConnectionObject_Initialize( mysql_options(&(self->connection), MYSQL_OPT_LOCAL_INFILE, (char *) &local_infile); if (ssl) { - mysql_ssl_set(&(self->connection), key, cert, ca, capath, cipher); + mysql_options(&(self->connection), MYSQL_OPT_SSL_KEY, key); + mysql_options(&(self->connection), MYSQL_OPT_SSL_CERT, cert); + mysql_options(&(self->connection), MYSQL_OPT_SSL_CA, ca); + mysql_options(&(self->connection), MYSQL_OPT_SSL_CAPATH, capath); + mysql_options(&(self->connection), MYSQL_OPT_SSL_CIPHER, cipher); } - if (ssl_mode) { + for (int i=0 ; iconnection), MYSQL_OPT_SSL_MODE, &ssl_mode_num); + } #else - // MariaDB doesn't support MYSQL_OPT_SSL_MODE. - // See https://github.com/PyMySQL/mysqlclient/issues/474 - // TODO: Does MariaDB supports PREFERRED and VERIFY_CA? - // We support only two levels for now. - my_bool enforce_tls = 1; - if (ssl_mode_num >= SSLMODE_REQUIRED) { - mysql_optionsv(&(self->connection), MYSQL_OPT_SSL_ENFORCE, (void *)&enforce_tls); - } - if (ssl_mode_num >= SSLMODE_VERIFY_CA) { - mysql_optionsv(&(self->connection), MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (void *)&enforce_tls); - } -#endif + // MariaDB doesn't support MYSQL_OPT_SSL_MODE. + // See https://github.com/PyMySQL/mysqlclient/issues/474 + // And MariDB 11.4 changed the default value of MYSQL_OPT_SSL_ENFORCE and + // MYSQL_OPT_SSL_VERIFY_SERVER_CERT to 1. + // https://github.com/mariadb-corporation/mariadb-connector-c/commit/8dffd56936df3d03eeccf47904773860a0cdeb57 + // We emulate the ssl_mode and old behavior. + my_bool my_true = 1; + my_bool my_false = 0; + if (ssl_mode_num >= SSLMODE_REQUIRED) { + mysql_options(&(self->connection), MYSQL_OPT_SSL_ENFORCE, (void *)&my_true); + } else { + mysql_options(&(self->connection), MYSQL_OPT_SSL_ENFORCE, (void *)&my_false); } + if (ssl_mode_num >= SSLMODE_VERIFY_CA) { + mysql_options(&(self->connection), MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (void *)&my_true); + } else { + mysql_options(&(self->connection), MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (void *)&my_false); + } +#endif if (charset) { mysql_options(&(self->connection), MYSQL_SET_CHARSET_NAME, charset); @@ -550,20 +606,23 @@ _mysql_ConnectionObject_Initialize( if (auth_plugin) { mysql_options(&(self->connection), MYSQL_DEFAULT_AUTH, auth_plugin); } +#ifdef HAVE_MYSQL_SERVER_PUBLIC_KEY + if (server_public_key_path) { + mysql_options(&(self->connection), MYSQL_SERVER_PUBLIC_KEY, server_public_key_path); + } +#endif + +#ifdef HAVE_MYSQL_OPT_LOCAL_INFILE_DIR + if (local_infile_dir) { + mysql_options(&(self->connection), MYSQL_OPT_LOAD_DATA_LOCAL_DIR, local_infile_dir); + } +#endif Py_BEGIN_ALLOW_THREADS conn = mysql_real_connect(&(self->connection), host, user, passwd, db, port, unix_socket, client_flag); Py_END_ALLOW_THREADS - if (ssl) { - int i; - for (i=0; iconnection), pid); + r = mysql_query(&(self->connection), query); Py_END_ALLOW_THREADS if (r) return _mysql_Exception(self); Py_RETURN_NONE; @@ -1997,7 +2058,7 @@ _mysql_ConnectionObject_select_db( static char _mysql_ConnectionObject_shutdown__doc__[] = "Asks the database server to shut down. The connected user must\n\ -have shutdown privileges. Non-standard.\n\ +have shutdown privileges. Non-standard. Deprecated.\n\ "; static PyObject * @@ -2008,7 +2069,7 @@ _mysql_ConnectionObject_shutdown( int r; check_connection(self); Py_BEGIN_ALLOW_THREADS - r = mysql_shutdown(&(self->connection), SHUTDOWN_DEFAULT); + r = mysql_query(&(self->connection), "SHUTDOWN"); Py_END_ALLOW_THREADS if (r) return _mysql_Exception(self); Py_RETURN_NONE; diff --git a/src/MySQLdb/connections.py b/src/MySQLdb/connections.py index 7456aeac..a61aaaed 100644 --- a/src/MySQLdb/connections.py +++ b/src/MySQLdb/connections.py @@ -134,9 +134,21 @@ class object, used to create cursors (keyword only) see the MySQL documentation for more details (mysql_ssl_set()). If this is set, and the client does not support SSL, NotSupportedError will be raised. + Since mysqlclient 2.2.4, ssl=True is alias of ssl_mode=REQUIRED + for better compatibility with PyMySQL and MariaDB. + + :param str server_public_key_path: + specify the path to a file RSA public key file for caching_sha2_password. + See https://dev.mysql.com/doc/refman/9.0/en/caching-sha2-pluggable-authentication.html :param bool local_infile: - enables LOAD LOCAL INFILE; zero disables + sets ``MYSQL_OPT_LOCAL_INFILE`` in ``mysql_options()`` enabling LOAD LOCAL INFILE from any path; zero disables; + + :param str local_infile_dir: + sets ``MYSQL_OPT_LOAD_DATA_LOCAL_DIR`` in ``mysql_options()`` enabling LOAD LOCAL INFILE from any path; + if ``local_infile`` is set to ``True`` then this is ignored; + + supported for mysql version >= 8.0.21 :param bool autocommit: If False (default), autocommit is disabled. @@ -190,16 +202,18 @@ class object, used to create cursors (keyword only) # PEP-249 requires autocommit to be initially off autocommit = kwargs2.pop("autocommit", False) + self._set_attributes(*args, **kwargs2) super().__init__(*args, **kwargs2) + self.cursorclass = cursorclass self.encoders = { - k: v for k, v in conv.items() if type(k) is not int # noqa: E721 + k: v + for k, v in conv.items() + if type(k) is not int # noqa: E721 } - self._server_version = tuple( [numeric_part(n) for n in self.get_server_info().split(".")[:2]] ) - self.encoding = "ascii" # overridden in set_character_set() if not charset: @@ -230,6 +244,21 @@ class object, used to create cursors (keyword only) self.autocommit(autocommit) self.messages = [] + def _set_attributes(self, host=None, user=None, password=None, database="", port=3306, + unix_socket=None, **kwargs): + """set some attributes for otel""" + if unix_socket and not host: + host = "localhost" + # support opentelemetry-instrumentation-dbapi + self.host = host + # _mysql.Connection provides self.port + self.user = user + self.database = database + # otel-inst-mysqlclient uses db instead of database. + self.db = database + # NOTE: We have not supported semantic conventions yet. + # https://opentelemetry.io/docs/specs/semconv/database/sql/ + def __enter__(self): return self diff --git a/src/MySQLdb/release.py b/src/MySQLdb/release.py index c5281a5a..234d9958 100644 --- a/src/MySQLdb/release.py +++ b/src/MySQLdb/release.py @@ -1,3 +1,3 @@ __author__ = "Inada Naoki " -__version__ = "2.2.1" -version_info = (2, 2, 1, "final", 0) +__version__ = "2.2.7" +version_info = (2, 2, 7, "final", 0)