瀏覽代碼

HUE-1741 [dbquery] bugs

- PostgreSQL now requires a database name.
  This means that get_databases will return the configured database.
- Moved rdbms libs + db selction part into rdbms app.
- Errors now go away when a new query or explain is ran.
- Revamped front end storage management.
Abraham Elmahrek 12 年之前
父節點
當前提交
65ab2b5

+ 6 - 97
apps/beeswax/src/beeswax/server/dbms.py

@@ -16,7 +16,6 @@
 # limitations under the License.
 
 import logging
-import thrift
 import time
 
 from django.core.urlresolvers import reverse
@@ -39,30 +38,13 @@ LOG = logging.getLogger(__name__)
 
 
 def get(user, query_server=None):
+  # Avoid circular dependency
+  from beeswax.server.hive_server2_lib import HiveServerClientCompatible, HiveServerClient
+
   if query_server is None:
     query_server = get_query_server_config()
 
-  if query_server['server_name'] in ('impala', 'beeswax'):
-    # Avoid circular dependency
-    from beeswax.server.hive_server2_lib import HiveServerClientCompatible, HiveServerClient
-
-    return HS2Dbms(HiveServerClientCompatible(HiveServerClient(query_server, user)), QueryHistory.SERVER_TYPE[1][0])
-  elif query_server['server_name'] == 'mysql':
-    from beeswax.server.mysql_lib import MySQLClient
-
-    return Rdbms(MySQLClient(query_server, user), QueryHistory.SERVER_TYPE[2][0])
-  elif query_server['server_name'] in ('postgresql', 'postgresql_psycopg2'):
-    from beeswax.server.postgresql_lib import PostgreSQLClient
-
-    return Rdbms(PostgreSQLClient(query_server, user), QueryHistory.SERVER_TYPE[2][0])
-  elif query_server['server_name'] in ('sqlite', 'sqlite3'):
-    from beeswax.server.sqlite_lib import SQLiteClient
-
-    return Rdbms(SQLiteClient(query_server, user), QueryHistory.SERVER_TYPE[2][0])
-  elif query_server['server_name'] == 'oracle':
-    from beeswax.server.oracle_lib import OracleClient
-
-    return Rdbms(OracleClient(query_server, user), QueryHistory.SERVER_TYPE[2][0])
+  return HS2Dbms(HiveServerClientCompatible(HiveServerClient(query_server, user)), QueryHistory.SERVER_TYPE[1][0])
 
 
 def get_query_server_config(name='beeswax', server=None):
@@ -77,31 +59,6 @@ def get_query_server_config(name='beeswax', server=None):
         'principal': IMPALA_PRINCIPAL.get(),
         'impersonation_enabled': IMPERSONATION_ENABLED.get()
     }
-  elif name == 'rdbms':
-    from rdbms.conf import RDBMS
-
-    if not server or server not in RDBMS:
-      keys = RDBMS.keys()
-      name = keys and keys[0] or None
-    else:
-      name = server
-
-    if name:
-      query_server = {
-        'server_name': RDBMS[name].ENGINE.get().split('.')[-1],
-        'server_host': RDBMS[name].HOST.get(),
-        'server_port': RDBMS[name].PORT.get(),
-        'username': RDBMS[name].USER.get(),
-        'password': RDBMS[name].PASSWORD.get(),
-        'password': RDBMS[name].PASSWORD.get(),
-        'alias': name
-      }
-
-      if RDBMS[name].NAME.get():
-        query_server['name'] = RDBMS[name].NAME.get()
-    else:
-      query_server = {}
-
   else:
     kerberos_principal = hive_site.get_hiveserver2_kerberos_principal(HIVE_SERVER_HOST.get())
 
@@ -128,15 +85,12 @@ class QueryServerException(Exception):
 class NoSuchObjectException: pass
 
 
-class Dbms:
+class HS2Dbms(object):
+  """SQL"""
   def __init__(self, client, server_type):
     self.client = client
     self.server_type = server_type
 
-
-class HS2Dbms(Dbms):
-  """SQL"""
-
   def get_table(self, database, table_name):
     # DB name not supported in SHOW PARTITIONS required in Table
     self.use(database)
@@ -487,51 +441,6 @@ class HS2Dbms(Dbms):
     return ""
 
 
-class Rdbms(Dbms):
-  def get_table(self, database, table_name):
-    return self.client.get_table(database, table_name)
-
-  def get_databases(self):
-    return self.client.get_databases()
-
-  def execute_query(self, query, design):
-    sql_query = query.sql_query
-    query_history = QueryHistory.build(
-      owner=self.client.user,
-      query=sql_query,
-      server_host='%(server_host)s' % self.client.query_server,
-      server_port='%(server_port)d' % self.client.query_server,
-      server_name='%(server_name)s' % self.client.query_server,
-      server_type=self.server_type,
-      last_state=QueryHistory.STATE.available.index,
-      design=design,
-      notify=False,
-      query_type=query.query['type'],
-      statement_number=0
-    )
-    query_history.save()
-
-    LOG.debug("Updated QueryHistory id %s user %s statement_number: %s" % (query_history.id, self.client.user, query_history.statement_number))
-
-    return query_history
-
-  def explain(self, statement):
-    return self.client.explain(statement)
-
-  def use(self, database):
-    self.client.use(database)
-
-  def execute_and_wait(self, query, timeout_sec=30.0):
-    """
-    Run query
-
-    Simply run query irrespective of timeout.
-    Timeout exists to comply with interface.
-    """
-
-    return self.client.query(query)
-
-
 class Table:
   """
   Represents the metadata of a Hive Table.

+ 4 - 7
apps/rdbms/src/rdbms/api.py

@@ -25,12 +25,12 @@ from desktop.context_processors import get_app_name
 
 from beeswax import models as beeswax_models
 from beeswax.forms import SaveForm
-from beeswax.server import dbms
 from beeswax.views import authorized_get_history, safe_get_design
 
 from rdbms import conf
 from rdbms.forms import SQLForm
 from rdbms.design import SQLdesign
+from rdbms.server import dbms
 from rdbms.views import save_design
 
 
@@ -48,8 +48,7 @@ def servers(request):
 
 
 def databases(request, server):
-  app_name = get_app_name(request)
-  query_server = dbms.get_query_server_config(app_name, server)
+  query_server = dbms.get_query_server_config(server)
 
   if not query_server:
     raise Http404
@@ -80,7 +79,7 @@ def execute_query(request, design_id=None):
       design = save_design(request, SaveForm(), form, query_type, design)
 
       query = SQLdesign(form, query_type=query_type)
-      query_server = dbms.get_query_server_config(app_name)
+      query_server = dbms.get_query_server_config(request.POST.get('server'))
       db = dbms.get(request.user, query_server)
       query_history = db.execute_query(query, design)
       query_history.last_state = beeswax_models.QueryHistory.STATE.expired.index
@@ -253,12 +252,10 @@ def design_to_dict(design):
 
 
 def get_query_form(request, design_id=None):
-  app_name = get_app_name(request)
   servers = conf.get_server_choices()
 
   # Get database choices
-  app_name = get_app_name(request)
-  query_server = dbms.get_query_server_config(app_name, request.POST.get('server', None))
+  query_server = dbms.get_query_server_config(request.POST.get('server'))
 
   if not query_server:
     raise RuntimeError(_("Server specified doesn't exist."))

+ 2 - 0
apps/rdbms/src/rdbms/conf.py

@@ -92,6 +92,8 @@ def config_validator(user):
         res.append((RDBMS[server].NAME, _("Database name should not be empty for the SQLite backend. The %s may not work correctly.") % NICE_NAME))
       if engine == 'oracle':
         res.append((RDBMS[server].NAME, _("Database name should not be empty for the Oracle backend. It should be the SID of your database. The %s may not work correctly.") % NICE_NAME))
+      if engine in ('postgresql_psycopg2', 'postgresql'):
+        res.append((RDBMS[server].NAME, _("Database name should not be empty for the PostgreSQL backend. The %s may not work correctly.") % NICE_NAME))
 
   return res
 

+ 16 - 0
apps/rdbms/src/rdbms/models.py

@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.

+ 0 - 0
apps/rdbms/src/rdbms/server/__init__.py


+ 124 - 0
apps/rdbms/src/rdbms/server/dbms.py

@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+
+from beeswax.models import QueryHistory
+
+from rdbms.conf import RDBMS
+
+
+LOG = logging.getLogger(__name__)
+
+
+def get(user, query_server=None):
+  if query_server is None:
+    query_server = get_query_server_config()
+
+  if query_server['server_name'] == 'mysql':
+    from rdbms.server.mysql_lib import MySQLClient
+
+    return Rdbms(MySQLClient(query_server, user), QueryHistory.SERVER_TYPE[2][0])
+  elif query_server['server_name'] in ('postgresql', 'postgresql_psycopg2'):
+    from rdbms.server.postgresql_lib import PostgreSQLClient
+
+    return Rdbms(PostgreSQLClient(query_server, user), QueryHistory.SERVER_TYPE[2][0])
+  elif query_server['server_name'] in ('sqlite', 'sqlite3'):
+    from rdbms.server.sqlite_lib import SQLiteClient
+
+    return Rdbms(SQLiteClient(query_server, user), QueryHistory.SERVER_TYPE[2][0])
+  elif query_server['server_name'] == 'oracle':
+    from rdbms.server.oracle_lib import OracleClient
+
+    return Rdbms(OracleClient(query_server, user), QueryHistory.SERVER_TYPE[2][0])
+
+
+def get_query_server_config(server=None):
+  if not server or server not in RDBMS:
+    keys = RDBMS.keys()
+    name = keys and keys[0] or None
+  else:
+    name = server
+
+  if name:
+    query_server = {
+      'server_name': RDBMS[name].ENGINE.get().split('.')[-1],
+      'server_host': RDBMS[name].HOST.get(),
+      'server_port': RDBMS[name].PORT.get(),
+      'username': RDBMS[name].USER.get(),
+      'password': RDBMS[name].PASSWORD.get(),
+      'password': RDBMS[name].PASSWORD.get(),
+      'alias': name
+    }
+
+    if RDBMS[name].NAME.get():
+      query_server['name'] = RDBMS[name].NAME.get()
+  else:
+    query_server = {}
+
+  LOG.debug("Query Server: %s" % query_server)
+
+  return query_server
+
+
+class Rdbms(object):
+  def __init__(self, client, server_type):
+    self.client = client
+    self.server_type = server_type
+
+  def get_table(self, database, table_name):
+    return self.client.get_table(database, table_name)
+
+  def get_databases(self):
+    return self.client.get_databases()
+
+  def execute_query(self, query, design):
+    sql_query = query.sql_query
+    query_history = QueryHistory.build(
+      owner=self.client.user,
+      query=sql_query,
+      server_host='%(server_host)s' % self.client.query_server,
+      server_port='%(server_port)d' % self.client.query_server,
+      server_name='%(server_name)s' % self.client.query_server,
+      server_type=self.server_type,
+      last_state=QueryHistory.STATE.available.index,
+      design=design,
+      notify=False,
+      query_type=query.query['type'],
+      statement_number=0
+    )
+    query_history.save()
+
+    LOG.debug("Updated QueryHistory id %s user %s statement_number: %s" % (query_history.id, self.client.user, query_history.statement_number))
+
+    return query_history
+
+  def explain(self, statement):
+    return self.client.explain(statement)
+
+  def use(self, database):
+    self.client.use(database)
+
+  def execute_and_wait(self, query, timeout_sec=30.0):
+    """
+    Run query
+
+    Simply run query irrespective of timeout.
+    Timeout exists to comply with interface.
+    """
+
+    return self.client.query(query)

+ 1 - 1
apps/beeswax/src/beeswax/server/mysql_lib.py → apps/rdbms/src/rdbms/server/mysql_lib.py

@@ -32,7 +32,7 @@ if (version < (1,2,1) or (version[:3] == (1, 2, 1) and
     from django.core.exceptions import ImproperlyConfigured
     raise ImproperlyConfigured("MySQLdb-1.2.1p2 or newer is required; you have %s" % Database.__version__)
 
-from beeswax.server.rdbms_base_lib import BaseRDBMSDataTable, BaseRDBMSResult, BaseRDMSClient
+from rdbms.server.rdbms_base_lib import BaseRDBMSDataTable, BaseRDBMSResult, BaseRDMSClient
 
 
 LOG = logging.getLogger(__name__)

+ 1 - 1
apps/beeswax/src/beeswax/server/oracle_lib.py → apps/rdbms/src/rdbms/server/oracle_lib.py

@@ -23,7 +23,7 @@ except ImportError, e:
   from django.core.exceptions import ImproperlyConfigured
   raise ImproperlyConfigured("Error loading cx_Oracle module: %s" % e)
 
-from beeswax.server.rdbms_base_lib import BaseRDBMSDataTable, BaseRDBMSResult, BaseRDMSClient
+from rdbms.server.rdbms_base_lib import BaseRDBMSDataTable, BaseRDBMSResult, BaseRDMSClient
 
 
 LOG = logging.getLogger(__name__)

+ 6 - 15
apps/beeswax/src/beeswax/server/postgresql_lib.py → apps/rdbms/src/rdbms/server/postgresql_lib.py

@@ -23,7 +23,7 @@ except ImportError, e:
     from django.core.exceptions import ImproperlyConfigured
     raise ImproperlyConfigured("Error loading psycopg2 module: %s" % e)
 
-from beeswax.server.rdbms_base_lib import BaseRDBMSDataTable, BaseRDBMSResult, BaseRDMSClient
+from rdbms.server.rdbms_base_lib import BaseRDBMSDataTable, BaseRDBMSResult, BaseRDMSClient
 
 
 LOG = logging.getLogger(__name__)
@@ -52,21 +52,15 @@ class PostgreSQLClient(BaseRDMSClient):
       'user': self.query_server['username'],
       'password': self.query_server['password'],
       'host': self.query_server['server_host'],
-      'port': self.query_server['server_port'] == 0 and 5432 or self.query_server['server_port']
+      'port': self.query_server['server_port'] == 0 and 5432 or self.query_server['server_port'],
+      'database': self.query_server['name']
     }
-    if 'name' in self.query_server:
-      params['database'] = self.query_server['name']
     return params
 
 
   def use(self, database):
-    # No op if a database has been specified.
-    if 'database' in self._conn_params and self._conn_params['database'] != database:
-      raise RuntimeError("Tried to use database %s when %s was specified." % (database, self._conn_params['db']))
-    else:
-      conn_params = self._conn_params
-      conn_params['database'] = database
-      self.connection = Database.connect(**conn_params)
+    # No op since postgresql requires a new connection per database
+    pass
 
 
   def execute_statement(self, statement):
@@ -81,10 +75,7 @@ class PostgreSQLClient(BaseRDMSClient):
 
 
   def get_databases(self):
-    cursor = self.connection.cursor()
-    cursor.execute("SELECT datname FROM pg_database")
-    self.connection.commit()
-    return [row[0] for row in cursor.fetchall()]
+    return [self._conn_params['database']]
 
 
   def get_tables(self, database, table_names):

+ 0 - 0
apps/beeswax/src/beeswax/server/rdbms_base_lib.py → apps/rdbms/src/rdbms/server/rdbms_base_lib.py


+ 1 - 1
apps/beeswax/src/beeswax/server/sqlite_lib.py → apps/rdbms/src/rdbms/server/sqlite_lib.py

@@ -26,7 +26,7 @@ except ImportError, exc:
   from django.core.exceptions import ImproperlyConfigured
   raise ImproperlyConfigured("Error loading either pysqlite2 or sqlite3 modules (tried in that order): %s" % exc)
 
-from beeswax.server.rdbms_base_lib import BaseRDBMSDataTable, BaseRDBMSResult, BaseRDMSClient
+from rdbms.server.rdbms_base_lib import BaseRDBMSDataTable, BaseRDBMSResult, BaseRDMSClient
 
 
 LOG = logging.getLogger(__name__)

+ 19 - 14
apps/rdbms/src/rdbms/templates/execute.mako

@@ -47,9 +47,13 @@ ${ commonheader(_('Query'), app_name, user) | n,unicode }
       <ul class="nav nav-pills hueBreadcrumbBar" id="breadcrumbs">
         <li>
           <div style="display: inline" class="dropdown">
-            ${_('Server')}&nbsp;<a data-toggle="dropdown" href="#"><strong data-bind="text: $root.server"></strong> <i class="fa fa-caret-down"></i></a>
-            <ul data-bind="foreach: Object.keys($root.servers())" class="dropdown-menu">
-              <li data-bind="click: $root.chooseServer, text: $root.servers()[$data]" class="selectable"></li>
+            ${_('Server')}&nbsp;
+            <a data-bind="if: $root.server" data-toggle="dropdown" href="javascript:void(0);">
+              <strong data-bind="text: $root.server().nice_name"></strong>
+              <i class="fa fa-caret-down"></i>
+            </a>
+            <ul data-bind="foreach: $root.servers" class="dropdown-menu">
+              <li data-bind="click: $root.chooseServer, text: nice_name" class="selectable"></li>
             </ul>
           </div>
         </li>
@@ -454,6 +458,18 @@ ${ commonheader(_('Query'), app_name, user) | n,unicode }
     }
   }
 
+  function checkLastDatabase(server, database) {
+    var key = "hueRdbmsLastDatabase-" + server;
+    if (database != $.totalStorage(key)) {
+      $.totalStorage(key, database);
+    }
+  }
+
+  function getLastDatabase(server) {
+    var key = "hueRdbmsLastDatabase-" + server;
+    return $.totalStorage(key);
+  }
+
 
   // Knockout
   viewModel = new RdbmsViewModel();
@@ -468,18 +484,8 @@ ${ commonheader(_('Query'), app_name, user) | n,unicode }
           viewModel.fetchQuery(${design.id});
         }
       % endif
-
-      if (counter++ > 0) {
-        if (value != $.totalStorage("hueRdbmsLastDatabase")) {
-          $.totalStorage("hueRdbmsLastDatabase", value);
-        }
-      }
     }
   })());
-  viewModel.databases.subscribe(function() {
-    viewModel.database($.totalStorage("hueRdbmsLastDatabase"));
-  });
-
   viewModel.query.query.subscribe((function() {
     // First call skipped to avoid reset of hueRdbmsLastDatabase
     var counter = 0;
@@ -489,7 +495,6 @@ ${ commonheader(_('Query'), app_name, user) | n,unicode }
       }
     }
   })());
-
   ko.applyBindings(viewModel);
 
 

+ 56 - 22
apps/rdbms/static/js/rdbms.vm.js

@@ -18,10 +18,10 @@
 function RdbmsViewModel() {
   var self = this;
 
-  self.selectedServer = ko.observable();
-  self.servers = ko.observable({});
+  self.servers = ko.observableArray();
+  self.selectedServer = ko.observable(0);
+  self.databases = ko.observableArray();
   self.selectedDatabase = ko.observable(0);
-  self.databases = ko.observableArray([]);
   self.query = ko.mapping.fromJS({
     'id': -1,
     'query': '',
@@ -38,20 +38,24 @@ function RdbmsViewModel() {
 
   self.server = ko.computed({
     'read': function() {
-      if (self.servers() && self.selectedServer()) {
+      if (self.servers().length > 0) {
         return self.servers()[self.selectedServer()];
       } else{
-        return "";
+        return null;
       }
     },
     'write': function(value) {
-      self.selectedServer(value);
+      var filtered = $.each(self.servers(), function(index, server) {
+        if (server.name() == value) {
+          self.selectedServer(index);
+        }
+      });
     }
   });
 
   self.database = ko.computed({
     'read': function() {
-      if (self.databases) {
+      if (self.databases()) {
         return self.databases()[self.selectedDatabase()];
       } else{
         return "";
@@ -62,9 +66,17 @@ function RdbmsViewModel() {
     }
   });
 
-  self.selectedServer.subscribe(function(value) {
-    self.fetchDatabases();
-  });
+  self.getFirstDatabase = function() {
+    if (self.databases()) {
+      return self.databases()[0];
+    } else {
+      return null;
+    }
+  };
+
+  self.getServerNiceName = function(value) {
+    return self.servers[value];
+  };
 
   self.updateResults = function(results) {
     var rows = [];
@@ -80,15 +92,29 @@ function RdbmsViewModel() {
   };
 
   self.updateServers = function(servers) {
-    self.servers(servers);
-    if (servers) {
-      self.selectedServer(Object.keys(servers)[0]);
+    var newServers = [];
+    $.each(servers, function(name, nice_name) {
+      newServers.push({
+        'name': ko.observable(name),
+        'nice_name': ko.observable(nice_name)
+      });
+    });
+    self.servers(newServers);
+
+    var last = $.totalStorage('hueRdbmsLastServer') || ((newServers[0].length > 0) ? newServers[0].name() : null);
+    if (last) {
+      self.server(last);
     }
   };
 
   self.updateDatabases = function(databases) {
     self.databases(databases);
-    self.selectedDatabase.valueHasMutated();
+
+    var key = 'hueRdbmsLastDatabase-' + self.server().name();
+    var last = $.totalStorage(key) || ((databases.length > 0) ? databases[0] : null);
+    if (last) {
+      self.database(last);
+    }
   };
 
   self.updateQuery = function(design) {
@@ -101,29 +127,37 @@ function RdbmsViewModel() {
   };
 
   self.chooseServer = function(value, e) {
-    self.selectedServer(value);
+    $.each(self.servers(), function(index, server) {
+      if (server.name() == value.name()) {
+        self.selectedServer(index);
+      }
+    });
+    $.totalStorage('hueRdbmsLastServer', self.server().name());
+    self.fetchDatabases();
   };
 
   self.chooseDatabase = function(value, e) {
+    var key = 'hueRdbmsLastDatabase-' + self.server().name();
     self.selectedDatabase(self.databases.indexOf(value));
+    $.totalStorage(key, value);
   };
 
   self.explainQuery = function() {
     var data = ko.mapping.toJS(self.query);
     data.database = self.database();
-    data.server = self.selectedServer();
+    data.server = self.server().name();
     var request = {
       url: '/rdbms/api/explain/',
       dataType: 'json',
       type: 'POST',
       success: function(data) {
+        self.query.errors.removeAll();
         if (data.status === 0) {
           $(document).trigger('explain.query', data);
           self.updateResults(data.results);
           self.query.id(data.design);
           $(document).trigger('explained.query', data);
         } else {
-          self.query.errors.removeAll();
           self.query.errors.push(data.message);
         }
       },
@@ -154,7 +188,7 @@ function RdbmsViewModel() {
     if (self.query.query() && self.query.name()) {
       var data = ko.mapping.toJS(self.query);
       data['desc'] = data['description'];
-      data['server'] = self.selectedServer();
+      data['server'] = self.server().name();
       data['database'] = self.database();
       var url = '/rdbms/api/query/';
       if (self.query.id() && self.query.id() != -1) {
@@ -179,19 +213,19 @@ function RdbmsViewModel() {
   self.executeQuery = function() {
     var data = ko.mapping.toJS(self.query);
     data.database = self.database();
-    data.server = self.selectedServer();
+    data.server = self.server().name();
     var request = {
       url: '/rdbms/api/execute/',
       dataType: 'json',
       type: 'POST',
       success: function(data) {
+        self.query.errors.removeAll();
         if (data.status === 0) {
           $(document).trigger('execute.query', data);
           self.updateResults(data.results);
           self.query.id(data.design);
           $(document).trigger('executed.query', data);
         } else {
-          self.query.errors.removeAll();
           self.query.errors.push(data.message);
         }
       },
@@ -216,9 +250,9 @@ function RdbmsViewModel() {
   };
 
   self.fetchDatabases = function() {
-    if (self.selectedServer()) {
+    if (self.server()) {
       var request = {
-        url: '/rdbms/api/servers/' + self.selectedServer() + '/databases/',
+        url: '/rdbms/api/servers/' + self.server().name() + '/databases/',
         dataType: 'json',
         type: 'GET',
         success: function(data) {