From a7bc1aea03508f544c9dfac0f34b01996653cef4 Mon Sep 17 00:00:00 2001
From: bakabiko <ahmedabt@gmail.com>
Date: Sat, 19 May 2018 01:37:36 +0200
Subject: [PATCH] Fixed #29380 -- Added support for
 QuerySet.select_for_update()'s nowait and skip_locked options on MySQL 8+.

---
 AUTHORS                               |  1 +
 django/db/backends/mysql/features.py  |  7 ++++++-
 tests/backends/mysql/test_features.py | 13 +++++++++++++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/AUTHORS b/AUTHORS
index 3224be14a5..43729adca1 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -21,6 +21,7 @@ answer newbie questions, and generally made Django that much better:
     AgarFu <heaven@croasanaso.sytes.net>
     Ahmad Alhashemi <trans@ahmadh.com>
     Ahmad Al-Ibrahim
+    Ahmed Eltawela <https://github.com/ahmedabt>
     ajs <adi@sieker.info>
     Akis Kesoglou <akiskesoglou@gmail.com>
     Aksel Ethem <aksel.ethem@gmail.com>
diff --git a/django/db/backends/mysql/features.py b/django/db/backends/mysql/features.py
index 57f4c8ee76..56370bfcd9 100644
--- a/django/db/backends/mysql/features.py
+++ b/django/db/backends/mysql/features.py
@@ -10,7 +10,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     # MySQL doesn't support sliced subqueries with IN/ALL/ANY/SOME.
     allow_sliced_subqueries_with_in = False
     has_select_for_update = True
-    has_select_for_update_nowait = False
     supports_forward_references = False
     supports_regex_backreferencing = False
     supports_date_lookup_using_string = False
@@ -83,6 +82,12 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     def supports_over_clause(self):
         return self.connection.mysql_version >= (8, 0, 2)
 
+    @cached_property
+    def has_select_for_update_skip_locked(self):
+        return self.connection.mysql_version >= (8, 0, 1)
+
+    has_select_for_update_nowait = has_select_for_update_skip_locked
+
     @cached_property
     def needs_explain_extended(self):
         # EXTENDED is deprecated (and not required) in 5.7 and removed in 8.0.
diff --git a/tests/backends/mysql/test_features.py b/tests/backends/mysql/test_features.py
index 65c897823b..51282792b3 100644
--- a/tests/backends/mysql/test_features.py
+++ b/tests/backends/mysql/test_features.py
@@ -1,6 +1,7 @@
 from unittest import mock, skipUnless
 
 from django.db import connection
+from django.db.backends.mysql.features import DatabaseFeatures
 from django.test import TestCase
 
 
@@ -17,3 +18,15 @@ class TestFeatures(TestCase):
         with mock.patch('django.db.connection.features._mysql_storage_engine', 'MyISAM'):
             self.assertFalse(connection.features.supports_transactions)
         del connection.features.supports_transactions
+
+    def test_skip_locked_no_wait(self):
+        with mock.MagicMock() as _connection:
+            _connection.mysql_version = (8, 0, 1)
+            database_features = DatabaseFeatures(_connection)
+            self.assertTrue(database_features.has_select_for_update_skip_locked)
+            self.assertTrue(database_features.has_select_for_update_nowait)
+        with mock.MagicMock() as _connection:
+            _connection.mysql_version = (8, 0, 0)
+            database_features = DatabaseFeatures(_connection)
+            self.assertFalse(database_features.has_select_for_update_skip_locked)
+            self.assertFalse(database_features.has_select_for_update_nowait)