1- from urllib .parse import quote
1+ from urllib .parse import quote , urlencode
22
33import pandas as pd
44from sqlalchemy import create_engine
1212from mindsdb .integrations .libs .response import (
1313 HandlerStatusResponse as StatusResponse ,
1414 HandlerResponse as Response ,
15- RESPONSE_TYPE
15+ RESPONSE_TYPE ,
1616)
1717
1818logger = log .getLogger (__name__ )
@@ -23,15 +23,15 @@ class ClickHouseHandler(DatabaseHandler):
2323 This handler handles connection and execution of the ClickHouse statements.
2424 """
2525
26- name = ' clickhouse'
26+ name = " clickhouse"
2727
2828 def __init__ (self , name , connection_data , ** kwargs ):
2929 super ().__init__ (name )
30- self .dialect = ' clickhouse'
30+ self .dialect = " clickhouse"
3131 self .connection_data = connection_data
3232 self .renderer = SqlalchemyRender (ClickHouseDialect )
3333 self .is_connected = False
34- self .protocol = connection_data .get (' protocol' , ' native' )
34+ self .protocol = connection_data .get (" protocol" , " native" )
3535
3636 def __del__ (self ):
3737 if self .is_connected is True :
@@ -50,23 +50,31 @@ def connect(self):
5050 if self .is_connected :
5151 return self .connection
5252
53- protocol = "clickhouse+native" if self .protocol == 'native' else "clickhouse+http"
54- host = quote (self .connection_data ['host' ])
55- port = self .connection_data ['port' ]
56- user = quote (self .connection_data ['user' ])
57- password = quote (self .connection_data ['password' ])
58- database = quote (self .connection_data ['database' ])
59- url = f'{ protocol } ://{ user } :{ password } @{ host } :{ port } /{ database } '
53+ protocol = "clickhouse+native" if self .protocol == "native" else "clickhouse+http"
54+ host = quote (self .connection_data ["host" ])
55+ port = self .connection_data ["port" ]
56+ user = quote (self .connection_data ["user" ])
57+ password = quote (self .connection_data ["password" ])
58+ database = quote (self .connection_data ["database" ])
59+ verify = self .connection_data .get ("verify" , True )
60+ url = f"{ protocol } ://{ user } :{ password } @{ host } :{ port } /{ database } "
6061 # This is not redundunt. Check https://clickhouse-sqlalchemy.readthedocs.io/en/latest/connection.html#http
61- if self .protocol == 'https' :
62- url = url + "?protocol=https"
62+
63+ params = {}
64+ if self .protocol == "https" :
65+ params ["protocol" ] = "https"
66+ if verify is False :
67+ params ["verify" ] = "false"
68+ if params :
69+ url = f"{ url } ?{ urlencode (params )} "
70+
6371 try :
6472 engine = create_engine (url )
6573 connection = engine .raw_connection ()
6674 self .is_connected = True
6775 self .connection = connection
6876 except SQLAlchemyError as e :
69- logger .error (f' Error connecting to ClickHouse { self .connection_data [" database" ]} , { e } !' )
77+ logger .error (f" Error connecting to ClickHouse { self .connection_data [' database' ]} , { e } !" )
7078 self .is_connected = False
7179 raise
7280
@@ -86,12 +94,12 @@ def check_connection(self) -> StatusResponse:
8694 connection = self .connect ()
8795 cur = connection .cursor ()
8896 try :
89- cur .execute (' select 1;' )
97+ cur .execute (" select 1;" )
9098 finally :
9199 cur .close ()
92100 response .success = True
93101 except SQLAlchemyError as e :
94- logger .error (f' Error connecting to ClickHouse { self .connection_data [" database" ]} , { e } !' )
102+ logger .error (f" Error connecting to ClickHouse { self .connection_data [' database' ]} , { e } !" )
95103 response .error_message = str (e )
96104 self .is_connected = False
97105
@@ -117,22 +125,13 @@ def native_query(self, query: str) -> Response:
117125 cur .execute (query )
118126 result = cur .fetchall ()
119127 if result :
120- response = Response (
121- RESPONSE_TYPE .TABLE ,
122- pd .DataFrame (
123- result ,
124- columns = [x [0 ] for x in cur .description ]
125- )
126- )
128+ response = Response (RESPONSE_TYPE .TABLE , pd .DataFrame (result , columns = [x [0 ] for x in cur .description ]))
127129 else :
128130 response = Response (RESPONSE_TYPE .OK )
129131 connection .commit ()
130132 except SQLAlchemyError as e :
131- logger .error (f'Error running query: { query } on { self .connection_data ["database" ]} !' )
132- response = Response (
133- RESPONSE_TYPE .ERROR ,
134- error_message = str (e )
135- )
133+ logger .error (f"Error running query: { query } on { self .connection_data ['database' ]} !" )
134+ response = Response (RESPONSE_TYPE .ERROR , error_message = str (e ))
136135 connection .rollback ()
137136 finally :
138137 cur .close ()
@@ -155,7 +154,7 @@ def get_tables(self) -> Response:
155154 df = result .data_frame
156155
157156 if df is not None :
158- result .data_frame = df .rename (columns = {df .columns [0 ]: ' table_name' })
157+ result .data_frame = df .rename (columns = {df .columns [0 ]: " table_name" })
159158
160159 return result
161160
0 commit comments