Forráskód Böngészése

[impala] Support Data sample even without metastore app permissions

Added an API in Beeswax
Impala does not support `DB.TABLE` syntax
New query button should work with impala only
Romain Rigaux 11 éve
szülő
commit
af4b0f9

+ 10 - 0
apps/beeswax/src/beeswax/api.py

@@ -41,6 +41,7 @@ from beeswax.views import authorized_get_design, authorized_get_query_history, m
                           safe_get_design, save_design, massage_columns_for_json, _get_query_handle_and_state,\
                           _parse_out_hadoop_jobs
 from desktop.lib.i18n import force_unicode
+from desktop.lib.exceptions_renderable import PopupException
 
 
 LOG = logging.getLogger(__name__)
@@ -485,6 +486,15 @@ def query_history_to_dict(request, query_history):
   return query_history_dict
 
 
+# Proxy API for Metastore App
+def describe_table(request, database, table):
+  try:
+    from metastore.views import describe_table
+    return describe_table(request, database, table)
+  except Exception, e:
+    raise PopupException(_('Problem accessing table metadata'), detail=e)
+
+
 def get_query_form(request):
   # Get database choices
   query_server = dbms.get_query_server_config(get_app_name(request))

+ 1 - 1
apps/beeswax/src/beeswax/server/dbms.py

@@ -151,7 +151,7 @@ class HiveServer2Dbms(object):
     """No samples if it's a view (HUE-526)"""
     if not table.is_view:
       limit = min(100, BROWSE_PARTITIONED_TABLE_LIMIT.get())
-      hql = "SELECT * FROM `%s.%s` LIMIT %s" % (database, table.name, limit)
+      hql = "SELECT * FROM %s.%s LIMIT %s" % (database, table.name, limit)
       query = hql_query(hql)
       handle = self.execute_and_wait(query, timeout_sec=5.0)
 

+ 5 - 4
apps/beeswax/src/beeswax/templates/execute.mako

@@ -1004,7 +1004,7 @@ $(document).ready(function () {
       $(data.split(" ")).each(function (cnt, table) {
         if ($.trim(table) != "") {
           var _table = $("<li>");
-          _table.html("<a href='javascript:void(0)' class='pull-right'><i class='fa fa-list' title='" + "${ _('Preview Sample data') }" + "' style='margin-left:5px'></i></a><a href='/metastore/table/" + viewModel.database() + "/" + table + "' target='_blank' class='pull-right hide'><i class='fa fa-eye' title='" + "${ _('View in Metastore Browser') }" + "'></i></a><a href='javascript:void(0)' title='" + table + "'><i class='fa fa-table'></i> " + table + "</a><ul class='unstyled'></ul>");
+          _table.html("<a href='javascript:void(0)' class='pull-right'><i class='fa fa-list' title='" + "${ _('Preview Sample data') }" + "' style='margin-left:5px'></i></a><a href='/${ app_name }/api/table/" + viewModel.database() + "/" + table + "' target='_blank' class='pull-right hide'><i class='fa fa-eye' title='" + "${ _('View in Metastore Browser') }" + "'></i></a><a href='javascript:void(0)' title='" + table + "'><i class='fa fa-table'></i> " + table + "</a><ul class='unstyled'></ul>");
           _table.data("table", table).attr("id", "navigatorTables_" + table);
           _table.find("a:eq(2)").on("click", function () {
             _table.find(".fa-table").removeClass("fa-table").addClass("fa-spin").addClass("fa-spinner");
@@ -1030,12 +1030,13 @@ $(document).ready(function () {
             codeMirror.focus();
           });
           _table.find("a:eq(0)").on("click", function () {
+            var tableUrl = "/${ app_name }/api/table/" + viewModel.database() + "/" + _table.data("table");
             $("#navigatorQuicklook").find(".tableName").text(table);
-            $("#navigatorQuicklook").find(".tableLink").attr("href", "/metastore/table/" + viewModel.database() + "/" + _table.data("table"));
+            $("#navigatorQuicklook").find(".tableLink").attr("href", tableUrl);
             $("#navigatorQuicklook").find(".sample").empty("");
             $("#navigatorQuicklook").attr("style", "width: " + ($(window).width() - 120) + "px;margin-left:-" + (($(window).width() - 80) / 2) + "px!important;");
             $.ajax({
-              url: "/metastore/table/" + viewModel.database() + "/" + _table.data("table"),
+              url: tableUrl,
               data: {"sample": true},
               beforeSend: function (xhr) {
                 xhr.setRequestHeader("X-Requested-With", "Hue");
@@ -1879,7 +1880,7 @@ function tryCancelQuery() {
 
 function createNewQuery() {
   $.totalStorage("${app_name}_temp_query", null);
-  location.href="${ url('beeswax:execute_query') }";
+  location.href="${ url(app_name + ':execute_query') }";
 }
 
 function checkLastDatabase(server, database) {

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

@@ -1409,6 +1409,16 @@ for x in sys.stdin:
     SavedQuery.objects.filter(name='my query history').delete()
 
 
+  def test_get_table_sample(self):
+    client = make_logged_in_client()
+
+    resp = client.get(reverse('beeswax:describe_table', kwargs={'database': 'default', 'table': 'test'}) + '?sample=true')
+
+    assert_equal(resp.status_code, 200)
+    assert_true('<th>foo</th>' in resp.content, resp.content)
+    assert_true([0, '0x0'] in resp.context['sample'], resp.context['sample'])
+
+
 def test_import_gzip_reader():
   """Test the gzip reader in create table"""
   # Make gzipped data

+ 2 - 0
apps/beeswax/src/beeswax/urls.py

@@ -69,4 +69,6 @@ urlpatterns += patterns(
   url(r'^api/query/(?P<query_history_id>\d+)/close/?$', 'close_operation', name='api_close_operation'),
   url(r'^api/query/(?P<query_history_id>\d+)/results/save$', 'save_results', name='api_save_results'),
   url(r'^api/watch/json/(?P<id>\d+)$', 'watch_query_refresh_json', name='api_watch_query_refresh_json'),
+
+  url(r'^api/table/(?P<database>\w+)/(?P<table>\w+)$', 'describe_table', name='describe_table'),
 )

+ 3 - 4
apps/metastore/src/metastore/templates/sample.mako

@@ -15,22 +15,21 @@
 ## limitations under the License.
 <%!
 from desktop.lib.i18n import smart_unicode
-from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
 %>
 
 % if sample is not None:
   % if error_message:
     <div class="alert alert-error">
-      <h3>${_('Error!')}</h3>
-      <pre>${error_message | h}</pre>
+      <h3>${ _('Error!') }</h3>
+      <pre>${ error_message | h }</pre>
     </div>
   % else:
   <table class="table table-striped table-condensed sampleTable">
     <thead>
       <tr>
         % for col in table.cols:
-          <th>${col.name}</th>
+          <th>${ col.name }</th>
         % endfor
       </tr>
     </thead>

+ 10 - 3
apps/metastore/src/metastore/views.py

@@ -24,17 +24,20 @@ from django.utils.functional import wraps
 from django.utils.translation import ugettext as _
 from django.core.urlresolvers import reverse
 
+from desktop.context_processors import get_app_name
 from desktop.lib.django_util import render
 from desktop.lib.exceptions_renderable import PopupException
 
 from beeswax.design import hql_query
 from beeswax.models import SavedQuery, MetaInstall
 from beeswax.server import dbms
-
+from beeswax.server.dbms import get_query_server_config
 from metastore.forms import LoadDataForm, DbForm
 from metastore.settings import DJANGO_APPS
 
+
 LOG = logging.getLogger(__name__)
+
 SAVE_RESULTS_CTAS_TIMEOUT = 300         # seconds
 
 
@@ -131,7 +134,10 @@ def show_tables(request, database=None):
 
 
 def describe_table(request, database, table):
-  db = dbms.get(request.user)
+  app_name = get_app_name(request)
+  query_server = get_query_server_config(app_name)
+  db = dbms.get(request.user, query_server)
+
   error_message = ''
   table_data = ''
 
@@ -139,8 +145,9 @@ def describe_table(request, database, table):
     table = db.get_table(database, table)
   except Exception, e:
     raise PopupException(_("Hive Error"), detail=e)
+
   partitions = None
-  if table.partition_keys:
+  if app_name != 'impala' and table.partition_keys:
     partitions = db.get_partitions(database, table, max_parts=None)
 
   try: