Ensure the query tool will work with older versions of psycopg2 than we officially support, albeit without updateable resultsets. Fixes #4520

This commit is contained in:
Yosry Muhammad
2019-08-01 13:59:53 +01:00
committed by Dave Page
parent cbe40176c1
commit 7b65507533
8 changed files with 54 additions and 25 deletions

View File

@@ -134,6 +134,9 @@ A result set is updatable if:
* All the primary keys or OIDs of the table are explicitly selected. * All the primary keys or OIDs of the table are explicitly selected.
* No columns are duplicated. * No columns are duplicated.
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 An updatable result set can be modified just like in
:ref:`View/Edit Data <modifying-data-grid>` mode. :ref:`View/Edit Data <modifying-data-grid>` mode.

View File

@@ -26,3 +26,4 @@ Bug fixes
| `Issue #4496 <https://redmine.postgresql.org/issues/4496>`_ - Ensure columns can be created when they are IDENTITY fields with the CYCLE option enabled. | `Issue #4496 <https://redmine.postgresql.org/issues/4496>`_ - Ensure columns can be created when they are IDENTITY fields with the CYCLE option enabled.
| `Issue #4497 <https://redmine.postgresql.org/issues/4497>`_ - Ensure purely numeric comments can be saved on new columns. | `Issue #4497 <https://redmine.postgresql.org/issues/4497>`_ - Ensure purely numeric comments can be saved on new columns.
| `Issue #4508 <https://redmine.postgresql.org/issues/4508>`_ - Fix accessibility issue for Datetime cell in backgrid. | `Issue #4508 <https://redmine.postgresql.org/issues/4508>`_ - Fix accessibility issue for Datetime cell in backgrid.
| `Issue #4520 <https://redmine.postgresql.org/issues/4520>`_ - Ensure the query tool will work with older versions of psycopg2 than we officially support, albeit without updatable resultsets.

View File

