2017-05-19 18:54:05 +00:00
|
|
|
import errno
|
|
|
|
import subprocess as sp
|
|
|
|
from threading import Timer
|
2017-05-30 11:49:17 +00:00
|
|
|
import tempfile
|
2017-05-19 18:54:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Client:
|
|
|
|
def __init__(self, host, port=9000, command='/usr/bin/clickhouse-client'):
|
|
|
|
self.host = host
|
|
|
|
self.port = port
|
|
|
|
self.command = [command, '--host', self.host, '--port', str(self.port)]
|
|
|
|
|
2017-05-30 11:49:17 +00:00
|
|
|
|
|
|
|
def query(self, sql, stdin=None, timeout=None):
|
|
|
|
return QueryRequest(self, sql, stdin, timeout).get_answer()
|
|
|
|
|
|
|
|
|
|
|
|
def get_query_request(self, sql, stdin=None, timeout=None):
|
|
|
|
return QueryRequest(self, sql, stdin, timeout)
|
|
|
|
|
|
|
|
|
|
|
|
class QueryRequest:
|
|
|
|
def __init__(self, client, sql, stdin=None, timeout=None):
|
|
|
|
self.client = client
|
|
|
|
|
|
|
|
command = self.client.command[:]
|
2017-05-19 18:54:05 +00:00
|
|
|
if stdin is None:
|
2017-05-30 11:49:17 +00:00
|
|
|
command += ['--multiquery']
|
2017-05-19 18:54:05 +00:00
|
|
|
stdin = sql
|
|
|
|
else:
|
2017-05-30 11:49:17 +00:00
|
|
|
command += ['--query', sql]
|
2017-05-19 18:54:05 +00:00
|
|
|
|
2017-05-30 11:49:17 +00:00
|
|
|
# Write data to tmp file to avoid PIPEs and execution blocking
|
|
|
|
stdin_file = tempfile.TemporaryFile()
|
|
|
|
stdin_file.write(stdin)
|
|
|
|
stdin_file.seek(0)
|
|
|
|
self.stdout_file = tempfile.TemporaryFile()
|
|
|
|
self.stderr_file = tempfile.TemporaryFile()
|
2017-05-19 18:54:05 +00:00
|
|
|
|
2017-05-30 11:49:17 +00:00
|
|
|
#print " ".join(command), "\nQuery:", sql
|
|
|
|
|
|
|
|
self.process = sp.Popen(command, stdin=stdin_file, stdout=self.stdout_file, stderr=self.stderr_file)
|
|
|
|
|
|
|
|
self.timer = None
|
|
|
|
self.process_finished_before_timeout = True
|
2017-05-19 18:54:05 +00:00
|
|
|
if timeout is not None:
|
|
|
|
def kill_process():
|
2017-05-30 11:49:17 +00:00
|
|
|
if self.process.poll() is None:
|
|
|
|
self.process.kill()
|
|
|
|
self.process_finished_before_timeout = False
|
|
|
|
|
|
|
|
self.timer = Timer(timeout, kill_process)
|
|
|
|
self.timer.start()
|
2017-05-19 18:54:05 +00:00
|
|
|
|
|
|
|
|
2017-05-30 11:49:17 +00:00
|
|
|
def get_answer(self):
|
|
|
|
self.process.wait()
|
|
|
|
self.stdout_file.seek(0)
|
|
|
|
self.stderr_file.seek(0)
|
2017-05-19 18:54:05 +00:00
|
|
|
|
2017-05-30 11:49:17 +00:00
|
|
|
stdout = self.stdout_file.read()
|
|
|
|
stderr = self.stderr_file.read()
|
2017-05-19 18:54:05 +00:00
|
|
|
|
2017-05-30 11:49:17 +00:00
|
|
|
if self.process.returncode != 0 or stderr:
|
|
|
|
raise Exception('Client failed! Return code: {}, stderr: {}'.format(self.process.returncode, stderr))
|
|
|
|
|
|
|
|
if self.timer is not None and not self.process_finished_before_timeout:
|
|
|
|
raise Exception('Client timed out!')
|
2017-05-19 18:54:05 +00:00
|
|
|
|
|
|
|
return stdout
|
2017-05-30 11:49:17 +00:00
|
|
|
|