google-cloud-spanner 3.55.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.
- google/cloud/spanner.py +47 -0
- google/cloud/spanner_admin_database_v1/__init__.py +146 -0
- google/cloud/spanner_admin_database_v1/gapic_metadata.json +418 -0
- google/cloud/spanner_admin_database_v1/gapic_version.py +16 -0
- google/cloud/spanner_admin_database_v1/py.typed +2 -0
- google/cloud/spanner_admin_database_v1/services/__init__.py +15 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/__init__.py +22 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/async_client.py +4097 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/client.py +4602 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/pagers.py +989 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/__init__.py +38 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/base.py +820 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc.py +1303 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc_asyncio.py +1688 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest.py +6512 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest_base.py +1650 -0
- google/cloud/spanner_admin_database_v1/types/__init__.py +144 -0
- google/cloud/spanner_admin_database_v1/types/backup.py +1106 -0
- google/cloud/spanner_admin_database_v1/types/backup_schedule.py +369 -0
- google/cloud/spanner_admin_database_v1/types/common.py +180 -0
- google/cloud/spanner_admin_database_v1/types/spanner_database_admin.py +1303 -0
- google/cloud/spanner_admin_instance_v1/__init__.py +110 -0
- google/cloud/spanner_admin_instance_v1/gapic_metadata.json +343 -0
- google/cloud/spanner_admin_instance_v1/gapic_version.py +16 -0
- google/cloud/spanner_admin_instance_v1/py.typed +2 -0
- google/cloud/spanner_admin_instance_v1/services/__init__.py +15 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/__init__.py +22 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/async_client.py +3466 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/client.py +3881 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/pagers.py +856 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/__init__.py +38 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/base.py +545 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc.py +1347 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc_asyncio.py +1539 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest.py +4834 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest_base.py +1198 -0
- google/cloud/spanner_admin_instance_v1/types/__init__.py +104 -0
- google/cloud/spanner_admin_instance_v1/types/common.py +99 -0
- google/cloud/spanner_admin_instance_v1/types/spanner_instance_admin.py +2375 -0
- google/cloud/spanner_dbapi/__init__.py +93 -0
- google/cloud/spanner_dbapi/_helpers.py +113 -0
- google/cloud/spanner_dbapi/batch_dml_executor.py +135 -0
- google/cloud/spanner_dbapi/checksum.py +80 -0
- google/cloud/spanner_dbapi/client_side_statement_executor.py +140 -0
- google/cloud/spanner_dbapi/client_side_statement_parser.py +106 -0
- google/cloud/spanner_dbapi/connection.py +818 -0
- google/cloud/spanner_dbapi/cursor.py +609 -0
- google/cloud/spanner_dbapi/exceptions.py +172 -0
- google/cloud/spanner_dbapi/parse_utils.py +392 -0
- google/cloud/spanner_dbapi/parsed_statement.py +63 -0
- google/cloud/spanner_dbapi/parser.py +258 -0
- google/cloud/spanner_dbapi/partition_helper.py +41 -0
- google/cloud/spanner_dbapi/transaction_helper.py +294 -0
- google/cloud/spanner_dbapi/types.py +106 -0
- google/cloud/spanner_dbapi/utils.py +147 -0
- google/cloud/spanner_dbapi/version.py +20 -0
- google/cloud/spanner_v1/__init__.py +154 -0
- google/cloud/spanner_v1/_helpers.py +751 -0
- google/cloud/spanner_v1/_opentelemetry_tracing.py +165 -0
- google/cloud/spanner_v1/backup.py +397 -0
- google/cloud/spanner_v1/batch.py +433 -0
- google/cloud/spanner_v1/client.py +538 -0
- google/cloud/spanner_v1/data_types.py +350 -0
- google/cloud/spanner_v1/database.py +1968 -0
- google/cloud/spanner_v1/database_sessions_manager.py +249 -0
- google/cloud/spanner_v1/gapic_metadata.json +268 -0
- google/cloud/spanner_v1/gapic_version.py +16 -0
- google/cloud/spanner_v1/instance.py +735 -0
- google/cloud/spanner_v1/keyset.py +193 -0
- google/cloud/spanner_v1/merged_result_set.py +146 -0
- google/cloud/spanner_v1/metrics/constants.py +71 -0
- google/cloud/spanner_v1/metrics/metrics_capture.py +75 -0
- google/cloud/spanner_v1/metrics/metrics_exporter.py +384 -0
- google/cloud/spanner_v1/metrics/metrics_interceptor.py +156 -0
- google/cloud/spanner_v1/metrics/metrics_tracer.py +588 -0
- google/cloud/spanner_v1/metrics/metrics_tracer_factory.py +328 -0
- google/cloud/spanner_v1/metrics/spanner_metrics_tracer_factory.py +172 -0
- google/cloud/spanner_v1/param_types.py +110 -0
- google/cloud/spanner_v1/pool.py +813 -0
- google/cloud/spanner_v1/py.typed +2 -0
- google/cloud/spanner_v1/request_id_header.py +64 -0
- google/cloud/spanner_v1/services/__init__.py +15 -0
- google/cloud/spanner_v1/services/spanner/__init__.py +22 -0
- google/cloud/spanner_v1/services/spanner/async_client.py +2205 -0
- google/cloud/spanner_v1/services/spanner/client.py +2624 -0
- google/cloud/spanner_v1/services/spanner/pagers.py +196 -0
- google/cloud/spanner_v1/services/spanner/transports/__init__.py +38 -0
- google/cloud/spanner_v1/services/spanner/transports/base.py +520 -0
- google/cloud/spanner_v1/services/spanner/transports/grpc.py +911 -0
- google/cloud/spanner_v1/services/spanner/transports/grpc_asyncio.py +1144 -0
- google/cloud/spanner_v1/services/spanner/transports/rest.py +3468 -0
- google/cloud/spanner_v1/services/spanner/transports/rest_base.py +981 -0
- google/cloud/spanner_v1/session.py +631 -0
- google/cloud/spanner_v1/session_options.py +133 -0
- google/cloud/spanner_v1/snapshot.py +1057 -0
- google/cloud/spanner_v1/streamed.py +402 -0
- google/cloud/spanner_v1/table.py +181 -0
- google/cloud/spanner_v1/testing/__init__.py +0 -0
- google/cloud/spanner_v1/testing/database_test.py +121 -0
- google/cloud/spanner_v1/testing/interceptors.py +118 -0
- google/cloud/spanner_v1/testing/mock_database_admin.py +38 -0
- google/cloud/spanner_v1/testing/mock_spanner.py +261 -0
- google/cloud/spanner_v1/testing/spanner_database_admin_pb2_grpc.py +1267 -0
- google/cloud/spanner_v1/testing/spanner_pb2_grpc.py +882 -0
- google/cloud/spanner_v1/transaction.py +747 -0
- google/cloud/spanner_v1/types/__init__.py +118 -0
- google/cloud/spanner_v1/types/commit_response.py +94 -0
- google/cloud/spanner_v1/types/keys.py +248 -0
- google/cloud/spanner_v1/types/mutation.py +201 -0
- google/cloud/spanner_v1/types/query_plan.py +220 -0
- google/cloud/spanner_v1/types/result_set.py +379 -0
- google/cloud/spanner_v1/types/spanner.py +1815 -0
- google/cloud/spanner_v1/types/transaction.py +818 -0
- google/cloud/spanner_v1/types/type.py +288 -0
- google_cloud_spanner-3.55.0.dist-info/LICENSE +202 -0
- google_cloud_spanner-3.55.0.dist-info/METADATA +318 -0
- google_cloud_spanner-3.55.0.dist-info/RECORD +119 -0
- google_cloud_spanner-3.55.0.dist-info/WHEEL +5 -0
- google_cloud_spanner-3.55.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,818 @@
|
|
|
1
|
+
# Copyright 2020 Google LLC All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""DB-API Connection for the Google Cloud Spanner."""
|
|
16
|
+
import warnings
|
|
17
|
+
|
|
18
|
+
from google.api_core.exceptions import Aborted
|
|
19
|
+
from google.api_core.gapic_v1.client_info import ClientInfo
|
|
20
|
+
from google.auth.credentials import AnonymousCredentials
|
|
21
|
+
|
|
22
|
+
from google.cloud import spanner_v1 as spanner
|
|
23
|
+
from google.cloud.spanner_dbapi import partition_helper
|
|
24
|
+
from google.cloud.spanner_dbapi.batch_dml_executor import BatchMode, BatchDmlExecutor
|
|
25
|
+
from google.cloud.spanner_dbapi.parsed_statement import AutocommitDmlMode
|
|
26
|
+
from google.cloud.spanner_dbapi.partition_helper import PartitionId
|
|
27
|
+
from google.cloud.spanner_dbapi.parsed_statement import ParsedStatement, Statement
|
|
28
|
+
from google.cloud.spanner_dbapi.transaction_helper import TransactionRetryHelper
|
|
29
|
+
from google.cloud.spanner_dbapi.cursor import Cursor
|
|
30
|
+
from google.cloud.spanner_v1 import RequestOptions, TransactionOptions
|
|
31
|
+
from google.cloud.spanner_v1.snapshot import Snapshot
|
|
32
|
+
|
|
33
|
+
from google.cloud.spanner_dbapi.exceptions import (
|
|
34
|
+
InterfaceError,
|
|
35
|
+
OperationalError,
|
|
36
|
+
ProgrammingError,
|
|
37
|
+
)
|
|
38
|
+
from google.cloud.spanner_dbapi.version import DEFAULT_USER_AGENT
|
|
39
|
+
from google.cloud.spanner_dbapi.version import PY_VERSION
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
CLIENT_TRANSACTION_NOT_STARTED_WARNING = (
|
|
43
|
+
"This method is non-operational as a transaction has not been started."
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def check_not_closed(function):
|
|
48
|
+
"""`Connection` class methods decorator.
|
|
49
|
+
|
|
50
|
+
Raise an exception if the connection is closed.
|
|
51
|
+
|
|
52
|
+
:raises: :class:`InterfaceError` if the connection is closed.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def wrapper(connection, *args, **kwargs):
|
|
56
|
+
if connection.is_closed:
|
|
57
|
+
raise InterfaceError("Connection is already closed")
|
|
58
|
+
|
|
59
|
+
return function(connection, *args, **kwargs)
|
|
60
|
+
|
|
61
|
+
return wrapper
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Connection:
|
|
65
|
+
"""Representation of a DB-API connection to a Cloud Spanner database.
|
|
66
|
+
|
|
67
|
+
You most likely don't need to instantiate `Connection` objects
|
|
68
|
+
directly, use the `connect` module function instead.
|
|
69
|
+
|
|
70
|
+
:type instance: :class:`~google.cloud.spanner_v1.instance.Instance`
|
|
71
|
+
:param instance: Cloud Spanner instance to connect to.
|
|
72
|
+
|
|
73
|
+
:type database: :class:`~google.cloud.spanner_v1.database.Database`
|
|
74
|
+
:param database: The database to which the connection is linked.
|
|
75
|
+
|
|
76
|
+
:type read_only: bool
|
|
77
|
+
:param read_only:
|
|
78
|
+
Flag to indicate that the connection may only execute queries and no update or DDL statements.
|
|
79
|
+
If True, the connection will use a single use read-only transaction with strong timestamp
|
|
80
|
+
bound for each new statement, and will immediately see any changes that have been committed by
|
|
81
|
+
any other transaction.
|
|
82
|
+
If autocommit is false, the connection will automatically start a new multi use read-only transaction
|
|
83
|
+
with strong timestamp bound when the first statement is executed. This read-only transaction will be
|
|
84
|
+
used for all subsequent statements until either commit() or rollback() is called on the connection. The
|
|
85
|
+
read-only transaction will read from a consistent snapshot of the database at the time that the
|
|
86
|
+
transaction started. This means that the transaction will not see any changes that have been
|
|
87
|
+
committed by other transactions since the start of the read-only transaction. Commit or rolling back
|
|
88
|
+
the read-only transaction is semantically the same, and only indicates that the read-only transaction
|
|
89
|
+
should end a that a new one should be started when the next statement is executed.
|
|
90
|
+
|
|
91
|
+
**kwargs: Initial value for connection variables.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
def __init__(self, instance, database=None, read_only=False, **kwargs):
|
|
95
|
+
self._instance = instance
|
|
96
|
+
self._database = database
|
|
97
|
+
self._ddl_statements = []
|
|
98
|
+
|
|
99
|
+
self._transaction = None
|
|
100
|
+
self._session = None
|
|
101
|
+
self._snapshot = None
|
|
102
|
+
|
|
103
|
+
self.is_closed = False
|
|
104
|
+
self._autocommit = False
|
|
105
|
+
# indicator to know if the session pool used by
|
|
106
|
+
# this connection should be cleared on the
|
|
107
|
+
# connection close
|
|
108
|
+
self._own_pool = True
|
|
109
|
+
self._read_only = read_only
|
|
110
|
+
self._staleness = None
|
|
111
|
+
self.request_priority = None
|
|
112
|
+
self._transaction_begin_marked = False
|
|
113
|
+
self._transaction_isolation_level = None
|
|
114
|
+
# whether transaction started at Spanner. This means that we had
|
|
115
|
+
# made at least one call to Spanner.
|
|
116
|
+
self._spanner_transaction_started = False
|
|
117
|
+
self._batch_mode = BatchMode.NONE
|
|
118
|
+
self._batch_dml_executor: BatchDmlExecutor = None
|
|
119
|
+
self._transaction_helper = TransactionRetryHelper(self)
|
|
120
|
+
self._autocommit_dml_mode: AutocommitDmlMode = AutocommitDmlMode.TRANSACTIONAL
|
|
121
|
+
self._connection_variables = kwargs
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def spanner_client(self):
|
|
125
|
+
"""Client for interacting with Cloud Spanner API. This property exposes
|
|
126
|
+
the spanner client so that underlying methods can be accessed.
|
|
127
|
+
"""
|
|
128
|
+
return self._instance._client
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def current_schema(self):
|
|
132
|
+
"""schema name for this connection.
|
|
133
|
+
|
|
134
|
+
:rtype: str
|
|
135
|
+
:returns: the current default schema of this connection. Currently, this
|
|
136
|
+
is always "" for GoogleSQL and "public" for PostgreSQL databases.
|
|
137
|
+
"""
|
|
138
|
+
if self.database is None:
|
|
139
|
+
raise ValueError("database property not set on the connection")
|
|
140
|
+
return self.database.default_schema_name
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def autocommit(self):
|
|
144
|
+
"""Autocommit mode flag for this connection.
|
|
145
|
+
|
|
146
|
+
:rtype: bool
|
|
147
|
+
:returns: Autocommit mode flag value.
|
|
148
|
+
"""
|
|
149
|
+
return self._autocommit
|
|
150
|
+
|
|
151
|
+
@autocommit.setter
|
|
152
|
+
def autocommit(self, value):
|
|
153
|
+
"""Change this connection autocommit mode. Setting this value to True
|
|
154
|
+
while a transaction is active will commit the current transaction.
|
|
155
|
+
|
|
156
|
+
:type value: bool
|
|
157
|
+
:param value: New autocommit mode state.
|
|
158
|
+
"""
|
|
159
|
+
if value and not self._autocommit and self._spanner_transaction_started:
|
|
160
|
+
self.commit()
|
|
161
|
+
|
|
162
|
+
self._autocommit = value
|
|
163
|
+
|
|
164
|
+
@property
|
|
165
|
+
def database(self):
|
|
166
|
+
"""Database to which this connection relates.
|
|
167
|
+
|
|
168
|
+
:rtype: :class:`~google.cloud.spanner_v1.database.Database`
|
|
169
|
+
:returns: The related database object.
|
|
170
|
+
"""
|
|
171
|
+
return self._database
|
|
172
|
+
|
|
173
|
+
@property
|
|
174
|
+
def autocommit_dml_mode(self):
|
|
175
|
+
"""Modes for executing DML statements in autocommit mode for this connection.
|
|
176
|
+
|
|
177
|
+
The DML autocommit modes are:
|
|
178
|
+
1) TRANSACTIONAL - DML statements are executed as single read-write transaction.
|
|
179
|
+
After successful execution, the DML statement is guaranteed to have been applied
|
|
180
|
+
exactly once to the database.
|
|
181
|
+
|
|
182
|
+
2) PARTITIONED_NON_ATOMIC - DML statements are executed as partitioned DML transactions.
|
|
183
|
+
If an error occurs during the execution of the DML statement, it is possible that the
|
|
184
|
+
statement has been applied to some but not all of the rows specified in the statement.
|
|
185
|
+
|
|
186
|
+
:rtype: :class:`~google.cloud.spanner_dbapi.parsed_statement.AutocommitDmlMode`
|
|
187
|
+
"""
|
|
188
|
+
return self._autocommit_dml_mode
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def inside_transaction(self):
|
|
192
|
+
warnings.warn(
|
|
193
|
+
"This method is deprecated. Use _spanner_transaction_started field",
|
|
194
|
+
DeprecationWarning,
|
|
195
|
+
)
|
|
196
|
+
return (
|
|
197
|
+
self._transaction
|
|
198
|
+
and not self._transaction.committed
|
|
199
|
+
and not self._transaction.rolled_back
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def _client_transaction_started(self):
|
|
204
|
+
"""Flag: whether transaction started at client side.
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
bool: True if transaction started, False otherwise.
|
|
208
|
+
"""
|
|
209
|
+
return (not self._autocommit) or self._transaction_begin_marked
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
def _ignore_transaction_warnings(self):
|
|
213
|
+
return self._connection_variables.get("ignore_transaction_warnings", False)
|
|
214
|
+
|
|
215
|
+
@property
|
|
216
|
+
def instance(self):
|
|
217
|
+
"""Instance to which this connection relates.
|
|
218
|
+
|
|
219
|
+
:rtype: :class:`~google.cloud.spanner_v1.instance.Instance`
|
|
220
|
+
:returns: The related instance object.
|
|
221
|
+
"""
|
|
222
|
+
return self._instance
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def read_only(self):
|
|
226
|
+
"""Flag: the connection can be used only for database reads.
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
bool:
|
|
230
|
+
True if the connection may only be used for database reads.
|
|
231
|
+
"""
|
|
232
|
+
return self._read_only
|
|
233
|
+
|
|
234
|
+
@read_only.setter
|
|
235
|
+
def read_only(self, value):
|
|
236
|
+
"""`read_only` flag setter.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
value (bool): True for ReadOnly mode, False for ReadWrite.
|
|
240
|
+
"""
|
|
241
|
+
if self._read_only != value and self._spanner_transaction_started:
|
|
242
|
+
raise ValueError(
|
|
243
|
+
"Connection read/write mode can't be changed while a transaction is in progress. "
|
|
244
|
+
"Commit or rollback the current transaction and try again."
|
|
245
|
+
)
|
|
246
|
+
self._read_only = value
|
|
247
|
+
|
|
248
|
+
@property
|
|
249
|
+
def request_options(self):
|
|
250
|
+
"""Options for the next SQL operations.
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
google.cloud.spanner_v1.RequestOptions:
|
|
254
|
+
Request options.
|
|
255
|
+
"""
|
|
256
|
+
if self.request_priority is None:
|
|
257
|
+
return
|
|
258
|
+
|
|
259
|
+
req_opts = RequestOptions(priority=self.request_priority)
|
|
260
|
+
self.request_priority = None
|
|
261
|
+
return req_opts
|
|
262
|
+
|
|
263
|
+
@property
|
|
264
|
+
def transaction_tag(self):
|
|
265
|
+
"""The transaction tag that will be applied to the next read/write
|
|
266
|
+
transaction on this `Connection`. This property is automatically cleared
|
|
267
|
+
when a new transaction is started.
|
|
268
|
+
|
|
269
|
+
Returns:
|
|
270
|
+
str: The transaction tag that will be applied to the next read/write transaction.
|
|
271
|
+
"""
|
|
272
|
+
return self._connection_variables.get("transaction_tag", None)
|
|
273
|
+
|
|
274
|
+
@transaction_tag.setter
|
|
275
|
+
def transaction_tag(self, value):
|
|
276
|
+
"""Sets the transaction tag for the next read/write transaction on this
|
|
277
|
+
`Connection`. This property is automatically cleared when a new transaction
|
|
278
|
+
is started.
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
value (str): The transaction tag for the next read/write transaction.
|
|
282
|
+
"""
|
|
283
|
+
self._connection_variables["transaction_tag"] = value
|
|
284
|
+
|
|
285
|
+
@property
|
|
286
|
+
def isolation_level(self):
|
|
287
|
+
"""The default isolation level that is used for all read/write
|
|
288
|
+
transactions on this `Connection`.
|
|
289
|
+
|
|
290
|
+
Returns:
|
|
291
|
+
google.cloud.spanner_v1.types.TransactionOptions.IsolationLevel:
|
|
292
|
+
The isolation level that is used for read/write transactions on
|
|
293
|
+
this `Connection`.
|
|
294
|
+
"""
|
|
295
|
+
return self._connection_variables.get(
|
|
296
|
+
"isolation_level",
|
|
297
|
+
TransactionOptions.IsolationLevel.ISOLATION_LEVEL_UNSPECIFIED,
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
@isolation_level.setter
|
|
301
|
+
def isolation_level(self, value: TransactionOptions.IsolationLevel):
|
|
302
|
+
"""Sets the isolation level that is used for all read/write
|
|
303
|
+
transactions on this `Connection`.
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
value (google.cloud.spanner_v1.types.TransactionOptions.IsolationLevel):
|
|
307
|
+
The isolation level for all read/write transactions on this
|
|
308
|
+
`Connection`.
|
|
309
|
+
"""
|
|
310
|
+
self._connection_variables["isolation_level"] = value
|
|
311
|
+
|
|
312
|
+
@property
|
|
313
|
+
def staleness(self):
|
|
314
|
+
"""Current read staleness option value of this `Connection`.
|
|
315
|
+
|
|
316
|
+
Returns:
|
|
317
|
+
dict: Staleness type and value.
|
|
318
|
+
"""
|
|
319
|
+
return self._staleness or {}
|
|
320
|
+
|
|
321
|
+
@staleness.setter
|
|
322
|
+
def staleness(self, value):
|
|
323
|
+
"""Read staleness option setter.
|
|
324
|
+
|
|
325
|
+
Args:
|
|
326
|
+
value (dict): Staleness type and value.
|
|
327
|
+
"""
|
|
328
|
+
if self._spanner_transaction_started and value != self._staleness:
|
|
329
|
+
raise ValueError(
|
|
330
|
+
"`staleness` option can't be changed while a transaction is in progress. "
|
|
331
|
+
"Commit or rollback the current transaction and try again."
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
possible_opts = (
|
|
335
|
+
"read_timestamp",
|
|
336
|
+
"min_read_timestamp",
|
|
337
|
+
"max_staleness",
|
|
338
|
+
"exact_staleness",
|
|
339
|
+
)
|
|
340
|
+
if value is not None and sum([opt in value for opt in possible_opts]) != 1:
|
|
341
|
+
raise ValueError(
|
|
342
|
+
"Expected one of the following staleness options: "
|
|
343
|
+
"read_timestamp, min_read_timestamp, max_staleness, exact_staleness."
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
self._staleness = value
|
|
347
|
+
|
|
348
|
+
def _session_checkout(self):
|
|
349
|
+
"""Get a Cloud Spanner session from the pool.
|
|
350
|
+
|
|
351
|
+
If there is already a session associated with
|
|
352
|
+
this connection, it'll be used instead.
|
|
353
|
+
|
|
354
|
+
:rtype: :class:`google.cloud.spanner_v1.session.Session`
|
|
355
|
+
:returns: Cloud Spanner session object ready to use.
|
|
356
|
+
"""
|
|
357
|
+
if self.database is None:
|
|
358
|
+
raise ValueError("Database needs to be passed for this operation")
|
|
359
|
+
if not self._session:
|
|
360
|
+
self._session = self.database._pool.get()
|
|
361
|
+
|
|
362
|
+
return self._session
|
|
363
|
+
|
|
364
|
+
def _release_session(self):
|
|
365
|
+
"""Release the currently used Spanner session.
|
|
366
|
+
|
|
367
|
+
The session will be returned into the sessions pool.
|
|
368
|
+
"""
|
|
369
|
+
if self._session is None:
|
|
370
|
+
return
|
|
371
|
+
if self.database is None:
|
|
372
|
+
raise ValueError("Database needs to be passed for this operation")
|
|
373
|
+
self.database._pool.put(self._session)
|
|
374
|
+
self._session = None
|
|
375
|
+
|
|
376
|
+
def transaction_checkout(self):
|
|
377
|
+
"""Get a Cloud Spanner transaction.
|
|
378
|
+
|
|
379
|
+
Begin a new transaction, if there is no transaction in
|
|
380
|
+
this connection yet. Return the started one otherwise.
|
|
381
|
+
|
|
382
|
+
This method is a no-op if the connection is in autocommit mode and no
|
|
383
|
+
explicit transaction has been started
|
|
384
|
+
|
|
385
|
+
:rtype: :class:`google.cloud.spanner_v1.transaction.Transaction`
|
|
386
|
+
:returns: A Cloud Spanner transaction object, ready to use.
|
|
387
|
+
"""
|
|
388
|
+
if not self.read_only and self._client_transaction_started:
|
|
389
|
+
if not self._spanner_transaction_started:
|
|
390
|
+
self._transaction = self._session_checkout().transaction()
|
|
391
|
+
self._transaction.transaction_tag = self.transaction_tag
|
|
392
|
+
if self._transaction_isolation_level:
|
|
393
|
+
self._transaction.isolation_level = (
|
|
394
|
+
self._transaction_isolation_level
|
|
395
|
+
)
|
|
396
|
+
else:
|
|
397
|
+
self._transaction.isolation_level = self.isolation_level
|
|
398
|
+
self.transaction_tag = None
|
|
399
|
+
self._snapshot = None
|
|
400
|
+
self._spanner_transaction_started = True
|
|
401
|
+
self._transaction.begin()
|
|
402
|
+
|
|
403
|
+
return self._transaction
|
|
404
|
+
|
|
405
|
+
def snapshot_checkout(self):
|
|
406
|
+
"""Get a Cloud Spanner snapshot.
|
|
407
|
+
|
|
408
|
+
Initiate a new multi-use snapshot, if there is no snapshot in
|
|
409
|
+
this connection yet. Return the existing one otherwise.
|
|
410
|
+
|
|
411
|
+
:rtype: :class:`google.cloud.spanner_v1.snapshot.Snapshot`
|
|
412
|
+
:returns: A Cloud Spanner snapshot object, ready to use.
|
|
413
|
+
"""
|
|
414
|
+
if self.read_only and self._client_transaction_started:
|
|
415
|
+
if not self._spanner_transaction_started:
|
|
416
|
+
self._snapshot = Snapshot(
|
|
417
|
+
self._session_checkout(), multi_use=True, **self.staleness
|
|
418
|
+
)
|
|
419
|
+
self._transaction = None
|
|
420
|
+
self._snapshot.begin()
|
|
421
|
+
self._spanner_transaction_started = True
|
|
422
|
+
|
|
423
|
+
return self._snapshot
|
|
424
|
+
|
|
425
|
+
def close(self):
|
|
426
|
+
"""Closes this connection.
|
|
427
|
+
|
|
428
|
+
The connection will be unusable from this point forward. If the
|
|
429
|
+
connection has an active transaction, it will be rolled back.
|
|
430
|
+
"""
|
|
431
|
+
if self._spanner_transaction_started and not self._read_only:
|
|
432
|
+
self._transaction.rollback()
|
|
433
|
+
|
|
434
|
+
if self._own_pool and self.database:
|
|
435
|
+
self.database._pool.clear()
|
|
436
|
+
|
|
437
|
+
self.is_closed = True
|
|
438
|
+
|
|
439
|
+
@check_not_closed
|
|
440
|
+
def begin(self, isolation_level=None):
|
|
441
|
+
"""
|
|
442
|
+
Marks the transaction as started.
|
|
443
|
+
|
|
444
|
+
:raises: :class:`InterfaceError`: if this connection is closed.
|
|
445
|
+
:raises: :class:`OperationalError`: if there is an existing transaction
|
|
446
|
+
that has been started
|
|
447
|
+
"""
|
|
448
|
+
if self._transaction_begin_marked:
|
|
449
|
+
raise OperationalError("A transaction has already started")
|
|
450
|
+
if self._spanner_transaction_started:
|
|
451
|
+
raise OperationalError(
|
|
452
|
+
"Beginning a new transaction is not allowed when a transaction "
|
|
453
|
+
"is already running"
|
|
454
|
+
)
|
|
455
|
+
self._transaction_begin_marked = True
|
|
456
|
+
self._transaction_isolation_level = isolation_level
|
|
457
|
+
|
|
458
|
+
def commit(self):
|
|
459
|
+
"""Commits any pending transaction to the database.
|
|
460
|
+
This is a no-op if there is no active client transaction.
|
|
461
|
+
"""
|
|
462
|
+
if self.database is None:
|
|
463
|
+
raise ValueError("Database needs to be passed for this operation")
|
|
464
|
+
if not self._client_transaction_started:
|
|
465
|
+
if not self._ignore_transaction_warnings:
|
|
466
|
+
warnings.warn(
|
|
467
|
+
CLIENT_TRANSACTION_NOT_STARTED_WARNING, UserWarning, stacklevel=2
|
|
468
|
+
)
|
|
469
|
+
return
|
|
470
|
+
|
|
471
|
+
self.run_prior_DDL_statements()
|
|
472
|
+
try:
|
|
473
|
+
if self._spanner_transaction_started and not self._read_only:
|
|
474
|
+
self._transaction.commit()
|
|
475
|
+
except Aborted:
|
|
476
|
+
self._transaction_helper.retry_transaction()
|
|
477
|
+
self.commit()
|
|
478
|
+
finally:
|
|
479
|
+
self._reset_post_commit_or_rollback()
|
|
480
|
+
|
|
481
|
+
def rollback(self):
|
|
482
|
+
"""Rolls back any pending transaction.
|
|
483
|
+
This is a no-op if there is no active client transaction.
|
|
484
|
+
"""
|
|
485
|
+
if not self._client_transaction_started:
|
|
486
|
+
if not self._ignore_transaction_warnings:
|
|
487
|
+
warnings.warn(
|
|
488
|
+
CLIENT_TRANSACTION_NOT_STARTED_WARNING, UserWarning, stacklevel=2
|
|
489
|
+
)
|
|
490
|
+
return
|
|
491
|
+
try:
|
|
492
|
+
if self._spanner_transaction_started and not self._read_only:
|
|
493
|
+
self._transaction.rollback()
|
|
494
|
+
finally:
|
|
495
|
+
self._reset_post_commit_or_rollback()
|
|
496
|
+
|
|
497
|
+
def _reset_post_commit_or_rollback(self):
|
|
498
|
+
self._release_session()
|
|
499
|
+
self._transaction_helper.reset()
|
|
500
|
+
self._transaction_begin_marked = False
|
|
501
|
+
self._transaction_isolation_level = None
|
|
502
|
+
self._spanner_transaction_started = False
|
|
503
|
+
|
|
504
|
+
@check_not_closed
|
|
505
|
+
def cursor(self):
|
|
506
|
+
"""Factory to create a DB API Cursor."""
|
|
507
|
+
return Cursor(self)
|
|
508
|
+
|
|
509
|
+
@check_not_closed
|
|
510
|
+
def run_prior_DDL_statements(self):
|
|
511
|
+
if self.database is None:
|
|
512
|
+
raise ValueError("Database needs to be passed for this operation")
|
|
513
|
+
if self._ddl_statements:
|
|
514
|
+
ddl_statements = self._ddl_statements
|
|
515
|
+
self._ddl_statements = []
|
|
516
|
+
|
|
517
|
+
return self.database.update_ddl(ddl_statements).result()
|
|
518
|
+
|
|
519
|
+
def run_statement(
|
|
520
|
+
self, statement: Statement, request_options: RequestOptions = None
|
|
521
|
+
):
|
|
522
|
+
"""Run single SQL statement in begun transaction.
|
|
523
|
+
|
|
524
|
+
This method is never used in autocommit mode. In
|
|
525
|
+
!autocommit mode however it remembers every executed
|
|
526
|
+
SQL statement with its parameters.
|
|
527
|
+
|
|
528
|
+
:type statement: :class:`Statement`
|
|
529
|
+
:param statement: SQL statement to execute.
|
|
530
|
+
|
|
531
|
+
:type retried: bool
|
|
532
|
+
:param retried: (Optional) Retry the SQL statement if statement
|
|
533
|
+
execution failed. Defaults to false.
|
|
534
|
+
|
|
535
|
+
:type request_options: :class:`RequestOptions`
|
|
536
|
+
:param request_options: Request options to use for this statement.
|
|
537
|
+
|
|
538
|
+
:rtype: :class:`google.cloud.spanner_v1.streamed.StreamedResultSet`,
|
|
539
|
+
:class:`google.cloud.spanner_dbapi.checksum.ResultsChecksum`
|
|
540
|
+
:returns: Streamed result set of the statement and a
|
|
541
|
+
checksum of this statement results.
|
|
542
|
+
"""
|
|
543
|
+
transaction = self.transaction_checkout()
|
|
544
|
+
return transaction.execute_sql(
|
|
545
|
+
statement.sql,
|
|
546
|
+
statement.params,
|
|
547
|
+
param_types=statement.param_types,
|
|
548
|
+
request_options=request_options or self.request_options,
|
|
549
|
+
)
|
|
550
|
+
|
|
551
|
+
@check_not_closed
|
|
552
|
+
def validate(self):
|
|
553
|
+
"""
|
|
554
|
+
Execute a minimal request to check if the connection
|
|
555
|
+
is valid and the related database is reachable.
|
|
556
|
+
|
|
557
|
+
Raise an exception in case if the connection is closed,
|
|
558
|
+
invalid, target database is not found, or the request result
|
|
559
|
+
is incorrect.
|
|
560
|
+
|
|
561
|
+
:raises: :class:`InterfaceError`: if this connection is closed.
|
|
562
|
+
:raises: :class:`OperationalError`: if the request result is incorrect.
|
|
563
|
+
:raises: :class:`google.cloud.exceptions.NotFound`: if the linked instance
|
|
564
|
+
or database doesn't exist.
|
|
565
|
+
"""
|
|
566
|
+
if self.database is None:
|
|
567
|
+
raise ValueError("Database needs to be passed for this operation")
|
|
568
|
+
with self.database.snapshot() as snapshot:
|
|
569
|
+
result = list(snapshot.execute_sql("SELECT 1"))
|
|
570
|
+
if result != [[1]]:
|
|
571
|
+
raise OperationalError(
|
|
572
|
+
"The checking query (SELECT 1) returned an unexpected result: %s. "
|
|
573
|
+
"Expected: [[1]]" % result
|
|
574
|
+
)
|
|
575
|
+
|
|
576
|
+
@check_not_closed
|
|
577
|
+
def start_batch_dml(self, cursor):
|
|
578
|
+
if self._batch_mode is not BatchMode.NONE:
|
|
579
|
+
raise ProgrammingError(
|
|
580
|
+
"Cannot start a DML batch when a batch is already active"
|
|
581
|
+
)
|
|
582
|
+
if self.read_only:
|
|
583
|
+
raise ProgrammingError(
|
|
584
|
+
"Cannot start a DML batch when the connection is in read-only mode"
|
|
585
|
+
)
|
|
586
|
+
self._batch_mode = BatchMode.DML
|
|
587
|
+
self._batch_dml_executor = BatchDmlExecutor(cursor)
|
|
588
|
+
|
|
589
|
+
@check_not_closed
|
|
590
|
+
def execute_batch_dml_statement(self, parsed_statement: ParsedStatement):
|
|
591
|
+
if self._batch_mode is not BatchMode.DML:
|
|
592
|
+
raise ProgrammingError(
|
|
593
|
+
"Cannot execute statement when the BatchMode is not DML"
|
|
594
|
+
)
|
|
595
|
+
self._batch_dml_executor.execute_statement(parsed_statement)
|
|
596
|
+
|
|
597
|
+
@check_not_closed
|
|
598
|
+
def run_batch(self):
|
|
599
|
+
if self._batch_mode is BatchMode.NONE:
|
|
600
|
+
raise ProgrammingError("Cannot run a batch when the BatchMode is not set")
|
|
601
|
+
try:
|
|
602
|
+
if self._batch_mode is BatchMode.DML:
|
|
603
|
+
many_result_set = self._batch_dml_executor.run_batch_dml()
|
|
604
|
+
finally:
|
|
605
|
+
self._batch_mode = BatchMode.NONE
|
|
606
|
+
self._batch_dml_executor = None
|
|
607
|
+
return many_result_set
|
|
608
|
+
|
|
609
|
+
@check_not_closed
|
|
610
|
+
def abort_batch(self):
|
|
611
|
+
if self._batch_mode is BatchMode.NONE:
|
|
612
|
+
raise ProgrammingError("Cannot abort a batch when the BatchMode is not set")
|
|
613
|
+
if self._batch_mode is BatchMode.DML:
|
|
614
|
+
self._batch_dml_executor = None
|
|
615
|
+
self._batch_mode = BatchMode.NONE
|
|
616
|
+
|
|
617
|
+
@check_not_closed
|
|
618
|
+
def partition_query(
|
|
619
|
+
self,
|
|
620
|
+
parsed_statement: ParsedStatement,
|
|
621
|
+
query_options=None,
|
|
622
|
+
):
|
|
623
|
+
statement = parsed_statement.statement
|
|
624
|
+
partitioned_query = parsed_statement.client_side_statement_params[0]
|
|
625
|
+
self._partitioned_query_validation(partitioned_query, statement)
|
|
626
|
+
|
|
627
|
+
batch_snapshot = self._database.batch_snapshot()
|
|
628
|
+
partition_ids = []
|
|
629
|
+
partitions = list(
|
|
630
|
+
batch_snapshot.generate_query_batches(
|
|
631
|
+
partitioned_query,
|
|
632
|
+
statement.params,
|
|
633
|
+
statement.param_types,
|
|
634
|
+
query_options=query_options,
|
|
635
|
+
)
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
batch_transaction_id = batch_snapshot.get_batch_transaction_id()
|
|
639
|
+
for partition in partitions:
|
|
640
|
+
partition_ids.append(
|
|
641
|
+
partition_helper.encode_to_string(batch_transaction_id, partition)
|
|
642
|
+
)
|
|
643
|
+
return partition_ids
|
|
644
|
+
|
|
645
|
+
@check_not_closed
|
|
646
|
+
def run_partition(self, encoded_partition_id):
|
|
647
|
+
partition_id: PartitionId = partition_helper.decode_from_string(
|
|
648
|
+
encoded_partition_id
|
|
649
|
+
)
|
|
650
|
+
batch_transaction_id = partition_id.batch_transaction_id
|
|
651
|
+
batch_snapshot = self._database.batch_snapshot(
|
|
652
|
+
read_timestamp=batch_transaction_id.read_timestamp,
|
|
653
|
+
session_id=batch_transaction_id.session_id,
|
|
654
|
+
transaction_id=batch_transaction_id.transaction_id,
|
|
655
|
+
)
|
|
656
|
+
return batch_snapshot.process(partition_id.partition_result)
|
|
657
|
+
|
|
658
|
+
@check_not_closed
|
|
659
|
+
def run_partitioned_query(
|
|
660
|
+
self,
|
|
661
|
+
parsed_statement: ParsedStatement,
|
|
662
|
+
):
|
|
663
|
+
statement = parsed_statement.statement
|
|
664
|
+
partitioned_query = parsed_statement.client_side_statement_params[0]
|
|
665
|
+
self._partitioned_query_validation(partitioned_query, statement)
|
|
666
|
+
batch_snapshot = self._database.batch_snapshot()
|
|
667
|
+
return batch_snapshot.run_partitioned_query(
|
|
668
|
+
partitioned_query, statement.params, statement.param_types
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
@check_not_closed
|
|
672
|
+
def _set_autocommit_dml_mode(
|
|
673
|
+
self,
|
|
674
|
+
parsed_statement: ParsedStatement,
|
|
675
|
+
):
|
|
676
|
+
autocommit_dml_mode_str = parsed_statement.client_side_statement_params[0]
|
|
677
|
+
autocommit_dml_mode = AutocommitDmlMode[autocommit_dml_mode_str.upper()]
|
|
678
|
+
self.set_autocommit_dml_mode(autocommit_dml_mode)
|
|
679
|
+
|
|
680
|
+
def set_autocommit_dml_mode(
|
|
681
|
+
self,
|
|
682
|
+
autocommit_dml_mode,
|
|
683
|
+
):
|
|
684
|
+
"""
|
|
685
|
+
Sets the mode for executing DML statements in autocommit mode for this connection.
|
|
686
|
+
This mode is only used when the connection is in autocommit mode, and may only
|
|
687
|
+
be set while the transaction is in autocommit mode and not in a temporary transaction.
|
|
688
|
+
"""
|
|
689
|
+
|
|
690
|
+
if self._client_transaction_started is True:
|
|
691
|
+
raise ProgrammingError(
|
|
692
|
+
"Cannot set autocommit DML mode while not in autocommit mode or while a transaction is active."
|
|
693
|
+
)
|
|
694
|
+
if self.read_only is True:
|
|
695
|
+
raise ProgrammingError(
|
|
696
|
+
"Cannot set autocommit DML mode for a read-only connection."
|
|
697
|
+
)
|
|
698
|
+
if self._batch_mode is not BatchMode.NONE:
|
|
699
|
+
raise ProgrammingError("Cannot set autocommit DML mode while in a batch.")
|
|
700
|
+
self._autocommit_dml_mode = autocommit_dml_mode
|
|
701
|
+
|
|
702
|
+
def _partitioned_query_validation(self, partitioned_query, statement):
|
|
703
|
+
if self.read_only is not True and self._client_transaction_started is True:
|
|
704
|
+
raise ProgrammingError(
|
|
705
|
+
"Partitioned query is not supported, because the connection is in a read/write transaction."
|
|
706
|
+
)
|
|
707
|
+
|
|
708
|
+
def __enter__(self):
|
|
709
|
+
return self
|
|
710
|
+
|
|
711
|
+
def __exit__(self, etype, value, traceback):
|
|
712
|
+
self.commit()
|
|
713
|
+
self.close()
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
def connect(
|
|
717
|
+
instance_id,
|
|
718
|
+
database_id=None,
|
|
719
|
+
project=None,
|
|
720
|
+
credentials=None,
|
|
721
|
+
pool=None,
|
|
722
|
+
user_agent=None,
|
|
723
|
+
client=None,
|
|
724
|
+
route_to_leader_enabled=True,
|
|
725
|
+
database_role=None,
|
|
726
|
+
**kwargs,
|
|
727
|
+
):
|
|
728
|
+
"""Creates a connection to a Google Cloud Spanner database.
|
|
729
|
+
|
|
730
|
+
:type instance_id: str
|
|
731
|
+
:param instance_id: The ID of the instance to connect to.
|
|
732
|
+
|
|
733
|
+
:type database_id: str
|
|
734
|
+
:param database_id: (Optional) The ID of the database to connect to.
|
|
735
|
+
|
|
736
|
+
:type project: str
|
|
737
|
+
:param project: (Optional) The ID of the project which owns the
|
|
738
|
+
instances, tables and data. If not provided, will
|
|
739
|
+
attempt to determine from the environment.
|
|
740
|
+
|
|
741
|
+
:type credentials: Union[:class:`~google.auth.credentials.Credentials`, str]
|
|
742
|
+
:param credentials: (Optional) The authorization credentials to attach to
|
|
743
|
+
requests. These credentials identify this application
|
|
744
|
+
to the service. These credentials may be specified as
|
|
745
|
+
a file path indicating where to retrieve the service
|
|
746
|
+
account JSON for the credentials to connect to
|
|
747
|
+
Cloud Spanner. If none are specified, the client will
|
|
748
|
+
attempt to ascertain the credentials from the
|
|
749
|
+
environment.
|
|
750
|
+
|
|
751
|
+
:type pool: Concrete subclass of
|
|
752
|
+
:class:`~google.cloud.spanner_v1.pool.AbstractSessionPool`.
|
|
753
|
+
:param pool: (Optional). Session pool to be used by database.
|
|
754
|
+
|
|
755
|
+
:type user_agent: str
|
|
756
|
+
:param user_agent: (Optional) User agent to be used with this connection's
|
|
757
|
+
requests.
|
|
758
|
+
|
|
759
|
+
:type client: Concrete subclass of
|
|
760
|
+
:class:`~google.cloud.spanner_v1.Client`.
|
|
761
|
+
:param client: (Optional) Custom user provided Client Object
|
|
762
|
+
|
|
763
|
+
:type route_to_leader_enabled: boolean
|
|
764
|
+
:param route_to_leader_enabled:
|
|
765
|
+
(Optional) Default True. Set route_to_leader_enabled as False to
|
|
766
|
+
disable leader aware routing. Disabling leader aware routing would
|
|
767
|
+
route all requests in RW/PDML transactions to the closest region.
|
|
768
|
+
|
|
769
|
+
:type database_role: str
|
|
770
|
+
:param database_role: (Optional) The database role to connect as when using
|
|
771
|
+
fine-grained access controls.
|
|
772
|
+
|
|
773
|
+
**kwargs: Initial value for connection variables.
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
:rtype: :class:`google.cloud.spanner_dbapi.connection.Connection`
|
|
777
|
+
:returns: Connection object associated with the given Google Cloud Spanner
|
|
778
|
+
resource.
|
|
779
|
+
"""
|
|
780
|
+
if client is None:
|
|
781
|
+
client_info = ClientInfo(
|
|
782
|
+
user_agent=user_agent or DEFAULT_USER_AGENT,
|
|
783
|
+
python_version=PY_VERSION,
|
|
784
|
+
client_library_version=spanner.__version__,
|
|
785
|
+
)
|
|
786
|
+
if isinstance(credentials, str):
|
|
787
|
+
client = spanner.Client.from_service_account_json(
|
|
788
|
+
credentials,
|
|
789
|
+
project=project,
|
|
790
|
+
client_info=client_info,
|
|
791
|
+
route_to_leader_enabled=route_to_leader_enabled,
|
|
792
|
+
)
|
|
793
|
+
else:
|
|
794
|
+
client_options = None
|
|
795
|
+
if isinstance(credentials, AnonymousCredentials):
|
|
796
|
+
client_options = kwargs.get("client_options")
|
|
797
|
+
client = spanner.Client(
|
|
798
|
+
project=project,
|
|
799
|
+
credentials=credentials,
|
|
800
|
+
client_info=client_info,
|
|
801
|
+
route_to_leader_enabled=route_to_leader_enabled,
|
|
802
|
+
client_options=client_options,
|
|
803
|
+
)
|
|
804
|
+
else:
|
|
805
|
+
if project is not None and client.project != project:
|
|
806
|
+
raise ValueError("project in url does not match client object project")
|
|
807
|
+
|
|
808
|
+
instance = client.instance(instance_id)
|
|
809
|
+
database = None
|
|
810
|
+
if database_id:
|
|
811
|
+
database = instance.database(
|
|
812
|
+
database_id, pool=pool, database_role=database_role
|
|
813
|
+
)
|
|
814
|
+
conn = Connection(instance, database, **kwargs)
|
|
815
|
+
if pool is not None:
|
|
816
|
+
conn._own_pool = False
|
|
817
|
+
|
|
818
|
+
return conn
|