Quellcode durchsuchen

HUE-1937 [beeswax] Clarify behavior of a multi query with error

When a multi query as an error, the user can modify the query and
click next to try to re-execute it without re-executing the queries
before.
The frontend was changed to transmit the full query each time between
two next statement. We also don't increase the statement number in
case of failure before.
We could also update the query between two statements but are not
doing it.

Fix in Oozie:
A PREP workflow should have the kill option
A coordinator workflow can become non in rare cases
Romain Rigaux vor 11 Jahren
Ursprung
Commit
e5c5e60184

+ 2 - 2
apps/beeswax/src/beeswax/api.py

@@ -157,7 +157,7 @@ def watch_query_refresh_json(request, id):
   # Go to next statement if asked to continue or when a statement with no dataset finished.
   try:
     if request.POST.get('next') or (not query_history.is_finished() and query_history.is_success() and not query_history.has_results):
-      query_history = db.execute_next_statement(query_history)
+      query_history = db.execute_next_statement(query_history, request.POST.get('query-query'))
       handle, state = _get_query_handle_and_state(query_history)
   except QueryServerException, ex:
     raise ex
@@ -192,7 +192,7 @@ def watch_query_refresh_json(request, id):
       result['message'] = res.errorMessage
     else:
       result['message'] = _('Bad status for request %s:\n%s') % (id, res)
-    result['status'] = 1
+    result['status'] = -1
 
   return HttpResponse(json.dumps(result), mimetype="application/json")
 

+ 1 - 1
apps/beeswax/src/beeswax/conf.py

@@ -76,7 +76,7 @@ CLOSE_QUERIES = Config(
   help=_t("Hue will try to close the Hive query when the user leaves the editor page. "
           "This will free all the query resources in HiveServer2, but also make its results inaccessible."),
   type=coerce_bool,
-  default=True
+  default=False
 )
 
 SSL = ConfigSection(

+ 4 - 0
apps/beeswax/src/beeswax/design.py

@@ -87,6 +87,10 @@ class HQLdesign(object):
   def hql_query(self):
     return self._data_dict['query']['query']
 
+  @hql_query.setter
+  def hql_query(self, query):
+    self._data_dict['query']['query'] = query
+
   @property
   def query(self):
     return self._data_dict['query'].copy()

+ 7 - 0
apps/beeswax/src/beeswax/models.py

@@ -128,6 +128,13 @@ class QueryHistory(models.Model):
     else:
       return self.query
 
+  def refresh_design(self, hql_query):
+    # Refresh only HQL query part
+    query = self.design.get_design()
+    query.hql_query = hql_query
+    self.design.data = query.dumps()
+    self.query = hql_query
+ 
   def is_finished(self):
     is_statement_finished = not self.is_running()
 

+ 9 - 2
apps/beeswax/src/beeswax/server/dbms.py

@@ -338,11 +338,18 @@ class HiveServer2Dbms(object):
     return None
 
 
-  def execute_next_statement(self, query_history):
-    query_history.statement_number += 1
+  def execute_next_statement(self, query_history, hql_query):
+    if query_history.is_success():
+      # We need to go to the next statement only if the previous one passed
+      query_history.statement_number += 1
+    else:
+      # We need to update the query in case it was fixed
+      query_history.refresh_design(hql_query)
+
     query_history.last_state = QueryHistory.STATE.submitted.index
     query_history.save()
     query = query_history.design.get_design()
+
     return self.execute_and_watch(query, query_history=query_history)
 
 

+ 10 - 1
apps/beeswax/src/beeswax/templates/execute.mako

@@ -244,7 +244,7 @@ ${layout.menubar(section='query')}
             <button data-bind="click: tryExecuteQuery, visible: $root.canExecute, enable: $root.queryEditorBlank" type="button" id="executeQuery" class="btn btn-primary disable-feedback" tabindex="2">${_('Execute')}</button>
             <button data-bind="click: tryCancelQuery, visible: $root.design.isRunning()" class="btn btn-danger" data-loading-text="${ _('Canceling...') }" rel="tooltip" data-original-title="${ _('Cancel the query') }">${ _('Cancel') }</button>
 
-            <button data-bind="click: executeNextStatement, visible: !$root.design.isFinished()" type="button" class="btn btn-primary disable-feedback" tabindex="2">${_('Next')}</button>
+            <button data-bind="click: tryExecuteNextStatement, visible: !$root.design.isFinished()" type="button" class="btn btn-primary disable-feedback" tabindex="2">${_('Next')}</button>
 
             <button data-bind="click: trySaveDesign, css: {'hide': !$root.design.id() || $root.design.id() == -1}" type="button" class="btn hide">${_('Save')}</button>
             <button data-bind="click: saveAsModal" type="button" class="btn">${_('Save as...')}</button>
@@ -1640,6 +1640,15 @@ function tryExecuteQuery() {
   logGA('query/execute');
 }
 
+function tryExecuteNextStatement() {
+  var query = getHighlightedQuery() || codeMirror.getValue();
+  viewModel.design.query.value(query);
+
+  viewModel.executeNextStatement();
+
+  logGA('query/execute_next');
+}
+
 function tryExecuteParameterizedQuery() {
   $(".tooltip").remove();
   viewModel.executeQuery();

+ 56 - 0
apps/beeswax/src/beeswax/tests.py

@@ -496,6 +496,62 @@ for x in sys.stdin:
     content = fetch_query_result_data(self.client, resp)
     assert_true(content.get('is_finished'), content)
 
+
+  def test_multiple_statements_with_next_button(self):
+    hql = """
+      show tables;
+      select * from test
+    """
+
+    resp = _make_query(self.client, hql)
+
+    # First statement
+    content = json.loads(resp.content)
+    watch_url = content['watch_url']
+    assert_equal('show tables', content.get('statement'), content)
+
+    resp = wait_for_query_to_finish(self.client, resp, max=30.0)
+    content = fetch_query_result_data(self.client, resp)
+    assert_true([u'test'] in content.get('results'), content)
+
+    # Next statement
+    resp = self.client.post(watch_url, {'next': True, 'query-query': hql})
+    content = json.loads(resp.content)
+    assert_equal('select * from test', content.get('statement'), content)
+
+    resp = wait_for_query_to_finish(self.client, resp, max=30.0)
+    content = fetch_query_result_data(self.client, resp)
+    assert_true([0, u'0x0'] in content.get('results'), content)
+
+  def test_multiple_statements_with_error(self):
+    hql = """
+      show tables;
+      select * from
+    """
+
+    resp = _make_query(self.client, hql)
+
+    content = json.loads(resp.content)
+    watch_url = content['watch_url']
+    assert_equal('show tables', content.get('statement'), content)
+
+    resp = wait_for_query_to_finish(self.client, resp, max=30.0)
+
+    resp = self.client.post(watch_url, {'next': True, 'query-query': hql})
+    content = json.loads(resp.content)
+    assert_true('Error while compiling statement' in content.get('message'), content)
+
+    hql = """
+      show tables;
+      select * from test
+    """
+
+    # Retry where we were with the statement fixed
+    resp = self.client.post(watch_url, {'next': True, 'query-query': hql})
+    content = json.loads(resp.content)
+    assert_equal('select * from test', content.get('statement'), content)
+
+
   def test_parallel_queries(self):
     """
     Test that we can issue two queries to the BeeswaxServer in parallel.

+ 2 - 1
apps/beeswax/static/js/beeswax.vm.js

@@ -508,7 +508,8 @@ function BeeswaxViewModel(server) {
     self.resetErrors();
 
     var data = {
-      'next': true
+      'next': true,
+      'query-query': self.design.query.value(),
     };
     var request = {
       url: self.design.watch.url(),

+ 2 - 2
apps/oozie/src/oozie/templates/dashboard/list_oozie_workflow.mako

@@ -453,7 +453,7 @@ ${ layout.menubar(section='workflows', dashboard=True) }
 
     function zoom(){
       $("#graph").css("zoom", CURRENT_ZOOM);
-      $("#graph").css("-moz-transform", "scale("+CURRENT_ZOOM+")");
+      $("#graph").css("-moz-transform", "scale(" + CURRENT_ZOOM + ")");
     }
 
     $("*[rel=tooltip]").tooltip();
@@ -604,7 +604,7 @@ ${ layout.menubar(section='workflows', dashboard=True) }
           $("#suspend-btn").hide();
         }
 
-        if (data.id && data.status != "RUNNING" && data.status != "SUSPENDED"){
+        if (data.id && data.status != "RUNNING" && data.status != "SUSPENDED" && data.status != "PREP"){
           $("#kill-btn").hide();
           $("#rerun-btn").show();
           $.jHueTitleUpdater.reset();

+ 1 - 1
apps/oozie/src/oozie/views/dashboard.py

@@ -184,7 +184,7 @@ def list_oozie_workflow(request, job_id, coordinator_job_id=None, bundle_job_id=
   hue_coord = history and history.get_coordinator() or History.get_coordinator_from_config(oozie_workflow.conf_dict)
   hue_workflow = (hue_coord and hue_coord.workflow) or (history and history.get_workflow()) or History.get_workflow_from_config(oozie_workflow.conf_dict)
 
-  if hue_coord: Job.objects.can_read_or_exception(request, hue_coord.workflow.id)
+  if hue_coord and hue_coord.workflow: Job.objects.can_read_or_exception(request, hue_coord.workflow.id)
   if hue_workflow: Job.objects.can_read_or_exception(request, hue_workflow.id)
 
   parameters = oozie_workflow.conf_dict.copy()