diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index 9e5d3cddc6..2f62cb5ddb 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -35,7 +35,7 @@ jobs: restore-keys: | ${{ runner.os }}-pip- - name: Install Dependencies - run: pip3 install -e ".[dev]" mysqlclient psycopg2-binary + run: pip3 install -e ".[dev]" psycopg2-binary - name: Run isort run: isort -c . working-directory: ./src @@ -55,7 +55,7 @@ jobs: restore-keys: | ${{ runner.os }}-pip- - name: Install Dependencies - run: pip3 install -e ".[dev]" mysqlclient psycopg2-binary + run: pip3 install -e ".[dev]" psycopg2-binary - name: Run flake8 run: flake8 . working-directory: ./src diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1538c3c8cb..3cbd920a81 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -25,24 +25,14 @@ jobs: strategy: matrix: python-version: ["3.9", "3.10", "3.11"] - database: [sqlite, postgres, mysql] + database: [sqlite, postgres] exclude: - - database: mysql - python-version: "3.9" - - database: mysql - python-version: "3.11" - database: sqlite python-version: "3.9" - database: sqlite python-version: "3.10" steps: - uses: actions/checkout@v2 - - uses: getong/mariadb-action@v1.1 - with: - mariadb version: '10.10' - mysql database: 'pretix' - mysql root password: '' - if: matrix.database == 'mysql' - uses: harmon758/postgresql-action@v1 with: postgresql version: '11' @@ -61,9 +51,9 @@ jobs: restore-keys: | ${{ runner.os }}-pip- - name: Install system dependencies - run: sudo apt update && sudo apt install gettext mariadb-client + run: sudo apt update && sudo apt install gettext - name: Install Python dependencies - run: pip3 install --ignore-requires-python -e ".[dev]" mysqlclient psycopg2-binary # We ignore that flake8 needs newer python as we don't run flake8 during tests + run: pip3 install --ignore-requires-python -e ".[dev]" psycopg2-binary # We ignore that flake8 needs newer python as we don't run flake8 during tests - name: Run checks run: python manage.py check working-directory: ./src diff --git a/Dockerfile b/Dockerfile index 48454ddcff..d149c384df 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,6 @@ FROM python:3.11-bullseye RUN apt-get update && \ apt-get install -y --no-install-recommends \ build-essential \ - libmariadb-dev \ gettext \ git \ libffi-dev \ @@ -58,7 +57,7 @@ RUN pip3 install -U \ wheel && \ cd /pretix && \ PRETIX_DOCKER_BUILD=TRUE pip3 install \ - -e ".[memcached,mysql]" \ + -e ".[memcached]" \ gunicorn django-extensions ipython && \ rm -rf ~/.cache/pip diff --git a/doc/admin/config.rst b/doc/admin/config.rst index b7a635adf9..d5978a327d 100644 --- a/doc/admin/config.rst +++ b/doc/admin/config.rst @@ -154,23 +154,15 @@ Example:: port=3306 ``backend`` - One of ``mysql`` (deprecated), ``sqlite3`` and ``postgresql``. + One of ``sqlite3`` and ``postgresql``. Default: ``sqlite3``. - If you use MySQL, be sure to create your database using - ``CREATE DATABASE CHARACTER SET utf8;``. Otherwise, Unicode - support will not properly work. - ``name`` The database's name. Default: ``db.sqlite3``. ``user``, ``password``, ``host``, ``port`` Connection details for the database connection. Empty by default. -``galera`` - (Deprecated) Indicates if the database backend is a MySQL/MariaDB Galera cluster and - turns on some optimizations/special case handlers. Default: ``False`` - .. _`config-replica`: Database replica settings diff --git a/doc/admin/installation/general.rst b/doc/admin/installation/general.rst index 940315963b..8985f543a6 100644 --- a/doc/admin/installation/general.rst +++ b/doc/admin/installation/general.rst @@ -16,14 +16,11 @@ To use pretix, you will need the following things: * A periodic task runner, e.g. ``cron`` * **A database**. This needs to be a SQL-based that is supported by Django. We highly recommend to either - go for **PostgreSQL** or **MySQL/MariaDB**. If you do not provide one, pretix will run on SQLite, which is useful + go for **PostgreSQL**. If you do not provide one, pretix will run on SQLite, which is useful for evaluation and development purposes. .. warning:: Do not ever use SQLite in production. It will break. - .. warning:: We recommend **PostgreSQL**. If you go for MySQL, make sure you run **MySQL 5.7 or newer** or - **MariaDB 10.2.7 or newer**. - * A **reverse proxy**. pretix needs to deliver some static content to your users (e.g. CSS, images, ...). While pretix is capable of doing this, having this handled by a proper web server like **nginx** or **Apache** will be much faster. Also, you need a proxying web server in front to provide SSL encryption. diff --git a/doc/admin/mysql2postgres.rst b/doc/admin/mysql2postgres.rst index 0c03150f18..1437cf6422 100644 --- a/doc/admin/mysql2postgres.rst +++ b/doc/admin/mysql2postgres.rst @@ -3,11 +3,11 @@ Migrating from MySQL/MariaDB to PostgreSQL ========================================== -Our recommended database for all production installations is PostgreSQL. Support for MySQL/MariaDB will be removed in -pretix 5.0. +Our recommended database for all production installations is PostgreSQL. Support for MySQL/MariaDB has been removed +in newer pretix releases. In order to follow this guide, your pretix installation needs to be a version that fully supports MySQL/MariaDB. If you -already upgraded to pretix 5.0, downgrade back to the last 4.x release using ``pip``. +already upgraded to pretix 5.0 or later, downgrade back to the last 4.x release using ``pip``. .. note:: We have tested this guide carefully, but we can't assume any liability for its correctness. The data loss risk should be low as long as pretix is not running while you do the migration. If you are a pretix Enterprise diff --git a/pyproject.toml b/pyproject.toml index 2d22e2160f..506ea9a997 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,6 @@ dependencies = [ "django-libsass==0.9", "django-localflavor==4.0", "django-markup", - "django-mysql", "django-oauth-toolkit==2.2.*", "django-otp==1.2.*", "django-phonenumber-field==7.1.*", @@ -109,7 +108,6 @@ dependencies = [ [project.optional-dependencies] memcached = ["pylibmc"] -mysql = ["mysqlclient"] dev = [ "coverage", "coveralls", diff --git a/src/pretix/base/management/commands/_migrations.py b/src/pretix/base/management/commands/_migrations.py index b5f1ee6535..521525be1f 100644 --- a/src/pretix/base/management/commands/_migrations.py +++ b/src/pretix/base/management/commands/_migrations.py @@ -24,7 +24,7 @@ Django, for theoretically very valid reasons, creates migrations for *every sing we change on a model. Even the `help_text`! This makes sense, as we don't know if any database backend unknown to us might actually use this information for its database schema. -However, pretix only supports PostgreSQL, MySQL, MariaDB and SQLite and we can be pretty +However, pretix only supports PostgreSQL and SQLite and we can be pretty certain that some changes to models will never require a change to the database. In this case, not creating a migration for certain changes will save us some performance while applying them *and* allow for a cleaner git history. Win-win! diff --git a/src/pretix/base/migrations/0102_auto_20181017_0024.py b/src/pretix/base/migrations/0102_auto_20181017_0024.py index 8c5744a04c..576c0bc939 100644 --- a/src/pretix/base/migrations/0102_auto_20181017_0024.py +++ b/src/pretix/base/migrations/0102_auto_20181017_0024.py @@ -3,7 +3,6 @@ from django.core.exceptions import ImproperlyConfigured from django.db import migrations, models -from django_mysql.checks import mysql_connections def set_attendee_name_parts(apps, schema_editor): @@ -24,40 +23,12 @@ def set_attendee_name_parts(apps, schema_editor): ia.save(update_fields=['name_parts']) -def check_mysqlversion(apps, schema_editor): - errors = [] - any_conn_works = False - conns = list(mysql_connections()) - found = 'Unknown version' - for alias, conn in conns: - if hasattr(conn, 'mysql_is_mariadb') and conn.mysql_is_mariadb and hasattr(conn, 'mysql_version'): - if conn.mysql_version >= (10, 2, 7): - any_conn_works = True - else: - found = 'MariaDB ' + '.'.join(str(v) for v in conn.mysql_version) - elif hasattr(conn, 'mysql_version'): - if conn.mysql_version >= (5, 7): - any_conn_works = True - else: - found = 'MySQL ' + '.'.join(str(v) for v in conn.mysql_version) - - if conns and not any_conn_works: - raise ImproperlyConfigured( - 'As of pretix 2.2, you need MySQL 5.7+ or MariaDB 10.2.7+ to run pretix. However, we detected a ' - 'database connection to {}'.format(found) - ) - return errors - - class Migration(migrations.Migration): dependencies = [ ('pretixbase', '0101_auto_20181025_2255'), ] operations = [ - migrations.RunPython( - check_mysqlversion, migrations.RunPython.noop - ), migrations.RenameField( model_name='cartposition', old_name='attendee_name', diff --git a/src/pretix/base/migrations/0230_auto_20230208_0939.py b/src/pretix/base/migrations/0230_auto_20230208_0939.py index e27e0c15b1..3ae1a81591 100644 --- a/src/pretix/base/migrations/0230_auto_20230208_0939.py +++ b/src/pretix/base/migrations/0230_auto_20230208_0939.py @@ -50,6 +50,6 @@ class Migration(migrations.Migration): ], options={ 'unique_together': {('event', 'secret')}, - } if 'mysql' not in settings.DATABASES['default']['ENGINE'] else {} + } ), ] diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py index 5bb2aaa751..bfcfe14616 100644 --- a/src/pretix/base/models/orders.py +++ b/src/pretix/base/models/orders.py @@ -3116,11 +3116,7 @@ class BlockedTicketSecret(models.Model): updated = models.DateTimeField(auto_now=True) class Meta: - if 'mysql' not in settings.DATABASES['default']['ENGINE']: - # MySQL does not support indexes on TextField(). Django knows this and just ignores db_index, but it will - # not silently ignore the UNIQUE index, causing this table to fail. I'm so glad we're deprecating MySQL - # in a few months, so we'll just live without an unique index until then. - unique_together = (('event', 'secret'),) + unique_together = (('event', 'secret'),) @receiver(post_delete, sender=CachedTicket) diff --git a/src/pretix/control/templates/pretixcontrol/base.html b/src/pretix/control/templates/pretixcontrol/base.html index e5a2aed189..ba5428764e 100644 --- a/src/pretix/control/templates/pretixcontrol/base.html +++ b/src/pretix/control/templates/pretixcontrol/base.html @@ -423,17 +423,6 @@ {% endif %} - {% if "mysql" in settings.DATABASES.default.ENGINE and not request.organizer %} -
- {% blocktrans trimmed %} - You are using MySQL or MariaDB as your database backend for pretix. - Starting in pretix 5.0, these will no longer be supported and you will need to migrate to PostgreSQL. - Please see the pretix administrator documentation for a migration guide, and the pretix 4.16 - release notes for more information. - {% endblocktrans %} -
- {% endif %} - {% if debug_warning %}
{% trans "pretix is running in debug mode. For security reasons, please never run debug mode on a production instance." %} diff --git a/src/pretix/control/views/search.py b/src/pretix/control/views/search.py index 0199249a64..5feb2aa2c3 100644 --- a/src/pretix/control/views/search.py +++ b/src/pretix/control/views/search.py @@ -93,7 +93,7 @@ class OrderSearch(PaginationMixin, ListView): if self.filter_form.use_query_hack(): """ - We need to work around a bug in PostgreSQL's (and likely MySQL's) query plan optimizer here. + We need to work around a bug in PostgreSQL's query plan optimizer here. The database lacks statistical data to predict how common our search filter is and therefore assumes that it is cheaper to first ORDER *all* orders in the system (since we got an index on datetime), then filter out with a full scan until OFFSET/LIMIT condition is fulfilled. If we @@ -167,7 +167,7 @@ class PaymentSearch(PaginationMixin, ListView): if self.filter_form.cleaned_data.get('query'): """ - We need to work around a bug in PostgreSQL's (and likely MySQL's) query plan optimizer here. + We need to work around a bug in PostgreSQL's query plan optimizer here. The database lacks statistical data to predict how common our search filter is and therefore assumes that it is cheaper to first ORDER *all* orders in the system (since we got an index on datetime), then filter out with a full scan until OFFSET/LIMIT condition is fulfilled. If we diff --git a/src/pretix/helpers/templatetags/jsonfield.py b/src/pretix/helpers/templatetags/jsonfield.py index dc7d3dc8d7..2c4362aa49 100644 --- a/src/pretix/helpers/templatetags/jsonfield.py +++ b/src/pretix/helpers/templatetags/jsonfield.py @@ -29,7 +29,7 @@ def postgres_compile_json_path(key_transforms): return "{" + ','.join(key_transforms) + "}" -def mysql_compile_json_path(key_transforms): +def sqlite_compile_json_path(key_transforms): path = ['$'] for key_transform in key_transforms: try: @@ -41,9 +41,6 @@ def mysql_compile_json_path(key_transforms): return ''.join(path) -sqlite_compile_json_path = mysql_compile_json_path - - class JSONExtract(Expression): def __init__(self, expression, *path, output_field=JSONField(), **extra): super().__init__(output_field=output_field) @@ -66,14 +63,6 @@ class JSONExtract(Expression): params.append(json_path) template = '{} #> %s'.format(arg_sql) return template, params - elif '.mysql' in connection.settings_dict['ENGINE']: - params = [] - arg_sql, arg_params = compiler.compile(self.source_expression) - params.extend(arg_params) - json_path = mysql_compile_json_path(self.path) - params.append(json_path) - template = 'JSON_EXTRACT({}, %s)'.format(arg_sql) - return template, params elif '.sqlite' in connection.settings_dict['ENGINE']: params = [] arg_sql, arg_params = compiler.compile(self.source_expression) @@ -84,7 +73,7 @@ class JSONExtract(Expression): return template, params else: raise NotSupportedError( - 'Functions on JSONFields are only supported on SQLite, PostgreSQL, and MySQL at the moment.' + 'Functions on JSONFields are only supported on SQLite and PostgreSQL at the moment.' ) def copy(self): diff --git a/src/pretix/settings.py b/src/pretix/settings.py index 7a73b4e797..ea382712ad 100644 --- a/src/pretix/settings.py +++ b/src/pretix/settings.py @@ -110,16 +110,11 @@ PRETIX_AUTH_BACKENDS = config.get('pretix', 'auth_backends', fallback='pretix.ba db_backend = config.get('database', 'backend', fallback='sqlite3') if db_backend == 'postgresql_psycopg2': db_backend = 'postgresql' -DATABASE_IS_GALERA = config.getboolean('database', 'galera', fallback=False) -if DATABASE_IS_GALERA and 'mysql' in db_backend: - db_options = { - 'init_command': 'SET SESSION wsrep_sync_wait = 1;' - } -else: - db_options = {} +elif 'mysql' in db_backend: + print("pretix does no longer support running on MySQL/MariaDB") + sys.exit(1) -if 'mysql' in db_backend: - db_options['charset'] = 'utf8mb4' +db_options = {} DATABASES = { 'default': { @@ -132,10 +127,7 @@ DATABASES = { 'CONN_MAX_AGE': 0 if db_backend == 'sqlite3' else 120, 'CONN_HEALTH_CHECKS': db_backend != 'sqlite3', # Will only be used from Django 4.1 onwards 'OPTIONS': db_options, - 'TEST': { - 'CHARSET': 'utf8mb4', - 'COLLATION': 'utf8mb4_unicode_ci', - } if 'mysql' in db_backend else {} + 'TEST': {} } } DATABASE_REPLICA = 'default' @@ -150,10 +142,7 @@ if config.has_section('replica'): 'PORT': config.get('replica', 'port', fallback=DATABASES['default']['PORT']), 'CONN_MAX_AGE': 0 if db_backend == 'sqlite3' else 120, 'OPTIONS': db_options, - 'TEST': { - 'CHARSET': 'utf8mb4', - 'COLLATION': 'utf8mb4_unicode_ci', - } if 'mysql' in db_backend else {} + 'TEST': {} } DATABASE_ROUTERS = ['pretix.helpers.database.ReplicaRouter'] diff --git a/src/tests/api/test_items.py b/src/tests/api/test_items.py index 89d9bea6c5..8944c931f2 100644 --- a/src/tests/api/test_items.py +++ b/src/tests/api/test_items.py @@ -835,7 +835,7 @@ def test_item_create_with_addon(token_client, organizer, event, item, category, assert resp.status_code == 400 assert resp.content.decode() in [ '{"addons":["The minimum count needs to be equal to or greater than zero."]}', - '{"addons":[{"min_count":["Ensure this value is greater than or equal to 0."]}]}', # mysql + '{"addons":[{"min_count":["Ensure this value is greater than or equal to 0."]}]}', ] with scopes_disabled(): assert 2 == Item.objects.all().count() diff --git a/src/tests/travis_mysql.cfg b/src/tests/travis_mysql.cfg deleted file mode 100644 index 48dc3133ec..0000000000 --- a/src/tests/travis_mysql.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[database] -backend=mysql -name=pretix -user=root -password= -host=127.0.0.1 -port=3306