瀏覽代碼

HUE-3412 [editor] Provide start and end position in multiquery execute() API

Jenny Kim 9 年之前
父節點
當前提交
45a5141

+ 26 - 11
apps/beeswax/src/beeswax/design.py

@@ -127,7 +127,7 @@ class HQLdesign(object):
   @property
   def statements(self):
     hql_query = strip_trailing_semicolon(self.hql_query)
-    return [strip_trailing_semicolon(statement.strip()) for statement in split_statements(hql_query)]
+    return [strip_trailing_semicolon(statement.strip()) for (start_row, start_col), (end_row, end_col), statement in split_statements(hql_query)]
 
   @staticmethod
   def get_default_data_dict():
@@ -234,25 +234,37 @@ class HQLdesign(object):
 
 def split_statements(hql):
   """
-  Split statments at semicolons ignoring the ones inside
-  quotes and comments. The comment symbols that come
-  inside quotes should be ignored.
+  Split statements at semicolons ignoring the ones inside quotes and comments.
+  The comment symbols that come inside quotes should be ignored.
   """
-
   statements = []
   current = ''
   prev = ''
   between_quotes = None
   is_comment = None
+  start_row = 0
+  start_col = 0
+  end_row = 0
+  end_col = len(hql) - 1
 
   if hql.find(';') in (-1, len(hql) - 1):
-    return [hql]
+    return [((start_row, start_col), (end_row, end_col), hql)]
 
   lines = hql.splitlines()
 
-  for line in lines:
-    for c in line:
+  for row, line in enumerate(lines):
+    end_col = 0
+    end_row = row
+
+    if start_row == row and line.strip() == '':  # ignore leading whitespace rows
+      start_row += 1
+    elif current.strip() == '':  # reset start_row
+      start_row = row
+      start_col = 0
+
+    for col, c in enumerate(line):
       current += c
+
       if c in ('"', "'") and prev != '\\' and is_comment is None:
         if between_quotes == c:
           between_quotes = None
@@ -266,24 +278,27 @@ def split_statements(hql):
           # Strip off the trailing semicolon
           current = current[:-1]
           if len(current) > 1:
-            statements.append(current)
+            statements.append(((start_row, start_col), (row, col + 1), current))
+            start_col = col + 1
           current = ''
       # This character holds no significance if it was escaped within a string
       if prev == '\\' and between_quotes is not None:
         c = ''
       prev = c
+      end_col = col
+
     is_comment = None
     prev = os.linesep
+
     if current != '':
       current += os.linesep
 
   if current and current != ';':
     current = current.strip()
-    statements.append(current)
+    statements.append(((start_row, start_col), (end_row, end_col), current))
 
   return statements
 
-
 def normalize_form_dict(form, attr_list):
   """
   normalize_form_dict(form, attr_list) -> A dictionary of (attr, value)

+ 1 - 1
desktop/libs/librdbms/src/librdbms/design.py

@@ -92,7 +92,7 @@ class SQLdesign(object):
   @property
   def statements(self):
     sql_query = strip_trailing_semicolon(self.sql_query)
-    return [strip_trailing_semicolon(statement.strip()) for statement in split_statements(sql_query)]
+    return [strip_trailing_semicolon(statement.strip()) for (start_row, start_col), (end_row, end_col), statement in split_statements(sql_query)]
 
   @staticmethod
   def loads(data):

+ 30 - 13
desktop/libs/notebook/src/notebook/connectors/hiveserver2.py

@@ -129,11 +129,6 @@ class HS2Api(Api):
     return response
 
 
-  def _get_statements(self, hql_query):
-    hql_query = strip_trailing_semicolon(hql_query)
-    return [strip_trailing_semicolon(statement.strip()) for statement in split_statements(hql_query)]
-
-
   @query_error_handler
   def check_status(self, notebook, snippet):
     response = {}
@@ -281,6 +276,24 @@ class HS2Api(Api):
     }
 
 
+  def _get_statements(self, hql_query):
+    hql_query = strip_trailing_semicolon(hql_query)
+    statements = []
+    for (start_row, start_col), (end_row, end_col), statement in split_statements(hql_query):
+      statements.append({
+        'start': {
+          'row': start_row,
+          'column': start_col
+        },
+        'end': {
+          'row': end_row,
+          'column': end_col
+        },
+        'statement': strip_trailing_semicolon(statement.strip())
+      })
+    return statements
+
+
   def _get_current_statement(self, db, snippet):
     # Multiquery, if not first statement or arrived to the last query
     statement_id = snippet['result']['handle'].get('statement_id', 0)
@@ -297,17 +310,19 @@ class HS2Api(Api):
       statement_id = 0
 
     statements = self._get_statements(snippet['statement'])
-    if statements_count != len(statements):
-      statement_id = 0
-    statement = statements[statement_id]
 
-    return {
+    resp = {
       'statement_id': statement_id,
-      'statement': statement,
       'has_more_statements': statement_id < len(statements) - 1,
       'statements_count': len(statements)
     }
 
+    if statements_count != len(statements):
+      statement_id = 0
+
+    resp.update(statements[statement_id])
+    return resp
+
 
   def _prepare_hql_query(self, snippet, statement):
     settings = snippet['properties'].get('settings', None)
@@ -333,9 +348,11 @@ class HS2Api(Api):
 
   def _get_handle(self, snippet):
     snippet['result']['handle']['secret'], snippet['result']['handle']['guid'] = HiveServerQueryHandle.get_decoded(snippet['result']['handle']['secret'], snippet['result']['handle']['guid'])
-    snippet['result']['handle'].pop('statement_id')
-    snippet['result']['handle'].pop('has_more_statements')
-    snippet['result']['handle'].pop('statements_count')
+
+    for key in snippet['result']['handle'].keys():
+      if key not in ('log_context', 'secret', 'has_result_set', 'operation_type', 'modified_row_count', 'guid'):
+        snippet['result']['handle'].pop(key)
+
     return HiveServerQueryHandle(**snippet['result']['handle'])
 
 

+ 71 - 1
desktop/libs/notebook/src/notebook/connectors/tests/tests_hiveserver2.py

@@ -125,7 +125,9 @@ class TestHiveserver2ApiWithHadoop(BeeswaxSampleProvider):
       {
         "uuid": "f5d6394d-364f-56e8-6dd3-b1c5a4738c52",
         "id": 1234,
-        "sessions": [{"type": "hive", "properties": [], "id": null}]
+        "sessions": [{"type": "hive", "properties": [], "id": "1234"}],
+        "type": "query-hive",
+        "name": "Test Hiveserver2 Editor"
       }
     """
     self.statement = 'SELECT description, salary FROM sample_07 WHERE (sample_07.salary > 100000) ORDER BY salary DESC LIMIT 1000'
@@ -158,6 +160,74 @@ class TestHiveserver2ApiWithHadoop(BeeswaxSampleProvider):
       data=self.notebook_json)
 
 
+  def test_get_current_statement(self):
+    multi_statement = "SELECT description, salary FROM sample_07 LIMIT 20;\\r\\nSELECT AVG(salary) FROM sample_07;"
+    snippet_json = """
+      {
+          "status": "running",
+          "database": "default",
+          "id": "d70d31ee-a62a-4854-b2b1-b852f6a390f5",
+          "result": {
+              "type": "table",
+              "handle": {},
+              "id": "ca11fcb1-11a5-f534-8200-050c8e1e57e3"
+          },
+          "statement": "%(statement)s",
+          "type": "hive",
+          "properties": {
+              "files": [],
+              "functions": [],
+              "settings": []
+          }
+      }
+    """ % {'statement': multi_statement}
+
+    response = self.client.post(reverse('notebook:execute'), {'notebook': self.notebook_json, 'snippet': snippet_json})
+    data = json.loads(response.content)
+
+    assert_equal(0, data['status'], data)
+    assert_equal(0, data['handle']['statement_id'], data)
+    assert_equal(2, data['handle']['statements_count'], data)
+    assert_equal(True, data['handle']['has_more_statements'], data)
+    assert_equal({'row': 0, 'column': 0}, data['handle']['start'], data)
+    assert_equal({'row': 0, 'column': 51}, data['handle']['end'], data)
+
+
+    snippet_json = """
+      {
+          "status": "running",
+          "database": "default",
+          "id": "d70d31ee-a62a-4854-b2b1-b852f6a390f5",
+          "result": {
+              "type": "table",
+              "handle": {
+                "statement_id": 0,
+                "statements_count": 2,
+                "has_more_statements": true
+              },
+              "id": "ca11fcb1-11a5-f534-8200-050c8e1e57e3"
+          },
+          "statement": "%(statement)s",
+          "type": "hive",
+          "properties": {
+              "files": [],
+              "functions": [],
+              "settings": []
+          }
+      }
+    """ % {'statement': multi_statement}
+
+    response = self.client.post(reverse('notebook:execute'), {'notebook': self.notebook_json, 'snippet': snippet_json})
+    data = json.loads(response.content)
+
+    assert_equal(0, data['status'], data)
+    assert_equal(1, data['handle']['statement_id'], data)
+    assert_equal(2, data['handle']['statements_count'], data)
+    assert_equal(False, data['handle']['has_more_statements'], data)
+    assert_equal({'row': 1, 'column': 0}, data['handle']['start'], data)
+    assert_equal({'row': 1, 'column': 32}, data['handle']['end'], data)
+
+
   def test_explain(self):
     response = self.client.post(reverse('notebook:explain'), {'notebook': self.notebook_json, 'snippet': self.snippet_json})
     data = json.loads(response.content)