3 Connect to an HeavyDB database.
5 from collections
import namedtuple
6 from sqlalchemy.engine.url
import make_url
7 from thrift.protocol
import TBinaryProtocol, TJSONProtocol
8 from thrift.transport
import TSocket, TSSLSocket, THttpClient, TTransport
9 from thrift.transport.TSocket
import TTransportException
13 from .cursor
import Cursor
14 from .exceptions
import _translate_exception, OperationalError
16 from ._samlutils
import get_saml_response
18 from packaging.version
import Version
21 ConnectionInfo = namedtuple(
45 bin_cert_validate=
None,
48 idpformusernamefield=
'username',
49 idpformpasswordfield=
'password',
53 Create a new Connection.
63 protocol: {'binary', 'http', 'https'}
65 bin_cert_validate: bool, optional, binary encrypted connection only
66 Whether to continue if there is any certificate error
67 bin_ca_certs: str, optional, binary encrypted connection only
68 Path to the CA certificate file
70 EXPERIMENTAL Enable SAML authentication by providing
71 the logon page of the SAML Identity Provider.
72 idpformusernamefield: str
73 The HTML form ID for the username, defaults to 'username'.
74 idpformpasswordfield: str
75 The HTML form ID for the password, defaults to 'password'.
77 Enable / disable certificate checking, defaults to True.
85 You can either pass a string ``uri``, all the individual components,
86 or an existing sessionid excluding user, password, and database
88 >>> connect('heavydb://admin:HyperInteractive@localhost:6274/heavyai?'
89 ... 'protocol=binary')
90 Connection(mapd://mapd:***@localhost:6274/mapd?protocol=binary)
92 >>> connect(user='admin', password='HyperInteractive', host='localhost',
93 ... port=6274, dbname='heavyai')
95 >>> connect(user='admin', password='HyperInteractive', host='localhost',
96 ... port=443, idpurl='https://sso.localhost/logon',
99 >>> connect(sessionid='XihlkjhdasfsadSDoasdllMweieisdpo', host='localhost',
100 ... port=6273, protocol='http')
112 bin_cert_validate=bin_cert_validate,
113 bin_ca_certs=bin_ca_certs,
115 idpformusernamefield=idpformusernamefield,
116 idpformpasswordfield=idpformpasswordfield,
117 idpsslverify=idpsslverify,
123 Parse connection string
128 a URI containing connection information
136 The URI may include information on
149 password = url.password
152 dbname = url.database
153 protocol = url.query.get(
'protocol',
'binary')
154 bin_cert_validate = url.query.get(
'bin_cert_validate',
None)
155 bin_ca_certs = url.query.get(
'bin_ca_certs',
None)
170 """Connect to your HeavyDB database."""
182 bin_cert_validate=
None,
185 idpformusernamefield=
'username',
186 idpformpasswordfield=
'password',
192 if sessionid
is not None:
193 if any([user, password, uri, dbname, idpurl]):
195 "Cannot specify sessionid with user, password,"
196 " dbname, uri, or idpurl"
206 protocol ==
'binary',
207 bin_cert_validate
is None,
208 bin_ca_certs
is None,
212 raise TypeError(
"Cannot specify both URI and other arguments")
224 raise TypeError(
"`host` parameter is required.")
225 if protocol !=
'binary' and not all(
226 [bin_cert_validate
is None, bin_ca_certs
is None]
229 "Cannot specify bin_cert_validate or bin_ca_certs,"
230 " without binary protocol"
232 if protocol
in (
"http",
"https"):
233 if not host.startswith(protocol):
235 host =
'{0}://{1}'.format(protocol, host)
236 transport = THttpClient.THttpClient(
"{}:{}".format(host, port))
237 proto = TJSONProtocol.TJSONProtocol(transport)
239 elif protocol ==
"binary":
240 if any([bin_cert_validate
is not None, bin_ca_certs]):
241 socket = TSSLSocket.TSSLSocket(
244 validate=(bin_cert_validate),
245 ca_certs=bin_ca_certs,
248 socket = TSocket.TSocket(host, port)
249 transport = TTransport.TBufferedTransport(socket)
250 proto = TBinaryProtocol.TBinaryProtocolAccelerated(transport)
253 "`protocol` should be one of"
254 " ['http', 'https', 'binary'],"
255 " got {} instead".format(protocol),
268 self._transport.open()
269 except TTransportException
as e:
271 err = OperationalError(
"Could not connect to database")
280 self._client.get_tables(self.
_session)
289 userformfield=idpformusernamefield,
290 passwordformfield=idpformpasswordfield,
291 sslverify=idpsslverify,
299 self.
_session = self._client.connect(user, password, dbname)
300 except TDBException
as e:
302 except TTransportException:
304 f
"Connection failed with port {port} and "
305 f
"protocol '{protocol}'. Try port 6274 for "
306 "protocol == binary or 6273, 6278 or 443 for "
313 semver = self._client.get_version()
314 if Version(semver.split(
"-")[0]) < Version(
"4.6"):
316 f
"Version {semver} of HeavyDB detected. "
317 "Please use pymapd <0.11. See release notes "
323 'Connection(heavydb://{user}:***@{host}:{port}/{dbname}?'
324 'protocol={protocol})'
348 """Disconnect from the database unless created with sessionid"""
351 self._client.disconnect(self.
_session)
352 except (TDBException, AttributeError, TypeError):
358 """This is a noop, as HeavyDB does not provide transactions.
360 Implemented to comply with the DBI specification.
364 def execute(self, operation, parameters=None):
365 """Execute a SQL statement
370 A SQL statement to exucute
377 return c.execute(operation, parameters=parameters)
380 """Create a new :class:`Cursor` object attached to this connection."""
384 """Runtime UDF decorator.
386 The connection object can be applied to a Python function as
387 decorator that will add the function to bending registration
391 from rbc.heavydb
import RemoteHeavyDB
393 raise ImportError(
"The 'rbc' package is required for `__call__`")
394 if self.
_rbc is None:
395 self.
_rbc = RemoteHeavyDB(
403 return self.
_rbc(*args, **kwargs)
406 """Register any bending Runtime UDF functions in HeavyDB server.
408 If no Runtime UDFs have been defined, the call to this method
411 if self.
_rbc is not None:
def register_runtime_udfs