mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2026-10-12 16:11:59 -05:00
Remove some files committed in error.
This commit is contained in:
1 parent
863f62f4d8
commit
bd0e4a5a8f
6 files changed
-962
No files matched your search
@@ -1,12 +0,0 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="enable-background:new 0 0 1792 1792;" xml:space="preserve" width="1792" height="1792"><rect id="backgroundrect" width="100%" height="100%" x="0" y="0" fill="none" stroke="none"/>
|
||||
<style type="text/css">
|
||||
.st0{fill:#222222;}
|
||||
.st1{fill:#FFFFFF;}
|
||||
</style>
|
||||
<title>save_data_changes</title>
|
||||
|
||||
|
||||
<g class="currentLayer" style=""><title>Layer 1</title><path class="st0 selected" d="M614.0211181640625,1381.039882183075 v-170.18182373046875 c0,-8.243182182312012 -2.6703295707702637,-15.068181991577148 -8.01098918914795,-20.386363983154297 s-12.19450569152832,-7.9772725105285645 -20.4725284576416,-7.9772725105285645 H300.70343017578125 c-8.278021812438965,0 -15.131868362426758,2.659090995788574 -20.4725284576416,7.9772725105285645 s-8.01098918914795,12.143181800842285 -8.01098918914795,20.386363983154297 v170.18182373046875 c0,8.243182182312012 2.6703295707702637,15.068181991577148 8.01098918914795,20.386363983154297 s12.19450569152832,7.9772725105285645 20.4725284576416,7.9772725105285645 h284.8351745605469 c8.278021812438965,0 15.131868362426758,-2.659090995788574 20.4725284576416,-7.9772725105285645 S614.0211181640625,1389.2831683158875 614.0211181640625,1381.039882183075 zM614.0211181640625,1040.6748919487 V870.49276304245 c0,-8.243182182312012 -2.6703295707702637,-15.068181991577148 -8.01098918914795,-20.386363983154297 s-12.19450569152832,-7.9772725105285645 -20.4725284576416,-7.9772725105285645 H300.70343017578125 c-8.278021812438965,0 -15.131868362426758,2.659090995788574 -20.4725284576416,7.9772725105285645 s-8.01098918914795,12.143181800842285 -8.01098918914795,20.386363983154297 v170.18182373046875 c0,8.243182182312012 2.6703295707702637,15.068181991577148 8.01098918914795,20.386363983154297 s12.19450569152832,7.9772725105285645 20.4725284576416,7.9772725105285645 h284.8351745605469 c8.278021812438965,0 15.131868362426758,-2.659090995788574 20.4725284576416,-7.9772725105285645 S614.0211181640625,1048.918300151825 614.0211181640625,1040.6748919487 zM1069.7584228515625,1381.039882183075 v-170.18182373046875 c0,-8.243182182312012 -2.6703295707702637,-15.068181991577148 -8.01098918914795,-20.386363983154297 s-12.19450569152832,-7.9772725105285645 -20.4725284576416,-7.9772725105285645 H756.438720703125 c-8.278021812438965,0 -15.131868362426758,2.659090995788574 -20.4725284576416,7.9772725105285645 s-8.01098918914795,12.143181800842285 -8.01098918914795,20.386363983154297 v170.18182373046875 c0,8.243182182312012 2.6703295707702637,15.068181991577148 8.01098918914795,20.386363983154297 s12.19450569152832,7.9772725105285645 20.4725284576416,7.9772725105285645 h284.8351745605469 c8.278021812438965,0 15.131868362426758,-2.659090995788574 20.4725284576416,-7.9772725105285645 S1069.7584228515625,1389.2831683158875 1069.7584228515625,1381.039882183075 zM614.0211181640625,700.3109393119812 V530.1298480033875 c0,-8.243182182312012 -2.6703295707702637,-15.068181991577148 -8.01098918914795,-20.386363983154297 s-12.19450569152832,-7.9772725105285645 -20.4725284576416,-7.9772725105285645 H300.70343017578125 c-8.278021812438965,0 -15.131868362426758,2.659090995788574 -20.4725284576416,7.9772725105285645 s-8.01098918914795,12.143181800842285 -8.01098918914795,20.386363983154297 v170.18182373046875 c0,8.243182182312012 2.6703295707702637,15.068181991577148 8.01098918914795,20.386363983154297 s12.19450569152832,7.9772725105285645 20.4725284576416,7.9772725105285645 h284.8351745605469 c8.278021812438965,0 15.131868362426758,-2.659090995788574 20.4725284576416,-7.9772725105285645 S614.0211181640625,708.5541033744812 614.0211181640625,700.3109393119812 zM1069.7584228515625,1040.6748919487 V870.49276304245 c0,-8.243182182312012 -2.6703295707702637,-15.068181991577148 -8.01098918914795,-20.386363983154297 s-12.19450569152832,-7.9772725105285645 -20.4725284576416,-7.9772725105285645 H756.438720703125 c-8.278021812438965,0 -15.131868362426758,2.659090995788574 -20.4725284576416,7.9772725105285645 s-8.01098918914795,12.143181800842285 -8.01098918914795,20.386363983154297 v170.18182373046875 c0,8.243182182312012 2.6703295707702637,15.068181991577148 8.01098918914795,20.386363983154297 s12.19450569152832,7.9772725105285645 20.4725284576416,7.9772725105285645 h284.8351745605469 c8.278021812438965,0 15.131868362426758,-2.659090995788574 20.4725284576416,-7.9772725105285645 S1069.7584228515625,1048.918300151825 1069.7584228515625,1040.6748919487 zM1525.49560546875,1381.039882183075 v-170.18182373046875 c0,-8.243182182312012 -2.6703295707702637,-15.068181991577148 -8.01098918914795,-20.386363983154297 s-12.19450569152832,-7.9772725105285645 -20.4725284576416,-7.9772725105285645 h-284.8351745605469 c-8.278021812438965,0 -15.131868362426758,2.659090995788574 -20.4725284576416,7.9772725105285645 s-8.01098918914795,12.143181800842285 -8.01098918914795,20.386363983154297 v170.18182373046875 c0,8.243182182312012 2.6703295707702637,15.068181991577148 8.01098918914795,20.386363983154297 s12.19450569152832,7.9772725105285645 20.4725284576416,7.9772725105285645 h284.8351745605469 c8.278021812438965,0 15.131868362426758,-2.659090995788574 20.4725284576416,-7.9772725105285645 S1525.49560546875,1389.2831683158875 1525.49560546875,1381.039882183075 zM1069.7584228515625,700.3109393119812 V530.1298480033875 c0,-8.243182182312012 -2.670329570770Line truncated
|
||||
<path class="st0" d="M898.8562622070312,1342.7491106987 c-22.69780158996582,0 -43.081321716308594,-8.331817626953125 -58.92527389526367,-24.19772720336914 l-289.4637451171875,-288.6886291503906 c-16.378021240234375,-15.51136302947998 -25.012088775634766,-35.897727966308594 -25.012088775634766,-58.943180084228516 c0,-22.868181228637695 8.278021812438965,-42.72272872924805 24.656044006347656,-59.03181457519531 l32.84505844116211,-33.150001525878906 c0.17802198231220245,-0.1772727221250534 0.44505494832992554,-0.4431818127632141 0.6230769157409668,-0.6204545497894287 c16.46703338623047,-15.51136302947998 36.761539459228516,-23.665908813476562 58.83626174926758,-23.665908813476562 c22.69780158996582,0 43.081321716308594,8.331817626953125 58.92527389526367,24.19772720336914 l85.27252960205078,84.91363525390625 V715.5564227104187 c0,-22.247726440429688 8.545055389404297,-42.54545593261719 24.745054244995117,-58.677268981933594 s36.58351516723633,-24.640907287597656 58.92527389526367,-24.640907287597656 h56.96703338623047 c22.341758728027344,0 42.72527313232422,8.5090913772583 58.92527389526367,24.640907287597656 s24.745054244995117,36.429542541503906 24.745054244995117,58.677268981933594 v247.8272705078125 l85.27252960205078,-84.91363525390625 c15.932967185974121,-15.8659086227417 36.227474212646484,-24.19772720336914 58.92527389526367,-24.19772720336914 c22.074724197387695,0 42.45824432373047,8.154544830322266 58.83626174926758,23.665908813476562 c0.17802198231220245,0.1772727221250534 0.3560439646244049,0.3545454442501068 0.5340659618377686,0.5318182110786438 l33.379119873046875,33.2386360168457 c0.17802198231220245,0.1772727221250534 0.3560439646244049,0.3545454442501068 0.5340659618377686,0.5318182110786438 c15.576923370361328,16.397727966308594 23.765933990478516,36.606815338134766 23.765933990478516,58.5886344909668 c0,22.602272033691406 -8.367033004760742,42.900001525878906 -24.299999237060547,58.677268981933594 l-289.73077392578125,288.95452880859375 c-0.17802198231220245,0.1772727221250534 -0.3560439646244049,0.3545454442501068 -0.5340659618377686,0.5318182110786438 C941.3145141601562,1334.5058245658875 920.9309692382812,1342.7491106987 898.8562622070312,1342.7491106987 z" id="svg_3"/>
|
||||
<path class="st1" d="M927.3397827148438,658.8291277885437 c15.398900985717773,0 28.75054931640625,5.5840911865234375 40.05494689941406,16.84090805053711 s16.91208839416504,24.55227279663086 16.91208839416504,39.8863639831543 v312 l130.84616088867188,-130.2954559326172 c10.948351860046387,-10.902273178100586 24.299999237060547,-16.397727966308594 40.05494689941406,-16.397727966308594 c15.398900985717773,0 28.928571701049805,5.49545431137085 40.5,16.397727966308594 l33.379119873046875,33.2386360168457 c10.948351860046387,11.522727012634277 16.46703338623047,24.995454788208008 16.46703338623047,40.32954406738281 c0,15.688636779785156 -5.518681049346924,28.98409080505371 -16.46703338623047,39.8863639831543 l-289.73077392578125,288.95452880859375 c-11.571428298950195,10.902273178100586 -25.101099014282227,16.397727966308594 -40.5,16.397727966308594 c-15.754945755004883,0 -29.10659408569336,-5.49545431137085 -40.05494689941406,-16.397727966308594 l-289.73077392578125,-288.95452880859375 c-11.30439567565918,-10.636363983154297 -16.91208839416504,-23.93181800842285 -16.91208839416504,-39.8863639831543 c0,-15.688636779785156 5.607692718505859,-29.072725296020508 16.91208839416504,-40.32954406738281 l32.93406677246094,-33.2386360168457 c11.571428298950195,-10.902273178100586 25.101099014282227,-16.397727966308594 40.5,-16.397727966308594 c15.754945755004883,0 29.10659408569336,5.49545431137085 40.05494689941406,16.397727966308594 l130.84616088867188,130.2954559326172 v-312 c0,-15.334090232849121 5.607692718505859,-28.629545211791992 16.91208839416504,-39.8863639831543 s24.656044006347656,-16.84090805053711 40.05494689941406,-16.84090805053711 L927.3397827148438,658.8291277885437 M927.3397827148438,605.647304058075 h-56.96703338623047 c-29.64065933227539,0 -56.52198028564453,11.168182373046875 -77.79560852050781,32.4409065246582 c-21.36263656616211,21.272727966308594 -32.57802200317383,48.04090881347656 -32.57802200317383,77.46818542480469 v183.56591796875 l-39.69889831542969,-39.53181457519531 c-21.006593704223633,-20.918182373046875 -47.88791275024414,-31.997726440429688 -77.79560852050781,-31.997726440429688 c-29.017581939697266,0 -55.72087860107422,10.725000381469727 -77.17252349853516,30.934091567993164 c-0.44505494832992554,0.4431818127632141 -0.8901098966598511,0.8863636255264282 -1.3351647853851318,1.2409090995788574 l-32.84505844116211,33.150001525878906 c-21.184614181518555,21.18408966064453 -32.400001525878906,48.04090881347656 -32.400001525878906,77.8227310180664 c0,30.402271270751953 11.393406867980957,57.259090423583984 33.023075103759766,77.91136169433594 l289.28570556640625,288.5113525390625 c21.006593704223633,20.918182373046875 47.976924896240234,31.997726440429688 77.88461303710938,31.997726440429688 c29.017581939697266,0 55.72087860107422,-10.725000381469727 77.17252349853516,-30.934091567993164 c0.3560439646244049,-0.3545454442501068 0.7120879292488098,-0.7090908885002136 1.068131923675537,-1.0636364221572876 l289.73077392578125,-288.95452880859375 c21.006593704223633,-20.918182373046875 32.0439567565918,-47.686363220214844 32.0439567565918,-77.46818542480469 c0,-28.89545249938965 -10.770330429077148,-55.48636245727539 -31.064836502075195,-76.84772491455078 c-0.3560439646244049,-0.3545454442501068 -0.7120879292488098,-0.7090908885002136 -1.068131923675537,-1.0636364221572876 l-33.379119873046875,-33.2386360168457 c-0.3560439646244049,-0.3545454442501068 -0.7120879292488098,-0.7090908885002136 -1.068131923675537,-1.0636364221572876 c-21.451648712158203,-20.209089279174805 -48.154945373535156,-30.934091567993164 -77.17252349853516,-30.934091567993164 c-29.907691955566406,0 -56.78900909423828,11.079545021057129 -77.79560852050781,31.997726440429688 l-39.69889831542969,39.53181457519531 V715.5564227104187 c0,-29.515907287597656 -11.215385437011719,-56.28409194946289 -32.57802200317383,-77.46818542480469 C983.8617553710938,616.904139995575 956.98046875,605.647304058075 927.3397827148438,605.647304058075 L927.3397827148438,605.647304058075 z" id="svg_4"/>
|
||||
</g></g></svg>
|
||||
|
Before Width: | Height: | Size: 14 KiB |
@@ -1,41 +0,0 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2019, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import json
|
||||
|
||||
# Utility functions used by tests
|
||||
|
||||
|
||||
# Executes a query and polls for the results, then returns them
|
||||
def execute_query(tester, query, start_query_tool_url, poll_url):
|
||||
# Start query tool and execute sql
|
||||
response = tester.post(start_query_tool_url,
|
||||
data=json.dumps({"sql": query}),
|
||||
content_type='html/json')
|
||||
|
||||
if response.status_code != 200:
|
||||
return False, None
|
||||
|
||||
# Poll for results
|
||||
return poll_for_query_results(tester=tester, poll_url=poll_url)
|
||||
|
||||
|
||||
# Polls for the result of an executed query
|
||||
def poll_for_query_results(tester, poll_url):
|
||||
# Poll for results until they are successful
|
||||
while True:
|
||||
response = tester.get(poll_url)
|
||||
if response.status_code != 200:
|
||||
return False, None
|
||||
response_data = json.loads(response.data.decode('utf-8'))
|
||||
status = response_data['data']['status']
|
||||
if status == 'Success':
|
||||
return True, response_data
|
||||
elif status == 'NotConnected' or status == 'Cancel':
|
||||
return False, None
|
||||
@@ -1,125 +0,0 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2019, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import json
|
||||
|
||||
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
|
||||
database_utils
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression import parent_node_dict
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from .execute_query_utils import execute_query
|
||||
|
||||
|
||||
class TestQueryUpdatableResultset(BaseTestGenerator):
|
||||
""" This class will test the detection of whether the query
|
||||
result-set is updatable. """
|
||||
scenarios = [
|
||||
('When selecting all columns of the table', dict(
|
||||
sql='SELECT * FROM test_for_updatable_resultset;',
|
||||
primary_keys={
|
||||
'pk_col1': 'int4',
|
||||
'pk_col2': 'int4'
|
||||
}
|
||||
)),
|
||||
('When selecting all primary keys of the table', dict(
|
||||
sql='SELECT pk_col1, pk_col2 FROM test_for_updatable_resultset;',
|
||||
primary_keys={
|
||||
'pk_col1': 'int4',
|
||||
'pk_col2': 'int4'
|
||||
}
|
||||
)),
|
||||
('When selecting some of the primary keys of the table', dict(
|
||||
sql='SELECT pk_col2 FROM test_for_updatable_resultset;',
|
||||
primary_keys=None
|
||||
)),
|
||||
('When selecting none of the primary keys of the table', dict(
|
||||
sql='SELECT normal_col1 FROM test_for_updatable_resultset;',
|
||||
primary_keys=None
|
||||
)),
|
||||
('When renaming a primary key', dict(
|
||||
sql='SELECT pk_col1 as some_col, '
|
||||
'pk_col2 FROM test_for_updatable_resultset;',
|
||||
primary_keys=None
|
||||
)),
|
||||
('When renaming a column to a primary key name', dict(
|
||||
sql='SELECT pk_col1, pk_col2, normal_col1 as pk_col1 '
|
||||
'FROM test_for_updatable_resultset;',
|
||||
primary_keys=None
|
||||
))
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
self._initialize_database_connection()
|
||||
self._initialize_query_tool()
|
||||
self._initialize_urls()
|
||||
self._create_test_table()
|
||||
|
||||
def runTest(self):
|
||||
is_success, response_data = \
|
||||
execute_query(tester=self.tester,
|
||||
query=self.sql,
|
||||
poll_url=self.poll_url,
|
||||
start_query_tool_url=self.start_query_tool_url)
|
||||
self.assertEquals(is_success, True)
|
||||
|
||||
# Check primary keys
|
||||
primary_keys = response_data['data']['primary_keys']
|
||||
self.assertEquals(primary_keys, self.primary_keys)
|
||||
|
||||
def tearDown(self):
|
||||
# Disconnect the database
|
||||
database_utils.disconnect_database(self, self.server_id, self.db_id)
|
||||
|
||||
def _initialize_database_connection(self):
|
||||
database_info = parent_node_dict["database"][-1]
|
||||
self.server_id = database_info["server_id"]
|
||||
|
||||
self.db_id = database_info["db_id"]
|
||||
db_con = database_utils.connect_database(self,
|
||||
utils.SERVER_GROUP,
|
||||
self.server_id,
|
||||
self.db_id)
|
||||
if not db_con["info"] == "Database connected.":
|
||||
raise Exception("Could not connect to the database.")
|
||||
|
||||
def _initialize_query_tool(self):
|
||||
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}'.format(
|
||||
utils.SERVER_GROUP, self.server_id, self.db_id)
|
||||
response = self.tester.post(url)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
response_data = json.loads(response.data.decode('utf-8'))
|
||||
self.trans_id = response_data['data']['gridTransId']
|
||||
|
||||
def _initialize_urls(self):
|
||||
self.start_query_tool_url = \
|
||||
'/sqleditor/query_tool/start/{0}'.format(self.trans_id)
|
||||
|
||||
self.poll_url = '/sqleditor/poll/{0}'.format(self.trans_id)
|
||||
|
||||
def _create_test_table(self):
|
||||
create_sql = """
|
||||
DROP TABLE IF EXISTS test_for_updatable_resultset;
|
||||
|
||||
CREATE TABLE test_for_updatable_resultset(
|
||||
pk_col1 SERIAL,
|
||||
pk_col2 SERIAL,
|
||||
normal_col1 VARCHAR,
|
||||
normal_col2 VARCHAR,
|
||||
PRIMARY KEY(pk_col1, pk_col2)
|
||||
);
|
||||
"""
|
||||
|
||||
is_success, _ = \
|
||||
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)
|
||||
@@ -1,347 +0,0 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2019, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import json
|
||||
|
||||
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
|
||||
database_utils
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression import parent_node_dict
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from .execute_query_utils import execute_query
|
||||
|
||||
|
||||
class TestSaveChangedData(BaseTestGenerator):
|
||||
""" This class tests saving data changes in the grid to the database """
|
||||
scenarios = [
|
||||
('When inserting new valid row', dict(
|
||||
save_payload={
|
||||
"updated": {},
|
||||
"added": {
|
||||
"2": {
|
||||
"err": False,
|
||||
"data": {
|
||||
"pk_col": "3",
|
||||
"__temp_PK": "2",
|
||||
"normal_col": "three"
|
||||
}
|
||||
}
|
||||
},
|
||||
"staged_rows": {},
|
||||
"deleted": {},
|
||||
"updated_index": {},
|
||||
"added_index": {"2": "2"},
|
||||
"columns": [
|
||||
{
|
||||
"name": "pk_col",
|
||||
"display_name": "pk_col",
|
||||
"column_type": "[PK] integer",
|
||||
"column_type_internal": "integer",
|
||||
"pos": 0,
|
||||
"label": "pk_col<br>[PK] integer",
|
||||
"cell": "number",
|
||||
"can_edit": True,
|
||||
"type": "integer",
|
||||
"not_null": True,
|
||||
"has_default_val": False,
|
||||
"is_array": False},
|
||||
{"name": "normal_col",
|
||||
"display_name": "normal_col",
|
||||
"column_type": "character varying",
|
||||
"column_type_internal": "character varying",
|
||||
"pos": 1,
|
||||
"label": "normal_col<br>character varying",
|
||||
"cell": "string",
|
||||
"can_edit": True,
|
||||
"type": "character varying",
|
||||
"not_null": False,
|
||||
"has_default_val": False,
|
||||
"is_array": False}
|
||||
]
|
||||
},
|
||||
save_status=True,
|
||||
check_sql='SELECT * FROM test_for_save_data WHERE pk_col = 3',
|
||||
check_result=[[3, "three"]]
|
||||
)),
|
||||
('When inserting new invalid row', dict(
|
||||
save_payload={
|
||||
"updated": {},
|
||||
"added": {
|
||||
"2": {
|
||||
"err": False,
|
||||
"data": {
|
||||
"pk_col": "1",
|
||||
"__temp_PK": "2",
|
||||
"normal_col": "four"
|
||||
}
|
||||
}
|
||||
},
|
||||
"staged_rows": {},
|
||||
"deleted": {},
|
||||
"updated_index": {},
|
||||
"added_index": {"2": "2"},
|
||||
"columns": [
|
||||
{
|
||||
"name": "pk_col",
|
||||
"display_name": "pk_col",
|
||||
"column_type": "[PK] integer",
|
||||
"column_type_internal": "integer",
|
||||
"pos": 0,
|
||||
"label": "pk_col<br>[PK] integer",
|
||||
"cell": "number",
|
||||
"can_edit": True,
|
||||
"type": "integer",
|
||||
"not_null": True,
|
||||
"has_default_val": False,
|
||||
"is_array": False},
|
||||
{"name": "normal_col",
|
||||
"display_name": "normal_col",
|
||||
"column_type": "character varying",
|
||||
"column_type_internal": "character varying",
|
||||
"pos": 1,
|
||||
"label": "normal_col<br>character varying",
|
||||
"cell": "string",
|
||||
"can_edit": True,
|
||||
"type": "character varying",
|
||||
"not_null": False,
|
||||
"has_default_val": False,
|
||||
"is_array": False}
|
||||
]
|
||||
},
|
||||
save_status=False,
|
||||
check_sql=None,
|
||||
check_result=None
|
||||
)),
|
||||
('When updating a row in a valid way', dict(
|
||||
save_payload={
|
||||
"updated": {
|
||||
"1":
|
||||
{"err": False,
|
||||
"data": {"normal_col": "ONE"},
|
||||
"primary_keys":
|
||||
{"pk_col": 1}
|
||||
}
|
||||
},
|
||||
"added": {},
|
||||
"staged_rows": {},
|
||||
"deleted": {},
|
||||
"updated_index": {"1": "1"},
|
||||
"added_index": {},
|
||||
"columns": [
|
||||
{
|
||||
"name": "pk_col",
|
||||
"display_name": "pk_col",
|
||||
"column_type": "[PK] integer",
|
||||
"column_type_internal": "integer",
|
||||
"pos": 0,
|
||||
"label": "pk_col<br>[PK] integer",
|
||||
"cell": "number",
|
||||
"can_edit": True,
|
||||
"type": "integer",
|
||||
"not_null": True,
|
||||
"has_default_val": False,
|
||||
"is_array": False},
|
||||
{"name": "normal_col",
|
||||
"display_name": "normal_col",
|
||||
"column_type": "character varying",
|
||||
"column_type_internal": "character varying",
|
||||
"pos": 1,
|
||||
"label": "normal_col<br>character varying",
|
||||
"cell": "string",
|
||||
"can_edit": True,
|
||||
"type": "character varying",
|
||||
"not_null": False,
|
||||
"has_default_val": False,
|
||||
"is_array": False}
|
||||
]
|
||||
},
|
||||
save_status=True,
|
||||
check_sql='SELECT * FROM test_for_save_data WHERE pk_col = 1',
|
||||
check_result=[[1, "ONE"]]
|
||||
)),
|
||||
('When updating a row in an invalid way', dict(
|
||||
save_payload={
|
||||
"updated": {
|
||||
"1":
|
||||
{"err": False,
|
||||
"data": {"pk_col": "2"},
|
||||
"primary_keys":
|
||||
{"pk_col": 1}
|
||||
}
|
||||
},
|
||||
"added": {},
|
||||
"staged_rows": {},
|
||||
"deleted": {},
|
||||
"updated_index": {"1": "1"},
|
||||
"added_index": {},
|
||||
"columns": [
|
||||
{
|
||||
"name": "pk_col",
|
||||
"display_name": "pk_col",
|
||||
"column_type": "[PK] integer",
|
||||
"column_type_internal": "integer",
|
||||
"pos": 0,
|
||||
"label": "pk_col<br>[PK] integer",
|
||||
"cell": "number",
|
||||
"can_edit": True,
|
||||
"type": "integer",
|
||||
"not_null": True,
|
||||
"has_default_val": False,
|
||||
"is_array": False},
|
||||
{"name": "normal_col",
|
||||
"display_name": "normal_col",
|
||||
"column_type": "character varying",
|
||||
"column_type_internal": "character varying",
|
||||
"pos": 1,
|
||||
"label": "normal_col<br>character varying",
|
||||
"cell": "string",
|
||||
"can_edit": True,
|
||||
"type": "character varying",
|
||||
"not_null": False,
|
||||
"has_default_val": False,
|
||||
"is_array": False}
|
||||
]
|
||||
},
|
||||
save_status=False,
|
||||
check_sql=None,
|
||||
check_result=None
|
||||
)),
|
||||
('When deleting a row', dict(
|
||||
save_payload={
|
||||
"updated": {},
|
||||
"added": {},
|
||||
"staged_rows": {"1": {"pk_col": 2}},
|
||||
"deleted": {"1": {"pk_col": 2}},
|
||||
"updated_index": {},
|
||||
"added_index": {},
|
||||
"columns": [
|
||||
{
|
||||
"name": "pk_col",
|
||||
"display_name": "pk_col",
|
||||
"column_type": "[PK] integer",
|
||||
"column_type_internal": "integer",
|
||||
"pos": 0,
|
||||
"label": "pk_col<br>[PK] integer",
|
||||
"cell": "number",
|
||||
"can_edit": True,
|
||||
"type": "integer",
|
||||
"not_null": True,
|
||||
"has_default_val": False,
|
||||
"is_array": False},
|
||||
{"name": "normal_col",
|
||||
"display_name": "normal_col",
|
||||
"column_type": "character varying",
|
||||
"column_type_internal": "character varying",
|
||||
"pos": 1,
|
||||
"label": "normal_col<br>character varying",
|
||||
"cell": "string",
|
||||
"can_edit": True,
|
||||
"type": "character varying",
|
||||
"not_null": False,
|
||||
"has_default_val": False,
|
||||
"is_array": False}
|
||||
]
|
||||
},
|
||||
save_status=True,
|
||||
check_sql='SELECT * FROM test_for_save_data WHERE pk_col = 2',
|
||||
check_result='SELECT 0'
|
||||
)),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
self._initialize_database_connection()
|
||||
self._initialize_query_tool()
|
||||
self._initialize_urls_and_select_sql()
|
||||
self._create_test_table()
|
||||
|
||||
def runTest(self):
|
||||
# Execute select sql
|
||||
is_success, _ = \
|
||||
execute_query(tester=self.tester,
|
||||
query=self.select_sql,
|
||||
start_query_tool_url=self.start_query_tool_url,
|
||||
poll_url=self.poll_url)
|
||||
self.assertEquals(is_success, True)
|
||||
|
||||
# Send a request to save changed data
|
||||
response = self.tester.post(self.save_url,
|
||||
data=json.dumps(self.save_payload),
|
||||
content_type='html/json')
|
||||
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
# Check that the save is successful
|
||||
response_data = json.loads(response.data.decode('utf-8'))
|
||||
save_status = response_data['data']['status']
|
||||
self.assertEquals(save_status, self.save_status)
|
||||
|
||||
if self.check_sql:
|
||||
# Execute check sql
|
||||
is_success, response_data = \
|
||||
execute_query(tester=self.tester,
|
||||
query=self.check_sql,
|
||||
start_query_tool_url=self.start_query_tool_url,
|
||||
poll_url=self.poll_url)
|
||||
self.assertEquals(is_success, True)
|
||||
|
||||
# Check table for updates
|
||||
result = response_data['data']['result']
|
||||
self.assertEquals(result, self.check_result)
|
||||
|
||||
def tearDown(self):
|
||||
# Disconnect the database
|
||||
database_utils.disconnect_database(self, self.server_id, self.db_id)
|
||||
|
||||
def _initialize_database_connection(self):
|
||||
database_info = parent_node_dict["database"][-1]
|
||||
self.server_id = database_info["server_id"]
|
||||
|
||||
self.db_id = database_info["db_id"]
|
||||
db_con = database_utils.connect_database(self,
|
||||
utils.SERVER_GROUP,
|
||||
self.server_id,
|
||||
self.db_id)
|
||||
if not db_con["info"] == "Database connected.":
|
||||
raise Exception("Could not connect to the database.")
|
||||
|
||||
def _initialize_query_tool(self):
|
||||
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}'.format(
|
||||
utils.SERVER_GROUP, self.server_id, self.db_id)
|
||||
response = self.tester.post(url)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
response_data = json.loads(response.data.decode('utf-8'))
|
||||
self.trans_id = response_data['data']['gridTransId']
|
||||
|
||||
def _initialize_urls_and_select_sql(self):
|
||||
self.start_query_tool_url = \
|
||||
'/sqleditor/query_tool/start/{0}'.format(self.trans_id)
|
||||
self.save_url = '/sqleditor/save/{0}'.format(self.trans_id)
|
||||
self.poll_url = '/sqleditor/poll/{0}'.format(self.trans_id)
|
||||
|
||||
self.select_sql = 'SELECT * FROM test_for_save_data;'
|
||||
|
||||
def _create_test_table(self):
|
||||
create_sql = """
|
||||
DROP TABLE IF EXISTS test_for_save_data;
|
||||
|
||||
CREATE TABLE test_for_save_data(
|
||||
pk_col INT PRIMARY KEY,
|
||||
normal_col VARCHAR);
|
||||
|
||||
INSERT INTO test_for_save_data VALUES
|
||||
(1, 'one'),
|
||||
(2, 'two');
|
||||
"""
|
||||
is_success, _ = \
|
||||
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)
|
||||
@@ -1,120 +0,0 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2019, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
"""
|
||||
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
|
||||
"""
|
||||
from flask import render_template
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
from ordereddict import OrderedDict
|
||||
|
||||
|
||||
def is_query_resultset_updatable(conn, sql_path):
|
||||
"""
|
||||
This function is used to check whether the last successful query
|
||||
produced updatable results.
|
||||
|
||||
Args:
|
||||
conn: Connection object.
|
||||
sql_path: the path to the sql templates.
|
||||
"""
|
||||
columns_info = conn.get_column_info()
|
||||
|
||||
if columns_info is None or len(columns_info) < 1:
|
||||
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):
|
||||
return return_not_updatable()
|
||||
|
||||
if conn.connected():
|
||||
primary_keys, primary_keys_columns, pk_names = \
|
||||
_get_primary_keys(conn=conn,
|
||||
table_oid=table_oid,
|
||||
sql_path=sql_path)
|
||||
|
||||
if not _check_primary_keys_uniquely_exist(primary_keys_columns,
|
||||
columns_info):
|
||||
return return_not_updatable()
|
||||
|
||||
return True, primary_keys, pk_names, table_oid
|
||||
else:
|
||||
return return_not_updatable()
|
||||
|
||||
|
||||
def _check_single_table(columns_info):
|
||||
table_oid = columns_info[0]['table_oid']
|
||||
for column in columns_info:
|
||||
if 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_primary_keys_uniquely_exist(primary_keys_columns, columns_info):
|
||||
for pk in primary_keys_columns:
|
||||
pk_exists = False
|
||||
for col in columns_info:
|
||||
if 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 not pk_exists:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _get_primary_keys(sql_path, table_oid, conn):
|
||||
query = render_template(
|
||||
"/".join([sql_path, 'primary_keys.sql']),
|
||||
obj_id=table_oid
|
||||
)
|
||||
status, result = conn.execute_dict(query)
|
||||
if not status:
|
||||
return return_not_updatable()
|
||||
|
||||
primary_keys_columns = []
|
||||
primary_keys = OrderedDict()
|
||||
pk_names = []
|
||||
|
||||
for row in result['rows']:
|
||||
primary_keys[row['attname']] = row['typname']
|
||||
primary_keys_columns.append({
|
||||
'name': row['attname'],
|
||||
'column_number': row['attnum']
|
||||
})
|
||||
pk_names.append(row['attname'])
|
||||
|
||||
return primary_keys, primary_keys_columns, pk_names
|
||||
|
||||
|
||||
def return_not_updatable():
|
||||
return False, None, None, None
|
||||
@@ -1,317 +0,0 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2019, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
from flask import render_template
|
||||
from pgadmin.tools.sqleditor.utils.constant_definition import TX_STATUS_IDLE
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
from ordereddict import OrderedDict
|
||||
|
||||
|
||||
def save_changed_data(changed_data, columns_info, conn, command_obj,
|
||||
client_primary_key, auto_commit=True):
|
||||
"""
|
||||
This function is used to save the data into the database.
|
||||
Depending on condition it will either update or insert the
|
||||
new row into the database.
|
||||
|
||||
Args:
|
||||
changed_data: Contains data to be saved
|
||||
command_obj: The transaction object (command_obj or trans_obj)
|
||||
conn: The connection object
|
||||
columns_info: session_obj['columns_info']
|
||||
client_primary_key: session_obj['client_primary_key']
|
||||
auto_commit: If the changes should be commited automatically.
|
||||
"""
|
||||
status = False
|
||||
res = None
|
||||
query_res = dict()
|
||||
count = 0
|
||||
list_of_rowid = []
|
||||
operations = ('added', 'updated', 'deleted')
|
||||
list_of_sql = {}
|
||||
_rowid = None
|
||||
is_commit_required = False
|
||||
|
||||
pgadmin_alias = {
|
||||
col_name: col_info['pgadmin_alias']
|
||||
for col_name, col_info in columns_info.items()
|
||||
}
|
||||
|
||||
if conn.connected():
|
||||
is_savepoint = False
|
||||
# Start the transaction if the session is idle
|
||||
if conn.transaction_status() == TX_STATUS_IDLE:
|
||||
conn.execute_void('BEGIN;')
|
||||
else:
|
||||
conn.execute_void('SAVEPOINT save_data;')
|
||||
is_savepoint = True
|
||||
|
||||
# Iterate total number of records to be updated/inserted
|
||||
for of_type in changed_data:
|
||||
# No need to go further if its not add/update/delete operation
|
||||
if of_type not in operations:
|
||||
continue
|
||||
# if no data to be save then continue
|
||||
if len(changed_data[of_type]) < 1:
|
||||
continue
|
||||
|
||||
column_type = {}
|
||||
column_data = {}
|
||||
for each_col in columns_info:
|
||||
if (
|
||||
columns_info[each_col]['not_null'] and
|
||||
not columns_info[each_col]['has_default_val']
|
||||
):
|
||||
column_data[each_col] = None
|
||||
column_type[each_col] = \
|
||||
columns_info[each_col]['type_name']
|
||||
else:
|
||||
column_type[each_col] = \
|
||||
columns_info[each_col]['type_name']
|
||||
|
||||
# For newly added rows
|
||||
if of_type == 'added':
|
||||
# Python dict does not honour the inserted item order
|
||||
# So to insert data in the order, we need to make ordered
|
||||
# list of added index We don't need this mechanism in
|
||||
# updated/deleted rows as it does not matter in
|
||||
# those operations
|
||||
added_index = OrderedDict(
|
||||
sorted(
|
||||
changed_data['added_index'].items(),
|
||||
key=lambda x: int(x[0])
|
||||
)
|
||||
)
|
||||
list_of_sql[of_type] = []
|
||||
|
||||
# When new rows are added, only changed columns data is
|
||||
# sent from client side. But if column is not_null and has
|
||||
# no_default_value, set column to blank, instead
|
||||
# of not null which is set by default.
|
||||
column_data = {}
|
||||
pk_names, primary_keys = command_obj.get_primary_keys()
|
||||
has_oids = 'oid' in column_type
|
||||
|
||||
for each_row in added_index:
|
||||
# Get the row index to match with the added rows
|
||||
# dict key
|
||||
tmp_row_index = added_index[each_row]
|
||||
data = changed_data[of_type][tmp_row_index]['data']
|
||||
# Remove our unique tracking key
|
||||
data.pop(client_primary_key, None)
|
||||
data.pop('is_row_copied', None)
|
||||
list_of_rowid.append(data.get(client_primary_key))
|
||||
|
||||
# Update columns value with columns having
|
||||
# not_null=False and has no default value
|
||||
column_data.update(data)
|
||||
|
||||
sql = render_template(
|
||||
"/".join([command_obj.sql_path, 'insert.sql']),
|
||||
data_to_be_saved=column_data,
|
||||
pgadmin_alias=pgadmin_alias,
|
||||
primary_keys=None,
|
||||
object_name=command_obj.object_name,
|
||||
nsp_name=command_obj.nsp_name,
|
||||
data_type=column_type,
|
||||
pk_names=pk_names,
|
||||
has_oids=has_oids
|
||||
)
|
||||
|
||||
select_sql = render_template(
|
||||
"/".join([command_obj.sql_path, 'select.sql']),
|
||||
object_name=command_obj.object_name,
|
||||
nsp_name=command_obj.nsp_name,
|
||||
primary_keys=primary_keys,
|
||||
has_oids=has_oids
|
||||
)
|
||||
|
||||
list_of_sql[of_type].append({
|
||||
'sql': sql, 'data': data,
|
||||
'client_row': tmp_row_index,
|
||||
'select_sql': select_sql
|
||||
})
|
||||
# Reset column data
|
||||
column_data = {}
|
||||
|
||||
# For updated rows
|
||||
elif of_type == 'updated':
|
||||
list_of_sql[of_type] = []
|
||||
for each_row in changed_data[of_type]:
|
||||
data = changed_data[of_type][each_row]['data']
|
||||
pk_escaped = {
|
||||
pk: pk_val.replace('%', '%%') if hasattr(
|
||||
pk_val, 'replace') else pk_val
|
||||
for pk, pk_val in
|
||||
changed_data[of_type][each_row]['primary_keys'].items()
|
||||
}
|
||||
sql = render_template(
|
||||
"/".join([command_obj.sql_path, 'update.sql']),
|
||||
data_to_be_saved=data,
|
||||
pgadmin_alias=pgadmin_alias,
|
||||
primary_keys=pk_escaped,
|
||||
object_name=command_obj.object_name,
|
||||
nsp_name=command_obj.nsp_name,
|
||||
data_type=column_type
|
||||
)
|
||||
list_of_sql[of_type].append({'sql': sql, 'data': data})
|
||||
list_of_rowid.append(data.get(client_primary_key))
|
||||
|
||||
# For deleted rows
|
||||
elif of_type == 'deleted':
|
||||
list_of_sql[of_type] = []
|
||||
is_first = True
|
||||
rows_to_delete = []
|
||||
keys = None
|
||||
no_of_keys = None
|
||||
for each_row in changed_data[of_type]:
|
||||
rows_to_delete.append(changed_data[of_type][each_row])
|
||||
# Fetch the keys for SQL generation
|
||||
if is_first:
|
||||
# We need to covert dict_keys to normal list in
|
||||
# Python3
|
||||
# In Python2, it's already a list & We will also
|
||||
# fetch column names using index
|
||||
keys = list(
|
||||
changed_data[of_type][each_row].keys()
|
||||
)
|
||||
no_of_keys = len(keys)
|
||||
is_first = False
|
||||
# Map index with column name for each row
|
||||
for row in rows_to_delete:
|
||||
for k, v in row.items():
|
||||
# Set primary key with label & delete index based
|
||||
# mapped key
|
||||
try:
|
||||
row[changed_data['columns']
|
||||
[int(k)]['name']] = v
|
||||
except ValueError:
|
||||
continue
|
||||
del row[k]
|
||||
|
||||
sql = render_template(
|
||||
"/".join([command_obj.sql_path, 'delete.sql']),
|
||||
data=rows_to_delete,
|
||||
primary_key_labels=keys,
|
||||
no_of_keys=no_of_keys,
|
||||
object_name=command_obj.object_name,
|
||||
nsp_name=command_obj.nsp_name
|
||||
)
|
||||
list_of_sql[of_type].append({'sql': sql, 'data': {}})
|
||||
|
||||
for opr, sqls in list_of_sql.items():
|
||||
for item in sqls:
|
||||
if item['sql']:
|
||||
item['data'] = {
|
||||
pgadmin_alias[k] if k in pgadmin_alias else k: v
|
||||
for k, v in item['data'].items()
|
||||
}
|
||||
|
||||
row_added = None
|
||||
|
||||
def failure_handle(res):
|
||||
if is_savepoint:
|
||||
conn.execute_void('ROLLBACK TO SAVEPOINT '
|
||||
'save_data;')
|
||||
msg = 'Query ROLLBACK, but the current ' \
|
||||
'transaction is still ongoing.'
|
||||
res += ' Saving ROLLBACK, but the current ' \
|
||||
'transaction is still ongoing'
|
||||
else:
|
||||
conn.execute_void('ROLLBACK;')
|
||||
msg = 'Transaction ROLLBACK'
|
||||
# If we roll backed every thing then update the
|
||||
# message for each sql query.
|
||||
for val in query_res:
|
||||
if query_res[val]['status']:
|
||||
query_res[val]['result'] = msg
|
||||
|
||||
# If list is empty set rowid to 1
|
||||
try:
|
||||
if list_of_rowid:
|
||||
_rowid = list_of_rowid[count]
|
||||
else:
|
||||
_rowid = 1
|
||||
except Exception:
|
||||
_rowid = 0
|
||||
|
||||
return status, res, query_res, _rowid,\
|
||||
is_commit_required
|
||||
|
||||
try:
|
||||
# Fetch oids/primary keys
|
||||
if 'select_sql' in item and item['select_sql']:
|
||||
status, res = conn.execute_dict(
|
||||
item['sql'], item['data'])
|
||||
else:
|
||||
status, res = conn.execute_void(
|
||||
item['sql'], item['data'])
|
||||
except Exception as _:
|
||||
failure_handle(res)
|
||||
raise
|
||||
|
||||
if not status:
|
||||
return failure_handle(res)
|
||||
|
||||
# Select added row from the table
|
||||
if 'select_sql' in item:
|
||||
status, sel_res = conn.execute_dict(
|
||||
item['select_sql'], res['rows'][0])
|
||||
|
||||
if not status:
|
||||
if is_savepoint:
|
||||
conn.execute_void('ROLLBACK TO SAVEPOINT'
|
||||
' save_data;')
|
||||
msg = 'Query ROLLBACK, the current' \
|
||||
' transaction is still ongoing.'
|
||||
else:
|
||||
conn.execute_void('ROLLBACK;')
|
||||
msg = 'Transaction ROLLBACK'
|
||||
# If we roll backed every thing then update
|
||||
# the message for each sql query.
|
||||
for val in query_res:
|
||||
if query_res[val]['status']:
|
||||
query_res[val]['result'] = msg
|
||||
|
||||
# If list is empty set rowid to 1
|
||||
try:
|
||||
if list_of_rowid:
|
||||
_rowid = list_of_rowid[count]
|
||||
else:
|
||||
_rowid = 1
|
||||
except Exception:
|
||||
_rowid = 0
|
||||
|
||||
return status, sel_res, query_res, _rowid,\
|
||||
is_commit_required
|
||||
|
||||
if 'rows' in sel_res and len(sel_res['rows']) > 0:
|
||||
row_added = {
|
||||
item['client_row']: sel_res['rows'][0]}
|
||||
|
||||
rows_affected = conn.rows_affected()
|
||||
# store the result of each query in dictionary
|
||||
query_res[count] = {
|
||||
'status': status,
|
||||
'result': None if row_added else res,
|
||||
'sql': item['sql'], 'rows_affected': rows_affected,
|
||||
'row_added': row_added
|
||||
}
|
||||
|
||||
count += 1
|
||||
|
||||
# Commit the transaction if no error is found & autocommit is activated
|
||||
if auto_commit:
|
||||
conn.execute_void('COMMIT;')
|
||||
else:
|
||||
is_commit_required = True
|
||||
|
||||
return status, res, query_res, _rowid, is_commit_required
|
||||
Reference in new issue
Block a user