Hi Dave, On Tue, Jul 18, 2017 at 8:31 PM, Dave Page <dp...@pgadmin.org> wrote:
> > > On Tue, Jul 18, 2017 at 2:40 PM, Harshal Dhumal < > harshal.dhu...@enterprisedb.com> wrote: > >> Hi Dave, >> >> On Tue, Jul 18, 2017 at 1:24 PM, Dave Page <dp...@pgadmin.org> wrote: >> >>> >>> >>> On Tue, Jul 18, 2017 at 8:26 AM, Harshal Dhumal < >>> harshal.dhu...@enterprisedb.com> wrote: >>> >>>> Hi Dave, >>>> >>>> >>>> On Mon, Jul 17, 2017 at 9:33 PM, Dave Page <dp...@pgadmin.org> wrote: >>>> >>>>> Hi >>>>> >>>>> On Mon, Jul 17, 2017 at 1:09 PM, Harshal Dhumal < >>>>> harshal.dhu...@enterprisedb.com> wrote: >>>>> >>>>>> Hi, >>>>>> >>>>>> Please find updated patch. Now placeholder string for bytea and >>>>>> bytea[] data will only appear in datagrid (view all/1000/500 rows). If >>>>>> user >>>>>> executes query using Query tool then placeholder won't appear (similar to >>>>>> pgAdminIII behaviour) >>>>>> >>>>> >>>>> I'm getting the following error when testing this: >>>>> >>>> >>>> I ran all feature test cases 5-6 times and each time they ran >>>> successfully. >>>> May be this is occasional failure which we get after running test cases >>>> for many times. >>>> >>>> Please let me know if you are getting this failure consistently at your >>>> end. >>>> >>> >>> I ran it twice and it failed twice. I can't keep running tests over and >>> over again as they take quite a while to run and I can't use my machine for >>> anything else at the same time as occasionally the test browser will grab >>> focus. >>> >> >> Please find updated patch. >> I have slightly modified feature test case for 'view data dml queries' >> (though I wasn't getting failure as mentioned). >> >> > Thanks, that passes. > > Now I've played with it though, I think that the query tool should also > hide the binary data. I don't see a good reason to see it in one place but > not another - ultimately it's still not human readable. > > Also, we need to make it look like the [null] placeholder I think; e.g. > use [ ] instead of < > and give it a lighter colour. > > Please find updated patch. I have fixed all of above review comments. > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company >
diff --git a/web/pgadmin/feature_tests/pg_datatype_validation_test.py b/web/pgadmin/feature_tests/pg_datatype_validation_test.py index 149a496..703f0c5 100644 --- a/web/pgadmin/feature_tests/pg_datatype_validation_test.py +++ b/web/pgadmin/feature_tests/pg_datatype_validation_test.py @@ -103,7 +103,7 @@ class PGDataypeFeatureTest(BaseFeatureTest): '922337203685.922337203685', '-92233720368547758.08', '{1,2,3}', '{NaN,NaN,NaN}', 'Infinity', '{Infinity}', - r'\336\255\276\357', r'{"\\336\\255\\276\\357","\\336\\255\\276\\357"}' + r'[binary data]', r'[binary data[]]' ] self.page.open_query_tool() @@ -122,7 +122,7 @@ class PGDataypeFeatureTest(BaseFeatureTest): cells.pop(0) for val, cell in zip(expected_output, cells): try: - source_code = cell.get_attribute('innerHTML') + source_code = cell.text PGDataypeFeatureTest.check_result( source_code, diff --git a/web/pgadmin/feature_tests/view_data_dml_queries.py b/web/pgadmin/feature_tests/view_data_dml_queries.py index 622387e..e8cf598 100644 --- a/web/pgadmin/feature_tests/view_data_dml_queries.py +++ b/web/pgadmin/feature_tests/view_data_dml_queries.py @@ -101,6 +101,7 @@ CREATE TABLE public.defaults # Open Object -> View/Edit data self._view_data_grid() + self.page.wait_for_query_tool_loading_indicator_to_disappear() # Run test to insert a new row in table with default values self._add_row() self._verify_row_data(True) @@ -160,6 +161,7 @@ CREATE TABLE public.defaults Returns: None """ + self.wait.until(EC.visibility_of_element_located( (By.XPATH, xpath)), CheckForViewDataTest.TIMEOUT_STRING ) @@ -197,6 +199,8 @@ CREATE TABLE public.defaults self.page.toggle_open_tree_item(self.server['name']) self.page.toggle_open_tree_item('Databases') self.page.toggle_open_tree_item('acceptance_test_db') + # wait until all database dependant modules/js are loaded. + time.sleep(5) self.page.toggle_open_tree_item('Schemas') self.page.toggle_open_tree_item('public') self.page.toggle_open_tree_item('Tables') @@ -263,6 +267,7 @@ CREATE TABLE public.defaults cell_xpath = CheckForViewDataTest._get_cell_xpath( 'r'+str(idx), 1 ) + time.sleep(0.4) self._update_cell(cell_xpath, config_data[str(idx)]) self.page.find_by_id("btn-save").click() # Save data diff --git a/web/pgadmin/static/js/slickgrid/slick.pgadmin.formatters.js b/web/pgadmin/static/js/slickgrid/slick.pgadmin.formatters.js index d14b181..1a0d60b 100644 --- a/web/pgadmin/static/js/slickgrid/slick.pgadmin.formatters.js +++ b/web/pgadmin/static/js/slickgrid/slick.pgadmin.formatters.js @@ -92,6 +92,9 @@ (_.isUndefined(value) || _.isNull(value)) ) { return "<span class='pull-left disabled_cell'>[null]</span>"; + } else if(columnDef.column_type_internal == 'bytea' || + columnDef.column_type_internal == 'bytea[]') { + return "<span class='pull-left disabled_cell'>[" + _.escape(value) + "]</span>"; } else { return _.escape(value); diff --git a/web/pgadmin/tools/datagrid/__init__.py b/web/pgadmin/tools/datagrid/__init__.py index 95c83dd..08b01ab 100644 --- a/web/pgadmin/tools/datagrid/__init__.py +++ b/web/pgadmin/tools/datagrid/__init__.py @@ -117,7 +117,8 @@ def initialize_datagrid(cmd_type, obj_type, sid, did, obj_id): conn_id = str(random.randint(1, 9999999)) try: manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid) - conn = manager.connection(did=did, conn_id=conn_id) + conn = manager.connection(did=did, conn_id=conn_id, + use_binary_placeholder=True) except Exception as e: return internal_server_error(errormsg=str(e)) diff --git a/web/pgadmin/tools/sqleditor/__init__.py b/web/pgadmin/tools/sqleditor/__init__.py index 762765e..2ffc74a 100644 --- a/web/pgadmin/tools/sqleditor/__init__.py +++ b/web/pgadmin/tools/sqleditor/__init__.py @@ -257,7 +257,8 @@ def check_transaction_status(trans_id): try: manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(trans_obj.sid) - conn = manager.connection(did=trans_obj.did, conn_id=trans_obj.conn_id) + conn = manager.connection(did=trans_obj.did, conn_id=trans_obj.conn_id, + use_binary_placeholder=True) except Exception as e: return False, internal_server_error(errormsg=str(e)), None, None, None @@ -396,7 +397,8 @@ def start_query_tool(trans_id): try: manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(trans_obj.sid) - conn = manager.connection(did=trans_obj.did, conn_id=conn_id) + conn = manager.connection(did=trans_obj.did, conn_id=conn_id, + use_binary_placeholder=True) except Exception as e: return internal_server_error(errormsg=str(e)) diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js index ff98563..b3ce2f0 100644 --- a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js +++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js @@ -578,6 +578,7 @@ define('tools.querytool', [ name: c.label, display_name: c.display_name, column_type: c.column_type, + column_type_internal: c.column_type_internal, not_null: c.not_null, has_default_val: c.has_default_val }; @@ -744,6 +745,11 @@ define('tools.querytool', [ // Listener function which will be called before user updates existing cell // This will be used to collect primary key for that row grid.onBeforeEditCell.subscribe(function (e, args) { + if (args.column.column_type_internal == 'bytea' || + args.column.column_type_internal == 'bytea[]') { + return false; + } + var before_data = args.item; // If newly added row is saved but grid is not refreshed, @@ -2074,9 +2080,9 @@ define('tools.querytool', [ pg_types[pg_types.length - 1][0] : 'unknown'; if (!is_primary_key) - col_type += ' ' + type; + col_type += type; else - col_type += ' [PK] ' + type; + col_type += '[PK] ' + type; if (c.precision && c.precision >= 0 && c.precision != 65535) { col_type += ' (' + c.precision; @@ -2125,6 +2131,7 @@ define('tools.querytool', [ 'name': c.name, 'display_name': c.display_name, 'column_type': col_type, + 'column_type_internal': type, 'pos': c.pos, 'label': column_label, 'cell': col_cell, diff --git a/web/pgadmin/utils/driver/psycopg2/__init__.py b/web/pgadmin/utils/driver/psycopg2/__init__.py index 8a20521..5301f73 100644 --- a/web/pgadmin/utils/driver/psycopg2/__init__.py +++ b/web/pgadmin/utils/driver/psycopg2/__init__.py @@ -120,6 +120,31 @@ def register_string_typecasters(connection): psycopg2.extensions.register_type(unicode_array_type) +def register_binary_typecasters(connection): + psycopg2.extensions.register_type( + psycopg2.extensions.new_type( + ( + # To cast bytea type + 17, + ), + 'BYTEA_PLACEHOLDER', + # Only show placeholder if data actually exists. + lambda value, cursor: 'binary data' if value is not None else None), + connection + ) + + psycopg2.extensions.register_type( + psycopg2.extensions.new_type( + ( + # To cast bytea[] type + 1001, + ), + 'BYTEA_ARRAY_PLACEHOLDER', + # Only show placeholder if data actually exists. + lambda value, cursor: 'binary data[]' if value is not None else None), + connection + ) + class Connection(BaseConnection): """ class Connection(object) @@ -201,7 +226,8 @@ class Connection(BaseConnection): """ - def __init__(self, manager, conn_id, db, auto_reconnect=True, async=0): + def __init__(self, manager, conn_id, db, auto_reconnect=True, async=0, + use_binary_placeholder=False): assert (manager is not None) assert (conn_id is not None) @@ -222,6 +248,7 @@ class Connection(BaseConnection): self.wasConnected = False # This flag indicates the connection reconnecting status. self.reconnecting = False + self.use_binary_placeholder = use_binary_placeholder super(Connection, self).__init__() @@ -239,6 +266,7 @@ class Connection(BaseConnection): res['database'] = self.db res['async'] = self.async res['wasConnected'] = self.wasConnected + res['use_binary_placeholder'] = self.use_binary_placeholder return res @@ -397,6 +425,10 @@ Failed to connect to the database server(#{server_id}) for connection ({conn_id} self.conn.autocommit = True register_string_typecasters(self.conn) + + if self.use_binary_placeholder: + register_binary_typecasters(self.conn) + status = _execute(cur, """ SET DateStyle=ISO; SET client_min_messages=notice; @@ -1639,7 +1671,7 @@ class ServerManager(object): def connection( self, database=None, conn_id=None, auto_reconnect=True, did=None, - async=None + async=None, use_binary_placeholder=False ): if database is not None: if hasattr(str, 'decode') and \ @@ -1693,7 +1725,8 @@ WHERE db.oid = {0}""".format(did)) else: async = 1 if async is True else 0 self.connections[my_id] = Connection( - self, my_id, database, auto_reconnect, async + self, my_id, database, auto_reconnect, async, + use_binary_placeholder=use_binary_placeholder ) return self.connections[my_id] @@ -1722,7 +1755,8 @@ WHERE db.oid = {0}""".format(did)) conn_info = connections[conn_id] conn = self.connections[conn_info['conn_id']] = Connection( self, conn_info['conn_id'], conn_info['database'], - True, conn_info['async'] + True, conn_info['async'], + use_binary_placeholder=conn_info['use_binary_placeholder'] ) # only try to reconnect if connection was connected previously. if conn_info['wasConnected']: