mirror of
https://github.com/django/django.git
synced 2025-09-04 19:35:05 +03:00
Compare commits
4 Commits
666a37dc5a
...
a834e61820
Author | SHA1 | Date | |
---|---|---|---|
|
a834e61820 | ||
|
6c37a2fbb2 | ||
|
21603c5b50 | ||
|
2709ee9cf1 |
|
@ -269,20 +269,12 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
|
|
||||||
conn_params.pop("assume_role", None)
|
conn_params.pop("assume_role", None)
|
||||||
conn_params.pop("isolation_level", None)
|
conn_params.pop("isolation_level", None)
|
||||||
|
conn_params.pop("server_side_binding", None)
|
||||||
|
|
||||||
pool_options = conn_params.pop("pool", None)
|
pool_options = conn_params.pop("pool", None)
|
||||||
if pool_options and not is_psycopg3:
|
if pool_options and not is_psycopg3:
|
||||||
raise ImproperlyConfigured("Database pooling requires psycopg >= 3")
|
raise ImproperlyConfigured("Database pooling requires psycopg >= 3")
|
||||||
|
|
||||||
server_side_binding = conn_params.pop("server_side_binding", None)
|
|
||||||
conn_params.setdefault(
|
|
||||||
"cursor_factory",
|
|
||||||
(
|
|
||||||
ServerBindingCursor
|
|
||||||
if is_psycopg3 and server_side_binding is True
|
|
||||||
else Cursor
|
|
||||||
),
|
|
||||||
)
|
|
||||||
if settings_dict["USER"]:
|
if settings_dict["USER"]:
|
||||||
conn_params["user"] = settings_dict["USER"]
|
conn_params["user"] = settings_dict["USER"]
|
||||||
if settings_dict["PASSWORD"]:
|
if settings_dict["PASSWORD"]:
|
||||||
|
@ -297,9 +289,8 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
)
|
)
|
||||||
# Disable prepared statements by default to keep connection poolers
|
# Disable prepared statements by default to keep connection poolers
|
||||||
# working. Can be reenabled via OPTIONS in the settings dict.
|
# working. Can be reenabled via OPTIONS in the settings dict.
|
||||||
conn_params["prepare_threshold"] = conn_params.pop(
|
if "prepare_threshold" not in conn_params:
|
||||||
"prepare_threshold", None
|
conn_params["prepare_threshold"] = None
|
||||||
)
|
|
||||||
return conn_params
|
return conn_params
|
||||||
|
|
||||||
@async_unsafe
|
@async_unsafe
|
||||||
|
@ -406,28 +397,20 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
|
|
||||||
@async_unsafe
|
@async_unsafe
|
||||||
def create_cursor(self, name=None):
|
def create_cursor(self, name=None):
|
||||||
|
ssb = self.settings_dict["OPTIONS"].get("server_side_binding")
|
||||||
|
cursor_factory = self.settings_dict["OPTIONS"].get("cursor_factory")
|
||||||
|
|
||||||
if name:
|
if name:
|
||||||
if is_psycopg3 and (
|
# In autocommit mode, the cursor will be used outside of a
|
||||||
self.settings_dict["OPTIONS"].get("server_side_binding") is not True
|
# transaction, hence use a holdable cursor.
|
||||||
):
|
cursor = _server_cursor_factory(ssb, cursor_factory)(
|
||||||
# psycopg >= 3 forces the usage of server-side bindings for
|
self.connection,
|
||||||
# named cursors so a specialized class that implements
|
name=name,
|
||||||
# server-side cursors while performing client-side bindings
|
scrollable=False,
|
||||||
# must be used if `server_side_binding` is disabled (default).
|
withhold=self.connection.autocommit,
|
||||||
cursor = ServerSideCursor(
|
)
|
||||||
self.connection,
|
|
||||||
name=name,
|
|
||||||
scrollable=False,
|
|
||||||
withhold=self.connection.autocommit,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# In autocommit mode, the cursor will be used outside of a
|
|
||||||
# transaction, hence use a holdable cursor.
|
|
||||||
cursor = self.connection.cursor(
|
|
||||||
name, scrollable=False, withhold=self.connection.autocommit
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
cursor = self.connection.cursor()
|
cursor = _cursor_factory(ssb, cursor_factory)(self.connection)
|
||||||
|
|
||||||
if is_psycopg3:
|
if is_psycopg3:
|
||||||
# Register the cursor timezone only if the connection disagrees, to
|
# Register the cursor timezone only if the connection disagrees, to
|
||||||
|
@ -572,15 +555,32 @@ if is_psycopg3:
|
||||||
return args
|
return args
|
||||||
|
|
||||||
class ServerBindingCursor(CursorMixin, Database.Cursor):
|
class ServerBindingCursor(CursorMixin, Database.Cursor):
|
||||||
pass
|
"""
|
||||||
|
Cursor that performs server-side parameter binding.
|
||||||
|
|
||||||
|
This is the default in psycopg3.
|
||||||
|
"""
|
||||||
|
|
||||||
class Cursor(CursorMixin, Database.ClientCursor):
|
class Cursor(CursorMixin, Database.ClientCursor):
|
||||||
pass
|
|
||||||
|
|
||||||
class ServerSideCursor(
|
|
||||||
CursorMixin, Database.client_cursor.ClientCursorMixin, Database.ServerCursor
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
|
Cursor that performs client-side parameter binding.
|
||||||
|
|
||||||
|
This is the default in Django.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class ServerCursor(CursorMixin, Database.ServerCursor):
|
||||||
|
"""
|
||||||
|
Cursor that performs server-side parameter binding and uses
|
||||||
|
server side cursors.
|
||||||
|
|
||||||
|
This is the default for named cursors in psycopg3.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class ServerSideCursor(Database.client_cursor.ClientCursorMixin, ServerCursor):
|
||||||
|
"""
|
||||||
|
Cursor that performs client-side parameter binding and uses
|
||||||
|
server side cursors.
|
||||||
|
|
||||||
psycopg >= 3 forces the usage of server-side bindings when using named
|
psycopg >= 3 forces the usage of server-side bindings when using named
|
||||||
cursors but the ORM doesn't yet support the systematic generation of
|
cursors but the ORM doesn't yet support the systematic generation of
|
||||||
prepareable SQL (#20516).
|
prepareable SQL (#20516).
|
||||||
|
@ -592,8 +592,18 @@ if is_psycopg3:
|
||||||
Mixing ClientCursorMixin in wouldn't be necessary if Cursor allowed to
|
Mixing ClientCursorMixin in wouldn't be necessary if Cursor allowed to
|
||||||
specify how parameters should be bound instead, which ServerCursor
|
specify how parameters should be bound instead, which ServerCursor
|
||||||
would inherit, but that's not the case.
|
would inherit, but that's not the case.
|
||||||
|
|
||||||
|
This is the default for named cursors in Django.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def _cursor_factory(server_side_binding, cursor_factory):
|
||||||
|
if cursor_factory:
|
||||||
|
return cursor_factory
|
||||||
|
return ServerBindingCursor if server_side_binding else Cursor
|
||||||
|
|
||||||
|
def _server_cursor_factory(server_side_binding, cursor_factory):
|
||||||
|
return ServerCursor if server_side_binding else ServerSideCursor
|
||||||
|
|
||||||
class CursorDebugWrapper(BaseCursorDebugWrapper):
|
class CursorDebugWrapper(BaseCursorDebugWrapper):
|
||||||
def copy(self, statement):
|
def copy(self, statement):
|
||||||
with self.debug_sql(statement):
|
with self.debug_sql(statement):
|
||||||
|
@ -602,6 +612,11 @@ if is_psycopg3:
|
||||||
else:
|
else:
|
||||||
Cursor = psycopg2.extensions.cursor
|
Cursor = psycopg2.extensions.cursor
|
||||||
|
|
||||||
|
def _cursor_factory(server_side_binding, cursor_factory):
|
||||||
|
return cursor_factory or Cursor
|
||||||
|
|
||||||
|
_server_cursor_factory = _cursor_factory
|
||||||
|
|
||||||
class CursorDebugWrapper(BaseCursorDebugWrapper):
|
class CursorDebugWrapper(BaseCursorDebugWrapper):
|
||||||
def copy_expert(self, sql, file, *args):
|
def copy_expert(self, sql, file, *args):
|
||||||
with self.debug_sql(sql):
|
with self.debug_sql(sql):
|
||||||
|
|
|
@ -1220,7 +1220,6 @@ values. It will return the first column or value that isn't ``NULL``.
|
||||||
We'll start by defining the template to be used for SQL generation and
|
We'll start by defining the template to be used for SQL generation and
|
||||||
an ``__init__()`` method to set some attributes::
|
an ``__init__()`` method to set some attributes::
|
||||||
|
|
||||||
import copy
|
|
||||||
from django.db.models import Expression
|
from django.db.models import Expression
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -583,9 +583,6 @@ Miscellaneous
|
||||||
* The undocumented ``django.core.mail.forbid_multi_line_headers()`` and
|
* The undocumented ``django.core.mail.forbid_multi_line_headers()`` and
|
||||||
``django.core.mail.message.sanitize_address()`` functions are deprecated.
|
``django.core.mail.message.sanitize_address()`` functions are deprecated.
|
||||||
|
|
||||||
* The ``django.utils.crypto.constant_time_compare()`` function is deprecated
|
|
||||||
because it is merely an alias of :func:`hmac.compare_digest`.
|
|
||||||
|
|
||||||
Features removed in 6.0
|
Features removed in 6.0
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user