doris-python 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,25 @@
1
+ #! /usr/bin/python3
2
+
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ __version__ = "1.0.0"
20
+
21
+ # Register SQLAlchemy dialects (``doris://``, ``doris+aiomysql://`` etc.).
22
+ # Importing this module must register the entry points for the
23
+ # ``doris`` dialect to be discoverable by ``create_engine`` /
24
+ # ``create_async_engine``.
25
+ from . import sqlalchemy # noqa: E402, F401
@@ -0,0 +1,43 @@
1
+ #! /usr/bin/python3
2
+
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ """SQLAlchemy dialects for Apache Doris.
20
+
21
+ Registering these entry points lets users connect with any of the three
22
+ supported MySQL-wire drivers via the standard URL scheme::
23
+
24
+ doris:// # defaults to mysqlclient (mysqldb)
25
+ doris+mysqldb://
26
+ doris+pymysql://
27
+ doris+aiomysql:// # asyncio
28
+ doris+asyncmy:// # asyncio
29
+ """
30
+
31
+ from sqlalchemy.dialects import registry
32
+
33
+ # Default sync dialect — kept for backwards compatibility with the original
34
+ # ``doris://`` URL form, which used the mysqlclient driver.
35
+ registry.register("doris", "pydoris.sqlalchemy.dialect", "DorisDialect_mysqldb")
36
+
37
+ # Sync drivers
38
+ registry.register("doris.mysqldb", "pydoris.sqlalchemy.dialect", "DorisDialect_mysqldb")
39
+ registry.register("doris.pymysql", "pydoris.sqlalchemy.pymysql", "DorisDialect_pymysql")
40
+
41
+ # Async drivers
42
+ registry.register("doris.aiomysql", "pydoris.sqlalchemy.aiomysql", "DorisDialect_aiomysql")
43
+ registry.register("doris.asyncmy", "pydoris.sqlalchemy.asyncmy", "DorisDialect_asyncmy")
@@ -0,0 +1,47 @@
1
+ #! /usr/bin/python3
2
+
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+
20
+ r"""
21
+ .. dialect:: doris+aiomysql
22
+ :name: Doris via aiomysql
23
+ :dbapi: aiomysql
24
+ :connectstring: doris+aiomysql://user:password@host:port/dbname[?key=value&key=value...]
25
+
26
+ The aiomysql dialect for Doris mirrors SQLAlchemy's
27
+ :ref:`mysql+aiomysql <dialect.mysql.aiomysql>` dialect and re-uses the same
28
+ asyncio mediation layer. It should normally be used with
29
+ :func:`_asyncio.create_async_engine`::
30
+
31
+ from sqlalchemy.ext.asyncio import create_async_engine
32
+
33
+ engine = create_async_engine(
34
+ "doris+aiomysql://user:pass@hostname:9030/dbname?charset=utf8mb4"
35
+ )
36
+ """ # noqa: E501
37
+
38
+ from sqlalchemy.dialects.mysql.aiomysql import MySQLDialect_aiomysql
39
+
40
+ from .dialect import DorisDialect_base
41
+
42
+
43
+ class DorisDialect_aiomysql(DorisDialect_base, MySQLDialect_aiomysql):
44
+ """Doris dialect using the ``aiomysql`` async driver."""
45
+
46
+
47
+ dialect = MySQLDialect_aiomysql
@@ -0,0 +1,47 @@
1
+ #! /usr/bin/python3
2
+
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+
20
+ r"""
21
+ .. dialect:: doris+asyncmy
22
+ :name: Doris via asyncmy
23
+ :dbapi: asyncmy
24
+ :connectstring: doris+asyncmy://user:password@host:port/dbname[?key=value&key=value...]
25
+
26
+ The asyncmy dialect for Doris mirrors SQLAlchemy's
27
+ :ref:`mysql+asyncmy <dialect.mysql.asyncmy>` dialect and re-uses the same
28
+ asyncio mediation layer. It should normally be used with
29
+ :func:`_asyncio.create_async_engine`::
30
+
31
+ from sqlalchemy.ext.asyncio import create_async_engine
32
+
33
+ engine = create_async_engine(
34
+ "doris+asyncmy://user:pass@hostname:9030/dbname?charset=utf8mb4"
35
+ )
36
+ """ # noqa: E501
37
+
38
+ from sqlalchemy.dialects.mysql.asyncmy import MySQLDialect_asyncmy
39
+
40
+ from .dialect import DorisDialect_base
41
+
42
+
43
+ class DorisDialect_asyncmy(DorisDialect_base, MySQLDialect_asyncmy):
44
+ """Doris dialect using the ``asyncmy`` async driver."""
45
+
46
+
47
+ dialect = DorisDialect_asyncmy
@@ -0,0 +1,200 @@
1
+ #! /usr/bin/python3
2
+
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ import datetime
20
+ import logging
21
+ import re
22
+ from typing import Optional, List, Any, Type, Dict
23
+ from sqlalchemy import Numeric, Integer, Float, String
24
+ from sqlalchemy.sql import sqltypes
25
+ from sqlalchemy.sql.type_api import TypeEngine
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+
30
+ class TINYINT(Integer): # pylint: disable=no-init
31
+ __visit_name__ = "TINYINT"
32
+
33
+
34
+ class LARGEINT(Integer): # pylint: disable=no-init
35
+ __visit_name__ = "LARGEINT"
36
+
37
+
38
+ class DOUBLE(Float): # pylint: disable=no-init
39
+ __visit_name__ = "DOUBLE"
40
+
41
+
42
+ class HLL(Numeric): # pylint: disable=no-init
43
+ __visit_name__ = "HLL"
44
+
45
+
46
+ class BITMAP(Numeric): # pylint: disable=no-init
47
+ __visit_name__ = "BITMAP"
48
+
49
+
50
+ class QUANTILE_STATE(Numeric): # pylint: disable=no-init
51
+ __visit_name__ = "QUANTILE_STATE"
52
+
53
+
54
+ class AGG_STATE(Numeric): # pylint: disable=no-init
55
+ __visit_name__ = "AGG_STATE"
56
+
57
+
58
+ class ARRAY(TypeEngine): # pylint: disable=no-init
59
+ __visit_name__ = "ARRAY"
60
+
61
+ @property
62
+ def python_type(self) -> Optional[Type[List[Any]]]:
63
+ return list
64
+
65
+
66
+ class MAP(TypeEngine): # pylint: disable=no-init
67
+ __visit_name__ = "MAP"
68
+
69
+ @property
70
+ def python_type(self) -> Optional[Type[Dict[Any, Any]]]:
71
+ return dict
72
+
73
+
74
+ class STRUCT(TypeEngine): # pylint: disable=no-init
75
+ __visit_name__ = "STRUCT"
76
+
77
+ @property
78
+ def python_type(self) -> Optional[Type[Any]]:
79
+ return None
80
+
81
+
82
+ class IPV4(TypeEngine): # pylint: disable=no-init
83
+ __visit_name__ = "IPV4"
84
+
85
+ @property
86
+ def python_type(self) -> Optional[Type[str]]:
87
+ return str
88
+
89
+
90
+ class IPV6(TypeEngine): # pylint: disable=no-init
91
+ __visit_name__ = "IPV6"
92
+
93
+ @property
94
+ def python_type(self) -> Optional[Type[str]]:
95
+ return str
96
+
97
+
98
+ class TIME(TypeEngine): # pylint: disable=no-init
99
+ """Doris TIME type — only appears in query results (e.g. TIMEDIFF, MAKETIME),
100
+ cannot be used as a column storage type."""
101
+
102
+ __visit_name__ = "TIME"
103
+
104
+ @property
105
+ def python_type(self) -> Optional[Type[datetime.timedelta]]:
106
+ return datetime.timedelta
107
+
108
+
109
+ class VARIANT(TypeEngine): # pylint: disable=no-init
110
+ __visit_name__ = "VARIANT"
111
+
112
+ @property
113
+ def python_type(self) -> Optional[Type[Any]]:
114
+ return dict
115
+
116
+
117
+ _type_map = {
118
+ # === Boolean ===
119
+ "boolean": sqltypes.BOOLEAN,
120
+ # === Integer ===
121
+ "tinyint": TINYINT,
122
+ "smallint": sqltypes.SMALLINT,
123
+ "int": sqltypes.INTEGER,
124
+ "integer": sqltypes.INTEGER,
125
+ "bigint": sqltypes.BIGINT,
126
+ "largeint": LARGEINT,
127
+ # === Floating-point ===
128
+ "float": sqltypes.FLOAT,
129
+ "double": DOUBLE,
130
+ # === Fixed-precision ===
131
+ # Doris 4.x reports DECIMALV3 as "decimal" in SHOW COLUMNS.
132
+ # DECIMALV2 is deprecated; keep for backward-compat when reading old schemas.
133
+ "decimal": sqltypes.DECIMAL,
134
+ "decimalv2": sqltypes.DECIMAL,
135
+ "decimalv3": sqltypes.DECIMAL,
136
+ # === String ===
137
+ "varchar": sqltypes.VARCHAR,
138
+ "char": sqltypes.CHAR,
139
+ "json": sqltypes.JSON,
140
+ "jsonb": sqltypes.JSON,
141
+ "text": sqltypes.TEXT,
142
+ "string": sqltypes.String,
143
+ # === Date and time ===
144
+ # Doris normalises all date variants to "date"/"datetime" in SHOW COLUMNS.
145
+ "date": sqltypes.DATE,
146
+ "datev1": sqltypes.DATE,
147
+ "datev2": sqltypes.DATE,
148
+ "datetime": sqltypes.DATETIME,
149
+ "datetimev1": sqltypes.DATETIME,
150
+ "datetimev2": sqltypes.DATETIME,
151
+ "time": TIME,
152
+ # === Structural ===
153
+ "array": ARRAY,
154
+ "map": MAP,
155
+ "struct": STRUCT,
156
+ "hll": HLL,
157
+ "quantile_state": QUANTILE_STATE,
158
+ "bitmap": BITMAP,
159
+ "agg_state": AGG_STATE,
160
+ # === Network ===
161
+ "ipv4": IPV4,
162
+ "ipv6": IPV6,
163
+ # === Semi-structured ===
164
+ "variant": VARIANT,
165
+ }
166
+
167
+ # Types that accept (length) parameter
168
+ _types_with_length = {"varchar", "char", "string"}
169
+ # Types that accept (precision, scale) parameters
170
+ _types_with_precision = {"decimal", "decimalv2", "decimalv3"}
171
+
172
+
173
+ def parse_sqltype(type_str: str) -> TypeEngine:
174
+ type_str = type_str.strip().lower()
175
+ match = re.match(r"^(?P<type>\w+)\s*(?:\((?P<options>.*)\))?", type_str)
176
+ if not match:
177
+ logger.warning(f"Could not parse type name '{type_str}'")
178
+ return sqltypes.NULLTYPE
179
+ type_name = match.group("type")
180
+ options = match.group("options")
181
+
182
+ if type_name not in _type_map:
183
+ logger.warning(f"Did not recognize type '{type_name}'")
184
+ return sqltypes.NULLTYPE
185
+ type_class = _type_map[type_name]
186
+
187
+ if options:
188
+ options = options.strip()
189
+ if type_name in _types_with_precision:
190
+ parts = [p.strip() for p in options.split(",")]
191
+ precision = int(parts[0])
192
+ scale = int(parts[1]) if len(parts) > 1 else 0
193
+ return type_class(precision=precision, scale=scale)
194
+ elif type_name in _types_with_length:
195
+ try:
196
+ return type_class(length=int(options))
197
+ except (ValueError, TypeError):
198
+ return type_class()
199
+
200
+ return type_class()