summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/dialects
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/dialects')
-rw-r--r--lib/sqlalchemy/dialects/mssql/base.py96
-rw-r--r--lib/sqlalchemy/dialects/mysql/base.py3
-rw-r--r--lib/sqlalchemy/dialects/oracle/base.py27
-rw-r--r--lib/sqlalchemy/dialects/oracle/cx_oracle.py3
-rw-r--r--lib/sqlalchemy/dialects/postgresql/_psycopg_common.py19
-rw-r--r--lib/sqlalchemy/dialects/postgresql/asyncpg.py34
-rw-r--r--lib/sqlalchemy/dialects/postgresql/base.py115
-rw-r--r--lib/sqlalchemy/dialects/postgresql/pg8000.py27
-rw-r--r--lib/sqlalchemy/dialects/postgresql/psycopg.py7
-rw-r--r--lib/sqlalchemy/dialects/postgresql/psycopg2.py2
10 files changed, 140 insertions, 193 deletions
diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py
index b4c620f91..4295e0ed0 100644
--- a/lib/sqlalchemy/dialects/mssql/base.py
+++ b/lib/sqlalchemy/dialects/mssql/base.py
@@ -813,7 +813,9 @@ import codecs
import datetime
import operator
import re
+from typing import overload
from typing import TYPE_CHECKING
+from uuid import UUID as _python_UUID
from . import information_schema as ischema
from .json import JSON
@@ -854,6 +856,7 @@ from ...types import SMALLINT
from ...types import TEXT
from ...types import VARCHAR
from ...util import update_wrapper
+from ...util.typing import Literal
if TYPE_CHECKING:
from ...sql.dml import DMLState
@@ -1369,9 +1372,89 @@ class SMALLMONEY(sqltypes.TypeEngine):
__visit_name__ = "SMALLMONEY"
-class UNIQUEIDENTIFIER(sqltypes.TypeEngine):
+class MSUUid(sqltypes.Uuid):
+ def bind_processor(self, dialect):
+ if self.native_uuid:
+ # this is currently assuming pyodbc; might not work for
+ # some other mssql driver
+ return None
+ else:
+ if self.as_uuid:
+
+ def process(value):
+ if value is not None:
+ value = value.hex
+ return value
+
+ return process
+ else:
+
+ def process(value):
+ if value is not None:
+ value = value.replace("-", "").replace("''", "'")
+ return value
+
+ return process
+
+ def literal_processor(self, dialect):
+ if self.native_uuid:
+
+ def process(value):
+ if value is not None:
+ value = f"""'{str(value).replace("''", "'")}'"""
+ return value
+
+ return process
+ else:
+ if self.as_uuid:
+
+ def process(value):
+ if value is not None:
+ value = f"""'{value.hex}'"""
+ return value
+
+ return process
+ else:
+
+ def process(value):
+ if value is not None:
+ value = f"""'{
+ value.replace("-", "").replace("'", "''")
+ }'"""
+ return value
+
+ return process
+
+
+class UNIQUEIDENTIFIER(sqltypes.Uuid[sqltypes._UUID_RETURN]):
__visit_name__ = "UNIQUEIDENTIFIER"
+ @overload
+ def __init__(
+ self: "UNIQUEIDENTIFIER[_python_UUID]", as_uuid: Literal[True] = ...
+ ):
+ ...
+
+ @overload
+ def __init__(self: "UNIQUEIDENTIFIER[str]", as_uuid: Literal[False] = ...):
+ ...
+
+ def __init__(self, as_uuid: bool = True):
+ """Construct a :class:`_mssql.UNIQUEIDENTIFIER` type.
+
+
+ :param as_uuid=True: if True, values will be interpreted
+ as Python uuid objects, converting to/from string via the
+ DBAPI.
+
+ .. versionchanged: 2.0 Added direct "uuid" support to the
+ :class:`_mssql.UNIQUEIDENTIFIER` datatype; uuid interpretation
+ defaults to ``True``.
+
+ """
+ self.as_uuid = as_uuid
+ self.native_uuid = True
+
class SQL_VARIANT(sqltypes.TypeEngine):
__visit_name__ = "SQL_VARIANT"
@@ -1619,6 +1702,12 @@ class MSTypeCompiler(compiler.GenericTypeCompiler):
def visit_SMALLMONEY(self, type_, **kw):
return "SMALLMONEY"
+ def visit_uuid(self, type_, **kw):
+ if type_.native_uuid:
+ return self.visit_UNIQUEIDENTIFIER(type_, **kw)
+ else:
+ return super().visit_uuid(type_, **kw)
+
def visit_UNIQUEIDENTIFIER(self, type_, **kw):
return "UNIQUEIDENTIFIER"
@@ -2709,6 +2798,10 @@ class MSDialect(default.DefaultDialect):
supports_statement_cache = True
supports_default_values = True
supports_empty_insert = False
+
+ # supports_native_uuid is partial here, so we implement our
+ # own impl type
+
execution_ctx_cls = MSExecutionContext
use_scope_identity = True
max_identifier_length = 128
@@ -2730,6 +2823,7 @@ class MSDialect(default.DefaultDialect):
DATETIME2: DATETIME2,
SMALLDATETIME: SMALLDATETIME,
DATETIME: DATETIME,
+ sqltypes.Uuid: MSUUid,
}
engine_config_types = default.DefaultDialect.engine_config_types.union(
diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py
index 65de88cfe..b585ea992 100644
--- a/lib/sqlalchemy/dialects/mysql/base.py
+++ b/lib/sqlalchemy/dialects/mysql/base.py
@@ -2248,6 +2248,9 @@ class MySQLTypeCompiler(compiler.GenericTypeCompiler):
else:
return self._extend_string(type_, {"national": True}, "CHAR")
+ def visit_UUID(self, type_, **kw):
+ return "UUID"
+
def visit_VARBINARY(self, type_, **kw):
return "VARBINARY(%d)" % type_.length
diff --git a/lib/sqlalchemy/dialects/oracle/base.py b/lib/sqlalchemy/dialects/oracle/base.py
index 55d5a4fb5..37b81e1dd 100644
--- a/lib/sqlalchemy/dialects/oracle/base.py
+++ b/lib/sqlalchemy/dialects/oracle/base.py
@@ -690,7 +690,7 @@ class LONG(sqltypes.Text):
class _OracleDateLiteralRender:
- def literal_processor(self, dialect):
+ def _literal_processor_datetime(self, dialect):
def process(value):
if value is not None:
if getattr(value, "microsecond", None):
@@ -709,6 +709,25 @@ class _OracleDateLiteralRender:
return process
+ def _literal_processor_date(self, dialect):
+ def process(value):
+ if value is not None:
+ if getattr(value, "microsecond", None):
+ value = (
+ f"""TO_TIMESTAMP"""
+ f"""('{value.isoformat().split("T")[0]}', """
+ """'YYYY-MM-DD')"""
+ )
+ else:
+ value = (
+ f"""TO_DATE"""
+ f"""('{value.isoformat().split("T")[0]}', """
+ """'YYYY-MM-DD')"""
+ )
+ return value
+
+ return process
+
class DATE(_OracleDateLiteralRender, sqltypes.DateTime):
"""Provide the oracle DATE type.
@@ -723,12 +742,16 @@ class DATE(_OracleDateLiteralRender, sqltypes.DateTime):
__visit_name__ = "DATE"
+ def literal_processor(self, dialect):
+ return self._literal_processor_datetime(dialect)
+
def _compare_type_affinity(self, other):
return other._type_affinity in (sqltypes.DateTime, sqltypes.Date)
class _OracleDate(_OracleDateLiteralRender, sqltypes.Date):
- pass
+ def literal_processor(self, dialect):
+ return self._literal_processor_date(dialect)
class INTERVAL(sqltypes.NativeForEmulated, sqltypes._AbstractInterval):
diff --git a/lib/sqlalchemy/dialects/oracle/cx_oracle.py b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
index 290789f32..fbac8b93e 100644
--- a/lib/sqlalchemy/dialects/oracle/cx_oracle.py
+++ b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
@@ -580,7 +580,8 @@ class _CXOracleDate(oracle._OracleDate):
class _CXOracleTIMESTAMP(oracle._OracleDateLiteralRender, sqltypes.TIMESTAMP):
- pass
+ def literal_processor(self, dialect):
+ return self._literal_processor_datetime(dialect)
# TODO: the names used across CHAR / VARCHAR / NCHAR / NVARCHAR
diff --git a/lib/sqlalchemy/dialects/postgresql/_psycopg_common.py b/lib/sqlalchemy/dialects/postgresql/_psycopg_common.py
index 6b8b3f6d0..e831f2ed9 100644
--- a/lib/sqlalchemy/dialects/postgresql/_psycopg_common.py
+++ b/lib/sqlalchemy/dialects/postgresql/_psycopg_common.py
@@ -8,7 +8,6 @@ from .base import _FLOAT_TYPES
from .base import _INT_TYPES
from .base import PGDialect
from .base import PGExecutionContext
-from .base import UUID
from .hstore import HSTORE
from ... import exc
from ... import types as sqltypes
@@ -63,21 +62,6 @@ class _PsycopgHStore(HSTORE):
)
-class _PsycopgUUID(UUID):
- def bind_processor(self, dialect):
- return None
-
- def result_processor(self, dialect, coltype):
- if not self.as_uuid and dialect.use_native_uuid:
-
- def process(value):
- if value is not None:
- value = str(value)
- return value
-
- return process
-
-
class _PsycopgARRAY(PGARRAY):
render_bind_cast = True
@@ -106,7 +90,6 @@ class _PGDialect_common_psycopg(PGDialect):
{
sqltypes.Numeric: _PsycopgNumeric,
HSTORE: _PsycopgHStore,
- UUID: _PsycopgUUID,
sqltypes.ARRAY: _PsycopgARRAY,
},
)
@@ -115,14 +98,12 @@ class _PGDialect_common_psycopg(PGDialect):
self,
client_encoding=None,
use_native_hstore=True,
- use_native_uuid=True,
**kwargs,
):
PGDialect.__init__(self, **kwargs)
if not use_native_hstore:
self._has_native_hstore = False
self.use_native_hstore = use_native_hstore
- self.use_native_uuid = use_native_uuid
self.client_encoding = client_encoding
def create_connect_args(self, url):
diff --git a/lib/sqlalchemy/dialects/postgresql/asyncpg.py b/lib/sqlalchemy/dialects/postgresql/asyncpg.py
index d320c323c..1ec787e1f 100644
--- a/lib/sqlalchemy/dialects/postgresql/asyncpg.py
+++ b/lib/sqlalchemy/dialects/postgresql/asyncpg.py
@@ -138,7 +138,6 @@ from .base import PGDialect
from .base import PGExecutionContext
from .base import PGIdentifierPreparer
from .base import REGCLASS
-from .base import UUID
from ... import exc
from ... import pool
from ... import util
@@ -150,12 +149,6 @@ from ...util.concurrency import await_fallback
from ...util.concurrency import await_only
-try:
- from uuid import UUID as _python_UUID # noqa
-except ImportError:
- _python_UUID = None
-
-
class AsyncpgString(sqltypes.String):
render_bind_cast = True
@@ -237,30 +230,6 @@ class AsyncpgJSONPathType(json.JSONPathType):
return process
-class AsyncpgUUID(UUID):
- render_bind_cast = True
-
- def bind_processor(self, dialect):
- if not self.as_uuid and dialect.use_native_uuid:
-
- def process(value):
- if value is not None:
- value = _python_UUID(value)
- return value
-
- return process
-
- def result_processor(self, dialect, coltype):
- if not self.as_uuid and dialect.use_native_uuid:
-
- def process(value):
- if value is not None:
- value = str(value)
- return value
-
- return process
-
-
class AsyncpgNumeric(sqltypes.Numeric):
render_bind_cast = True
@@ -831,8 +800,6 @@ class PGDialect_asyncpg(PGDialect):
statement_compiler = PGCompiler_asyncpg
preparer = PGIdentifierPreparer_asyncpg
- use_native_uuid = True
-
colspecs = util.update_copy(
PGDialect.colspecs,
{
@@ -842,7 +809,6 @@ class PGDialect_asyncpg(PGDialect):
sqltypes.DateTime: AsyncpgDateTime,
sqltypes.Interval: AsyncPgInterval,
INTERVAL: AsyncPgInterval,
- UUID: AsyncpgUUID,
sqltypes.Boolean: AsyncpgBoolean,
sqltypes.Integer: AsyncpgInteger,
sqltypes.BigInteger: AsyncpgBigInteger,
diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py
index 0aeeb806b..146e59c4d 100644
--- a/lib/sqlalchemy/dialects/postgresql/base.py
+++ b/lib/sqlalchemy/dialects/postgresql/base.py
@@ -1453,9 +1453,6 @@ from collections import defaultdict
import datetime as dt
import re
from typing import Any
-from typing import overload
-from typing import TypeVar
-from uuid import UUID as _python_UUID
from . import array as _array
from . import dml
@@ -1489,8 +1486,8 @@ from ...types import NUMERIC
from ...types import REAL
from ...types import SMALLINT
from ...types import TEXT
+from ...types import UUID as UUID
from ...types import VARCHAR
-from ...util.typing import Literal
IDX_USING = re.compile(r"^(?:btree|hash|gist|gin|[\w_]+)$", re.I)
@@ -1606,6 +1603,11 @@ _FLOAT_TYPES = (700, 701, 1021, 1022)
_INT_TYPES = (20, 21, 23, 26, 1005, 1007, 1016)
+class PGUuid(UUID):
+ render_bind_cast = True
+ render_literal_cast = True
+
+
class BYTEA(sqltypes.LargeBinary[bytes]):
__visit_name__ = "BYTEA"
@@ -1765,103 +1767,6 @@ class BIT(sqltypes.TypeEngine[int]):
PGBit = BIT
-_UUID_RETURN = TypeVar("_UUID_RETURN", str, _python_UUID)
-
-
-class UUID(sqltypes.TypeEngine[_UUID_RETURN]):
-
- """PostgreSQL UUID type.
-
- Represents the UUID column type, interpreting
- data either as natively returned by the DBAPI
- or as Python uuid objects.
-
- The UUID type is currently known to work within the prominent DBAPI
- drivers supported by SQLAlchemy including psycopg, psycopg2, pg8000 and
- asyncpg. Support for other DBAPI drivers may be incomplete or non-present.
-
- """
-
- __visit_name__ = "UUID"
-
- @overload
- def __init__(self: "UUID[_python_UUID]", as_uuid: Literal[True] = ...):
- ...
-
- @overload
- def __init__(self: "UUID[str]", as_uuid: Literal[False] = ...):
- ...
-
- def __init__(self, as_uuid: bool = True):
- """Construct a UUID type.
-
-
- :param as_uuid=True: if True, values will be interpreted
- as Python uuid objects, converting to/from string via the
- DBAPI.
-
- .. versionchanged: 2 ``as_uuid`` now defaults to ``True``.
-
- """
- self.as_uuid = as_uuid
-
- def coerce_compared_value(self, op, value):
- """See :meth:`.TypeEngine.coerce_compared_value` for a description."""
-
- if isinstance(value, str):
- return self
- else:
- return super(UUID, self).coerce_compared_value(op, value)
-
- def bind_processor(self, dialect):
- if self.as_uuid:
-
- def process(value):
- if value is not None:
- value = str(value)
- return value
-
- return process
- else:
- return None
-
- def result_processor(self, dialect, coltype):
- if self.as_uuid:
-
- def process(value):
- if value is not None:
- value = _python_UUID(value)
- return value
-
- return process
- else:
- return None
-
- def literal_processor(self, dialect):
- if self.as_uuid:
-
- def process(value):
- if value is not None:
- value = "'%s'::UUID" % value
- return value
-
- return process
- else:
-
- def process(value):
- if value is not None:
- value = "'%s'" % value
- return value
-
- return process
-
- @property
- def python_type(self):
- return _python_UUID if self.as_uuid else str
-
-
-PGUuid = UUID
-
class TSVECTOR(sqltypes.TypeEngine[Any]):
@@ -2162,6 +2067,7 @@ colspecs = {
sqltypes.Enum: ENUM,
sqltypes.JSON.JSONPathType: _json.JSONPathType,
sqltypes.JSON: _json.JSON,
+ UUID: PGUuid,
}
ischema_names = {
@@ -3043,6 +2949,12 @@ class PGTypeCompiler(compiler.GenericTypeCompiler):
compiled = "BIT(%d)" % type_.length
return compiled
+ def visit_uuid(self, type_, **kw):
+ if type_.native_uuid:
+ return self.visit_UUID(type_, **kw)
+ else:
+ return super().visit_uuid(type_, **kw)
+
def visit_UUID(self, type_, **kw):
return "UUID"
@@ -3267,6 +3179,7 @@ class PGDialect(default.DefaultDialect):
supports_native_enum = True
supports_native_boolean = True
+ supports_native_uuid = True
supports_smallserial = True
supports_sequences = True
diff --git a/lib/sqlalchemy/dialects/postgresql/pg8000.py b/lib/sqlalchemy/dialects/postgresql/pg8000.py
index fbed3a464..6cb97ece4 100644
--- a/lib/sqlalchemy/dialects/postgresql/pg8000.py
+++ b/lib/sqlalchemy/dialects/postgresql/pg8000.py
@@ -93,7 +93,6 @@ of the :ref:`psycopg2 <psycopg2_isolation_level>` dialect:
""" # noqa
import decimal
import re
-from uuid import UUID as _python_UUID
from .array import ARRAY as PGARRAY
from .base import _DECIMAL_TYPES
@@ -105,7 +104,6 @@ from .base import PGCompiler
from .base import PGDialect
from .base import PGExecutionContext
from .base import PGIdentifierPreparer
-from .base import UUID
from .json import JSON
from .json import JSONB
from .json import JSONPathType
@@ -195,30 +193,6 @@ class _PGJSONPathType(JSONPathType):
# DBAPI type 1009
-class _PGUUID(UUID):
- render_bind_cast = True
-
- def bind_processor(self, dialect):
- if not self.as_uuid:
-
- def process(value):
- if value is not None:
- value = _python_UUID(value)
- return value
-
- return process
-
- def result_processor(self, dialect, coltype):
- if not self.as_uuid:
-
- def process(value):
- if value is not None:
- value = str(value)
- return value
-
- return process
-
-
class _PGEnum(ENUM):
def get_dbapi_type(self, dbapi):
return dbapi.UNKNOWN
@@ -391,7 +365,6 @@ class PGDialect_pg8000(PGDialect):
sqltypes.JSON.JSONIndexType: _PGJSONIndexType,
sqltypes.JSON.JSONIntIndexType: _PGJSONIntIndexType,
sqltypes.JSON.JSONStrIndexType: _PGJSONStrIndexType,
- UUID: _PGUUID,
sqltypes.Interval: _PGInterval,
INTERVAL: _PGInterval,
sqltypes.DateTime: _PGTimeStamp,
diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg.py b/lib/sqlalchemy/dialects/postgresql/psycopg.py
index 634cea38a..7ec26cb4e 100644
--- a/lib/sqlalchemy/dialects/postgresql/psycopg.py
+++ b/lib/sqlalchemy/dialects/postgresql/psycopg.py
@@ -62,11 +62,9 @@ import re
from ._psycopg_common import _PGDialect_common_psycopg
from ._psycopg_common import _PGExecutionContext_common_psycopg
-from ._psycopg_common import _PsycopgUUID
from .base import INTERVAL
from .base import PGCompiler
from .base import PGIdentifierPreparer
-from .base import UUID
from .json import JSON
from .json import JSONB
from .json import JSONPathType
@@ -120,10 +118,6 @@ class _PGJSONPathType(JSONPathType):
pass
-class _PGUUID(_PsycopgUUID):
- render_bind_cast = True
-
-
class _PGInterval(INTERVAL):
render_bind_cast = True
@@ -201,7 +195,6 @@ class PGDialect_psycopg(_PGDialect_common_psycopg):
sqltypes.JSON.JSONPathType: _PGJSONPathType,
sqltypes.JSON.JSONIntIndexType: _PGJSONIntIndexType,
sqltypes.JSON.JSONStrIndexType: _PGJSONStrIndexType,
- UUID: _PGUUID,
sqltypes.Interval: _PGInterval,
INTERVAL: _PGInterval,
sqltypes.Date: _PGDate,
diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
index f7d1942a0..f5d84a5a3 100644
--- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py
+++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
@@ -676,7 +676,7 @@ class PGDialect_psycopg2(_PGDialect_common_psycopg):
fns.append(on_connect)
- if self.dbapi and self.use_native_uuid:
+ if self.dbapi:
def on_connect(dbapi_conn):
extras.register_uuid(None, dbapi_conn)