@@ -50,6 +50,9 @@ class QueryToolJourneyTest(BaseFeatureTest):
self.page.add_server(self.server) self.page.add_server(self.server)
driver_version = test_utils.get_driver_version()
self.driver_version = float('.'.join(driver_version.split('.')[:2]))
def runTest(self): def runTest(self):
self._navigate_to_query_tool() self._navigate_to_query_tool()
self._execute_query( self._execute_query(
@@ -190,6 +193,9 @@ class QueryToolJourneyTest(BaseFeatureTest):
self._assert_clickable(query_we_need_to_scroll_to) self._assert_clickable(query_we_need_to_scroll_to)
def _test_updatable_resultset(self): def _test_updatable_resultset(self):
if self.driver_version < 2.8:
return
self.page.click_tab("Query Editor") self.page.click_tab("Query Editor")
# Insert data into test table # Insert data into test table

View File

@@ -424,16 +424,16 @@ def poll(trans_id):
# If trans_obj is a QueryToolCommand then check for updatable # If trans_obj is a QueryToolCommand then check for updatable
# resultsets and primary keys # resultsets and primary keys
if isinstance(trans_obj, QueryToolCommand): if isinstance(trans_obj, QueryToolCommand):
trans_obj.check_updatable_results_pkeys_oids() if trans_obj.check_updatable_results_pkeys_oids():
pk_names, primary_keys = trans_obj.get_primary_keys() pk_names, primary_keys = trans_obj.get_primary_keys()
session_obj['has_oids'] = trans_obj.has_oids() session_obj['has_oids'] = trans_obj.has_oids()
# Update command_obj in session obj # Update command_obj in session obj
session_obj['command_obj'] = pickle.dumps( session_obj['command_obj'] = pickle.dumps(
trans_obj, -1) trans_obj, -1)
# If primary_keys exist, add them to the session_obj to # If primary_keys exist, add them to the session_obj to
# allow for saving any changes to the data # allow for saving any changes to the data
if primary_keys is not None: if primary_keys is not None:
session_obj['primary_keys'] = primary_keys session_obj['primary_keys'] = primary_keys
if 'has_oids' in session_obj: if 'has_oids' in session_obj:
has_oids = session_obj['has_oids'] has_oids = session_obj['has_oids']

View File

@@ -896,6 +896,13 @@ class QueryToolCommand(BaseCommand, FetchedRowTracker):
manager = driver.connection_manager(self.sid) manager = driver.connection_manager(self.sid)
conn = manager.connection(did=self.did, conn_id=self.conn_id) conn = manager.connection(did=self.did, conn_id=self.conn_id)
# Get the driver version as a float
driver_version = float('.'.join(driver.Version().split('.')[:2]))
# Checking for updatable resultsets uses features in psycopg 2.8
if driver_version < 2.8:
return False
# Get the path to the sql templates # Get the path to the sql templates
sql_path = 'sqleditor/sql/#{0}#'.format(manager.version) sql_path = 'sqleditor/sql/#{0}#'.format(manager.version)
@@ -918,6 +925,7 @@ class QueryToolCommand(BaseCommand, FetchedRowTracker):
self.__set_updatable_results_attrs(sql_path=sql_path, self.__set_updatable_results_attrs(sql_path=sql_path,
table_oid=table_oid, table_oid=table_oid,
conn=conn) conn=conn)
return self.is_updatable_resultset
def save(self, def save(self,
changed_data, changed_data,

View File

@@ -15,7 +15,7 @@ from pgadmin.browser.server_groups.servers.databases.tests import utils as \
from pgadmin.utils.route import BaseTestGenerator from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils from regression.python_test_utils import test_utils as utils
from .execute_query_utils import execute_query from pgadmin.tools.sqleditor.tests.execute_query_utils import execute_query
class TestQueryUpdatableResultset(BaseTestGenerator): class TestQueryUpdatableResultset(BaseTestGenerator):
@@ -120,6 +120,7 @@ class TestQueryUpdatableResultset(BaseTestGenerator):
def _initialize_database_connection(self): def _initialize_database_connection(self):
database_info = parent_node_dict["database"][-1] database_info = parent_node_dict["database"][-1]
self.db_name = database_info["db_name"]
self.server_id = database_info["server_id"] self.server_id = database_info["server_id"]
self.server_version = parent_node_dict["schema"][-1]["server_version"] self.server_version = parent_node_dict["schema"][-1]["server_version"]
@@ -128,6 +129,12 @@ class TestQueryUpdatableResultset(BaseTestGenerator):
self.skipTest('Tables with OIDs are not supported starting ' self.skipTest('Tables with OIDs are not supported starting '
'PostgreSQL 12') 'PostgreSQL 12')
driver_version = utils.get_driver_version()
driver_version = float('.'.join(driver_version.split('.')[:2]))
if driver_version < 2.8:
self.skipTest('Updatable resultsets require pyscopg 2.8 or later')
self.db_id = database_info["db_id"] self.db_id = database_info["db_id"]
db_con = database_utils.connect_database(self, db_con = database_utils.connect_database(self,
utils.SERVER_GROUP, utils.SERVER_GROUP,
@@ -172,10 +179,5 @@ class TestQueryUpdatableResultset(BaseTestGenerator):
else: else:
create_sql += ';' create_sql += ';'
is_success, _ = \ utils.create_table_with_query(self.server, self.db_name, create_sql)
execute_query(tester=self.tester,
query=create_sql,
start_query_tool_url=self.start_query_tool_url,
poll_url=self.poll_url)
self.assertEquals(is_success, True)
return test_table_name return test_table_name

View File

@@ -15,11 +15,11 @@ from pgadmin.browser.server_groups.servers.databases.tests import utils as \
from pgadmin.utils.route import BaseTestGenerator from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils from regression.python_test_utils import test_utils as utils
from .execute_query_utils import execute_query from pgadmin.tools.sqleditor.tests.execute_query_utils import execute_query
class TestSaveChangedData(BaseTestGenerator): class TestSaveChangedData(BaseTestGenerator):
""" This class tests saving data changes in the grid to the database """ """ This class tests saving data changes to updatable query resultsets """
scenarios = [ scenarios = [
('When inserting new valid row', dict( ('When inserting new valid row', dict(
save_payload={ save_payload={
@@ -304,6 +304,7 @@ class TestSaveChangedData(BaseTestGenerator):
def _initialize_database_connection(self): def _initialize_database_connection(self):
database_info = parent_node_dict["database"][-1] database_info = parent_node_dict["database"][-1]
self.db_name = database_info["db_name"]
self.server_id = database_info["server_id"] self.server_id = database_info["server_id"]
self.db_id = database_info["db_id"] self.db_id = database_info["db_id"]
@@ -311,6 +312,13 @@ class TestSaveChangedData(BaseTestGenerator):
utils.SERVER_GROUP, utils.SERVER_GROUP,
self.server_id, self.server_id,
self.db_id) self.db_id)
driver_version = utils.get_driver_version()
driver_version = float('.'.join(driver_version.split('.')[:2]))
if driver_version < 2.8:
self.skipTest('Updatable resultsets require pyscopg 2.8 or later')
if not db_con["info"] == "Database connected.": if not db_con["info"] == "Database connected.":
raise Exception("Could not connect to the database.") raise Exception("Could not connect to the database.")
@@ -347,9 +355,5 @@ class TestSaveChangedData(BaseTestGenerator):
self.test_table_name, self.test_table_name,
self.test_table_name) self.test_table_name)
self.select_sql = 'SELECT * FROM %s;' % self.test_table_name self.select_sql = 'SELECT * FROM %s;' % self.test_table_name
is_success, _ = \
execute_query(tester=self.tester, utils.create_table_with_query(self.server, self.db_name, create_sql)
query=create_sql,
start_query_tool_url=self.start_query_tool_url,
poll_url=self.poll_url)
self.assertEquals(is_success, True)

View File

@@ -1080,3 +1080,8 @@ def get_watcher_dialogue_status(self):
else: else:
break break
return status return status
def get_driver_version():
version = getattr(psycopg2, '__version__', None)
return version