diff --git a/web/pgadmin/feature_tests/connect_to_server_feature_test.py b/web/pgadmin/feature_tests/connect_to_server_feature_test.py
index 3999c6e0..e8de161a 100644
--- a/web/pgadmin/feature_tests/connect_to_server_feature_test.py
+++ b/web/pgadmin/feature_tests/connect_to_server_feature_test.py
@@ -69,7 +69,7 @@ class ConnectsToServerFeatureTest(BaseFeatureTest):
         self.page.find_by_xpath("//button[contains(.,'Save')]").click()
 
     def _tables_node_expandable(self):
-        self.page.toggle_open_tree_item(self.server['name'])
+        self.page.toggle_open_server(self.server['name'])
         self.page.toggle_open_tree_item('Databases')
         self.page.toggle_open_tree_item('acceptance_test_db')
         self.page.toggle_open_tree_item('Schemas')
diff --git a/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py b/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py
index 08fc5556..ac667001 100644
--- a/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py
+++ b/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py
@@ -55,6 +55,7 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
         self._copies_columns()
         self._copies_row_using_keyboard_shortcut()
         self._copies_column_using_keyboard_shortcut()
+        self._copies_rectangular_selection()
         self._shift_resizes_rectangular_selection()
         self._shift_resizes_column_selection()
 
@@ -99,6 +100,19 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
 'Yet-Another-Name'""",
             pyperclip.paste())
 
+    def _copies_rectangular_selection(self):
+        pyperclip.copy("old clipboard contents")
+
+        topLeftCell = self.page.find_by_xpath("//div[contains(@class, 'slick-cell') and contains(., 'Some-Other-Name')]")
+        bottomRightCell = self.page.find_by_xpath("//div[contains(@class, 'slick-cell') and contains(., '14')]")
+
+        ActionChains(self.page.driver).click_and_hold(topLeftCell).move_to_element(bottomRightCell).release(bottomRightCell).perform()
+
+        ActionChains(self.page.driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
+
+        self.assertEqual("""'Some-Other-Name','22'
+'Yet-Another-Name','14'""", pyperclip.paste())
+
     def _shift_resizes_rectangular_selection(self):
         pyperclip.copy("old clipboard contents")
 
diff --git a/web/pgadmin/feature_tests/table_ddl_feature_test.py b/web/pgadmin/feature_tests/table_ddl_feature_test.py
index a29995e6..9fb90d66 100644
--- a/web/pgadmin/feature_tests/table_ddl_feature_test.py
+++ b/web/pgadmin/feature_tests/table_ddl_feature_test.py
@@ -33,7 +33,7 @@ class TableDdlFeatureTest(BaseFeatureTest):
     def runTest(self):
         test_utils.create_table(self.server, "acceptance_test_db", "test_table")
 
-        self.page.toggle_open_tree_item(self.server['name'])
+        self.page.toggle_open_server(self.server['name'])
         self.page.toggle_open_tree_item('Databases')
         self.page.toggle_open_tree_item('acceptance_test_db')
         self.page.toggle_open_tree_item('Schemas')
diff --git a/web/pgadmin/feature_tests/xss_checks_panels_and_query_tool_test.py b/web/pgadmin/feature_tests/xss_checks_panels_and_query_tool_test.py
index 526d4e76..1876dbdf 100644
--- a/web/pgadmin/feature_tests/xss_checks_panels_and_query_tool_test.py
+++ b/web/pgadmin/feature_tests/xss_checks_panels_and_query_tool_test.py
@@ -88,7 +88,7 @@ class CheckForXssFeatureTest(BaseFeatureTest):
         self.page.find_by_xpath("//button[contains(.,'Save')]").click()
 
     def _tables_node_expandable(self):
-        self.page.toggle_open_tree_item(self.server['name'])
+        self.page.toggle_open_server(self.server['name'])
         self.page.toggle_open_tree_item('Databases')
         self.page.toggle_open_tree_item('acceptance_test_db')
         self.page.toggle_open_tree_item('Schemas')
diff --git a/web/pgadmin/feature_tests/xss_checks_pgadmin_debugger_test.py b/web/pgadmin/feature_tests/xss_checks_pgadmin_debugger_test.py
index 17bc7bf5..959b2c19 100644
--- a/web/pgadmin/feature_tests/xss_checks_pgadmin_debugger_test.py
+++ b/web/pgadmin/feature_tests/xss_checks_pgadmin_debugger_test.py
@@ -58,7 +58,7 @@ class CheckDebuggerForXssFeatureTest(BaseFeatureTest):
         self.page.find_by_xpath("//button[contains(.,'Save')]").click()
 
     def _function_node_expandable(self):
-        self.page.toggle_open_tree_item(self.server['name'])
+        self.page.toggle_open_server(self.server['name'])
         self.page.toggle_open_tree_item('Databases')
         self.page.toggle_open_tree_item('postgres')
         self.page.toggle_open_tree_item('Schemas')
diff --git a/web/pgadmin/static/js/selection/column_selector.js b/web/pgadmin/static/js/selection/column_selector.js
index 2923a796..b03c8cf3 100644
--- a/web/pgadmin/static/js/selection/column_selector.js
+++ b/web/pgadmin/static/js/selection/column_selector.js
@@ -52,7 +52,7 @@ define(['jquery', 'sources/selection/range_selection_helper', 'slickgrid'], func
       if (rangeSelectionHelper.isRangeSelected(ranges, columnRange)) {
         newRanges = rangeSelectionHelper.removeRange(ranges, columnRange);
       } else {
-        if (rangeSelectionHelper.areAllRangesColumns(ranges, grid)) {
+        if (rangeSelectionHelper.areAllRangesSingleColumns(ranges, grid)) {
           newRanges = rangeSelectionHelper.addRange(ranges, columnRange);
         } else {
           newRanges = [columnRange];
diff --git a/web/pgadmin/static/js/selection/range_selection_helper.js b/web/pgadmin/static/js/selection/range_selection_helper.js
index 6c69c390..3d121f4f 100644
--- a/web/pgadmin/static/js/selection/range_selection_helper.js
+++ b/web/pgadmin/static/js/selection/range_selection_helper.js
@@ -23,14 +23,13 @@ define(['slickgrid'], function () {
     return ranges;
   };
 
-  var areAllRangesRows = function (ranges, grid) {
+  var areAllRangesSingleRows = function (ranges, grid) {
     return _.every(ranges, function (range) {
-      return range.fromRow == range.toRow &&
-        range.fromCell == 1 && range.toCell == grid.getColumns().length - 1
+      return range.fromRow == range.toRow && rangeHasCompleteRows(grid, range);
     })
   };
 
-  var areAllRangesColumns = function (ranges, grid) {
+  var areAllRangesSingleColumns = function (ranges, grid) {
     return _.every(ranges, function (range) {
       return range.fromCell == range.toCell &&
         range.fromRow == 0 && range.toRow == grid.getDataLength() - 1
@@ -39,7 +38,7 @@ define(['slickgrid'], function () {
 
   var rangeForRow = function (grid, rowId) {
     var columnDefinitions = grid.getColumns();
-    if(isFirstColumnData(columnDefinitions)) {
+    if (isFirstColumnData(columnDefinitions)) {
       return new Slick.Range(rowId, 0, rowId, grid.getColumns().length - 1);
     }
     return new Slick.Range(rowId, 1, rowId, grid.getColumns().length - 1);
@@ -63,6 +62,28 @@ define(['slickgrid'], function () {
     return !_.isUndefined(columnDefinitions[0].pos);
   };
 
+  var areAllRangesCompleteRows = function (grid, ranges) {
+    return _.every(ranges, function (range) {
+      return rangeHasCompleteRows(grid, range);
+    })
+  };
+
+  var getIndexesOfCompleteRows = function (grid, ranges) {
+    var indexArray = [];
+    ranges.forEach(function (range) {
+      if (rangeHasCompleteRows(grid, range))
+        indexArray = _.union(indexArray, _.range(range.fromRow, range.toRow + 1));
+    });
+
+    return indexArray;
+  };
+
+  function rangeHasCompleteRows(grid, range) {
+    var firstDataColumn = isFirstColumnData(grid.getColumns()) ? 0 : 1;
+    return range.fromCell == firstDataColumn &&
+      range.toCell == grid.getColumns().length - 1;
+  }
+
   function selectAll(grid) {
     var range = getRangeOfWholeGrid(grid);
     var selectionModel = grid.getSelectionModel();
@@ -74,13 +95,15 @@ define(['slickgrid'], function () {
     addRange: addRange,
     removeRange: removeRange,
     isRangeSelected: isRangeSelected,
-    areAllRangesRows: areAllRangesRows,
-    areAllRangesColumns: areAllRangesColumns,
+    areAllRangesSingleRows: areAllRangesSingleRows,
+    areAllRangesSingleColumns: areAllRangesSingleColumns,
+    areAllRangesCompleteRows: areAllRangesCompleteRows,
     rangeForRow: rangeForRow,
     rangeForColumn: rangeForColumn,
     isEntireGridSelected: isEntireGridSelected,
     getRangeOfWholeGrid: getRangeOfWholeGrid,
     isFirstColumnData: isFirstColumnData,
     selectAll: selectAll,
+    getIndexesOfCompleteRows: getIndexesOfCompleteRows,
   }
 });
\ No newline at end of file
diff --git a/web/pgadmin/static/js/selection/row_selector.js b/web/pgadmin/static/js/selection/row_selector.js
index 8124b5cb..9e539353 100644
--- a/web/pgadmin/static/js/selection/row_selector.js
+++ b/web/pgadmin/static/js/selection/row_selector.js
@@ -44,7 +44,7 @@ define(['jquery', 'sources/selection/range_selection_helper', 'slickgrid'], func
       if (rangeSelectionHelper.isRangeSelected(ranges, rowRange)) {
         newRanges = rangeSelectionHelper.removeRange(ranges, rowRange);
       } else {
-        if (rangeSelectionHelper.areAllRangesRows(ranges, grid)) {
+        if (rangeSelectionHelper.areAllRangesSingleRows(ranges, grid)) {
           newRanges = rangeSelectionHelper.addRange(ranges, rowRange);
         } else {
           newRanges = [rowRange];
diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
index 1bf919f9..d142e2ee 100644
--- a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
+++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
@@ -675,22 +675,22 @@ define(
                rows_for_stage = {}, selected_rows_list = [];
 
                // Only if entire row(s) are selected via check box
-               if(_.has(this.selection, 'getSelectedRows')) {
-                 selected_rows_list = this.selection.getSelectedRows();
+               if(RangeSelectionHelper.areAllRangesCompleteRows(grid,this.selection.getSelectedRanges())) {
+                 selected_rows_list = RangeSelectionHelper.getIndexesOfCompleteRows(grid,this.selection.getSelectedRanges());
                  // We will map selected row primary key name with position
                  // For each Primary key
-                 _.each(primary_key_list, function(p) {
+                 _.each(primary_key_list, function(primaryKey) {
                    // For each columns search primary key position
-                   _.each(_columns, function(c) {
-                      if(c.name == p) {
-                        _tmp_keys.push(c.pos);
+                   _.each(_columns, function(column) {
+                      if(column.name == primaryKey) {
+                        _tmp_keys.push(column.pos);
                       }
                    });
                  });
                  // Now assign mapped temp PK to PK
                  primary_key_list =  _tmp_keys;
 
-                 // Check if selected is new row ?
+                 // Check if selected is new row
                  // Allow to delete if yes
                  var cell_el = this.grid.getCellNode(selected_rows_list[0], 0),
                   parent_el = $(cell_el).parent(),
diff --git a/web/regression/feature_utils/pgadmin_page.py b/web/regression/feature_utils/pgadmin_page.py
index b1dfa182..c9afdddd 100644
--- a/web/regression/feature_utils/pgadmin_page.py
+++ b/web/regression/feature_utils/pgadmin_page.py
@@ -82,6 +82,31 @@ class PgadminPage:
     def toggle_open_tree_item(self, tree_item_text):
         self.find_by_xpath("//*[@id='tree']//*[.='" + tree_item_text + "']/../*[@class='aciTreeButton']").click()
 
+    def toggle_open_server(self, tree_item_text):
+        def check_for_password_dialog_or_tree_open(driver):
+            try:
+                dialog = driver.find_element_by_id("frmPassword")
+            except WebDriverException:
+                dialog = None
+
+            try:
+                database_node = driver.find_element_by_xpath("//*[@id='tree']//*[.='Databases']/../*[@class='aciTreeButton']")
+            except WebDriverException:
+                database_node = None
+
+            return dialog is not None or database_node is not None
+
+        self.toggle_open_tree_item(tree_item_text)
+        self._wait_for("Waiting for password dialog or tree to open", check_for_password_dialog_or_tree_open)
+
+        try:
+            self.driver.find_element_by_id("frmPassword")
+            # Enter password here if needed
+            self.click_modal_ok()
+        except WebDriverException:
+            return
+
+
     def find_by_xpath(self, xpath):
         return self.wait_for_element(lambda driver: driver.find_element_by_xpath(xpath))
 
diff --git a/web/regression/javascript/selection/column_selector_spec.js b/web/regression/javascript/selection/column_selector_spec.js
index 4526b602..2b0c645f 100644
--- a/web/regression/javascript/selection/column_selector_spec.js
+++ b/web/regression/javascript/selection/column_selector_spec.js
@@ -59,7 +59,7 @@ define(
             selectable: false,
             pos: 3
           }
-        ]
+        ];
       });
 
       describe("when a column is not selectable", function () {
diff --git a/web/regression/javascript/selection/grid_selector_spec.js b/web/regression/javascript/selection/grid_selector_spec.js
index 1c2f7898..05d1208d 100644
--- a/web/regression/javascript/selection/grid_selector_spec.js
+++ b/web/regression/javascript/selection/grid_selector_spec.js
@@ -13,10 +13,12 @@ define(["jquery",
         container.height(9999);
         columns = [{
           id: '1',
-          name: 'some-column-name'
+          name: 'some-column-name',
+          pos: 0
         }, {
           id: '2',
-          name: 'second column'
+          name: 'second column',
+          pos: 1
         }];
 
         gridSelector = new GridSelector();
diff --git a/web/regression/javascript/selection/range_selection_helper_spec.js b/web/regression/javascript/selection/range_selection_helper_spec.js
new file mode 100644
index 00000000..cc81189b
--- /dev/null
+++ b/web/regression/javascript/selection/range_selection_helper_spec.js
@@ -0,0 +1,93 @@
+define([
+  'jquery',
+  'slickgrid/slick.grid',
+  'sources/selection/range_selection_helper'
+], function ($, SlickGrid, RangeSelectionHelper) {
+  describe("RangeSelectionHelper utility functions", function () {
+    var grid;
+    beforeEach(function () {
+      var container, data, columns, options;
+      container = $("<div></div>");
+      container.height(9999);
+
+      columns = [{
+        id: '1',
+        name: 'some-column-name',
+        pos: 0
+      }, {
+        id: 'second-column-id',
+        name: 'second column',
+        pos: 1
+      }];
+
+      data = [];
+      for (var i = 0; i < 10; i++) {
+        data.push({'some-column-name': 'some-value-' + i, 'second column': 'second value ' + i});
+      }
+
+      grid = new SlickGrid(container, data, columns, options);
+      grid.invalidate();
+    });
+
+    describe("#getIndexesOfCompleteRows", function () {
+      describe("when selected ranges are not rows", function () {
+        it("returns an empty array", function () {
+          var rowlessRanges = [RangeSelectionHelper.rangeForColumn(grid, 1)];
+
+          expect(RangeSelectionHelper.getIndexesOfCompleteRows(grid, rowlessRanges))
+            .toEqual([]);
+        });
+      });
+      describe("when selected range", function () {
+        describe("is a single row", function () {
+          it("returns an array with one index", function () {
+            var singleRowRange = [RangeSelectionHelper.rangeForRow(grid, 1)];
+
+            expect(RangeSelectionHelper.getIndexesOfCompleteRows(grid, singleRowRange))
+              .toEqual([1]);
+          });
+        });
+
+        describe("is multiple rows", function () {
+          it("returns an array of each row's index", function () {
+            var multipleRowRange = [
+              RangeSelectionHelper.rangeForRow(grid, 0),
+              RangeSelectionHelper.rangeForRow(grid, 3),
+              RangeSelectionHelper.rangeForRow(grid, 2),
+            ];
+
+            var indexesOfCompleteRows = RangeSelectionHelper.getIndexesOfCompleteRows(grid, multipleRowRange);
+            indexesOfCompleteRows.sort();
+            expect(indexesOfCompleteRows).toEqual([0, 2, 3]);
+          });
+        });
+
+        describe("contains a multi row selection", function () {
+          it("returns an array of each individual row's index", function () {
+            var multipleRowRange = [
+              new Slick.Range(3, 0, 5, 1)
+            ];
+
+            var indexesOfCompleteRows = RangeSelectionHelper.getIndexesOfCompleteRows(grid, multipleRowRange);
+            indexesOfCompleteRows.sort();
+            expect(indexesOfCompleteRows).toEqual([3, 4, 5]);
+          });
+
+          describe("and also contains a selection that is not a row", function () {
+            it("returns an array of only the complete rows' indexes", function () {
+              var multipleRowRange = [
+                new Slick.Range(8, 1, 9, 1),
+                new Slick.Range(3, 0, 5, 1)
+              ];
+
+              var indexesOfCompleteRows = RangeSelectionHelper.getIndexesOfCompleteRows(grid, multipleRowRange);
+              indexesOfCompleteRows.sort();
+              expect(indexesOfCompleteRows).toEqual([3, 4, 5]);
+            });
+          });
+        });
+      });
+    });
+  });
+
+});
diff --git a/web/regression/javascript/test-main.js b/web/regression/javascript/test-main.js
index b2db316d..1cabbe58 100644
--- a/web/regression/javascript/test-main.js
+++ b/web/regression/javascript/test-main.js
@@ -65,6 +65,24 @@ require.config({
       ],
       "exports": 'window.Slick.RowSelectionModel'
     },
+    "slickgrid/slick.cellrangedecorator": {
+      "deps": [
+        "jquery"
+      ],
+      "exports": 'window.Slick.RowRangeDecorator'
+    },
+    "slickgrid/slick.cellrangeselector": {
+      "deps": [
+        "jquery", "slickgrid/slick.cellrangedecorator"
+      ],
+      "exports": 'window.Slick.CellRangeSelector'
+    },
+    "slickgrid/slick.cellselectionmodel": {
+      "deps": [
+        "jquery", "slickgrid/slick.cellrangeselector"
+      ],
+      "exports": 'window.Slick.CellSelectionModel'
+    },
     "backbone": {
       "deps": ['underscore', 'jquery'],
       "exports": 'Backbone'
diff --git a/web/regression/requirements.txt b/web/regression/requirements.txt
index 6babf987..5959a183 100644
--- a/web/regression/requirements.txt
+++ b/web/regression/requirements.txt
@@ -1,5 +1,5 @@
 pyperclip~=1.5.27
-selenium==3.3.1
+selenium==3.3.3
 testscenarios==0.5.0
 testtools==2.0.0
 traceback2==1.4.0
