databricks-sql-connector 3.0.0b1__tar.gz → 3.0.1__tar.gz
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.
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/CHANGELOG.md +29 -5
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/PKG-INFO +7 -9
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/README.md +2 -3
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/pyproject.toml +6 -9
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/__init__.py +2 -4
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/auth/retry.py +11 -3
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/client.py +135 -47
- databricks_sql_connector-3.0.1/src/databricks/sql/parameters/__init__.py +15 -0
- databricks_sql_connector-3.0.1/src/databricks/sql/parameters/native.py +606 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/thrift_api/TCLIService/ttypes.py +6 -6
- databricks_sql_connector-3.0.1/src/databricks/sql/thrift_api/__init__.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/thrift_backend.py +12 -5
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/types.py +3 -1
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/utils.py +94 -180
- databricks_sql_connector-3.0.1/src/databricks/sqlalchemy/README.sqlalchemy.md +204 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/_parse.py +4 -1
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/base.py +1 -1
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/test/_future.py +20 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/test/_regression.py +5 -2
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/test/_unsupported.py +16 -0
- databricks_sql_connector-3.0.1/src/databricks/sqlalchemy/test/overrides/_componentreflectiontest.py +189 -0
- databricks_sql_connector-3.0.1/src/databricks/sqlalchemy/test/overrides/_ctetest.py +33 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/test/test_suite.py +0 -13
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/test_local/e2e/test_basic.py +43 -15
- databricks_sql_connector-3.0.0b1/src/databricks/sqlalchemy/_pytest.ini +0 -3
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/LICENSE +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/__init__.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/auth/__init__.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/auth/auth.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/auth/authenticators.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/auth/endpoint.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/auth/oauth.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/auth/oauth_http_handler.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/auth/thrift_http_client.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/cloudfetch/download_manager.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/cloudfetch/downloader.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/exc.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/experimental/__init__.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/experimental/oauth_persistence.py +0 -0
- /databricks_sql_connector-3.0.0b1/src/databricks/sql/thrift_api/__init__.py → /databricks_sql_connector-3.0.1/src/databricks/sql/parameters/py.typed +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/thrift_api/TCLIService/TCLIService-remote +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/thrift_api/TCLIService/TCLIService.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/thrift_api/TCLIService/__init__.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/thrift_api/TCLIService/constants.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/README.tests.md +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/__init__.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/_ddl.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/_types.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/pytest.ini +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/requirements.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/setup.cfg +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/test/_extra.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/test/conftest.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/test_local/__init__.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/test_local/e2e/MOCK_DATA.xlsx +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/test_local/test_parsing.py +0 -0
- {databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sqlalchemy/test_local/test_types.py +0 -0
|
@@ -1,11 +1,35 @@
|
|
|
1
1
|
# Release History
|
|
2
2
|
|
|
3
|
-
##
|
|
4
|
-
|
|
5
|
-
- Other:
|
|
6
|
-
-
|
|
7
|
-
-
|
|
3
|
+
## 3.0.1 (2023-12-01)
|
|
4
|
+
|
|
5
|
+
- Other: updated docstring comment about default parameterization approach (#287)
|
|
6
|
+
- Other: added tests for reading complex types and revised docstrings and type hints (#293)
|
|
7
|
+
- Fix: SQLAlchemy dialect raised DeprecationWarning due to `dbapi` classmethod (#294)
|
|
8
|
+
- Fix: SQLAlchemy dialect could not reflect TIMESTAMP_NTZ columns (#296)
|
|
9
|
+
|
|
10
|
+
## 3.0.0 (2023-11-17)
|
|
11
|
+
|
|
12
|
+
- Remove support for Python 3.7
|
|
13
|
+
- Add support for native parameterized SQL queries. Requires DBR 14.2 and above. See docs/parameters.md for more info.
|
|
14
|
+
- Completely rewritten SQLAlchemy dialect
|
|
15
|
+
- Adds support for SQLAlchemy >= 2.0 and drops support for SQLAlchemy 1.x
|
|
16
|
+
- Full e2e test coverage of all supported features
|
|
17
|
+
- Detailed usage notes in `README.sqlalchemy.md`
|
|
18
|
+
- Adds support for:
|
|
19
|
+
- New types: `TIME`, `TIMESTAMP`, `TIMESTAMP_NTZ`, `TINYINT`
|
|
20
|
+
- `Numeric` type scale and precision, like `Numeric(10,2)`
|
|
21
|
+
- Reading and writing `PrimaryKeyConstraint` and `ForeignKeyConstraint`
|
|
22
|
+
- Reading and writing composite keys
|
|
23
|
+
- Reading and writing from views
|
|
24
|
+
- Writing `Identity` to tables (i.e. autoincrementing primary keys)
|
|
25
|
+
- `LIMIT` and `OFFSET` for paging through results
|
|
26
|
+
- Caching metadata calls
|
|
8
27
|
- Enable cloud fetch by default. To disable, set `use_cloud_fetch=False` when building `databricks.sql.client`.
|
|
28
|
+
- Add integration tests for Databricks UC Volumes ingestion queries
|
|
29
|
+
- Retries:
|
|
30
|
+
- Add `_retry_max_redirects` config
|
|
31
|
+
- Set `_enable_v3_retries=True` and warn if users override it
|
|
32
|
+
- Security: bump minimum pyarrow version to 14.0.1 (CVE-2023-47248)
|
|
9
33
|
|
|
10
34
|
## 2.9.3 (2023-08-24)
|
|
11
35
|
|
|
@@ -1,29 +1,28 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: databricks-sql-connector
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.1
|
|
4
4
|
Summary: Databricks SQL Connector for Python
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Author: Databricks
|
|
7
7
|
Author-email: databricks-sql-connector-maintainers@databricks.com
|
|
8
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.8.0,<4.0.0
|
|
9
9
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.8
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.9
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.10
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
16
|
Provides-Extra: alembic
|
|
16
17
|
Provides-Extra: sqlalchemy
|
|
17
18
|
Requires-Dist: alembic (>=1.0.11,<2.0.0) ; extra == "alembic"
|
|
18
19
|
Requires-Dist: lz4 (>=4.0.2,<5.0.0)
|
|
19
|
-
Requires-Dist: numpy (>=1.16.6) ; python_version >= "3.
|
|
20
|
+
Requires-Dist: numpy (>=1.16.6) ; python_version >= "3.8" and python_version < "3.11"
|
|
20
21
|
Requires-Dist: numpy (>=1.23.4) ; python_version >= "3.11"
|
|
21
22
|
Requires-Dist: oauthlib (>=3.1.0,<4.0.0)
|
|
22
23
|
Requires-Dist: openpyxl (>=3.0.10,<4.0.0)
|
|
23
|
-
Requires-Dist: pandas (>=1.2.5,<1.4.0) ; python_version >= "3.7" and python_version < "3.8"
|
|
24
24
|
Requires-Dist: pandas (>=1.2.5,<3.0.0) ; python_version >= "3.8"
|
|
25
|
-
Requires-Dist: pyarrow (>=
|
|
26
|
-
Requires-Dist: pyarrow (>=6.0.0) ; python_version >= "3.7" and python_version < "3.11"
|
|
25
|
+
Requires-Dist: pyarrow (>=14.0.1,<15.0.0)
|
|
27
26
|
Requires-Dist: requests (>=2.18.1,<3.0.0)
|
|
28
27
|
Requires-Dist: sqlalchemy (>=2.0.21) ; extra == "sqlalchemy" or extra == "alembic"
|
|
29
28
|
Requires-Dist: thrift (>=0.16.0,<0.17.0)
|
|
@@ -45,7 +44,7 @@ You are welcome to file an issue here for general use cases. You can also contac
|
|
|
45
44
|
|
|
46
45
|
## Requirements
|
|
47
46
|
|
|
48
|
-
Python 3.
|
|
47
|
+
Python 3.8 or above is required.
|
|
49
48
|
|
|
50
49
|
## Documentation
|
|
51
50
|
|
|
@@ -81,8 +80,7 @@ connection = sql.connect(
|
|
|
81
80
|
access_token=access_token)
|
|
82
81
|
|
|
83
82
|
cursor = connection.cursor()
|
|
84
|
-
|
|
85
|
-
cursor.execute('SELECT * FROM RANGE(10)')
|
|
83
|
+
cursor.execute('SELECT :param `p`, * FROM RANGE(10)', {"param": "foo"})
|
|
86
84
|
result = cursor.fetchall()
|
|
87
85
|
for row in result:
|
|
88
86
|
print(row)
|
|
@@ -11,7 +11,7 @@ You are welcome to file an issue here for general use cases. You can also contac
|
|
|
11
11
|
|
|
12
12
|
## Requirements
|
|
13
13
|
|
|
14
|
-
Python 3.
|
|
14
|
+
Python 3.8 or above is required.
|
|
15
15
|
|
|
16
16
|
## Documentation
|
|
17
17
|
|
|
@@ -47,8 +47,7 @@ connection = sql.connect(
|
|
|
47
47
|
access_token=access_token)
|
|
48
48
|
|
|
49
49
|
cursor = connection.cursor()
|
|
50
|
-
|
|
51
|
-
cursor.execute('SELECT * FROM RANGE(10)')
|
|
50
|
+
cursor.execute('SELECT :param `p`, * FROM RANGE(10)', {"param": "foo"})
|
|
52
51
|
result = cursor.fetchall()
|
|
53
52
|
for row in result:
|
|
54
53
|
print(row)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "databricks-sql-connector"
|
|
3
|
-
version = "3.0.
|
|
3
|
+
version = "3.0.1"
|
|
4
4
|
description = "Databricks SQL Connector for Python"
|
|
5
5
|
authors = ["Databricks <databricks-sql-connector-maintainers@databricks.com>"]
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -9,21 +9,18 @@ packages = [{ include = "databricks", from = "src" }]
|
|
|
9
9
|
include = ["CHANGELOG.md"]
|
|
10
10
|
|
|
11
11
|
[tool.poetry.dependencies]
|
|
12
|
-
python = "^3.
|
|
12
|
+
python = "^3.8.0"
|
|
13
13
|
thrift = "^0.16.0"
|
|
14
14
|
pandas = [
|
|
15
|
-
{ version = ">=1.2.5,<
|
|
16
|
-
{ version = ">=1.2.5,<3.0.0", python = ">=3.8" },
|
|
17
|
-
]
|
|
18
|
-
pyarrow = [
|
|
19
|
-
{ version = ">=6.0.0", python = ">=3.7,<3.11" },
|
|
20
|
-
{ version = ">=10.0.1", python = ">=3.11" },
|
|
15
|
+
{ version = ">=1.2.5,<3.0.0", python = ">=3.8" }
|
|
21
16
|
]
|
|
17
|
+
pyarrow = "^14.0.1"
|
|
18
|
+
|
|
22
19
|
lz4 = "^4.0.2"
|
|
23
20
|
requests = "^2.18.1"
|
|
24
21
|
oauthlib = "^3.1.0"
|
|
25
22
|
numpy = [
|
|
26
|
-
{ version = ">=1.16.6", python = ">=3.
|
|
23
|
+
{ version = ">=1.16.6", python = ">=3.8,<3.11" },
|
|
27
24
|
{ version = ">=1.23.4", python = ">=3.11" },
|
|
28
25
|
]
|
|
29
26
|
sqlalchemy = { version = ">=2.0.21", optional = true }
|
{databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/__init__.py
RENAMED
|
@@ -6,9 +6,7 @@ from databricks.sql.exc import *
|
|
|
6
6
|
apilevel = "2.0"
|
|
7
7
|
threadsafety = 1 # Threads may share the module, but not connections.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
# Note that when we switch to ParameterApproach.NATIVE, paramstyle will be `named`
|
|
11
|
-
paramstyle = "pyformat"
|
|
9
|
+
paramstyle = "named"
|
|
12
10
|
|
|
13
11
|
|
|
14
12
|
class DBAPITypeObject(object):
|
|
@@ -31,7 +29,7 @@ DATETIME = DBAPITypeObject("timestamp")
|
|
|
31
29
|
DATE = DBAPITypeObject("date")
|
|
32
30
|
ROWID = DBAPITypeObject()
|
|
33
31
|
|
|
34
|
-
__version__ = "3.0.
|
|
32
|
+
__version__ = "3.0.1"
|
|
35
33
|
USER_AGENT_NAME = "PyDatabricksSqlConnector"
|
|
36
34
|
|
|
37
35
|
# These two functions are pyhive legacy
|
{databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/auth/retry.py
RENAMED
|
@@ -30,6 +30,7 @@ class CommandType(Enum):
|
|
|
30
30
|
EXECUTE_STATEMENT = "ExecuteStatement"
|
|
31
31
|
CLOSE_SESSION = "CloseSession"
|
|
32
32
|
CLOSE_OPERATION = "CloseOperation"
|
|
33
|
+
GET_OPERATION_STATUS = "GetOperationStatus"
|
|
33
34
|
OTHER = "Other"
|
|
34
35
|
|
|
35
36
|
@classmethod
|
|
@@ -314,9 +315,9 @@ class DatabricksRetryPolicy(Retry):
|
|
|
314
315
|
2. The request received a 501 (Not Implemented) status code
|
|
315
316
|
Because this request can never succeed.
|
|
316
317
|
3. The request received a 404 (Not Found) code and the request CommandType
|
|
317
|
-
was CloseSession or CloseOperation. This code indicates
|
|
318
|
-
or cursor was already closed. Further retries will
|
|
319
|
-
code.
|
|
318
|
+
was GetOperationStatus, CloseSession or CloseOperation. This code indicates
|
|
319
|
+
that the command, session or cursor was already closed. Further retries will
|
|
320
|
+
always return the same code.
|
|
320
321
|
4. The request CommandType was ExecuteStatement and the HTTP code does not
|
|
321
322
|
appear in the default status_forcelist or force_dangerous_codes list. By
|
|
322
323
|
default, this means ExecuteStatement is only retried for codes 429 and 503.
|
|
@@ -343,6 +344,13 @@ class DatabricksRetryPolicy(Retry):
|
|
|
343
344
|
if not self._is_method_retryable(method): # type: ignore
|
|
344
345
|
return False, "Only POST requests are retried"
|
|
345
346
|
|
|
347
|
+
# Request failed with 404 and was a GetOperationStatus. This is not recoverable. Don't retry.
|
|
348
|
+
if status_code == 404 and self.command_type == CommandType.GET_OPERATION_STATUS:
|
|
349
|
+
return (
|
|
350
|
+
False,
|
|
351
|
+
"GetOperationStatus received 404 code from Databricks. Operation was canceled.",
|
|
352
|
+
)
|
|
353
|
+
|
|
346
354
|
# Request failed with 404 because CloseSession returns 404 if you repeat the request.
|
|
347
355
|
if (
|
|
348
356
|
status_code == 404
|
{databricks_sql_connector-3.0.0b1 → databricks_sql_connector-3.0.1}/src/databricks/sql/client.py
RENAMED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
from typing import Dict, Tuple, List, Optional, Any, Union
|
|
1
|
+
from typing import Dict, Tuple, List, Optional, Any, Union, Sequence
|
|
2
2
|
|
|
3
3
|
import pandas
|
|
4
4
|
import pyarrow
|
|
5
5
|
import requests
|
|
6
6
|
import json
|
|
7
7
|
import os
|
|
8
|
+
import decimal
|
|
8
9
|
|
|
9
10
|
from databricks.sql import __version__
|
|
10
11
|
from databricks.sql import *
|
|
@@ -18,10 +19,21 @@ from databricks.sql.thrift_backend import ThriftBackend
|
|
|
18
19
|
from databricks.sql.utils import (
|
|
19
20
|
ExecuteResponse,
|
|
20
21
|
ParamEscaper,
|
|
21
|
-
named_parameters_to_tsparkparams,
|
|
22
22
|
inject_parameters,
|
|
23
|
+
transform_paramstyle,
|
|
24
|
+
)
|
|
25
|
+
from databricks.sql.parameters.native import (
|
|
26
|
+
DbsqlParameterBase,
|
|
27
|
+
TDbsqlParameter,
|
|
28
|
+
TParameterDict,
|
|
29
|
+
TParameterSequence,
|
|
30
|
+
TParameterCollection,
|
|
31
|
+
ParameterStructure,
|
|
32
|
+
dbsql_parameter_from_primitive,
|
|
23
33
|
ParameterApproach,
|
|
24
34
|
)
|
|
35
|
+
|
|
36
|
+
|
|
25
37
|
from databricks.sql.types import Row
|
|
26
38
|
from databricks.sql.auth.auth import get_python_sql_connector_auth_provider
|
|
27
39
|
from databricks.sql.experimental.oauth_persistence import OAuthPersistence
|
|
@@ -49,6 +61,7 @@ class Connection:
|
|
|
49
61
|
session_configuration: Dict[str, Any] = None,
|
|
50
62
|
catalog: Optional[str] = None,
|
|
51
63
|
schema: Optional[str] = None,
|
|
64
|
+
_use_arrow_native_complex_types: Optional[bool] = True,
|
|
52
65
|
**kwargs,
|
|
53
66
|
) -> None:
|
|
54
67
|
"""
|
|
@@ -62,11 +75,13 @@ class Connection:
|
|
|
62
75
|
Http Bearer access token, e.g. Databricks Personal Access Token.
|
|
63
76
|
Unless if you use auth_type=`databricks-oauth` you need to pass `access_token.
|
|
64
77
|
Examples:
|
|
78
|
+
```
|
|
65
79
|
connection = sql.connect(
|
|
66
80
|
server_hostname='dbc-12345.staging.cloud.databricks.com',
|
|
67
81
|
http_path='sql/protocolv1/o/6789/12abc567',
|
|
68
82
|
access_token='dabpi12345678'
|
|
69
83
|
)
|
|
84
|
+
```
|
|
70
85
|
:param http_headers: An optional list of (k, v) pairs that will be set as Http headers on every request
|
|
71
86
|
:param session_configuration: An optional dictionary of Spark session parameters. Defaults to None.
|
|
72
87
|
Execute the SQL command `SET -v` to get a full list of available commands.
|
|
@@ -74,12 +89,12 @@ class Connection:
|
|
|
74
89
|
:param schema: An optional initial schema to use. Requires DBR version 9.0+
|
|
75
90
|
|
|
76
91
|
Other Parameters:
|
|
77
|
-
use_inline_params: `boolean
|
|
92
|
+
use_inline_params: `boolean` | str, optional (default is False)
|
|
78
93
|
When True, parameterized calls to cursor.execute() will try to render parameter values inline with the
|
|
79
94
|
query text instead of using native bound parameters supported in DBR 14.1 and above. This connector will attempt to
|
|
80
|
-
sanitise parameterized inputs to prevent SQL injection.
|
|
81
|
-
|
|
82
|
-
|
|
95
|
+
sanitise parameterized inputs to prevent SQL injection. The inline parameter approach is maintained for
|
|
96
|
+
legacy purposes and will be deprecated in a future release. When this parameter is `True` you will see
|
|
97
|
+
a warning log message. To suppress this log message, set `use_inline_params="silent"`.
|
|
83
98
|
auth_type: `str`, optional
|
|
84
99
|
`databricks-oauth` : to use oauth with fine-grained permission scopes, set to `databricks-oauth`.
|
|
85
100
|
This is currently in private preview for Databricks accounts on AWS.
|
|
@@ -127,6 +142,7 @@ class Connection:
|
|
|
127
142
|
own implementation of OAuthPersistence.
|
|
128
143
|
|
|
129
144
|
Examples:
|
|
145
|
+
```
|
|
130
146
|
# for development only
|
|
131
147
|
from databricks.sql.experimental.oauth_persistence import DevOnlyFilePersistence
|
|
132
148
|
|
|
@@ -136,8 +152,14 @@ class Connection:
|
|
|
136
152
|
auth_type="databricks-oauth",
|
|
137
153
|
experimental_oauth_persistence=DevOnlyFilePersistence("~/dev-oauth.json")
|
|
138
154
|
)
|
|
139
|
-
|
|
140
|
-
|
|
155
|
+
```
|
|
156
|
+
:param _use_arrow_native_complex_types: `bool`, optional
|
|
157
|
+
Controls whether a complex type field value is returned as a string or as a native Arrow type. Defaults to True.
|
|
158
|
+
When True:
|
|
159
|
+
MAP is returned as List[Tuple[str, Any]]
|
|
160
|
+
STRUCT is returned as Dict[str, Any]
|
|
161
|
+
ARRAY is returned as numpy.ndarray
|
|
162
|
+
When False, complex types are returned as a strings. These are generally deserializable as JSON.
|
|
141
163
|
"""
|
|
142
164
|
|
|
143
165
|
# Internal arguments in **kwargs:
|
|
@@ -168,9 +190,6 @@ class Connection:
|
|
|
168
190
|
# _disable_pandas
|
|
169
191
|
# In case the deserialisation through pandas causes any issues, it can be disabled with
|
|
170
192
|
# this flag.
|
|
171
|
-
# _use_arrow_native_complex_types
|
|
172
|
-
# DBR will return native Arrow types for structs, arrays and maps instead of Arrow strings
|
|
173
|
-
# (True by default)
|
|
174
193
|
# _use_arrow_native_decimals
|
|
175
194
|
# Databricks runtime will return native Arrow types for decimals instead of Arrow strings
|
|
176
195
|
# (True by default)
|
|
@@ -209,6 +228,7 @@ class Connection:
|
|
|
209
228
|
http_path,
|
|
210
229
|
(http_headers or []) + base_headers,
|
|
211
230
|
auth_provider,
|
|
231
|
+
_use_arrow_native_complex_types=_use_arrow_native_complex_types,
|
|
212
232
|
**kwargs,
|
|
213
233
|
)
|
|
214
234
|
|
|
@@ -222,8 +242,36 @@ class Connection:
|
|
|
222
242
|
logger.info("Successfully opened session " + str(self.get_session_id_hex()))
|
|
223
243
|
self._cursors = [] # type: List[Cursor]
|
|
224
244
|
|
|
225
|
-
self.
|
|
226
|
-
|
|
245
|
+
self.use_inline_params = self._set_use_inline_params_with_warning(
|
|
246
|
+
kwargs.get("use_inline_params", False)
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
def _set_use_inline_params_with_warning(self, value: Union[bool, str]):
|
|
250
|
+
"""Valid values are True, False, and "silent"
|
|
251
|
+
|
|
252
|
+
False: Use native parameters
|
|
253
|
+
True: Use inline parameters and log a warning
|
|
254
|
+
"silent": Use inline parameters and don't log a warning
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
if value is False:
|
|
258
|
+
return False
|
|
259
|
+
|
|
260
|
+
if value not in [True, "silent"]:
|
|
261
|
+
raise ValueError(
|
|
262
|
+
f"Invalid value for use_inline_params: {value}. "
|
|
263
|
+
+ 'Valid values are True, False, and "silent"'
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
if value is True:
|
|
267
|
+
logger.warning(
|
|
268
|
+
"Parameterised queries executed with this client will use the inline parameter approach."
|
|
269
|
+
"This approach will be deprecated in a future release. Consider using native parameters."
|
|
270
|
+
"Learn more: https://github.com/databricks/databricks-sql-python/tree/main/docs/parameters.md"
|
|
271
|
+
'To suppress this warning, set use_inline_params="silent"'
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
return value
|
|
227
275
|
|
|
228
276
|
def __enter__(self):
|
|
229
277
|
return self
|
|
@@ -377,7 +425,7 @@ class Cursor:
|
|
|
377
425
|
raise Error("There is no active result set")
|
|
378
426
|
|
|
379
427
|
def _determine_parameter_approach(
|
|
380
|
-
self, params: Optional[
|
|
428
|
+
self, params: Optional[TParameterCollection]
|
|
381
429
|
) -> ParameterApproach:
|
|
382
430
|
"""Encapsulates the logic for choosing whether to send parameters in native vs inline mode
|
|
383
431
|
|
|
@@ -394,34 +442,60 @@ class Cursor:
|
|
|
394
442
|
if params is None:
|
|
395
443
|
return ParameterApproach.NONE
|
|
396
444
|
|
|
397
|
-
server_supports_native_approach = (
|
|
398
|
-
self.connection.server_parameterized_queries_enabled(
|
|
399
|
-
self.connection.protocol_version
|
|
400
|
-
)
|
|
401
|
-
)
|
|
402
|
-
|
|
403
445
|
if self.connection.use_inline_params:
|
|
404
|
-
if (
|
|
405
|
-
server_supports_native_approach
|
|
406
|
-
and not self.connection._suppress_inline_warning
|
|
407
|
-
):
|
|
408
|
-
logger.warning(
|
|
409
|
-
"This query will be executed with inline parameters."
|
|
410
|
-
"Consider using native parameters."
|
|
411
|
-
"Learn more: https://github.com/databricks/databricks-sql-python/tree/main/docs/parameters.md"
|
|
412
|
-
"To suppress this warning, pass use_inline_params=True when creating the connection."
|
|
413
|
-
)
|
|
414
446
|
return ParameterApproach.INLINE
|
|
415
447
|
|
|
416
|
-
|
|
448
|
+
else:
|
|
417
449
|
return ParameterApproach.NATIVE
|
|
450
|
+
|
|
451
|
+
def _all_dbsql_parameters_are_named(self, params: List[TDbsqlParameter]) -> bool:
|
|
452
|
+
"""Return True if all members of the list have a non-null .name attribute"""
|
|
453
|
+
return all([i.name is not None for i in params])
|
|
454
|
+
|
|
455
|
+
def _normalize_tparametersequence(
|
|
456
|
+
self, params: TParameterSequence
|
|
457
|
+
) -> List[TDbsqlParameter]:
|
|
458
|
+
"""Retains the same order as the input list."""
|
|
459
|
+
|
|
460
|
+
output: List[TDbsqlParameter] = []
|
|
461
|
+
for p in params:
|
|
462
|
+
if isinstance(p, DbsqlParameterBase):
|
|
463
|
+
output.append(p) # type: ignore
|
|
464
|
+
else:
|
|
465
|
+
output.append(dbsql_parameter_from_primitive(value=p)) # type: ignore
|
|
466
|
+
|
|
467
|
+
return output
|
|
468
|
+
|
|
469
|
+
def _normalize_tparameterdict(
|
|
470
|
+
self, params: TParameterDict
|
|
471
|
+
) -> List[TDbsqlParameter]:
|
|
472
|
+
return [
|
|
473
|
+
dbsql_parameter_from_primitive(value=value, name=name)
|
|
474
|
+
for name, value in params.items()
|
|
475
|
+
]
|
|
476
|
+
|
|
477
|
+
def _normalize_tparametercollection(
|
|
478
|
+
self, params: Optional[TParameterCollection]
|
|
479
|
+
) -> List[TDbsqlParameter]:
|
|
480
|
+
if params is None:
|
|
481
|
+
return []
|
|
482
|
+
if isinstance(params, dict):
|
|
483
|
+
return self._normalize_tparameterdict(params)
|
|
484
|
+
if isinstance(params, Sequence):
|
|
485
|
+
return self._normalize_tparametersequence(list(params))
|
|
486
|
+
|
|
487
|
+
def _determine_parameter_structure(
|
|
488
|
+
self,
|
|
489
|
+
parameters: List[TDbsqlParameter],
|
|
490
|
+
) -> ParameterStructure:
|
|
491
|
+
all_named = self._all_dbsql_parameters_are_named(parameters)
|
|
492
|
+
if all_named:
|
|
493
|
+
return ParameterStructure.NAMED
|
|
418
494
|
else:
|
|
419
|
-
|
|
420
|
-
"Parameterized operations are not supported by this server. DBR 14.1 is required."
|
|
421
|
-
)
|
|
495
|
+
return ParameterStructure.POSITIONAL
|
|
422
496
|
|
|
423
497
|
def _prepare_inline_parameters(
|
|
424
|
-
self, stmt: str, params: Optional[Union[
|
|
498
|
+
self, stmt: str, params: Optional[Union[Sequence, Dict[str, Any]]]
|
|
425
499
|
) -> Tuple[str, List]:
|
|
426
500
|
"""Return a statement and list of native parameters to be passed to thrift_backend for execution
|
|
427
501
|
|
|
@@ -446,7 +520,10 @@ class Cursor:
|
|
|
446
520
|
return rendered_statement, NO_NATIVE_PARAMS
|
|
447
521
|
|
|
448
522
|
def _prepare_native_parameters(
|
|
449
|
-
self,
|
|
523
|
+
self,
|
|
524
|
+
stmt: str,
|
|
525
|
+
params: List[TDbsqlParameter],
|
|
526
|
+
param_structure: ParameterStructure,
|
|
450
527
|
) -> Tuple[str, List[TSparkParameter]]:
|
|
451
528
|
"""Return a statement and a list of native parameters to be passed to thrift_backend for execution
|
|
452
529
|
|
|
@@ -466,9 +543,12 @@ class Cursor:
|
|
|
466
543
|
"""
|
|
467
544
|
|
|
468
545
|
stmt = stmt
|
|
469
|
-
|
|
546
|
+
output = [
|
|
547
|
+
p.as_tspark_param(named=param_structure == ParameterStructure.NAMED)
|
|
548
|
+
for p in params
|
|
549
|
+
]
|
|
470
550
|
|
|
471
|
-
return stmt,
|
|
551
|
+
return stmt, output
|
|
472
552
|
|
|
473
553
|
def _close_and_clear_active_result_set(self):
|
|
474
554
|
try:
|
|
@@ -627,24 +707,27 @@ class Cursor:
|
|
|
627
707
|
def execute(
|
|
628
708
|
self,
|
|
629
709
|
operation: str,
|
|
630
|
-
parameters: Optional[
|
|
710
|
+
parameters: Optional[TParameterCollection] = None,
|
|
631
711
|
) -> "Cursor":
|
|
632
712
|
"""
|
|
633
713
|
Execute a query and wait for execution to complete.
|
|
634
714
|
|
|
635
715
|
The parameterisation behaviour of this method depends on which parameter approach is used:
|
|
636
|
-
- With INLINE mode
|
|
637
|
-
- With NATIVE mode, parameters are sent to the server separately for binding
|
|
716
|
+
- With INLINE mode, parameters are rendered inline with the query text
|
|
717
|
+
- With NATIVE mode (default), parameters are sent to the server separately for binding
|
|
638
718
|
|
|
639
719
|
This behaviour is controlled by the `use_inline_params` argument passed when building a connection.
|
|
640
720
|
|
|
641
|
-
The
|
|
721
|
+
The paramstyle for these approaches is different:
|
|
642
722
|
|
|
643
|
-
If the connection was instantiated with use_inline_params=False, then parameters
|
|
644
|
-
should be given in PEP-249 `named` paramstyle like :param_name
|
|
723
|
+
If the connection was instantiated with use_inline_params=False (default), then parameters
|
|
724
|
+
should be given in PEP-249 `named` paramstyle like :param_name. Parameters passed by positionally
|
|
725
|
+
are indicated using a `?` in the query text.
|
|
645
726
|
|
|
646
|
-
If the connection was instantiated with use_inline_params=True
|
|
647
|
-
should be given in PEP-249 `pyformat` paramstyle like %(param_name)s
|
|
727
|
+
If the connection was instantiated with use_inline_params=True, then parameters
|
|
728
|
+
should be given in PEP-249 `pyformat` paramstyle like %(param_name)s. Parameters passed by positionally
|
|
729
|
+
are indicated using a `%s` marker in the query. Note: this approach is not recommended as it can break
|
|
730
|
+
your SQL query syntax and will be removed in a future release.
|
|
648
731
|
|
|
649
732
|
```python
|
|
650
733
|
inline_operation = "SELECT * FROM table WHERE field = %(some_value)s"
|
|
@@ -668,8 +751,13 @@ class Cursor:
|
|
|
668
751
|
operation, parameters
|
|
669
752
|
)
|
|
670
753
|
elif param_approach == ParameterApproach.NATIVE:
|
|
754
|
+
normalized_parameters = self._normalize_tparametercollection(parameters)
|
|
755
|
+
param_structure = self._determine_parameter_structure(normalized_parameters)
|
|
756
|
+
transformed_operation = transform_paramstyle(
|
|
757
|
+
operation, normalized_parameters, param_structure # type: ignore
|
|
758
|
+
)
|
|
671
759
|
prepared_operation, prepared_params = self._prepare_native_parameters(
|
|
672
|
-
|
|
760
|
+
transformed_operation, normalized_parameters, param_structure
|
|
673
761
|
)
|
|
674
762
|
|
|
675
763
|
self._check_not_closed()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from databricks.sql.parameters.native import (
|
|
2
|
+
IntegerParameter,
|
|
3
|
+
StringParameter,
|
|
4
|
+
BigIntegerParameter,
|
|
5
|
+
BooleanParameter,
|
|
6
|
+
DateParameter,
|
|
7
|
+
DoubleParameter,
|
|
8
|
+
FloatParameter,
|
|
9
|
+
VoidParameter,
|
|
10
|
+
SmallIntParameter,
|
|
11
|
+
TimestampParameter,
|
|
12
|
+
TimestampNTZParameter,
|
|
13
|
+
TinyIntParameter,
|
|
14
|
+
DecimalParameter,
|
|
15
|
+
)
|