Re: [GSoC][New Feature] Editable and Read-only Columns

Yosry Muhammad <[email protected]>
Newsgroups gmane.comp.db.postgresql.pgadmin.devel
Message-ID <CAFSMqn8CRKP=RrLzdko4n4RqAKHZ_cD2OeNGkhW9ukQe0tcUYA@mail.gmail.com>
Hi Dave,

I am now using the same versions of Python, Chrome and chromedriver. The
tests still pass every time. Are you sure you applied the latest patch? I
re-created the patch as a sanity check, please find it attached.

I tried running the specific test a lot of times, passes every time. The
only difference is that I am running Ubuntu, otherwise, everything is the
same.


On Fri, Aug 23, 2019 at 5:00 PM Dave Page <[email protected]> wrote:

> Hi
>
> I've run it again 4 more times and it fails consistently for me. I'm
> running on macOS 10.14.5 with Chrome 76.0.3809.100.
>
> On Fri, Aug 23, 2019 at 3:17 PM Yosry Muhammad <[email protected]> wrote:
>
>> Hi Dave,
>>
>> The tests pass on my device normally. I am using Python 3.6 on Ubuntu. I
>> have ran all tests using "make check" and they all succeeded. I also ran
>> feature_tests/query_tool_journey_test.py multiple times on its own using
>> "cd web && python regression/runtests.py --pkg feature_tests --modules
>> query_tool_journey_test" and it passed successfully. Could you try again?
>>
>> Generally, I have found that StaleElementReferenceException occurs
>> intermittently on various feature tests.
>>
>> On Fri, Aug 23, 2019 at 3:46 PM Dave Page <[email protected]> wrote:
>>
>>> Thanks. Unfortunately this is failing the tests:
>>>
>>> ======================================================================
>>> ERROR: runTest
>>> (pgadmin.feature_tests.query_tool_journey_test.QueryToolJourneyTest)
>>> Tests the path through the query tool
>>> ----------------------------------------------------------------------
>>> Traceback (most recent call last):
>>>   File
>>> "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/query_tool_journey_test.py",
>>> line 85, in runTest
>>>     self._test_updatable_resultset()
>>>   File
>>> "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/query_tool_journey_test.py",
>>> line 254, in _test_updatable_resultset
>>>     discard_changes_modal=True)
>>>   File
>>> "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/query_tool_journey_test.py",
>>> line 417, in _check_query_results_editable
>>>     is_editable = self._check_cell_editable(column_index)
>>>   File
>>> "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/query_tool_journey_test.py",
>>> line 430, in _check_cell_editable
>>>     cell_value = int(cell_el.text)
>>>   File
>>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python3.7/site-packages/selenium/webdriver/remote/webelement.py",
>>> line 76, in text
>>>     return self._execute(Command.GET_ELEMENT_TEXT)['value']
>>>   File
>>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python3.7/site-packages/selenium/webdriver/remote/webelement.py",
>>> line 628, in _execute
>>>     return self._parent.execute(command, params)
>>>   File
>>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py",
>>> line 312, in execute
>>>     self.error_handler.check_response(response)
>>>   File
>>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py",
>>> line 242, in check_response
>>>     raise exception_class(message, screen, stacktrace)
>>> selenium.common.exceptions.StaleElementReferenceException: Message:
>>> stale element reference: element is not attached to the page document
>>>   (Session info: chrome=76.0.3809.100)
>>>   (Driver info: chromedriver=76.0.3809.126
>>> (d80a294506b4c9d18015e755cee48f953ddc3f2f-refs/branch-heads/3809@{#1024}),platform=Mac
>>> OS X 10.14.5 x86_64)
>>>
>>> Without the patch, the tests pass.
>>>
>>>
>>> On Fri, Aug 23, 2019 at 1:10 PM Yosry Muhammad <[email protected]>
>>> wrote:
>>>
>>>> Please find an updated patch attached.
>>>>
>>>> On Fri, Aug 23, 2019 at 1:22 PM Dave Page <[email protected]> wrote:
>>>>
>>>>> Except it now doesn't apply as the async connection/rendering patch
>>>>> was in the queue right ahead of it :-(.
>>>>>
>>>>> Can I get a rebased patch please?
>>>>>
>>>>> On Fri, Aug 23, 2019 at 11:57 AM Aditya Toshniwal <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Excellent !! Looks good to me.
>>>>>>
>>>>>> On Fri, Aug 23, 2019 at 2:23 PM Yosry Muhammad <[email protected]>
>>>>>> wrote:
>>>>>>
>>>>>>>  I updated the patch for backwards compatibility anyway.
>>>>>>>
>>>>>>> On Fri, Aug 23, 2019 at 10:45 AM Dave Page <[email protected]>
>>>>>>> wrote:
>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> On Fri, Aug 23, 2019 at 9:43 AM Yosry Muhammad <[email protected]>
>>>>>>>> wrote:
>>>>>>>>
>>>>>>>>> Hi Aditya,
>>>>>>>>>
>>>>>>>>> On Fri, Aug 23, 2019 at 7:33 AM Aditya Toshniwal <
>>>>>>>>> [email protected]> wrote:
>>>>>>>>>
>>>>>>>>>> Hi Yosry,
>>>>>>>>>>
>>>>>>>>>> The previously mentioned issues seems to be fixed. Below are few
>>>>>>>>>> issues:
>>>>>>>>>> 1) On Python 2.7, I get below error when opening query tool:
>>>>>>>>>> 2019-08-23 10:49:09,329: ERROR flask.app: Object of type buffer
>>>>>>>>>> is not JSON serializable
>>>>>>>>>> Traceback (most recent call last):
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/venv/pypg27/lib/python2.7/site-packages/flask/app.py",
>>>>>>>>>> line 1813, in full_dispatch_request
>>>>>>>>>>     rv = self.dispatch_request()
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/venv/pypg27/lib/python2.7/site-packages/flask/app.py",
>>>>>>>>>> line 1799, in dispatch_request
>>>>>>>>>>     return self.view_functions[rule.endpoint](**req.view_args)
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/venv/pypg27/lib/python2.7/site-packages/flask_login/utils.py",
>>>>>>>>>> line 261, in decorated_view
>>>>>>>>>>     return func(*args, **kwargs)
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/projects/pgadmin4/web/pgadmin/tools/sqleditor/__init__.py",
>>>>>>>>>> line 1544, in get_query_history
>>>>>>>>>>     return QueryHistory.get(current_user.id, trans_obj.sid,
>>>>>>>>>> conn.db)
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/projects/pgadmin4/web/pgadmin/tools/sqleditor/utils/query_history.py",
>>>>>>>>>> line 21, in get
>>>>>>>>>>     'result': [rec.query_info for rec in result]
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/projects/pgadmin4/web/pgadmin/utils/ajax.py", line
>>>>>>>>>> 75, in make_json_response
>>>>>>>>>>     separators=(',', ':'), encoding=encoding),
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/venv/pypg27/lib/python2.7/site-packages/simplejson/__init__.py",
>>>>>>>>>> line 399, in dumps
>>>>>>>>>>     **kw).encode(obj)
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/venv/pypg27/lib/python2.7/site-packages/simplejson/encoder.py",
>>>>>>>>>> line 296, in encode
>>>>>>>>>>     chunks = self.iterencode(o, _one_shot=True)
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/venv/pypg27/lib/python2.7/site-packages/simplejson/encoder.py",
>>>>>>>>>> line 378, in iterencode
>>>>>>>>>>     return _iterencode(o, 0)
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/projects/pgadmin4/web/pgadmin/utils/ajax.py", line
>>>>>>>>>> 30, in default
>>>>>>>>>>     return json.JSONEncoder.default(self, obj)
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/venv/pypg27/lib/python2.7/site-packages/simplejson/encoder.py",
>>>>>>>>>> line 273, in default
>>>>>>>>>>     o.__class__.__name__)
>>>>>>>>>> TypeError: Object of type buffer is not JSON serializable
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> This error exists on the master branch on Python 2.7, it is not
>>>>>>>>> caused by the patch. It is also not a regression of my previous Query
>>>>>>>>> History Enhancement patch, I checked.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> 2) The patch is not compatible with older pyscopg2 (2.7.7). I get
>>>>>>>>>> below error in View/Edit data.
>>>>>>>>>> [image: Screenshot 2019-08-23 at 10.53.30.png]
>>>>>>>>>> 2019-08-23 10:53:12,020: ERROR flask.app: 'table_column'
>>>>>>>>>> Traceback (most recent call last):
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/venv/pypg35/lib/python3.5/site-packages/flask/app.py",
>>>>>>>>>> line 1813, in full_dispatch_request
>>>>>>>>>>     rv = self.dispatch_request()
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/venv/pypg35/lib/python3.5/site-packages/flask/app.py",
>>>>>>>>>> line 1799, in dispatch_request
>>>>>>>>>>     return self.view_functions[rule.endpoint](**req.view_args)
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/venv/pypg35/lib/python3.5/site-packages/flask_login/utils.py",
>>>>>>>>>> line 261, in decorated_view
>>>>>>>>>>     return func(*args, **kwargs)
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/projects/pgadmin4/web/pgadmin/tools/sqleditor/__init__.py",
>>>>>>>>>> line 435, in poll
>>>>>>>>>>     columns = trans_obj.get_columns_types(conn)
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/projects/pgadmin4/web/pgadmin/tools/sqleditor/command.py",
>>>>>>>>>> line 688, in get_columns_types
>>>>>>>>>>     table_oid=table_oid)
>>>>>>>>>>   File
>>>>>>>>>> "/Users/adityatoshniwal/projects/pgadmin4/web/pgadmin/tools/sqleditor/utils/get_column_types.py",
>>>>>>>>>> line 38, in get_columns_types
>>>>>>>>>>     if row['oid'] == col['table_column']:
>>>>>>>>>> KeyError: 'table_column'
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> I recall Dave mentioning that it is okay to use psycopg 2.8+
>>>>>>>>> features and that it was a requirement of pgAdmin 4 now (clearly mentioned
>>>>>>>>> in requirements.txt too).
>>>>>>>>>
>>>>>>>>
>>>>>>>> I did - then we had the whole table_oid issue on Debian/Ubuntu :-(
>>>>>>>>
>>>>>>>>
>>>>>>>>> However, I updated the patch for backwards compatibility. Please
>>>>>>>>> find an updated patch attached.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> *Yosry Muhammad Yosry*
>>>>>>>>>
>>>>>>>>> Computer Engineering student,
>>>>>>>>> The Faculty of Engineering,
>>>>>>>>> Cairo University (2021).
>>>>>>>>> Class representative of CMP 2021.
>>>>>>>>> https://www.linkedin.com/in/yosrym93/
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> Dave Page
>>>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>>>> Twitter: @pgsnake
>>>>>>>>
>>>>>>>> EnterpriseDB UK: http://www.enterprisedb.com
>>>>>>>> The Enterprise PostgreSQL Company
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> *Yosry Muhammad Yosry*
>>>>>>>
>>>>>>> Computer Engineering student,
>>>>>>> The Faculty of Engineering,
>>>>>>> Cairo University (2021).
>>>>>>> Class representative of CMP 2021.
>>>>>>> https://www.linkedin.com/in/yosrym93/
>>>>>>>
>>>>>>
>>>>>>
>>>>>> --
>>>>>> Thanks and Regards,
>>>>>> Aditya Toshniwal
>>>>>> Software Engineer | EnterpriseDB India | Pune
>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Dave Page
>>>>> Blog: http://pgsnake.blogspot.com
>>>>> Twitter: @pgsnake
>>>>>
>>>>> EnterpriseDB UK: http://www.enterprisedb.com
>>>>> The Enterprise PostgreSQL Company
>>>>>
>>>>
>>>>
>>>> --
>>>> *Yosry Muhammad Yosry*
>>>>
>>>> Computer Engineering student,
>>>> The Faculty of Engineering,
>>>> Cairo University (2021).
>>>> Class representative of CMP 2021.
>>>> https://www.linkedin.com/in/yosrym93/
>>>>
>>>
>>>
>>> --
>>> Dave Page
>>> Blog: http://pgsnake.blogspot.com
>>> Twitter: @pgsnake
>>>
>>> EnterpriseDB UK: http://www.enterprisedb.com
>>> The Enterprise PostgreSQL Company
>>>
>>
>>
>> --
>> *Yosry Muhammad Yosry*
>>
>> Computer Engineering student,
>> The Faculty of Engineering,
>> Cairo University (2021).
>> Class representative of CMP 2021.
>> https://www.linkedin.com/in/yosrym93/
>>
>
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EnterpriseDB UK: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>


-- 
*Yosry Muhammad Yosry*

Computer Engineering student,
The Faculty of Engineering,
Cairo University (2021).
Class representative of CMP 2021.
https://www.linkedin.com/in/yosrym93/
Screenshot 2019-08-23 at 10.53.30.png (image/png, 74.9 KB) - not displayed
editable_readonly_columns_v5.patch (text/x-patch, 75.8 KB)
diff --git a/docs/en_US/editgrid.rst b/docs/en_US/editgrid.rst
index b697449d6..c9f6d4723 100644
--- a/docs/en_US/editgrid.rst
+++ b/docs/en_US/editgrid.rst
@@ -35,6 +35,8 @@ disabled in either mode. Please see
 :ref:`The Query Tool Toolbar <query_tool_toolbar>` for a description of the
 available controls.
 
+.. _data-grid:
+
 The Data Grid
 *************
 
@@ -42,8 +44,6 @@ The top row of the data grid displays the name of each column, the data type,
 and if applicable, the number of characters allowed. A column that is part of
 the primary key will additionally be marked with [PK].
 
-.. _modifying-data-grid:
-
 To modify the displayed data:
 
 * To change a numeric value within the grid, double-click the value to select
diff --git a/docs/en_US/images/query_tool_editable_columns.png b/docs/en_US/images/query_tool_editable_columns.png
new file mode 100644
index 0000000000000000000000000000000000000000..922c0280f9de576cb2201953d29f4a1ab9f87414
GIT binary patch
literal 31676
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

literal 0
HcmV?d00001

diff --git a/docs/en_US/query_tool.rst b/docs/en_US/query_tool.rst
index 48f2c88f9..bf5162b64 100644
--- a/docs/en_US/query_tool.rst
+++ b/docs/en_US/query_tool.rst
@@ -130,15 +130,27 @@ You can:
 
 A result set is updatable if:
 
-* All the columns belong to the same table.
-* All the primary keys or OIDs of the table are explicitly selected.
-* No columns are duplicated.
+* All columns are either selected directly from a single table, or
+  are not table columns at all (e.g. concatenation of 2 columns).
+  Only columns that are selected directly from the table are
+  editable, other columns are read-only.
+* All the primary key columns or OIDs of the table are selected in the 
+  result set.
+
+Any columns that are renamed or selected more than once are also read-only.
+
+Editable and read-only columns are identified using pencil and lock icons 
+(respectively) in the column headers.
+
+.. image:: images/query_tool_editable_columns.png
+    :alt: Query tool editable and read-only columns
+    :align: center
 
 The  psycopg2 driver version should be equal to or above 2.8 for updatable
 query result sets to work.
 
-An updatable result set can be modified just like in
-:ref:`View/Edit Data <modifying-data-grid>` mode.
+An updatable result set is identical to the :ref:`Data Grid <data-grid>` in 
+View/Edit Data mode, and can be modified in the same way.
 
 If Auto-commit is off, the data changes are made as part of the ongoing
 transaction, if no transaction is ongoing a new one is initiated. The data
diff --git a/web/pgadmin/feature_tests/query_tool_journey_test.py b/web/pgadmin/feature_tests/query_tool_journey_test.py
index 8d8bfe34f..f59c29bf7 100644
--- a/web/pgadmin/feature_tests/query_tool_journey_test.py
+++ b/web/pgadmin/feature_tests/query_tool_journey_test.py
@@ -74,10 +74,9 @@ class QueryToolJourneyTest(BaseFeatureTest):
         self._test_history_tab()
         print(" OK.", file=sys.stderr)
 
-        # Insert data into test editable table
         self._insert_data_into_test_editable_table()
 
-        print("History query sources and generated queries toggle...",
+        print("History query source icons and generated queries toggle...",
               file=sys.stderr, end="")
         self._test_query_sources_and_generated_queries()
         print(" OK.", file=sys.stderr)
@@ -86,6 +85,10 @@ class QueryToolJourneyTest(BaseFeatureTest):
         self._test_updatable_resultset()
         print(" OK.", file=sys.stderr)
 
+        print("Is editable column header icons...", file=sys.stderr, end="")
+        self._test_is_editable_columns_icons()
+        print(" OK.", file=sys.stderr)
+
     def _test_copies_rows(self):
         pyperclip.copy("old clipboard contents")
         self.page.driver.switch_to.default_content()
@@ -237,16 +240,53 @@ class QueryToolJourneyTest(BaseFeatureTest):
             return
         self.page.click_tab("Query Editor")
 
-        # Select all data (contains the primary key -> should be editable)
+        # Select all data
+        # (contains the primary key -> all columns should be editable)
         self.page.clear_query_tool()
         query = "SELECT pk_column, normal_column FROM %s" \
                 % self.test_editable_table_name
-        self._check_query_results_editable(query, True)
+        self._check_query_results_editable(query, [True, True])
 
         # Select data without primary keys -> should not be editable
         self.page.clear_query_tool()
         query = "SELECT normal_column FROM %s" % self.test_editable_table_name
-        self._check_query_results_editable(query, False)
+        self._check_query_results_editable(query, [False],
+                                           discard_changes_modal=True)
+
+        # Select all data in addition to duplicate, renamed, and out-of-table
+        # columns
+        self.page.clear_query_tool()
+        query = """
+                SELECT pk_column, normal_column, normal_column,
+                normal_column as pk_column,
+                (normal_column::text || normal_column::text)::int
+                FROM %s
+                """ % self.test_editable_table_name
+        self._check_query_results_editable(query,
+                                           [True, True, False, False, False])
+
+    def _test_is_editable_columns_icons(self):
+        if self.driver_version < 2.8:
+            return
+        self.page.click_tab("Query Editor")
+
+        self.page.clear_query_tool()
+        query = "SELECT pk_column FROM %s" % self.test_editable_table_name
+        self.page.execute_query(query)
+        # Discard changes made by previous test to data grid
+        self.page.click_modal('Yes')
+        icon_exists = self.page.check_if_element_exist_by_xpath(
+            QueryToolLocators.editable_column_icon_xpath
+        )
+        self.assertTrue(icon_exists)
+
+        self.page.clear_query_tool()
+        query = "SELECT normal_column FROM %s" % self.test_editable_table_name
+        self.page.execute_query(query)
+        icon_exists = self.page.check_if_element_exist_by_xpath(
+            QueryToolLocators.read_only_column_icon_xpath
+        )
+        self.assertTrue(icon_exists)
 
     def _execute_sources_test_queries(self):
         self.page.clear_query_tool()
@@ -367,15 +407,18 @@ class QueryToolJourneyTest(BaseFeatureTest):
     def _assert_clickable(self, element):
         self.page.click_element(element)
 
-    def _check_query_results_editable(self, query, should_be_editable):
+    def _check_query_results_editable(self, query, cols_should_be_editable,
+                                      discard_changes_modal=False):
         self.page.execute_query(query)
-        # Check if the first cell in the first row is editable
-        is_editable = self._check_cell_editable(1)
-        self.assertEqual(is_editable, should_be_editable)
+        if discard_changes_modal:
+            self.page.click_modal('Yes')
+        enumerated_should_be_editable = enumerate(cols_should_be_editable, 1)
+        for column_index, should_be_editable in enumerated_should_be_editable:
+            is_editable = self._check_cell_editable(column_index)
+            self.assertEqual(is_editable, should_be_editable)
 
     def _check_cell_editable(self, cell_index):
         """Checks if a cell in the first row of the resultset is editable"""
-
         self.page.check_if_element_exist_by_xpath(
             "//div[contains(@style, 'top:0px')]//div[contains(@class, "
             "'l{0} r{1}')]".format(cell_index, cell_index))
diff --git a/web/pgadmin/static/js/sqleditor_utils.js b/web/pgadmin/static/js/sqleditor_utils.js
index bd4356c02..fde7283b0 100644
--- a/web/pgadmin/static/js/sqleditor_utils.js
+++ b/web/pgadmin/static/js/sqleditor_utils.js
@@ -8,8 +8,8 @@
 //////////////////////////////////////////////////////////////////////////
 // This file contains common utilities functions used in sqleditor modules
 
-define(['jquery', 'sources/gettext', 'sources/url_for'],
-  function ($, gettext, url_for) {
+define(['jquery', 'underscore', 'sources/gettext', 'sources/url_for'],
+  function ($, _, gettext, url_for) {
     var sqlEditorUtils = {
       /* Reference link http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
        * Modified as per requirement.
@@ -198,6 +198,32 @@ define(['jquery', 'sources/gettext', 'sources/url_for'],
         }
         return '1em';
       },
+
+      addEditableIcon: function(columnDefinition, is_editable) {
+        /* This uses Slickgrid.HeaderButtons plugin to add an icon to the
+        columns headers. Instead of a button, an icon is created */
+        let content = null;
+        if(is_editable) {
+          content = '<i class="fa fa-pencil"></i>';
+        }
+        else {
+          content = '<i class="fa fa-lock"></i>';
+        }
+        let button = {
+          cssClass: 'editable-column-header-icon',
+          content: content,
+        };
+        // Check for existing buttons
+        if(!_.isUndefined(columnDefinition.header) &&
+           !_.isUndefined(columnDefinition.header.buttons)) {
+          columnDefinition.header.buttons.push(button);
+        }
+        else {
+          columnDefinition.header = {
+            buttons: [button],
+          };
+        }
+      },
     };
     return sqlEditorUtils;
   });
diff --git a/web/pgadmin/tools/sqleditor/__init__.py b/web/pgadmin/tools/sqleditor/__init__.py
index b862f62cf..da612da1f 100644
--- a/web/pgadmin/tools/sqleditor/__init__.py
+++ b/web/pgadmin/tools/sqleditor/__init__.py
@@ -430,40 +430,17 @@ def poll(trans_id):
                         oids = {'oid': 'oid'}
 
                 if columns_info is not None:
-                    # If it is a QueryToolCommand that has obj_id attribute
-                    # then it should also be editable
-                    if hasattr(trans_obj, 'obj_id') and \
-                        (not isinstance(trans_obj, QueryToolCommand) or
-                         trans_obj.can_edit()):
-                        # Get the template path for the column
-                        template_path = 'columns/sql/#{0}#'.format(
-                            conn.manager.version
-                        )
-
-                        SQL = render_template(
-                            "/".join([template_path, 'nodes.sql']),
-                            tid=trans_obj.obj_id,
-                            has_oids=True
-                        )
-                        # rows with attribute not_null
-                        colst, rset = conn.execute_2darray(SQL)
-                        if not colst:
-                            return internal_server_error(errormsg=rset)
-
-                    for key, col in enumerate(columns_info):
-                        col_type = dict()
-                        col_type['type_code'] = col['type_code']
-                        col_type['type_name'] = None
-                        col_type['internal_size'] = col['internal_size']
-                        columns[col['name']] = col_type
-
-                        if rset:
-                            col_type['not_null'] = col['not_null'] = \
-                                rset['rows'][key]['not_null']
-
-                            col_type['has_default_val'] = \
-                                col['has_default_val'] = \
-                                rset['rows'][key]['has_default_val']
+                    # Only QueryToolCommand or TableCommand can be editable
+                    if hasattr(trans_obj, 'obj_id') and trans_obj.can_edit():
+                        columns = trans_obj.get_columns_types(conn)
+
+                    else:
+                        for col in columns_info:
+                            col_type = dict()
+                            col_type['type_code'] = col['type_code']
+                            col_type['type_name'] = None
+                            col_type['internal_size'] = col['internal_size']
+                            columns[col['name']] = col_type
 
                 if columns:
                     st, types = fetch_pg_types(columns, trans_obj)
diff --git a/web/pgadmin/tools/sqleditor/command.py b/web/pgadmin/tools/sqleditor/command.py
index 01815f8cf..05268f6d4 100644
--- a/web/pgadmin/tools/sqleditor/command.py
+++ b/web/pgadmin/tools/sqleditor/command.py
@@ -22,6 +22,7 @@ from pgadmin.utils.driver import get_driver
 from pgadmin.tools.sqleditor.utils.is_query_resultset_updatable \
     import is_query_resultset_updatable
 from pgadmin.tools.sqleditor.utils.save_changed_data import save_changed_data
+from pgadmin.tools.sqleditor.utils.get_column_types import get_columns_types
 
 from config import PG_DEFAULT_DRIVER
 
@@ -677,6 +678,16 @@ class TableCommand(GridCommand):
                                  client_primary_key=client_primary_key,
                                  conn=conn)
 
+    def get_columns_types(self, conn):
+        columns_info = conn.get_column_info()
+        has_oids = self.has_oids()
+        table_oid = self.obj_id
+        return get_columns_types(conn=conn,
+                                 columns_info=columns_info,
+                                 has_oids=has_oids,
+                                 table_oid=table_oid,
+                                 is_query_tool=False)
+
 
 class ViewCommand(GridCommand):
     """
@@ -864,6 +875,7 @@ class QueryToolCommand(BaseCommand, FetchedRowTracker):
         self.primary_keys = None
         self.pk_names = None
         self.table_has_oids = False
+        self.columns_types = None
 
     def get_sql(self, default_conn=None):
         return None
@@ -874,6 +886,9 @@ class QueryToolCommand(BaseCommand, FetchedRowTracker):
     def get_primary_keys(self):
         return self.pk_names, self.primary_keys
 
+    def get_columns_types(self, conn=None):
+        return self.columns_types
+
     def has_oids(self):
         return self.table_has_oids
 
@@ -906,8 +921,9 @@ class QueryToolCommand(BaseCommand, FetchedRowTracker):
         # Get the path to the sql templates
         sql_path = 'sqleditor/sql/#{0}#'.format(manager.version)
 
-        self.is_updatable_resultset, self.table_has_oids, self.primary_keys, \
-            pk_names, table_oid = is_query_resultset_updatable(conn, sql_path)
+        self.is_updatable_resultset, self.table_has_oids,\
+            self.primary_keys, pk_names, table_oid,\
+            self.columns_types = is_query_resultset_updatable(conn, sql_path)
 
         # Create pk_names attribute in the required format
         if pk_names is not None:
diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
index e078ea753..8831d5023 100644
--- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
+++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
@@ -385,13 +385,13 @@ input.editor-checkbox:focus {
 
 
 /* For geometry column button */
-.div-view-geometry-column {
+.div-view-geometry-column, .editable-column-header-icon {
   float: right;
   height: 100%;
   display: flex;
   display: -webkit-flex;
   align-items: center;
-  padding-right: 4px;
+  padding-right: 6px;
 }
 
 /* For leaflet popup */
diff --git a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
index 4433019c3..7e368ffba 100644
--- a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
+++ b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
@@ -778,6 +778,7 @@ define('tools.querytool', [
           not_null: c.not_null,
           has_default_val: c.has_default_val,
           is_array: c.is_array,
+          can_edit: c.can_edit,
         };
 
         // Get the columns width based on longer string among data type or
@@ -795,17 +796,17 @@ define('tools.querytool', [
         if (c.cell == 'oid' && c.name == 'oid') {
           options['editor'] = null;
         } else if (c.cell == 'Json') {
-          options['editor'] = is_editable ? Slick.Editors.JsonText :
+          options['editor'] = c.can_edit ? Slick.Editors.JsonText :
             Slick.Editors.ReadOnlyJsonText;
           options['formatter'] = Slick.Formatters.JsonString;
         } else if (c.cell == 'number' || c.cell == 'oid' ||
           $.inArray(c.type, ['xid', 'real']) !== -1
         ) {
-          options['editor'] = is_editable ? Slick.Editors.CustomNumber :
+          options['editor'] = c.can_edit ? Slick.Editors.CustomNumber :
             Slick.Editors.ReadOnlyText;
           options['formatter'] = Slick.Formatters.Numbers;
         } else if (c.cell == 'boolean') {
-          options['editor'] = is_editable ? Slick.Editors.Checkbox :
+          options['editor'] = c.can_edit ? Slick.Editors.Checkbox :
             Slick.Editors.ReadOnlyCheckbox;
           options['formatter'] = Slick.Formatters.Checkmark;
         } else if (c.cell == 'binary') {
@@ -814,23 +815,41 @@ define('tools.querytool', [
         } else if (c.cell == 'geometry' || c.cell == 'geography') {
           // increase width to add 'view' button
           options['width'] += 28;
+          options['can_edit'] = false;
         } else {
-          options['editor'] = is_editable ? Slick.Editors.pgText :
+          options['editor'] = c.can_edit ? Slick.Editors.pgText :
             Slick.Editors.ReadOnlypgText;
           options['formatter'] = Slick.Formatters.Text;
         }
 
+        if(!_.isUndefined(c.can_edit)) {
+          // Increase width for editable/read-only icon
+          options['width'] += 12;
+
+          let tooltip = '';
+          if(c.can_edit)
+            tooltip = gettext('Editable column');
+          else
+            tooltip = gettext('Read-only column');
+
+          options['toolTip'] = tooltip;
+        }
+
         grid_columns.push(options);
       });
 
       var gridSelector = new GridSelector();
       grid_columns = self.grid_columns = gridSelector.getColumnDefinitions(grid_columns);
 
-      // add 'view' button in geometry and geography type column header
       _.each(grid_columns, function (c) {
+        // Add 'view' button in geometry and geography type column headers
         if (c.column_type_internal == 'geometry' || c.column_type_internal == 'geography') {
           GeometryViewer.add_header_button(c);
         }
+        // Add editable/read-only icon to columns
+        if (!_.isUndefined(c.can_edit)) {
+          SqlEditorUtils.addEditableIcon(c, c.can_edit);
+        }
       });
 
       if (rows_affected) {
@@ -2634,10 +2653,11 @@ define('tools.querytool', [
 
         // Create columns required by slick grid to render
         _.each(colinfo, function(c) {
-          var is_primary_key = false;
+          var is_primary_key = false,
+            is_editable = self.can_edit && (!self.is_query_tool || c.is_editable);
 
-          // Check whether table have primary key
-          if (_.size(primary_keys) > 0) {
+          // Check whether this column is a primary key
+          if (is_editable && _.size(primary_keys) > 0) {
             _.each(primary_keys, function(value, key) {
               if (key === c.name)
                 is_primary_key = true;
@@ -2738,7 +2758,7 @@ define('tools.querytool', [
               'pos': c.pos,
               'label': column_label,
               'cell': col_cell,
-              'can_edit': (c.name == 'oid') ? false : self.can_edit,
+              'can_edit': (c.name == 'oid') ? false : is_editable,
               'type': type,
               'not_null': c.not_null,
               'has_default_val': c.has_default_val,
diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/sql/default/get_columns.sql b/web/pgadmin/tools/sqleditor/templates/sqleditor/sql/default/get_columns.sql
index 610747dfb..851b98523 100644
--- a/web/pgadmin/tools/sqleditor/templates/sqleditor/sql/default/get_columns.sql
+++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/sql/default/get_columns.sql
@@ -1,6 +1,6 @@
 {# ============= Fetch the columns ============= #}
 {% if obj_id %}
-SELECT at.attname, ty.typname
+SELECT at.attname, ty.typname, at.attnum
     FROM pg_attribute at
     LEFT JOIN pg_type ty ON (ty.oid = at.atttypid)
 WHERE attrelid={{obj_id}}::oid
diff --git a/web/pgadmin/tools/sqleditor/utils/get_column_types.py b/web/pgadmin/tools/sqleditor/utils/get_column_types.py
new file mode 100644
index 000000000..99bcb9fa8
--- /dev/null
+++ b/web/pgadmin/tools/sqleditor/utils/get_column_types.py
@@ -0,0 +1,57 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2019, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+"""
+    Get the column types for QueryToolCommand or TableCommand when
+    the result-set is editable.
+"""
+
+from flask import render_template
+
+
+def get_columns_types(is_query_tool, columns_info, table_oid, conn, has_oids):
+    nodes_sqlpath = 'columns/sql/#{0}#'.format(conn.manager.version)
+    query = render_template(
+        "/".join([nodes_sqlpath, 'nodes.sql']),
+        tid=table_oid,
+        has_oids=has_oids
+    )
+
+    colst, rset = conn.execute_2darray(query)
+    if not colst:
+        raise Exception(rset)
+
+    column_types = dict()
+    for key, col in enumerate(columns_info):
+        col_type = dict()
+        col_type['type_code'] = col['type_code']
+        col_type['type_name'] = None
+        col_type['internal_size'] = col['internal_size']
+        column_types[col['name']] = col_type
+
+        if not is_query_tool:
+            col_type['not_null'] = col['not_null'] = \
+                rset['rows'][key]['not_null']
+
+            col_type['has_default_val'] = \
+                col['has_default_val'] = \
+                rset['rows'][key]['has_default_val']
+
+        else:
+            for row in rset['rows']:
+                if row['oid'] == col['table_column']:
+                    col_type['not_null'] = col['not_null'] = row['not_null']
+
+                    col_type['has_default_val'] = \
+                        col['has_default_val'] = row['has_default_val']
+
+                else:
+                    col_type['not_null'] = col['not_null'] = None
+                    col_type['has_default_val'] = col['has_default_val'] = None
+
+    return column_types
diff --git a/web/pgadmin/tools/sqleditor/utils/is_query_resultset_updatable.py b/web/pgadmin/tools/sqleditor/utils/is_query_resultset_updatable.py
index 9c2bd09a6..0582ca3ab 100644
--- a/web/pgadmin/tools/sqleditor/utils/is_query_resultset_updatable.py
+++ b/web/pgadmin/tools/sqleditor/utils/is_query_resultset_updatable.py
@@ -8,11 +8,18 @@
 ##########################################################################
 
 """
-    Check if the result-set of a query is updatable, A resultset is
-    updatable (as of this version) if:
-        - All columns belong to the same table.
-        - All the primary key columns of the table are present in the resultset
-        - No duplicate columns
+    Check if the result-set of a query is editable, A result-set is
+    editable if:
+        - All columns are either selected directly from a single table, or
+          are not table columns at all (e.g. concatenation of 2 columns).
+          Only columns that are selected directly from a the table are
+          editable, other columns are read-only.
+        - All the primary key columns or oids (if applicable) of the table are
+          present in the result-set.
+
+    Note:
+        - Duplicate columns (selected twice) or renamed columns are also
+          read-only.
 """
 from flask import render_template
 from flask_babelex import gettext
@@ -20,16 +27,18 @@ try:
     from collections import OrderedDict
 except ImportError:
     from ordereddict import OrderedDict
+from pgadmin.tools.sqleditor.utils.get_column_types import get_columns_types
 
 
 def is_query_resultset_updatable(conn, sql_path):
     """
         This function is used to check whether the last successful query
-        produced updatable results.
+        produced editable results.
 
         Args:
             conn: Connection object.
-            sql_path: the path to the sql templates.
+            sql_path: the path to the sql templates
+                      primary_keys.sql & columns.sql.
     """
     columns_info = conn.get_column_info()
 
@@ -37,26 +46,43 @@ def is_query_resultset_updatable(conn, sql_path):
         return return_not_updatable()
 
     table_oid = _check_single_table(columns_info)
-    if not table_oid:
-        return return_not_updatable()
-
-    if not _check_duplicate_columns(columns_info):
+    if table_oid is None:
         return return_not_updatable()
 
     if conn.connected():
-        primary_keys, pk_names = _check_primary_keys(conn=conn,
-                                                     columns_info=columns_info,
-                                                     table_oid=table_oid,
-                                                     sql_path=sql_path)
+        # Get all the table columns
+        table_columns = _get_table_columns(conn=conn,
+                                           table_oid=table_oid,
+                                           sql_path=sql_path)
+
+        # Editable column: A column selected directly from a table, that is
+        # neither renamed nor is a duplicate of another selected column
+        _check_editable_columns(table_columns=table_columns,
+                                results_columns=columns_info)
+
+        primary_keys, pk_names = \
+            _check_primary_keys(conn=conn,
+                                columns_info=columns_info,
+                                table_oid=table_oid,
+                                sql_path=sql_path)
 
         has_oids = _check_oids(conn=conn,
                                columns_info=columns_info,
                                table_oid=table_oid,
                                sql_path=sql_path)
 
-        if has_oids or primary_keys is not None:
-            return True, has_oids, primary_keys, pk_names, table_oid
+        is_resultset_updatable = has_oids or primary_keys is not None
+
+        if is_resultset_updatable:
+            column_types = get_columns_types(columns_info=columns_info,
+                                             table_oid=table_oid,
+                                             conn=conn,
+                                             has_oids=has_oids,
+                                             is_query_tool=True)
+            return True, has_oids, primary_keys, \
+                pk_names, table_oid, column_types
         else:
+            _set_all_columns_not_editable(columns_info=columns_info)
             return return_not_updatable()
     else:
         raise Exception(
@@ -66,20 +92,34 @@ def is_query_resultset_updatable(conn, sql_path):
 
 
 def _check_single_table(columns_info):
-    table_oid = columns_info[0]['table_oid']
+    table_oid = None
     for column in columns_info:
-        if column['table_oid'] != table_oid:
+        # Skip columns that are not directly from tables
+        if column['table_oid'] is None:
+            continue
+        # If we don't have a table_oid yet, store this one
+        if table_oid is None:
+            table_oid = column['table_oid']
+        # If we already have one, check that all the columns have the same one
+        elif column['table_oid'] != table_oid:
             return None
     return table_oid
 
 
-def _check_duplicate_columns(columns_info):
-    column_numbers = \
-        [col['table_column'] for col in columns_info]
-    is_duplicate_columns = len(column_numbers) != len(set(column_numbers))
-    if is_duplicate_columns:
-        return False
-    return True
+def _check_editable_columns(table_columns, results_columns):
+    table_columns_numbers = set()
+    for results_column in results_columns:
+        table_column_number = results_column['table_column']
+        if table_column_number is None:  # Not a table column
+            results_column['is_editable'] = False
+        elif table_column_number in table_columns_numbers:  # Duplicate
+            results_column['is_editable'] = False
+        elif results_column['display_name'] \
+                != table_columns[table_column_number]:
+            results_column['is_editable'] = False
+        else:
+            results_column['is_editable'] = True
+            table_columns_numbers.add(table_column_number)
 
 
 def _check_oids(conn, sql_path, table_oid, columns_info):
@@ -111,26 +151,34 @@ def _check_primary_keys(conn, columns_info, sql_path, table_oid):
                           table_oid=table_oid,
                           sql_path=sql_path)
 
-    if not _check_primary_keys_uniquely_exist(primary_keys_columns,
-                                              columns_info):
+    if not _check_all_primary_keys_exist(primary_keys_columns,
+                                         columns_info):
         primary_keys = None
         pk_names = None
     return primary_keys, pk_names
 
 
-def _check_primary_keys_uniquely_exist(primary_keys_columns, columns_info):
+def _check_all_primary_keys_exist(primary_keys_columns, columns_info):
+    """
+        Check that all primary keys exist.
+
+        If another column is selected with the same name as the primary key
+        before the primary key (e.g SELECT some_col as pk, pk from table) the
+        name of the actual primary key column gets changed to pk-2.
+        This is also reversed here.
+    """
     for pk in primary_keys_columns:
         pk_exists = False
         for col in columns_info:
-            if col['table_column'] == pk['column_number']:
+            if col['is_editable'] and \
+               col['table_column'] == pk['column_number']:
                 pk_exists = True
-                # If the primary key column is renamed
-                if col['display_name'] != pk['name']:
-                    return False
-            # If a normal column is renamed to a primary key column name
-            elif col['display_name'] == pk['name']:
-                return False
-
+                # If the primary key is renamed, restore to its original name
+                if col['name'] != pk['name']:
+                    col['name'], _ = col['name'].split('-')
+            # If another column is renamed to the primary key name, change it
+            elif col['name'] == pk['name']:
+                col['name'] += '-0'
         if not pk_exists:
             return False
     return True
@@ -160,5 +208,26 @@ def _get_primary_keys(sql_path, table_oid, conn):
     return primary_keys, primary_keys_columns, pk_names
 
 
+def _get_table_columns(sql_path, table_oid, conn):
+    query = render_template(
+        "/".join([sql_path, 'get_columns.sql']),
+        obj_id=table_oid
+    )
+    status, result = conn.execute_dict(query)
+    if not status:
+        raise Exception(result)
+
+    columns = {}
+    for row in result['rows']:
+        columns[row['attnum']] = row['attname']
+
+    return columns
+
+
+def _set_all_columns_not_editable(columns_info):
+    for col in columns_info:
+        col['is_editable'] = False
+
+
 def return_not_updatable():
-    return False, False, None, None, None
+    return False, False, None, None, None, None
diff --git a/web/pgadmin/tools/sqleditor/utils/tests/test_is_query_resultset_updatable.py b/web/pgadmin/tools/sqleditor/utils/tests/test_is_query_resultset_updatable.py
index 40ca4c8f7..8b451174a 100644
--- a/web/pgadmin/tools/sqleditor/utils/tests/test_is_query_resultset_updatable.py
+++ b/web/pgadmin/tools/sqleditor/utils/tests/test_is_query_resultset_updatable.py
@@ -25,67 +25,109 @@ class TestQueryUpdatableResultset(BaseTestGenerator):
     scenarios = [
         ('When selecting all columns of the table', dict(
             sql='SELECT * FROM %s;',
-            primary_keys={
+            expected_primary_keys={
                 'pk_col1': 'int4',
                 'pk_col2': 'int4'
             },
             expected_has_oids=False,
-            table_has_oids=False
+            table_has_oids=False,
+            expected_cols_is_editable=[True, True, True, True]
         )),
         ('When selecting all primary keys of the table', dict(
             sql='SELECT pk_col1, pk_col2 FROM %s;',
-            primary_keys={
+            expected_primary_keys={
                 'pk_col1': 'int4',
                 'pk_col2': 'int4'
             },
             expected_has_oids=False,
-            table_has_oids=False
+            table_has_oids=False,
+            expected_cols_is_editable=[True, True]
         )),
         ('When selecting some of the primary keys of the table', dict(
             sql='SELECT pk_col2 FROM %s;',
-            primary_keys=None,
+            expected_primary_keys=None,
             expected_has_oids=False,
-            table_has_oids=False
+            table_has_oids=False,
+            expected_cols_is_editable=[False]
         )),
         ('When selecting none of the primary keys of the table', dict(
             sql='SELECT normal_col1 FROM %s;',
-            primary_keys=None,
+            expected_primary_keys=None,
             expected_has_oids=False,
-            table_has_oids=False
+            table_has_oids=False,
+            expected_cols_is_editable=[False]
         )),
         ('When renaming a primary key', dict(
             sql='SELECT pk_col1 as some_col, pk_col2 FROM "%s";',
-            primary_keys=None,
+            expected_primary_keys=None,
             expected_has_oids=False,
-            table_has_oids=False
+            table_has_oids=False,
+            expected_cols_is_editable=[False, False]
         )),
-        ('When renaming a column to a primary key name', dict(
-            sql='SELECT pk_col1, pk_col2, normal_col1 as pk_col1 FROM %s;',
-            primary_keys=None,
+        ('When renaming a normal column', dict(
+            sql='SELECT pk_col1, pk_col2, normal_col1 as some_col FROM "%s";',
+            expected_primary_keys={
+                'pk_col1': 'int4',
+                'pk_col2': 'int4'
+            },
+            expected_has_oids=False,
+            table_has_oids=False,
+            expected_cols_is_editable=[True, True, False]
+        )),
+        ('When renaming a normal column to a primary key name', dict(
+            sql='SELECT normal_col1 as pk_col1, pk_col1, pk_col2 FROM %s;',
+            expected_primary_keys={
+                'pk_col1': 'int4',
+                'pk_col2': 'int4'
+            },
             expected_has_oids=False,
-            table_has_oids=False
+            table_has_oids=False,
+            expected_cols_is_editable=[False, True, True]
+        )),
+        ('When selecting a normal column twice', dict(
+            sql='SELECT pk_col1, pk_col2, normal_col1, normal_col1 FROM %s;',
+            expected_primary_keys={
+                'pk_col1': 'int4',
+                'pk_col2': 'int4'
+            },
+            expected_has_oids=False,
+            table_has_oids=False,
+            expected_cols_is_editable=[True, True, True, False]
+        )),
+        ('When selecting a non-table column', dict(
+            sql='SELECT pk_col1, pk_col2, normal_col1 || normal_col2 FROM %s;',
+            expected_primary_keys={
+                'pk_col1': 'int4',
+                'pk_col2': 'int4'
+            },
+            expected_has_oids=False,
+            table_has_oids=False,
+            expected_cols_is_editable=[True, True, False]
         )),
         ('When selecting primary keys and oids (table with oids)', dict(
             sql='SELECT *, oid FROM %s;',
-            primary_keys={
+            expected_primary_keys={
                 'pk_col1': 'int4',
                 'pk_col2': 'int4'
             },
             expected_has_oids=True,
-            table_has_oids=True
+            table_has_oids=True,
+            expected_cols_is_editable=[True, True, True, True, False]
         )),
         ('When selecting oids without primary keys (table with oids)', dict(
             sql='SELECT oid, normal_col1, normal_col2 FROM %s;',
-            primary_keys=None,
+            expected_primary_keys=None,
             expected_has_oids=True,
-            table_has_oids=True
+            table_has_oids=True,
+            expected_cols_is_editable=[False, True, True]
         )),
         ('When selecting none of the primary keys or oids (table with oids)',
          dict(
              sql='SELECT normal_col1, normal_col2 FROM %s;',
-             primary_keys=None,
+             expected_primary_keys=None,
              expected_has_oids=False,
-             table_has_oids=True
+             table_has_oids=True,
+             expected_cols_is_editable=[False, False]
          ))
     ]
 
@@ -99,6 +141,7 @@ class TestQueryUpdatableResultset(BaseTestGenerator):
         response_data = self._execute_select_sql()
         self._check_primary_keys(response_data)
         self._check_oids(response_data)
+        self._check_editable_columns(response_data)
 
     def tearDown(self):
         # Disconnect the database
@@ -116,12 +159,18 @@ class TestQueryUpdatableResultset(BaseTestGenerator):
 
     def _check_primary_keys(self, response_data):
         primary_keys = response_data['data']['primary_keys']
-        self.assertEquals(primary_keys, self.primary_keys)
+        self.assertEquals(primary_keys, self.expected_primary_keys)
 
     def _check_oids(self, response_data):
         has_oids = response_data['data']['has_oids']
         self.assertEquals(has_oids, self.expected_has_oids)
 
+    def _check_editable_columns(self, response_data):
+        columns_info = response_data['data']['colinfo']
+        for col, expected_is_editable in \
+                zip(columns_info, self.expected_cols_is_editable):
+            self.assertEquals(col['is_editable'], expected_is_editable)
+
     def _initialize_database_connection(self):
         database_info = parent_node_dict["database"][-1]
         self.db_name = database_info["db_name"]
diff --git a/web/regression/feature_utils/locators.py b/web/regression/feature_utils/locators.py
index b2bcb6224..f37afddd5 100644
--- a/web/regression/feature_utils/locators.py
+++ b/web/regression/feature_utils/locators.py
@@ -219,3 +219,11 @@ class QueryToolLocators:
         "//div[label[normalize-space(" \
         "text())='Show queries generated internally by pgAdmin?']]" \
         "//div[contains(@class,'toggle btn')]"
+
+    editable_column_icon_xpath = "//div[contains(@class," \
+                                 " 'editable-column-header-icon')]" \
+                                 "/i[contains(@class, 'fa-pencil')]"
+
+    read_only_column_icon_xpath = "//div[contains(@class," \
+                                  " 'editable-column-header-icon')]" \
+                                  "/i[contains(@class, 'fa-lock')]"
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.