Commit b523913c authored by Jérome Perrin's avatar Jérome Perrin

Fix" Commands of sync" errors in SQL connector

We had nexedi/erp5@a6b588e7 but this was only solving the case of a trailing ;

See merge request nexedi/erp5!1710
parents 28bf61d4 6c56b7be
Pipeline #25787 passed with stage
in 0 seconds
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test_query_commands_out_of_sync</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html xmlns:tal="http://xml.zope.org/namespaces/tal" xmlns:metal="http://xml.zope.org/namespaces/metal">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title tal:content="template/title_and_id"></title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr>
<td rowspan="1" colspan="3" tal:content="template/title_and_id"></td>
</tr>
</thead>
<tbody>
<tr>
<td>open</td>
<td tal:content="string: ${here/portal_url}/erp5_sql_connection/ZMySQLDAConnection_viewQueryBrowser"></td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>css=div.monaco-editor.vs</td>
<td></td>
</tr>
<tr>
<td>assertEval</td>
<td>
selenium.browserbot.getCurrentWindow().monaco_editor.trigger('', 'type', {'text': 'select 1+1; select "boom"'})
</td>
<td>null</td>
</tr>
<tr>
<td>click</td>
<td>//button[@name="Query"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@class, "noty_message")]/span[@class="noty_text" and contains(text(), "Error")]</td>
<td></td>
</tr>
<tr>
<td>assertEval</td>
<td>
selenium.browserbot.getCurrentWindow().monaco_editor.trigger('', 'editor.action.smartSelect.expand');
selenium.browserbot.getCurrentWindow().monaco_editor.trigger('', 'editor.action.deleteLines');
selenium.browserbot.getCurrentWindow().monaco_editor.trigger('', 'type', {'text': 'select 1+1'})
</td>
<td>null</td>
</tr>
<tr>
<td>click</td>
<td>//button[@name="Query"]</td>
<td></td>
</tr>
<tr>
<td>waitForText</td>
<td>xpath=(//div[contains(@class, "handsontable")]//th//span[@class="colHeader"])[2]</td>
<td>1+1</td>
</tr>
<tr>
<td>assertText</td>
<td>//div[contains(@class, "handsontable")]//tbody/tr/td</td>
<td>2</td>
</tr>
</tbody>
</table>
</body>
</html>
\ No newline at end of file
......@@ -115,7 +115,8 @@ from Products.ERP5Type.Utils import str2bytes
hosed_connection = (
CR.SERVER_GONE_ERROR,
CR.SERVER_LOST
CR.SERVER_LOST,
CR.COMMANDS_OUT_OF_SYNC
)
query_syntax_error = (
......@@ -404,7 +405,12 @@ class DB(TM):
else:
LOG('ZMySQLDA', ERROR, 'query failed: %s' % (query,))
raise
except ProgrammingError:
except ProgrammingError as m:
if (allow_reconnect or not self._use_TM) and \
m[0] in hosed_connection:
self._forceReconnection()
self.db.query(query)
else:
LOG('ZMySQLDA', ERROR, 'query failed: %s' % (query,))
raise
try:
......
  • Is this the correct solution ? How does the overall Zope transaction fail in this setup ? Because it must fail, otherwise this is breaking inter-database consistency.

  • Yes, it's the same pattern as for OperationalError above. allow_reconnect is always False except in _begin, so what happens (for both case of OperationalError or ProgrammingError) is something like this:

    • the transaction with wrong SQL fails because allow_reconnect is False, so it goes into the else branch, this raises, so it will cause the transaction to be aborted at higher level.
    • the next transaction reuses the connection. It starts with self._query("BEGIN", allow_reconnect=True), this also gets a ProgrammingError, but this time allow_reconnect is True so it reconnects and do another BEGIN on the new connection.
    Edited by Jérome Perrin
  • I somehow completely missed the allow_reconnect check... Thanks for the explanation, it makes perfect sense now.

  • Great, thanks for checking this

Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment