diff --git a/docs/en_US/options-query_tool.rst b/docs/en_US/options-query_tool.rst
index 0b557e7..bb3f0af 100644
--- a/docs/en_US/options-query_tool.rst
+++ b/docs/en_US/options-query_tool.rst
@@ -23,6 +23,8 @@ Use the fields on the *Query editor* dialog to specify workspace preferences for
* **Enable Auto ROLLBACK** - Check the box next to *Enable Auto ROLLBACK* to instruct the query tool to execute a ROLLBACK if a query fails.
+* **Enable Auto COMMIT** - Check the box next to *Enable Auto COMMIT* to instruct the query tool to enable auto commit after executing the query.
+
* **Keywords in uppercase** - Check the box next to *Keywords in uppercase* to instruct the Query tool to convert any keywords entered to an uppercase font.
.. image:: images/options-colours.png
diff --git a/pgadmin/frm/frmOptions.cpp b/pgadmin/frm/frmOptions.cpp
index 4b3b1f1..4081319 100644
--- a/pgadmin/frm/frmOptions.cpp
+++ b/pgadmin/frm/frmOptions.cpp
@@ -89,6 +89,7 @@
#define chkColumnNames CTRL_CHECKBOX("chkColumnNames")
#define txtThousandsSeparator CTRL_TEXT("txtThousandsSeparator")
#define chkAutoRollback CTRL_CHECKBOX("chkAutoRollback")
+#define chkAutoCommit CTRL_CHECKBOX("chkAutoCommit")
#define chkDoubleClickProperties CTRL_CHECKBOX("chkDoubleClickProperties")
#define chkShowNotices CTRL_CHECKBOX("chkShowNotices")
#define cbLanguage CTRL_COMBOBOX("cbLanguage")
@@ -303,6 +304,7 @@ frmOptions::frmOptions(frmMain *parent)
chkIndicateNull->SetValue(settings->GetIndicateNull());
txtThousandsSeparator->SetValue(settings->GetThousandsSeparator());
chkAutoRollback->SetValue(settings->GetAutoRollback());
+ chkAutoCommit->SetValue(settings->GetAutoCommit());
chkDoubleClickProperties->SetValue(settings->GetDoubleClickProperties());
txtDecimalMark->SetValue(settings->GetDecimalMark());
chkColumnNames->SetValue(settings->GetColumnNames());
@@ -670,6 +672,7 @@ void frmOptions::OnOK(wxCommandEvent &ev)
settings->SetColumnNames(chkColumnNames->GetValue());
settings->SetThousandsSeparator(txtThousandsSeparator->GetValue());
settings->SetAutoRollback(chkAutoRollback->GetValue());
+ settings->SetAutoCommit(chkAutoCommit->GetValue());
settings->SetDoubleClickProperties(chkDoubleClickProperties->GetValue());
settings->SetShowNotices(chkShowNotices->GetValue());
diff --git a/pgadmin/frm/frmQuery.cpp b/pgadmin/frm/frmQuery.cpp
index 23ec45b..e6827f9 100644
--- a/pgadmin/frm/frmQuery.cpp
+++ b/pgadmin/frm/frmQuery.cpp
@@ -121,6 +121,7 @@ BEGIN_EVENT_TABLE(frmQuery, pgFrame)
EVT_MENU(MNU_EXPLAINANALYZE, frmQuery::OnExplain)
EVT_MENU(MNU_CANCEL, frmQuery::OnCancel)
EVT_MENU(MNU_AUTOROLLBACK, frmQuery::OnAutoRollback)
+ EVT_MENU(MNU_AUTOCOMMIT, frmQuery::OnAutoCommit)
EVT_MENU(MNU_CONTENTS, frmQuery::OnContents)
EVT_MENU(MNU_HELP, frmQuery::OnHelp)
EVT_MENU(MNU_CLEARHISTORY, frmQuery::OnClearHistory)
@@ -316,6 +317,7 @@ frmQuery::frmQuery(frmMain *form, const wxString &_title, pgConn *_conn, const w
queryMenu->Append(MNU_CLEARHISTORY, _("Clear history"), _("Clear history window."));
queryMenu->AppendSeparator();
queryMenu->Append(MNU_AUTOROLLBACK, _("&Auto-Rollback"), _("Rollback the current transaction if an error is detected"), wxITEM_CHECK);
+ queryMenu->Append(MNU_AUTOCOMMIT, _("&Auto-Commit"), _("Auto commit the cuurent transaction"), wxITEM_CHECK);
queryMenu->AppendSeparator();
queryMenu->Append(MNU_CANCEL, _("&Cancel\tAlt-Break"), _("Cancel query"));
menuBar->Append(queryMenu, _("&Query"));
@@ -559,9 +561,13 @@ frmQuery::frmQuery(frmMain *form, const wxString &_title, pgConn *_conn, const w
bool bVal;
// Auto-rollback
- settings->Read(wxT("frmQuery/AutoRollback"), &bVal, false);
+ bVal = settings->GetAutoRollback();
queryMenu->Check(MNU_AUTOROLLBACK, bVal);
+ // Auto-commit
+ bVal = settings->GetAutoCommit();
+ queryMenu->Check(MNU_AUTOCOMMIT, bVal);
+
// Auto indent
settings->Read(wxT("frmQuery/AutoIndent"), &bVal, true);
editMenu->Check(MNU_AUTOINDENT, bVal);
@@ -823,6 +829,15 @@ void frmQuery::OnAutoRollback(wxCommandEvent &event)
settings->WriteBool(wxT("frmQuery/AutoRollback"), queryMenu->IsChecked(MNU_AUTOROLLBACK));
}
+void frmQuery::OnAutoCommit(wxCommandEvent &event)
+{
+ queryMenu->Check(MNU_AUTOCOMMIT, event.IsChecked());
+ if(event.IsChecked() && conn->GetTxStatus() != PQTRANS_IDLE)
+ wxMessageBox(
+ _("The current transaction is still in progess.\n\nIn order to take the effect of AUTOCOMMIT mode, please complete the transaction by executing COMMIT, or ROLLBACK statement."),
+ _("Warning - Transaction in progress"), wxICON_INFORMATION | wxOK, this);
+ settings->WriteBool(wxT("frmQuery/AutoCommit"), queryMenu->IsChecked(MNU_AUTOCOMMIT));
+}
void frmQuery::OnAutoIndent(wxCommandEvent &event)
{
@@ -2486,6 +2501,9 @@ void frmQuery::execQuery(const wxString &query, int resultToRetrieve, bool singl
startTimeQuery = wxGetLocalTimeMillis();
timer.Start(10);
+ if (!queryMenu->IsChecked(MNU_AUTOCOMMIT) && conn->GetTxStatus() == PQTRANS_IDLE && !isBeginNotRequired(query))
+ conn->ExecuteVoid(wxT("BEGIN;"));
+
if (sqlResult->Execute(query, resultToRetrieve, this, QUERY_COMPLETE, qi) >= 0)
{
// Return and wait for the result
@@ -2495,6 +2513,177 @@ void frmQuery::execQuery(const wxString &query, int resultToRetrieve, bool singl
completeQuery(false, false, false);
}
+bool frmQuery::isBeginNotRequired(wxString query)
+{
+ int wordlen = 0;
+
+ query = query.Trim(false);
+
+ /*
+ * Check word length (since "beginx" is not "begin").
+ */
+ while(wxIsalpha(query.GetChar(wordlen)))
+ wordlen++;
+
+ /*
+ * Transaction control commands. These should include every keyword that
+ * gives rise to a TransactionStmt in the backend grammar, except for the
+ * savepoint-related commands.
+ *
+ * (We assume that START must be START TRANSACTION, since there is
+ * presently no other "START foo" command.)
+ */
+ wxString keyword = query.SubString(0, wordlen-1);
+ if (wordlen == 5 && keyword.CmpNoCase(wxT("abort")) == 0)
+ return true;
+ if (wordlen == 5 && keyword.CmpNoCase(wxT("begin")) == 0)
+ return true;
+ if (wordlen == 5 && keyword.CmpNoCase(wxT("start")) == 0)
+ return true;
+ if (wordlen == 6 && keyword.CmpNoCase(wxT("commit")) == 0)
+ return true;
+ if (wordlen == 3 && keyword.CmpNoCase(wxT("end")) == 0)
+ return true;
+ if (wordlen == 8 && keyword.CmpNoCase(wxT("rollback")) == 0)
+ return true;
+ if (wordlen == 7 && keyword.CmpNoCase(wxT("prepare")) == 0)
+ {
+ /* PREPARE TRANSACTION is a TC command, PREPARE foo is not */
+ query = query.SubString(keyword.Length(),query.Length()-1);
+ query = query.Trim(false);
+
+ wordlen = 0;
+ while(wxIsalpha(query.GetChar(wordlen)))
+ wordlen++;
+ keyword = query.SubString(0, wordlen-1);
+
+ if (wordlen == 11 && keyword.CmpNoCase(wxT("transaction")) == 0)
+ return true;
+ return false;
+ }
+
+ /*
+ * Commands not allowed within transactions. The statements checked for
+ * here should be exactly those that call PreventTransactionChain() in the
+ * backend.
+ */
+ if (wordlen == 6 && keyword.CmpNoCase(wxT("vacuum")) == 0)
+ return true;
+ if (wordlen == 7 && keyword.CmpNoCase(wxT("cluster")) == 0)
+ {
+ /* CLUSTER with any arguments is allowed in transactions */
+ query = query.SubString(keyword.Length(),query.Length()-1);
+ query = query.Trim(false);
+
+ if(wxIsalpha(((wxChar)query.at(0))))
+ return false; /* has additional words */
+ return true; /* it's CLUSTER without arguments */
+ }
+
+ if (wordlen == 6 && keyword.CmpNoCase(wxT("create")) == 0)
+ {
+ query = query.SubString(keyword.Length(),query.Length()-1);
+ query = query.Trim(false);
+
+ wordlen = 0;
+ while(wxIsalpha(query.GetChar(wordlen)))
+ wordlen++;
+ keyword = query.SubString(0, wordlen-1);
+
+ if (wordlen == 8 && keyword.CmpNoCase(wxT("database")) == 0)
+ return true;
+ if (wordlen == 10 && keyword.CmpNoCase(wxT("tablespace")) == 0)
+ return true;
+
+ /* CREATE [UNIQUE] INDEX CONCURRENTLY isn't allowed in xacts */
+ if (wordlen == 6 && keyword.CmpNoCase(wxT("cluster")) == 0)
+ {
+ query = query.SubString(keyword.Length(),query.Length()-1);
+ query = query.Trim(false);
+
+ wordlen = 0;
+ while(wxIsalpha(query.GetChar(wordlen)))
+ wordlen++;
+ keyword = query.SubString(0, wordlen-1);
+ }
+
+ if (wordlen == 5 && keyword.CmpNoCase(wxT("index")) == 0)
+ {
+ query = query.SubString(keyword.Length(),query.Length()-1);
+ query = query.Trim(false);
+
+ wordlen = 0;
+ while(wxIsalpha(query.GetChar(wordlen)))
+ wordlen++;
+ keyword = query.SubString(0, wordlen-1);
+
+ if (wordlen == 12 && keyword.CmpNoCase(wxT("concurrently")) == 0)
+ return true;
+ }
+
+ return false;
+ }
+
+ if (wordlen == 5 && keyword.CmpNoCase(wxT("alter")) == 0)
+ {
+ query = query.SubString(keyword.Length(),query.Length()-1);
+ query = query.Trim(false);
+
+ wordlen = 0;
+ while(wxIsalpha(query.GetChar(wordlen)))
+ wordlen++;
+ keyword = query.SubString(0, wordlen-1);
+
+ /* ALTER SYSTEM isn't allowed in xacts */
+ if (wordlen == 6 && keyword.CmpNoCase(wxT("system")) == 0)
+ return true;
+
+ return false;
+ }
+
+ /*
+ * Note: these tests will match DROP SYSTEM and REINDEX TABLESPACE, which
+ * aren't really valid commands so we don't care much. The other four
+ * possible matches are correct.
+ */
+ if ((wordlen == 4 && keyword.CmpNoCase(wxT("drop")) == 0) ||
+ (wordlen == 7 && keyword.CmpNoCase(wxT("reindex")) == 0))
+ {
+ query = query.SubString(keyword.Length(),query.Length()-1);
+ query = query.Trim(false);
+
+ wordlen = 0;
+ while(wxIsalpha(query.GetChar(wordlen)))
+ wordlen++;
+ keyword = query.SubString(0, wordlen-1);
+
+ if (wordlen == 8 && keyword.CmpNoCase(wxT("database")) == 0)
+ return true;
+ if (wordlen == 6 && keyword.CmpNoCase(wxT("system")) == 0)
+ return true;
+ if (wordlen == 10 && keyword.CmpNoCase(wxT("tablespace")) == 0)
+ return true;
+ return false;
+ }
+
+ /* DISCARD ALL isn't allowed in xacts, but other variants are allowed. */
+ if (wordlen == 7 && keyword.CmpNoCase(wxT("discard")) == 0)
+ {
+ query = query.SubString(keyword.Length(),query.Length()-1);
+ query = query.Trim(false);
+
+ wordlen = 0;
+ while(wxIsalpha(query.GetChar(wordlen)))
+ wordlen++;
+ keyword = query.SubString(0, wordlen-1);
+
+ if (wordlen == 3 && keyword.CmpNoCase(wxT("all")) == 0)
+ return true;
+ return false;
+ }
+
+ return false;
+}
// When the query completes, it raises an event which we process here.
void frmQuery::OnQueryComplete(pgQueryResultEvent &ev)
@@ -2839,7 +3028,7 @@ void frmQuery::completeQuery(bool done, bool explain, bool verbose)
msgHistory->ShowPosition(0);
// If the transaction aborted for some reason, issue a rollback to cleanup.
- if (settings->GetAutoRollback() && conn->GetTxStatus() == PGCONN_TXSTATUS_INERROR)
+ if (queryMenu->IsChecked(MNU_AUTOROLLBACK) && conn->GetTxStatus() == PGCONN_TXSTATUS_INERROR)
conn->ExecuteVoid(wxT("ROLLBACK;"));
setTools(false);
diff --git a/pgadmin/include/frm/frmQuery.h b/pgadmin/include/frm/frmQuery.h
index c698370..d53931b 100644
--- a/pgadmin/include/frm/frmQuery.h
+++ b/pgadmin/include/frm/frmQuery.h
@@ -199,6 +199,7 @@ private:
void OnRedo(wxCommandEvent &event);
void OnSaveHistory(wxCommandEvent &event);
void OnAutoRollback(wxCommandEvent &event);
+ void OnAutoCommit(wxCommandEvent &event);
void OnChangeConnection(wxCommandEvent &ev);
void OnClearHistory(wxCommandEvent &event);
void OnActivate(wxActivateEvent &event);
@@ -239,6 +240,7 @@ private:
void execQuery(const wxString &query, int resultToRetrieve = 0, bool singleResult = false, const int queryOffset = 0, bool toFile = false, bool explain = false, bool verbose = false);
void OnQueryComplete(pgQueryResultEvent &ev);
void completeQuery(bool done, bool explain, bool verbose);
+ bool isBeginNotRequired(wxString query);
void OnScriptComplete(wxCommandEvent &ev);
void setTools(const bool running);
void showMessage(const wxString &msg, const wxString &msgShort = wxT(""));
diff --git a/pgadmin/include/frm/menu.h b/pgadmin/include/frm/menu.h
index fb20b60..4d0f757 100644
--- a/pgadmin/include/frm/menu.h
+++ b/pgadmin/include/frm/menu.h
@@ -71,6 +71,7 @@ enum
MNU_BUFFERS,
MNU_TIMING,
MNU_AUTOROLLBACK,
+ MNU_AUTOCOMMIT,
MNU_CLEARHISTORY,
MNU_SAVEHISTORY,
MNU_CHECKALIVE,
diff --git a/pgadmin/include/utils/sysSettings.h b/pgadmin/include/utils/sysSettings.h
index eb11213..cecab7f 100644
--- a/pgadmin/include/utils/sysSettings.h
+++ b/pgadmin/include/utils/sysSettings.h
@@ -367,13 +367,23 @@ public:
bool GetAutoRollback() const
{
bool b;
- Read(wxT("frmQuery/AutoRollback"), &b, true);
+ Read(wxT("frmQuery/AutoRollback"), &b, false);
return b;
}
void SetAutoRollback(const bool newval)
{
WriteBool(wxT("frmQuery/AutoRollback"), newval);
}
+ bool GetAutoCommit() const
+ {
+ bool b;
+ Read(wxT("frmQuery/AutoCommit"), &b, true);
+ return b;
+ }
+ void SetAutoCommit(const bool newval)
+ {
+ WriteBool(wxT("frmQuery/AutoCommit"), newval);
+ }
wxString GetDecimalMark() const
{
wxString s;
diff --git a/pgadmin/ui/frmOptions.xrc b/pgadmin/ui/frmOptions.xrc
index a57b0ce..7b9dc6f 100644
--- a/pgadmin/ui/frmOptions.xrc
+++ b/pgadmin/ui/frmOptions.xrc
@@ -490,6 +490,21 @@
4
+
+
+
+ 1
+
+ wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT
+ 4
+
+