Browse Source

HUE-526. Clicking "Browse Table" on a Hive View in Beeswax launches MR job

Detect whether the "table" is a view or a real table. If it's a view,
do not show the sample rows (thus avoiding a "select *").

Also fixed some label consistency issues when displaying a view.
bc Wong 14 years ago
parent
commit
fe5af301b7

+ 25 - 12
apps/beeswax/src/beeswax/templates/describe_table.mako

@@ -15,7 +15,13 @@
 ## limitations under the License.
 <%namespace name="wrappers" file="header_footer.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
-${wrappers.head("Beeswax Table Metadata: " + table.tableName, section='tables')}
+<%
+  if is_view:
+    view_or_table_noun = "View"
+  else:
+    view_or_table_noun = "Table"
+%>
+${wrappers.head("Beeswax %s Metadata: %s" % (view_or_table_noun, table.tableName), section='tables')}
 <%def name="column_table(cols)">
   <div class="bw-col_table_wrapper">
     <table class="sortable" data-filters="HtmlTable" cellpadding="0" cellspacing="0">
@@ -51,7 +57,8 @@ ${wrappers.head("Beeswax Table Metadata: " + table.tableName, section='tables')}
         <dt class="hue-dt_cap">Actions</dt>
         <dd class="hue-dd_bottom bw-actions">
           <ul>
-            <li class="jframe-clear" data-filters="CollapsingElements"><a class="bw-load_data collapser">Import Data</a>
+	    % if not is_view:
+	      <li class="jframe-clear" data-filters="CollapsingElements"><a class="bw-load_data collapser">Import Data</a>
                 <div class="collapsible jframe-hidden">
                   <form action="${ url("beeswax.views.load_table", table=table_name) }">
                     <dl>
@@ -80,10 +87,13 @@ ${wrappers.head("Beeswax Table Metadata: " + table.tableName, section='tables')}
                     </dl>
                   </form>
                 </div>
-            </li>
+	      </li>
+	    % endif
             <li class="jframe-clear"><a href="${ url("beeswax.views.read_table", table=table_name) }" class="bw-browse_data">Browse Data</a></li>
-            <li class="jframe-clear"><a href="${ url("beeswax.views.drop_table", table=table_name) }" class="bw-drop_table">Drop Table</a></li>
-            <li class="jframe-clear"><a href="${hdfs_link}" target="FileBrowser" class="tip bw-location_link" data-filters="PointyTip" data-tip-direction="11" rel="${ table.sd.location }">View File Location</a></li>
+	    <li class="jframe-clear"><a href="${ url("beeswax.views.drop_table", table=table_name) }" class="bw-drop_table">Drop ${view_or_table_noun}</a></li>
+	    % if not is_view:
+	      <li class="jframe-clear"><a href="${hdfs_link}" target="FileBrowser" class="tip bw-location_link" data-filters="PointyTip" data-tip-direction="11" rel="${ table.sd.location }">View File Location</a></li>
+	    % endif
           </ul>
         </dd>
       </dl>
@@ -101,6 +111,16 @@ ${wrappers.head("Beeswax Table Metadata: " + table.tableName, section='tables')}
         % endif
       </ul>
       <ul class="tab_sections jframe-clear">
+	## Tab 1: Column description
+        <li>${column_table(table.sd.cols)}</li>
+	## Tab 2: Partition info (if present)
+        % if len(table.partitionKeys) > 0:
+          <li>
+            ${column_table(table.partitionKeys)}
+            <a href="${ url("beeswax.views.describe_partitions", table=table_name) }">Show Partitions</a>
+          </li>
+        % endif
+	## Tab 3: Sample rows (if present)
         % if top_rows is not None:
           <li class="bw-table_sample">
             <table data-filters="HtmlTable" cellpadding="0" cellspacing="0">
@@ -123,13 +143,6 @@ ${wrappers.head("Beeswax Table Metadata: " + table.tableName, section='tables')}
             </table>
           </li>
         % endif
-        <li>${column_table(table.sd.cols)}</li>
-        % if len(table.partitionKeys) > 0:
-          <li>
-            ${column_table(table.partitionKeys)}
-            <a href="${ url("beeswax.views.describe_partitions", table=table_name) }">Show Partitions</a>
-          </li>
-        % endif
       </ul>
     </div>
   </div>

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

@@ -337,6 +337,10 @@ class BeeswaxSampleProvider(object):
     cls._make_i18n_data_file(data_file % 4, 'latin1')
     cls._make_table(table_info['name'], CREATE_TABLE % table_info, data_file % 4)
 
+    # Create a "myview" view.
+    make_query(cls.client, "CREATE VIEW myview (foo, bar) as SELECT * FROM test",
+               wait=True)
+
     _INITIALIZED = True
 
   @staticmethod

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

@@ -857,6 +857,13 @@ for x in sys.stdin:
     assert_true("<td>nada</td>" in resp.content)
     assert_true("<td>sp ace</td>" in resp.content)
 
+  def test_describe_view(self):
+    resp = self.client.get('/beeswax/table/myview')
+    assert_equal(None, resp.context['top_rows'])
+    assert_true(resp.context['is_view'])
+    assert_true("Beeswax View Metadata" in resp.content)
+    assert_true("Drop View" in resp.content)
+
 
 def test_import_gzip_reader():
   """Test the gzip reader in create table"""

+ 30 - 14
apps/beeswax/src/beeswax/views.py

@@ -65,35 +65,51 @@ def show_tables(request):
 
 def describe_table(request, table):
   table_obj = db_utils.meta_client().get_table("default", table)
-  # Show the first few rows
-  hql = "SELECT * FROM `%s`" % (table,)
-  query_msg = make_beeswax_query(request, hql)
-  try:
-    results = db_utils.execute_and_wait(request.user, query_msg, timeout_sec=5.0)
-  except:
-    # Gracefully degrade if we're unable to load the results.
-    logging.exception("Failed to read table '%s'" % table)
-    results = None
+  sample_results = None
+  is_view = table_obj.tableType == 'VIRTUAL_VIEW'
+
+  # Don't show samples if it's a view (HUE-526).
+  if not is_view:
+    # Show the first few rows
+    hql = "SELECT * FROM `%s`" % (table,)
+    query_msg = make_beeswax_query(request, hql)
+    try:
+      sample_results = db_utils.execute_and_wait(request.user, query_msg, timeout_sec=5.0)
+    except:
+      # Gracefully degrade if we're unable to load the results.
+      logging.exception("Failed to read table '%s'" % table)
+      sample_results = None
+
   hdfs_link = location_to_url(request, table_obj.sd.location)
   load_form = beeswax.forms.LoadDataForm(table_obj)
   return render("describe_table.mako", request, dict(
       table=table_obj,
       table_name=table,
-      top_rows=results and list(parse_results(results.data)) or None,
+      top_rows=sample_results and list(parse_results(sample_results.data)) or None,
       hdfs_link=hdfs_link,
-      load_form=load_form
+      load_form=load_form,
+      is_view=is_view
   ))
 
 def drop_table(request, table):
+  table_obj = db_utils.meta_client().get_table("default", table)
+  is_view = table_obj.tableType == 'VIRTUAL_VIEW'
+
   if request.method == 'GET':
     # It may be possible to determine whether the table is
     # external by looking at db_utils.meta_client().get_table("default", table).tableType,
     # but this was introduced in Hive 0.5, and therefore may not be available
     # with older metastores.
-    title = "This may delete the underlying data as well as the metadata.  Drop table %s?" % table
+    if is_view:
+      title = "Do you really want to drop the view '%s'?" % (table,)
+    else:
+      title = "This may delete the underlying data as well as the metadata.  Drop table '%s'?" % table
     return render('confirm.html', request, dict(url=request.path, title=title))
   elif request.method == 'POST':
-    hql = "DROP TABLE `%s`" % (table,)
+    if is_view:
+      hql = "DROP VIEW `%s`" % (table,)
+    else:
+      hql = "DROP TABLE `%s`" % (table,)
     query_msg = make_beeswax_query(request, hql)
     try:
       return execute_directly(request,
@@ -102,7 +118,7 @@ def drop_table(request, table):
     except BeeswaxException, ex:
       # Note that this state is difficult to get to.
       error_message, log = expand_exception(ex)
-      error = "Failed to remove table.  Error: " + error_message
+      error = "Failed to remove %s.  Error: %s" % (table, error_message)
       raise PopupException(error, title="Beeswax Error", detail=log)
 
 

+ 2 - 0
apps/filebrowser/src/filebrowser/views.py

@@ -788,6 +788,8 @@ def location_to_url(request, location, strict=True):
   Python doesn't seem to have a readily-available URI-comparison
   library, so this is quite hacky.
   """
+  if location is None:
+    return None
   split_path = request.fs.urlsplit(location)
   if strict and not split_path[1]:
     # No netloc, not full url