android: Update app icon to new startcenter icon
[LibreOffice.git] / dbaccess / source / ui / dlg / directsql.cxx
blobeab893e4e4b100cbbf4596696f955996da917623
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <core_resource.hxx>
21 #include <directsql.hxx>
22 #include <sqledit.hxx>
23 #include <strings.hxx>
24 #include <strings.hrc>
25 #include <comphelper/types.hxx>
26 #include <osl/mutex.hxx>
27 #include <rtl/ustrbuf.hxx>
28 #include <comphelper/diagnose_ex.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/weld.hxx>
31 #include <com/sun/star/sdbc/SQLException.hpp>
32 #include <com/sun/star/sdbc/XRow.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/sdbc/DataType.hpp>
35 #include <com/sun/star/sdbc/XMultipleResults.hpp>
36 #include <com/sun/star/sdbc/XResultSetMetaData.hpp>
37 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
39 namespace dbaui
41 using namespace ::com::sun::star::uno;
42 using namespace ::com::sun::star::sdbc;
43 using namespace ::com::sun::star::lang;
45 constexpr sal_Int32 g_nHistoryLimit = 20;
47 // DirectSQLDialog
48 DirectSQLDialog::DirectSQLDialog(weld::Window* _pParent, const Reference< XConnection >& _rxConn)
49 : GenericDialogController(_pParent, "dbaccess/ui/directsqldialog.ui", "DirectSQLDialog")
50 , m_xExecute(m_xBuilder->weld_button("execute"))
51 , m_xSQLHistory(m_xBuilder->weld_combo_box("sqlhistory"))
52 , m_xStatus(m_xBuilder->weld_text_view("status"))
53 , m_xDirectSQL(m_xBuilder->weld_check_button("directsql"))
54 , m_xShowOutput(m_xBuilder->weld_check_button("showoutput"))
55 , m_xOutput(m_xBuilder->weld_text_view("output"))
56 , m_xClose(m_xBuilder->weld_button("close"))
57 , m_xSQL(new SQLEditView(m_xBuilder->weld_scrolled_window("scrolledwindow", true)))
58 , m_xSQLEd(new weld::CustomWeld(*m_xBuilder, "sql", *m_xSQL))
59 , m_nStatusCount(1)
60 , m_xConnection(_rxConn)
61 , m_pClosingEvent(nullptr)
63 int nWidth = m_xStatus->get_approximate_digit_width() * 60;
64 int nHeight = m_xStatus->get_height_rows(7);
66 m_xSQLEd->set_size_request(nWidth, nHeight);
67 m_xStatus->set_size_request(-1, nHeight);
68 m_xOutput->set_size_request(-1, nHeight);
70 m_xSQL->GrabFocus();
72 m_xExecute->connect_clicked(LINK(this, DirectSQLDialog, OnExecute));
73 m_xClose->connect_clicked(LINK(this, DirectSQLDialog, OnCloseClick));
74 m_xSQLHistory->connect_changed(LINK(this, DirectSQLDialog, OnListEntrySelected));
76 // add a dispose listener to the connection
77 Reference< XComponent > xConnComp(m_xConnection, UNO_QUERY);
78 OSL_ENSURE(xConnComp.is(), "DirectSQLDialog::DirectSQLDialog: invalid connection!");
79 if (xConnComp.is())
80 startComponentListening(xConnComp);
82 m_xSQL->SetModifyHdl(LINK(this, DirectSQLDialog, OnStatementModified));
83 OnStatementModified(nullptr);
86 DirectSQLDialog::~DirectSQLDialog()
88 ::osl::MutexGuard aGuard(m_aMutex);
89 if (m_pClosingEvent)
90 Application::RemoveUserEvent(m_pClosingEvent);
91 stopAllComponentListening();
94 void DirectSQLDialog::_disposing( const EventObject& _rSource )
96 SolarMutexGuard aSolarGuard;
97 ::osl::MutexGuard aGuard(m_aMutex);
99 assert(!m_pClosingEvent);
101 OSL_ENSURE(Reference< XConnection >(_rSource.Source, UNO_QUERY).get() == m_xConnection.get(),
102 "DirectSQLDialog::_disposing: where does this come from?");
105 OUString sMessage(DBA_RES(STR_DIRECTSQL_CONNECTIONLOST));
106 std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(),
107 VclMessageType::Warning, VclButtonsType::Ok,
108 sMessage));
109 xError->run();
112 m_pClosingEvent = Application::PostUserEvent(LINK(this, DirectSQLDialog, OnClose));
115 sal_Int32 DirectSQLDialog::getHistorySize() const
117 #ifdef DBG_UTIL
119 const char* pError = impl_CheckInvariants();
120 if (pError)
121 SAL_WARN("dbaccess.ui", "DirectSQLDialog::getHistorySize: " << pError);
123 #endif
124 return m_aStatementHistory.size();
127 void DirectSQLDialog::implEnsureHistoryLimit()
129 #ifdef DBG_UTIL
131 const char* pError = impl_CheckInvariants();
132 if (pError)
133 SAL_WARN("dbaccess.ui", "DirectSQLDialog::implEnsureHistoryLimit: " << pError);
135 #endif
137 if (getHistorySize() <= g_nHistoryLimit)
138 // nothing to do
139 return;
141 sal_Int32 nRemoveEntries = getHistorySize() - g_nHistoryLimit;
142 while (nRemoveEntries--)
144 m_aStatementHistory.pop_front();
145 m_aNormalizedHistory.pop_front();
146 m_xSQLHistory->remove(0);
150 void DirectSQLDialog::implAddToStatementHistory(const OUString& _rStatement)
152 #ifdef DBG_UTIL
154 const char* pError = impl_CheckInvariants();
155 if (pError)
156 SAL_WARN("dbaccess.ui", "DirectSQLDialog::implAddToStatementHistor: " << pError);
158 #endif
160 // add the statement to the history
161 m_aStatementHistory.push_back(_rStatement);
163 // normalize the statement, and remember the normalized form, too
164 OUString sNormalized = _rStatement.replaceAll("\n", " ");
165 m_aNormalizedHistory.push_back(sNormalized);
167 // add the normalized version to the list box
168 m_xSQLHistory->append_text(sNormalized);
170 // ensure that we don't exceed the history limit
171 implEnsureHistoryLimit();
174 #ifdef DBG_UTIL
175 const char* DirectSQLDialog::impl_CheckInvariants() const
177 if (m_aStatementHistory.size() != m_aNormalizedHistory.size())
178 return "statement history is inconsistent!";
180 if (!m_xSQLHistory)
181 return "invalid listbox!";
183 if (m_aStatementHistory.size() != static_cast<size_t>(m_xSQLHistory->get_count()))
184 return "invalid listbox entry count!";
186 if (!m_xConnection.is())
187 return "have no connection!";
189 return nullptr;
191 #endif
193 void DirectSQLDialog::implExecuteStatement(const OUString& _rStatement)
195 #ifdef DBG_UTIL
197 const char* pError = impl_CheckInvariants();
198 if (pError)
199 SAL_WARN("dbaccess.ui", "DirectSQLDialog::implExecuteStatement: " << pError);
201 #endif
203 ::osl::MutexGuard aGuard(m_aMutex);
205 OUString sStatus;
207 // clear the output box
208 m_xOutput->set_text(OUString());
211 // create a statement
212 Reference< XStatement > xStatement = m_xConnection->createStatement();
214 if (m_xDirectSQL->get_active())
216 Reference< com::sun::star::beans::XPropertySet > xStatementProps(xStatement, UNO_QUERY_THROW);
219 xStatementProps->setPropertyValue(PROPERTY_ESCAPE_PROCESSING, Any(false));
221 catch( const Exception& )
223 DBG_UNHANDLED_EXCEPTION("dbaccess");
227 Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
228 css::uno::Reference< css::sdbc::XMultipleResults > xMR ( xStatement, UNO_QUERY );
230 if (xMeta.is() && xMeta->supportsMultipleResultSets() && xMR.is())
232 bool hasRS = xStatement->execute(_rStatement);
233 if(hasRS)
235 css::uno::Reference< css::sdbc::XResultSet > xRS (xMR->getResultSet());
236 if (m_xShowOutput->get_active())
237 display(xRS);
239 else
240 addOutputText(
241 Concat2View(OUString::number(xMR->getUpdateCount()) + " rows updated\n"));
242 for (;;)
244 hasRS = xMR->getMoreResults();
245 if (!hasRS && xMR->getUpdateCount() == -1)
246 break;
247 if(hasRS)
249 css::uno::Reference< css::sdbc::XResultSet > xRS (xMR->getResultSet());
250 if (m_xShowOutput->get_active())
251 display(xRS);
255 else
257 const OUString upperStatement = _rStatement.toAsciiUpperCase();
258 if (upperStatement.startsWith("UPDATE"))
260 sal_Int32 resultCount = xStatement->executeUpdate(_rStatement);
261 addOutputText(Concat2View(OUString::number(resultCount) + " rows updated\n"));
263 else if (upperStatement.startsWith("INSERT"))
265 sal_Int32 resultCount = xStatement->executeUpdate(_rStatement);
266 addOutputText(Concat2View(OUString::number(resultCount) + " rows inserted\n"));
268 else if (upperStatement.startsWith("DELETE"))
270 sal_Int32 resultCount = xStatement->executeUpdate(_rStatement);
271 addOutputText(Concat2View(OUString::number(resultCount) + " rows deleted\n"));
273 else if (upperStatement.startsWith("CREATE"))
275 xStatement->executeUpdate(_rStatement);
276 addOutputText(u"Command executed\n");
278 else if (upperStatement.startsWith("SELECT") || m_xShowOutput->get_active())
280 css::uno::Reference< css::sdbc::XResultSet > xRS = xStatement->executeQuery(_rStatement);
281 if (m_xShowOutput->get_active())
282 display(xRS);
284 else
286 sal_Int32 resultCount = xStatement->executeUpdate(_rStatement);
287 addOutputText(Concat2View(OUString::number(resultCount) + " rows updated\n"));
290 // successful
291 sStatus = DBA_RES(STR_COMMAND_EXECUTED_SUCCESSFULLY);
293 // dispose the statement
294 ::comphelper::disposeComponent(xStatement);
296 catch(const SQLException& e)
298 sStatus = e.Message;
300 catch( const Exception& )
302 DBG_UNHANDLED_EXCEPTION("dbaccess");
305 // add the status text
306 addStatusText(sStatus);
309 void DirectSQLDialog::display(const css::uno::Reference< css::sdbc::XResultSet >& xRS)
312 const Reference<XResultSetMetaData> xResultSetMetaData = Reference<XResultSetMetaDataSupplier>(xRS,UNO_QUERY_THROW)->getMetaData();
313 const sal_Int32 nColumnsCount = xResultSetMetaData->getColumnCount();
315 // get a handle for the rows
316 css::uno::Reference< css::sdbc::XRow > xRow( xRS, css::uno::UNO_QUERY );
317 // work through each of the rows
318 while (xRS->next())
320 // initialise the output line for each row
321 OUStringBuffer out;
322 // work along the columns until that are none left
325 for (sal_Int32 i = 1; i <= nColumnsCount; ++i)
327 switch (xResultSetMetaData->getColumnType(i))
329 // tdf#153317, at least "Bit" type in Mysql/MariaDB gives: "\000" or "\001"
330 // so retrieve Sequence from getBytes, test if it has a length of 1 (so we avoid BLOB/CLOB or other complex types)
331 // and test if the value of first byte is one of those.
332 // In this case, there's a good chance it's a "Bit" field
333 case css::sdbc::DataType::BIT:
335 auto seq = xRow->getBytes(i);
336 if ((seq.getLength() == 1) && (seq[0] >= 0) && (seq[0] <= 1))
338 out.append(OUString::number(static_cast<int>(seq[0])) + ",");
340 else
342 out.append(xRow->getString(i) + ",");
344 break;
346 // for the rest, be dumb, treat everything as a string
347 default:
348 out.append(xRow->getString(i) + ",");
352 // trap for when we fall off the end of the row
353 catch (const SQLException&)
356 // report the output
357 addOutputText(out);
361 void DirectSQLDialog::addStatusText(std::u16string_view _rMessage)
363 OUString sAppendMessage = OUString::number(m_nStatusCount++) + ": " + _rMessage + "\n\n";
365 OUString sCompleteMessage = m_xStatus->get_text() + sAppendMessage;
366 m_xStatus->set_text(sCompleteMessage);
368 m_xStatus->select_region(sCompleteMessage.getLength(), sCompleteMessage.getLength());
371 void DirectSQLDialog::addOutputText(std::u16string_view _rMessage)
373 OUString sAppendMessage = OUString::Concat(_rMessage) + "\n";
375 OUString sCompleteMessage = m_xOutput->get_text() + sAppendMessage;
376 m_xOutput->set_text(sCompleteMessage);
379 void DirectSQLDialog::executeCurrent()
381 #ifdef DBG_UTIL
383 const char* pError = impl_CheckInvariants();
384 if (pError)
385 SAL_WARN("dbaccess.ui", "DirectSQLDialog::executeCurrent: " << pError);
387 #endif
389 OUString sStatement = m_xSQL->GetText();
391 // execute
392 implExecuteStatement(sStatement);
394 // add the statement to the history
395 implAddToStatementHistory(sStatement);
397 m_xSQL->GrabFocus();
400 void DirectSQLDialog::switchToHistory(sal_Int32 _nHistoryPos)
402 #ifdef DBG_UTIL
404 const char* pError = impl_CheckInvariants();
405 if (pError)
406 SAL_WARN("dbaccess.ui", "DirectSQLDialog::switchToHistory: " << pError);
408 #endif
410 if ((_nHistoryPos >= 0) && (_nHistoryPos < getHistorySize()))
412 // set the text in the statement editor
413 OUString sStatement = m_aStatementHistory[_nHistoryPos];
414 m_xSQL->SetTextAndUpdate(sStatement);
415 OnStatementModified(nullptr);
417 m_xSQL->GrabFocus();
419 else
420 OSL_FAIL("DirectSQLDialog::switchToHistory: invalid position!");
423 IMPL_LINK_NOARG( DirectSQLDialog, OnStatementModified, LinkParamNone*, void )
425 m_xExecute->set_sensitive(!m_xSQL->GetText().isEmpty());
428 IMPL_LINK_NOARG( DirectSQLDialog, OnCloseClick, weld::Button&, void )
430 m_xDialog->response(RET_OK);
433 IMPL_LINK_NOARG( DirectSQLDialog, OnClose, void*, void )
435 assert(m_pClosingEvent);
436 Application::RemoveUserEvent(m_pClosingEvent);
437 m_pClosingEvent = nullptr;
439 m_xDialog->response(RET_OK);
442 IMPL_LINK_NOARG( DirectSQLDialog, OnExecute, weld::Button&, void )
444 executeCurrent();
447 IMPL_LINK_NOARG( DirectSQLDialog, OnListEntrySelected, weld::ComboBox&, void )
449 const sal_Int32 nSelected = m_xSQLHistory->get_active();
450 if (nSelected != -1)
451 switchToHistory(nSelected);
454 } // namespace dbaui
456 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */