mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 06:05:49 -06:00
Выполнения запросов для окна "Активность" и "Состояние запроса" вынесено в отдельный поток. Соединение к БД одно.
4820 lines
174 KiB
C++
4820 lines
174 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// pgAdmin III - PostgreSQL Tools
|
||
//
|
||
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
|
||
// This software is released under the PostgreSQL Licence
|
||
//
|
||
// frmStatus.cpp - Status Screen
|
||
//
|
||
//////////////////////////////////////////////////////////////////////////
|
||
|
||
#include "pgAdmin3.h"
|
||
|
||
// wxWindows headers
|
||
#include <wx/wx.h>
|
||
#include <wx/regex.h>
|
||
#include <wx/xrc/xmlres.h>
|
||
#include <wx/image.h>
|
||
#include <wx/textbuf.h>
|
||
#include <wx/clipbrd.h>
|
||
#include <wx/sysopt.h>
|
||
#include <wx/rawbmp.h>
|
||
#include <wx/stdpaths.h>
|
||
// wxAUI
|
||
#include <wx/aui/aui.h>
|
||
|
||
// App headers
|
||
#include "frm/frmAbout.h"
|
||
#include "frm/frmStatus.h"
|
||
#include "frm/frmHint.h"
|
||
#include "frm/frmMain.h"
|
||
#include "db/pgConn.h"
|
||
#include "frm/frmQuery.h"
|
||
#include "utils/pgfeatures.h"
|
||
#include "schema/pgServer.h"
|
||
#include "schema/pgUser.h"
|
||
#include "ctl/ctlMenuToolbar.h"
|
||
#include "ctl/ctlAuiNotebook.h"
|
||
#include "utils/csvfiles.h"
|
||
#include "utils/utffile.h"
|
||
#include "ctl/ctlNavigatePanel.h"
|
||
#include "ctl/wxTopActivity.h"
|
||
// Icons
|
||
#include "images/clip_copy.pngc"
|
||
#include "images/readdata.pngc"
|
||
#include "images/query_cancel.pngc"
|
||
#include "images/terminate_backend.pngc"
|
||
#include "images/delete.pngc"
|
||
#include "images/storedata.pngc"
|
||
#include "images/sortfilterclear.pngc"
|
||
#include "images/down.pngc"
|
||
#include "images/up.pngc"
|
||
#include "images/server_status.pngc"
|
||
#include "images/warning_amber_48dp.pngc"
|
||
|
||
#include <algorithm>
|
||
#include "utils/FunctionPGHelper.h"
|
||
#include "utils/PreviewHtml.h"
|
||
|
||
#include "db/pgConn.h"
|
||
#ifdef __WXMSW__
|
||
#include "wx/msw/wrapcctl.h"
|
||
#endif
|
||
|
||
extern int s_pid_HIGHLIGH;
|
||
|
||
#define CTRLID_DATABASE 4200
|
||
|
||
//wxDEFINE_EVENT(EVENT_FIND_STR, wxCommandEvent);
|
||
|
||
BEGIN_EVENT_TABLE(frmStatus, pgFrame)
|
||
EVT_MENU(MNU_EXIT, frmStatus::OnExit)
|
||
EVT_MENU(MNU_COPY, frmStatus::OnCopy)
|
||
EVT_MENU(MNU_COPY_QUERY, frmStatus::OnCopyQuery)
|
||
EVT_MENU(MNU_HELP, frmStatus::OnHelp)
|
||
EVT_MENU(MNU_CONTENTS, frmStatus::OnContents)
|
||
EVT_MENU(MNU_STATUSPAGE, frmStatus::OnToggleStatusPane)
|
||
EVT_MENU(MNU_LOCKPAGE, frmStatus::OnToggleLockPane)
|
||
EVT_MENU(MNU_XACTPAGE, frmStatus::OnToggleXactPane)
|
||
EVT_MENU(MNU_LOGPAGE, frmStatus::OnToggleLogPane)
|
||
EVT_MENU(MNU_QUERYSTATEPAGE, frmStatus::OnToggleQuerystatePane)
|
||
EVT_MENU(MNU_WAITENABLE, frmStatus::OnToggleWaitEnable)
|
||
EVT_MENU(MNU_QUERYSTATEVERBOSE, frmStatus::OnEmptyAction)
|
||
EVT_MENU(MNU_QUERYSTATETIME, frmStatus::OnEmptyAction)
|
||
EVT_MENU(MNU_QUERYSTATEBUFFER, frmStatus::OnEmptyAction)
|
||
EVT_MENU(MNU_QUERYSTATETRIGGER, frmStatus::OnEmptyAction)
|
||
|
||
EVT_MENU(MNU_TOOLBAR, frmStatus::OnToggleToolBar)
|
||
EVT_MENU(MNU_DEFAULTVIEW, frmStatus::OnDefaultView)
|
||
EVT_MENU(MNU_HIGHLIGHTSTATUS, frmStatus::OnHighlightStatus)
|
||
|
||
EVT_AUI_PANE_CLOSE( frmStatus::OnPaneClose)
|
||
//EVT_AUI_PANE_ACTIVATED( frmStatus::OnPaneActivated)
|
||
EVT_COMBOBOX(CTL_RATECBO, frmStatus::OnRateChange)
|
||
EVT_MENU(MNU_REFRESH, frmStatus::OnRefresh)
|
||
EVT_MENU(MNU_CANCEL, frmStatus::OnCancelBtn)
|
||
EVT_MENU(MNU_TERMINATE, frmStatus::OnTerminateBtn)
|
||
EVT_MENU(MNU_COMMIT, frmStatus::OnCommit)
|
||
EVT_MENU(MNU_ROLLBACK, frmStatus::OnRollback)
|
||
EVT_MENU(MNU_CLEAR_FILTER_SERVER_STATUS, frmStatus::OnClearFilter)
|
||
EVT_MENU(MNU_SET_FILTER_HIGHLIGHT_STATUS, frmStatus::OnSetHighlightFilter)
|
||
EVT_MENU(CMD_EVENT_FIND_STR, frmStatus::OnCmdFindStrLog)
|
||
EVT_COMBOBOX(CTL_LOGCBO, frmStatus::OnLoadLogfile)
|
||
EVT_BUTTON(CTL_ROTATEBTN, frmStatus::OnRotateLogfile)
|
||
|
||
EVT_TIMER(TIMER_REFRESHUI_ID, frmStatus::OnRefreshUITimer)
|
||
|
||
EVT_TIMER(TIMER_STATUS_ID, frmStatus::OnRefreshStatusTimer)
|
||
EVT_LIST_ITEM_SELECTED(CTL_STATUSLIST, frmStatus::OnSelStatusItem)
|
||
|
||
//EVT_LIST_ITEM_DESELECTED(CTL_STATUSLIST, frmStatus::OnSelStatusItem)
|
||
EVT_LIST_ITEM_RIGHT_CLICK(CTL_STATUSLIST, frmStatus::OnRightClickStatusItem)
|
||
EVT_LIST_COL_CLICK(CTL_STATUSLIST, frmStatus::OnSortStatusGrid)
|
||
EVT_LIST_COL_RIGHT_CLICK(CTL_STATUSLIST, frmStatus::OnRightClickStatusGrid)
|
||
EVT_LIST_COL_END_DRAG(CTL_STATUSLIST, frmStatus::OnChgColSizeStatusGrid)
|
||
|
||
EVT_TIMER(TIMER_LOCKS_ID, frmStatus::OnRefreshLocksTimer)
|
||
EVT_LIST_ITEM_SELECTED(CTL_LOCKLIST, frmStatus::OnSelLockItem)
|
||
EVT_LIST_ITEM_DESELECTED(CTL_LOCKLIST, frmStatus::OnSelLockItem)
|
||
EVT_LIST_COL_CLICK(CTL_LOCKLIST, frmStatus::OnSortLockGrid)
|
||
EVT_LIST_COL_RIGHT_CLICK(CTL_LOCKLIST, frmStatus::OnRightClickLockGrid)
|
||
EVT_LIST_COL_END_DRAG(CTL_LOCKLIST, frmStatus::OnChgColSizeLockGrid)
|
||
|
||
EVT_TIMER(TIMER_XACT_ID, frmStatus::OnRefreshXactTimer)
|
||
EVT_LIST_ITEM_SELECTED(CTL_XACTLIST, frmStatus::OnSelXactItem)
|
||
EVT_LIST_ITEM_DESELECTED(CTL_XACTLIST, frmStatus::OnSelXactItem)
|
||
EVT_LIST_COL_CLICK(CTL_XACTLIST, frmStatus::OnSortXactGrid)
|
||
EVT_LIST_COL_RIGHT_CLICK(CTL_XACTLIST, frmStatus::OnRightClickXactGrid)
|
||
EVT_LIST_COL_END_DRAG(CTL_XACTLIST, frmStatus::OnChgColSizeXactGrid)
|
||
EVT_TIMER(TIMER_LOG_ID, frmStatus::OnRefreshLogTimer)
|
||
EVT_LIST_ITEM_SELECTED(CTL_LOGLIST, frmStatus::OnSelLogItem)
|
||
EVT_LIST_ITEM_DESELECTED(CTL_LOGLIST, frmStatus::OnSelLogItem)
|
||
EVT_LIST_ITEM_RIGHT_CLICK(CTL_LOGLIST, frmStatus::OnRightClickLogGrid)
|
||
EVT_TIMER(TIMER_LOGHINT_ID, frmStatus::OnTimerHintLog)
|
||
EVT_TIMER(TIMER_QUERYSTATE_ID, frmStatus::OnRefreshQuerystateTimer)
|
||
EVT_LIST_COL_RIGHT_CLICK(CTL_QUERYSTATELIST, frmStatus::OnRightClickQuerystateGrid)
|
||
EVT_LIST_ITEM_SELECTED(CTL_QUERYSTATELIST, frmStatus::OnSelQuerystateItem)
|
||
EVT_LIST_ITEM_DESELECTED(CTL_QUERYSTATELIST, frmStatus::OnSelQuerystateItem)
|
||
EVT_LIST_COL_END_DRAG(CTL_QUERYSTATELIST, frmStatus::OnChgColSizeQuerystateGrid)
|
||
EVT_COMBOBOX(CTRLID_DATABASE, frmStatus::OnChangeDatabase)
|
||
EVT_THREAD(-1, frmStatus::OnAddLabelTextThread)
|
||
EVT_CLOSE( frmStatus::OnClose)
|
||
END_EVENT_TABLE();
|
||
|
||
|
||
int frmStatus::cboToRate()
|
||
{
|
||
int rate = 0;
|
||
|
||
if (cbRate->GetValue() == _("Don't refresh"))
|
||
rate = 0;
|
||
if (cbRate->GetValue() == _("1 second"))
|
||
rate = 1;
|
||
if (cbRate->GetValue() == _("5 seconds"))
|
||
rate = 5;
|
||
if (cbRate->GetValue() == _("10 seconds"))
|
||
rate = 10;
|
||
if (cbRate->GetValue() == _("30 seconds"))
|
||
rate = 30;
|
||
if (cbRate->GetValue() == _("1 minute"))
|
||
rate = 60;
|
||
if (cbRate->GetValue() == _("5 minutes"))
|
||
rate = 300;
|
||
if (cbRate->GetValue() == _("10 minutes"))
|
||
rate = 600;
|
||
if (cbRate->GetValue() == _("30 minutes"))
|
||
rate = 1800;
|
||
if (cbRate->GetValue() == _("1 hour"))
|
||
rate = 3600;
|
||
|
||
return rate;
|
||
}
|
||
|
||
|
||
wxString frmStatus::rateToCboString(int rate)
|
||
{
|
||
wxString rateStr;
|
||
|
||
if (rate == 0)
|
||
rateStr = _("Don't refresh");
|
||
if (rate == 1)
|
||
rateStr = _("1 second");
|
||
if (rate == 5)
|
||
rateStr = _("5 seconds");
|
||
if (rate == 10)
|
||
rateStr = _("10 seconds");
|
||
if (rate == 30)
|
||
rateStr = _("30 seconds");
|
||
if (rate == 60)
|
||
rateStr = _("1 minute");
|
||
if (rate == 300)
|
||
rateStr = _("5 minutes");
|
||
if (rate == 600)
|
||
rateStr = _("10 minutes");
|
||
if (rate == 1800)
|
||
rateStr = _("30 minutes");
|
||
if (rate == 3600)
|
||
rateStr = _("1 hour");
|
||
|
||
return rateStr;
|
||
}
|
||
|
||
bool frmStatus::getTextSqlbyQid(long long qid) {
|
||
bool rez = false;
|
||
if (wait_sample && wait_enable && (std || pro)) {
|
||
wxString q;
|
||
wxString view;
|
||
if (std) view = "pg_stat_statements";
|
||
if (pro) view = "pgpro_stats_statements";
|
||
q=wxString::Format("select distinct queryid,query from %s s ",view);
|
||
if (qid != 0) {
|
||
// where
|
||
q+= wxString::Format("where s.queryid=%lld limit 1",qid);
|
||
}
|
||
wxCriticalSectionLocker lock(thread_execute);
|
||
pgSet* dataSet1 = connection->ExecuteSet(q,false);
|
||
if (dataSet1)
|
||
{
|
||
while (!dataSet1->Eof())
|
||
{
|
||
wxULongLong qid = dataSet1->GetLongLong("queryid");
|
||
wxString query = dataSet1->GetVal("query");
|
||
WS.AddQuery(qid.GetValue(), query);
|
||
rez = true;
|
||
dataSet1->MoveNext();
|
||
}
|
||
delete dataSet1;
|
||
}
|
||
|
||
}
|
||
return rez;
|
||
}
|
||
frmStatus::frmStatus(frmMain *form, const wxString &_title, pgConn *conn) : pgFrame(NULL, _title)
|
||
{
|
||
wxString initquery;
|
||
bool highlight = false;
|
||
|
||
dlgName = wxT("frmStatus");
|
||
|
||
loaded = false;
|
||
|
||
mainForm = form;
|
||
connection = conn;
|
||
locks_connection = conn;
|
||
logconn = NULL;
|
||
statusTimer = 0;
|
||
locksTimer = 0;
|
||
xactTimer = 0;
|
||
logTimer = 0;
|
||
|
||
logHasTimestamp = false;
|
||
logFormatKnown = false;
|
||
connection->BackendMinimumVersion(0, 0); // refresh version
|
||
major=connection->GetMajorVersion();
|
||
minor=connection->GetMinorVersion();
|
||
q_thread = new ExecuteThread(this,&queue_sql,&array_exec[0]);
|
||
if (q_thread->Create() != wxTHREAD_NO_ERROR)
|
||
{
|
||
wxLogError(wxT("Can’t create query execute thread thread!"));
|
||
delete q_thread;
|
||
q_thread = NULL;
|
||
} else
|
||
q_thread->Run();
|
||
|
||
// Only superusers can set these parameters...
|
||
|
||
if (connection->IsSuperuser())
|
||
{
|
||
// Make the connection quiet on the logs
|
||
if (connection->BackendMinimumVersion(8, 0))
|
||
initquery = wxT("SET log_statement='none';SET log_duration='off';SET log_min_duration_statement=-1;SET statement_timeout=10000;");
|
||
else
|
||
initquery = wxT("SET log_statement='off';SET log_duration='off';SET log_min_duration_statement=-1;");
|
||
#ifndef _DEBUG
|
||
initquery += wxT("set log_min_messages = FATAL;");
|
||
#endif // !_DEBUG
|
||
|
||
connection->ExecuteVoid(initquery, false);
|
||
}
|
||
//pg_is_in_recovery()
|
||
waitMenu = new wxMenu();
|
||
waitMenu->Append(MNU_WAITENABLE, _("&Wait trace"), _("Enable the wait event."), wxITEM_CHECK);
|
||
waitMenu->Append(MNU_WAITSAVE, _("&Wait event save"), _("Enable the wait event save to file sample.dat."), wxITEM_CHECK);
|
||
settings->Read(wxT("frmStatus/WaitTraceEnable"), &wait_enable, false);
|
||
settings->Read(wxT("frmStatus/WaitSave"), &wait_save, false);
|
||
waitMenu->Check(MNU_WAITENABLE,wait_enable);
|
||
waitMenu->Check(MNU_WAITSAVE, wait_save);
|
||
//MNU_WAITSAVE
|
||
wxString q = "select pg_is_in_recovery() recovery, \
|
||
(select setting from pg_settings s where name = 'pg_wait_sampling.history_size')::integer hsize, \
|
||
(select setting from pg_settings s where name = 'pg_wait_sampling.history_period')::integer hperiod, \
|
||
EXTRACT(epoch FROM coalesce(current_setting('idle_in_transaction_session_timeout',true),'30s')::interval)::integer idle_in_transaction_session_timeout,\
|
||
(select pg_table_is_visible(viewname::regclass) and has_table_privilege(viewname::regclass,'select') from pg_views where viewname = 'pg_wait_sampling_history') as wsh, \
|
||
(select pg_table_is_visible(viewname::regclass) and has_table_privilege(viewname::regclass,'select') from pg_views v where viewname='pgpro_stats_statements') as pro, \
|
||
(select pg_table_is_visible(viewname::regclass) and has_table_privilege(viewname::regclass,'select') from pg_views v where viewname='pg_stat_statements') as std, \
|
||
has_function_privilege('pg_read_binary_file(text,bigint,bigint,boolean)','execute') and has_function_privilege('pg_stat_file(text,boolean)','execute') and has_function_privilege('pg_ls_logdir()','execute') isreadlog \
|
||
";
|
||
|
||
pgSet* dataSet1 = connection->ExecuteSet(q);
|
||
pro = false;
|
||
std = false;
|
||
wait_sample = false;
|
||
is_read_log = false;
|
||
if (dataSet1)
|
||
{
|
||
while (!dataSet1->Eof())
|
||
{
|
||
wxString v = dataSet1->GetVal(wxT("recovery"));
|
||
pro= dataSet1->GetBool(wxT("pro"));
|
||
std = dataSet1->GetBool(wxT("std"));
|
||
is_read_log = dataSet1->GetBool(wxT("isreadlog"));
|
||
idle_in_transaction_session_timeout= dataSet1->GetLong(wxT("idle_in_transaction_session_timeout"));
|
||
isrecovery = (v == wxT("t"));
|
||
track_commit_timestamp = connection->HasFeature(FEATURE_TRACK_COMMIT_TS);
|
||
long sz = dataSet1->GetLong(wxT("hsize"));
|
||
long p = dataSet1->GetLong(wxT("hperiod"));
|
||
if (!dataSet1->GetBool(wxT("wsh"))) p = 0;
|
||
if (sz > 1000000) {
|
||
wxLogWarning(_("Value parameter pg_wait_sampling.history_size = %ld greet 1000000 monitoring wait events disabled.\n"),
|
||
sz
|
||
);
|
||
p = 0;
|
||
}
|
||
if (p > 0) {
|
||
wait_sample = true;
|
||
WS.SetConfig(p,sz,this);
|
||
}
|
||
dataSet1->MoveNext();
|
||
}
|
||
delete dataSet1 ;
|
||
}
|
||
if (!wait_sample) {
|
||
waitMenu->Enable(MNU_WAITENABLE, false);
|
||
waitMenu->Enable(MNU_WAITSAVE, false);
|
||
}
|
||
if (wait_sample && wait_enable && (std || pro)) {
|
||
getTextSqlbyQid(0);
|
||
}
|
||
|
||
// Notify wxAUI which frame to use
|
||
manager.SetManagedWindow(this);
|
||
manager.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_TRANSPARENT_DRAG | wxAUI_MGR_ALLOW_ACTIVE_PANE);
|
||
|
||
// Set different window's attributes
|
||
SetTitle(_title);
|
||
SetName(dlgName);
|
||
SetIcon(*server_status_png_ico);
|
||
RestorePosition(-1, -1, 700, 500, 700, 500);
|
||
SetMinSize(FromDIP(wxSize(700, 500)));
|
||
SetFont(settings->GetSystemFont());
|
||
|
||
// Build menu bar
|
||
menuBar = new wxMenuBar();
|
||
|
||
fileMenu = new wxMenu();
|
||
fileMenu->Append(MNU_EXIT, _("E&xit\tCtrl-W"), _("Exit query window"));
|
||
|
||
menuBar->Append(fileMenu, _("&File"));
|
||
|
||
editMenu = new wxMenu();
|
||
editMenu->Append(MNU_COPY, _("&Copy\tCtrl-C"), _("Copy selected text to clipboard"), wxITEM_NORMAL);
|
||
|
||
menuBar->Append(editMenu, _("&Edit"));
|
||
|
||
actionMenu = new wxMenu();
|
||
actionMenu->Append(MNU_REFRESH, _("Refresh\tCtrl-R"), _("Refresh the selected panel"), wxITEM_NORMAL);
|
||
actionMenu->AppendSeparator();
|
||
actionMenu->Append(MNU_COPY_QUERY, _("Copy to query tool\tCtrl-Shift-C"), _("Open the query tool with the selected query"), wxITEM_NORMAL);
|
||
actionMenu->Append(MNU_CANCEL, _("Cancel query\tDel"), _("Cancel the selected query"), wxITEM_NORMAL);
|
||
actionMenu->Append(MNU_TERMINATE, _("Terminate backend\tShift-Del"), _("Terminate the selected backend"), wxITEM_NORMAL);
|
||
actionMenu->AppendSeparator();
|
||
actionMenu->Append(MNU_COMMIT, _("Commit prepared transaction"), _("Commit the selected prepared transaction"), wxITEM_NORMAL);
|
||
actionMenu->Append(MNU_ROLLBACK, _("Rollback prepared transaction"), _("Rollback the selected prepared transaction"), wxITEM_NORMAL);
|
||
|
||
menuBar->Append(actionMenu, _("&Action"));
|
||
|
||
viewMenu = new wxMenu();
|
||
viewMenu->Append(MNU_STATUSPAGE, _("&Activity\tCtrl-Alt-A"), _("Show or hide the activity tab."), wxITEM_CHECK);
|
||
viewMenu->Append(MNU_LOCKPAGE, _("&Locks\tCtrl-Alt-L"), _("Show or hide the locks tab."), wxITEM_CHECK);
|
||
viewMenu->Append(MNU_XACTPAGE, _("Prepared &Transactions\tCtrl-Alt-T"), _("Show or hide the prepared transactions tab."), wxITEM_CHECK);
|
||
viewMenu->Append(MNU_LOGPAGE, _("Log&file\tCtrl-Alt-F"), _("Show or hide the logfile tab."), wxITEM_CHECK);
|
||
viewMenu->Append(MNU_QUERYSTATEPAGE, _("&Query state\tCtrl-Alt-Q"), _("Show or hide the query state tab."), wxITEM_CHECK);
|
||
viewMenu->AppendSeparator();
|
||
viewMenu->Append(MNU_QUERYSTATEVERBOSE, _("Append verbose"), _("Append verbose"), wxITEM_CHECK);
|
||
viewMenu->Append(MNU_QUERYSTATEBUFFER, _("Append use buffers"), _("Append use buffers"), wxITEM_CHECK);
|
||
viewMenu->Append(MNU_QUERYSTATETIME, _("Append real timing"), _("Append real timing"), wxITEM_CHECK);
|
||
viewMenu->Append(MNU_QUERYSTATETRIGGER, _("Append triggers"), _("Append triggers"), wxITEM_CHECK);
|
||
|
||
viewMenu->AppendSeparator();
|
||
viewMenu->Append(MNU_TOOLBAR, _("Tool&bar\tCtrl-Alt-B"), _("Show or hide the toolbar."), wxITEM_CHECK);
|
||
viewMenu->Append(MNU_HIGHLIGHTSTATUS, _("Highlight items of the activity list"), _("Highlight or not the items of the activity list."), wxITEM_CHECK);
|
||
viewMenu->AppendSeparator();
|
||
viewMenu->Append(MNU_DEFAULTVIEW, _("&Default view\tCtrl-Alt-V"), _("Restore the default view."));
|
||
|
||
menuBar->Append(waitMenu, _("&Wait"));
|
||
menuBar->Append(viewMenu, _("&View"));
|
||
|
||
wxMenu *helpMenu = new wxMenu();
|
||
helpMenu->Append(MNU_CONTENTS, _("&Help contents"), _("Open the helpfile."));
|
||
helpMenu->Append(MNU_HELP, _("&Server status help"), _("Display help on this window."));
|
||
|
||
#ifdef __WXMAC__
|
||
menuFactories = new menuFactoryList();
|
||
aboutFactory *af = new aboutFactory(menuFactories, helpMenu, 0);
|
||
wxApp::s_macAboutMenuItemId = af->GetId();
|
||
menuFactories->RegisterMenu(this, wxCommandEventHandler(pgFrame::OnAction));
|
||
#endif
|
||
|
||
menuBar->Append(helpMenu, _("&Help"));
|
||
|
||
// Setup edit menu
|
||
editMenu->Enable(MNU_COPY, false);
|
||
|
||
// Finish menu bar
|
||
SetMenuBar(menuBar);
|
||
|
||
// Set statusBar
|
||
statusBar = CreateStatusBar(1);
|
||
SetStatusBarPane(-1);
|
||
|
||
// Set up toolbar
|
||
toolBar = new ctlMenuToolbar(this, -1, wxDefaultPosition, wxDefaultSize, wxTB_FLAT | wxTB_NODIVIDER);
|
||
toolBar->SetToolBitmapSize(FromDIP(wxSize(32, 32)));
|
||
toolBar->AddTool(MNU_REFRESH, wxEmptyString, GetBundleSVG(readdata_png_bmp, "refresh.svg", FromDIP(wxSize(32, 32))), _("Refresh"), wxITEM_NORMAL);
|
||
toolBar->AddSeparator();
|
||
toolBar->AddTool(MNU_COPY, wxEmptyString, GetBundleSVG(clip_copy_png_bmp, "clip_copy.svg", FromDIP(wxSize(32, 32))), _("Copy selected text to clipboard"), wxITEM_NORMAL);
|
||
toolBar->AddTool(MNU_COPY_QUERY, wxEmptyString, GetBundleSVG(clip_copy_png_bmp, "clip_copy_sql.svg", FromDIP(wxSize(32, 32))), _("Open the query tool with the selected query"), wxITEM_NORMAL);
|
||
toolBar->AddSeparator();
|
||
toolBar->AddTool(MNU_CANCEL, wxEmptyString, GetBundleSVG(query_cancel_png_bmp, "query_cancel.svg", FromDIP(wxSize(32, 32))), _("Cancel query"), wxITEM_NORMAL);
|
||
toolBar->AddTool(MNU_TERMINATE, wxEmptyString, GetBundleSVG(terminate_backend_png_bmp, "terminate_backend.svg", FromDIP(wxSize(32, 32))), _("Terminate backend"), wxITEM_NORMAL);
|
||
toolBar->AddTool(MNU_COMMIT, wxEmptyString, GetBundleSVG(storedata_png_bmp, "storedata.svg", FromDIP(wxSize(32, 32))), _("Commit transaction"), wxITEM_NORMAL);
|
||
toolBar->AddTool(MNU_ROLLBACK, wxEmptyString, GetBundleSVG(delete_png_bmp, "drop.svg", FromDIP(wxSize(32, 32))), _("Rollback transaction"), wxITEM_NORMAL);
|
||
toolBar->AddSeparator();
|
||
toolBar->AddTool(MNU_CLEAR_FILTER_SERVER_STATUS, wxEmptyString, GetBundleSVG(sortfilterclear_png_bmp, "sortfilterclear.svg", FromDIP(wxSize(32, 32))), _("Clear filter"), wxITEM_NORMAL);
|
||
toolBar->AddTool(MNU_SET_FILTER_HIGHLIGHT_STATUS, wxEmptyString, GetBundleSVG(warning_amber_48dp_png_bmp, "warning_amber_48dp.svg", FromDIP(wxSize(32, 32))), _("Highlight items only"), wxITEM_NORMAL);
|
||
toolBar->AddSeparator();
|
||
cbLogfiles = new wxComboBox(toolBar, CTL_LOGCBO, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL,
|
||
wxCB_READONLY | wxCB_DROPDOWN);
|
||
toolBar->AddControl(cbLogfiles);
|
||
btnRotateLog = new wxButton(toolBar, CTL_ROTATEBTN, _("Rotate"));
|
||
toolBar->AddControl(btnRotateLog);
|
||
toolBar->AddSeparator();
|
||
cbRate = new wxComboBox(toolBar, CTL_RATECBO, wxEmptyString, wxDefaultPosition, wxSize(-1, -1), wxArrayString(), wxCB_READONLY | wxCB_DROPDOWN);
|
||
toolBar->AddControl(cbRate);
|
||
toolBar->AddSeparator();
|
||
cbDatabase = new ctlComboBoxFix(toolBar, CTRLID_DATABASE, wxDefaultPosition, wxSize(-1, -1), wxCB_READONLY | wxCB_DROPDOWN);
|
||
toolBar->AddControl(cbDatabase);
|
||
if (wait_sample && wait_enable) {
|
||
toolBar->AddSeparator();
|
||
top_small = new wxTopActivity(toolBar, &WS, wxSize(100, 32));
|
||
toolBar->AddControl(top_small);
|
||
}
|
||
else top_small = NULL;
|
||
|
||
toolBar->Realize();
|
||
|
||
// Append items to cbo
|
||
cbRate->Append(_("Don't refresh"));
|
||
cbRate->Append(_("1 second"));
|
||
cbRate->Append(_("5 seconds"));
|
||
cbRate->Append(_("10 seconds"));
|
||
cbRate->Append(_("30 seconds"));
|
||
cbRate->Append(_("1 minute"));
|
||
cbRate->Append(_("5 minutes"));
|
||
cbRate->Append(_("10 minutes"));
|
||
cbRate->Append(_("30 minutes"));
|
||
cbRate->Append(_("1 hour"));
|
||
|
||
// Disable toolbar's items
|
||
toolBar->EnableTool(MNU_CANCEL, false);
|
||
toolBar->EnableTool(MNU_TERMINATE, false);
|
||
toolBar->EnableTool(MNU_COMMIT, false);
|
||
toolBar->EnableTool(MNU_ROLLBACK, false);
|
||
toolBar->EnableTool(MNU_CLEAR_FILTER_SERVER_STATUS, false);
|
||
actionMenu->Enable(MNU_CANCEL, false);
|
||
actionMenu->Enable(MNU_TERMINATE, false);
|
||
actionMenu->Enable(MNU_COMMIT, false);
|
||
actionMenu->Enable(MNU_ROLLBACK, false);
|
||
cbLogfiles->Enable(false);
|
||
btnRotateLog->Enable(false);
|
||
|
||
// Add the database combobox
|
||
pgSet *dataSet3 = connection->ExecuteSet(wxT("SELECT datname FROM pg_database WHERE datallowconn ORDER BY datname"));
|
||
while (!dataSet3->Eof())
|
||
{
|
||
cbDatabase->Append(dataSet3->GetVal(wxT("datname")));
|
||
dataSet3->MoveNext();
|
||
}
|
||
delete dataSet3;
|
||
|
||
// Image list for all listviews
|
||
listimages = new wxImageList(13, 8, true, 2);
|
||
listimages->Add(*down_png_ico);
|
||
listimages->Add(*up_png_ico);
|
||
|
||
// Create panel
|
||
AddStatusPane();
|
||
AddLockPane();
|
||
AddXactPane();
|
||
AddQuerystatePane();
|
||
AddLogPane();
|
||
wxSize toolw = toolBar->GetBestSize();
|
||
|
||
manager.AddPane(toolBar, wxAuiPaneInfo().Name(wxT("toolBar")).Caption(_("Tool bar")).ToolbarPane().Top().LeftDockable(false).RightDockable(false));
|
||
|
||
// Now load the layout
|
||
wxString perspective;
|
||
settings->Read(wxT("frmStatus/Perspective-") + wxString(FRMSTATUS_PERSPECTIVE_VER), &perspective, FRMSTATUS_DEFAULT_PERSPECTIVE);
|
||
manager.LoadPerspective(perspective, true);
|
||
// Reset the captions for the current language
|
||
manager.GetPane(wxT("toolBar")).Caption(_("Tool bar"));
|
||
manager.GetPane(wxT("Activity")).Caption(_("Activity"));
|
||
manager.GetPane(wxT("Locks")).Caption(_("Locks"));
|
||
manager.GetPane(wxT("Transactions")).Caption(_("Prepared Transactions"));
|
||
manager.GetPane(wxT("Logfile")).Caption(_("Logfile"));
|
||
manager.GetPane(wxT("Querystate")).Caption(_("QueryState"));
|
||
manager.GetPane(wxT("toolBar")).BestSize(toolw);
|
||
//manager.GetPane(wxT("Activity")).GripperTop(true);
|
||
// Tell the manager to "commit" all the changes just made
|
||
manager.Update();
|
||
|
||
// Sync the View menu options
|
||
viewMenu->Check(MNU_STATUSPAGE, manager.GetPane(wxT("Activity")).IsShown());
|
||
viewMenu->Check(MNU_LOCKPAGE, manager.GetPane(wxT("Locks")).IsShown());
|
||
viewMenu->Check(MNU_XACTPAGE, manager.GetPane(wxT("Transactions")).IsShown());
|
||
viewMenu->Check(MNU_LOGPAGE, manager.GetPane(wxT("Logfile")).IsShown());
|
||
pgSet *set = connection->ExecuteSet(wxT("SELECT 1 FROM pg_available_extensions WHERE installed_version is not null and name='pg_query_state'"));
|
||
bool queryenable = set->NumRows() == 1;
|
||
viewMenu->Enable(MNU_QUERYSTATEPAGE, queryenable);
|
||
if (!queryenable) {
|
||
viewMenu->Check(MNU_QUERYSTATEPAGE, false);
|
||
manager.GetPane(wxT("Querystate")).Hide();
|
||
}
|
||
//viewMenu->Check(MNU_QUERYSTATEPAGE,set->NumRows() == 1);
|
||
delete set;
|
||
|
||
viewMenu->Check(MNU_TOOLBAR, manager.GetPane(wxT("toolBar")).IsShown());
|
||
//
|
||
//if (!viewMenu->IsEnabled(MNU_QUERYSTATEPAGE)) {
|
||
// manager.GetPane(wxT("Querystate")).Hide();
|
||
// } else manager.GetPane(wxT("Querystate")).Show();
|
||
|
||
viewMenu->Check(MNU_QUERYSTATEPAGE,manager.GetPane(wxT("Querystate")).IsShown());
|
||
// Read the highlight status checkbox
|
||
settings->Read(wxT("frmStatus/HighlightStatus"), &highlight, true);
|
||
viewMenu->Check(MNU_HIGHLIGHTSTATUS, highlight);
|
||
bool qu_status;
|
||
settings->Read(wxT("frmStatus/QuerystateVerboseStatus"), &qu_status, false);
|
||
viewMenu->Check(MNU_QUERYSTATEVERBOSE, qu_status);
|
||
settings->Read(wxT("frmStatus/QuerystateTimeStatus"), &qu_status, true);
|
||
viewMenu->Check(MNU_QUERYSTATETIME, qu_status);
|
||
settings->Read(wxT("frmStatus/QuerystateBufferStatus"), &qu_status, true);
|
||
viewMenu->Check(MNU_QUERYSTATEBUFFER, qu_status);
|
||
settings->Read(wxT("frmStatus/QuerystateTriggerStatus"), &qu_status, true);
|
||
viewMenu->Check(MNU_QUERYSTATETRIGGER, qu_status);
|
||
|
||
|
||
// Get our PID
|
||
backend_pid = connection->GetBackendPID();
|
||
|
||
// Create the refresh timer (quarter of a second)
|
||
// This is a horrible hack to get around the lack of a
|
||
// PANE_ACTIVATED event in wxAUI.
|
||
refreshUITimer = new wxTimer(this, TIMER_REFRESHUI_ID);
|
||
refreshUITimer->Start(250);
|
||
|
||
// The selected pane is the log pane by default
|
||
// so enable/disable the widgets according to this
|
||
wxListEvent nullevent;
|
||
OnSelLogItem(nullevent);
|
||
|
||
// We're good now
|
||
loaded = true;
|
||
}
|
||
|
||
|
||
frmStatus::~frmStatus()
|
||
{
|
||
// Delete the refresh timer
|
||
delete refreshUITimer;
|
||
// If the status window wasn't launched in standalone mode...
|
||
if (mainForm)
|
||
mainForm->RemoveFrame(this);
|
||
|
||
// Save the window's position
|
||
settings->Write(wxT("frmStatus/Perspective-") + wxString(FRMSTATUS_PERSPECTIVE_VER), manager.SavePerspective());
|
||
manager.UnInit();
|
||
SavePosition();
|
||
|
||
// Save the highlight status checkbox
|
||
settings->WriteBool(wxT("frmStatus/HighlightStatus"), viewMenu->IsChecked(MNU_HIGHLIGHTSTATUS));
|
||
settings->WriteBool(wxT("frmStatus/QuerystateVerboseStatus"), viewMenu->IsChecked(MNU_QUERYSTATEVERBOSE));
|
||
settings->WriteBool(wxT("frmStatus/QuerystateTimeStatus"), viewMenu->IsChecked(MNU_QUERYSTATETIME));
|
||
settings->WriteBool(wxT("frmStatus/QuerystateBufferStatus"), viewMenu->IsChecked(MNU_QUERYSTATEBUFFER));
|
||
settings->WriteBool(wxT("frmStatus/QuerystateTriggerStatus"), viewMenu->IsChecked(MNU_QUERYSTATETRIGGER));
|
||
if (wait_sample) settings->WriteBool(wxT("frmStatus/WaitTraceEnable"), waitMenu->IsChecked(MNU_WAITENABLE));
|
||
if (wait_sample) settings->WriteBool(wxT("frmStatus/WaitSave"), waitMenu->IsChecked(MNU_WAITSAVE));
|
||
if (wait_sample && wait_enable && waitMenu->IsChecked(MNU_WAITSAVE)) WS.SaveFileSamples(); else {
|
||
// remove file
|
||
WS.RemoveFiles();
|
||
}
|
||
|
||
|
||
// For each current page, save the slider's position and delete the timer
|
||
settings->WriteInt(wxT("frmStatus/RefreshStatusRate"), statusRate);
|
||
delete statusTimer;
|
||
settings->WriteInt(wxT("frmStatus/RefreshLockRate"), locksRate);
|
||
delete locksTimer;
|
||
if (viewMenu->IsEnabled(MNU_XACTPAGE))
|
||
{
|
||
settings->WriteInt(wxT("frmStatus/RefreshXactRate"), xactRate);
|
||
if (xactTimer)
|
||
{
|
||
delete xactTimer;
|
||
xactTimer = NULL;
|
||
}
|
||
}
|
||
if (viewMenu->IsEnabled(MNU_LOGPAGE))
|
||
{
|
||
settings->WriteInt(wxT("frmStatus/RefreshLogRate"), logRate);
|
||
emptyLogfileCombo();
|
||
if (logTimer)
|
||
{
|
||
delete logTimer;
|
||
logTimer = NULL;
|
||
}
|
||
}
|
||
if (viewMenu->IsEnabled(MNU_QUERYSTATEPAGE))
|
||
{
|
||
settings->WriteInt(wxT("frmStatus/RefreshQuerystateRate"), querystateRate);
|
||
if (querystateTimer)
|
||
{
|
||
delete querystateTimer;
|
||
querystateTimer = NULL;
|
||
}
|
||
}
|
||
|
||
// If connection is still available, delete it
|
||
if (locks_connection && locks_connection != connection)
|
||
{
|
||
if (locks_connection->IsAlive())
|
||
delete locks_connection;
|
||
}
|
||
if (connection)
|
||
{
|
||
connection->Close();
|
||
delete connection;
|
||
// if (connection->IsAlive())
|
||
// delete connection;
|
||
}
|
||
if (logThread) {
|
||
logThread->BreakRead();
|
||
wxMilliSleep(50);
|
||
logThread->DoTerminate();
|
||
//s_CloseLog.Wait();
|
||
while (logThread != NULL) wxMilliSleep(50) ;
|
||
}
|
||
if (logconn)
|
||
{
|
||
logconn->Close();
|
||
///if (logconn->IsAlive())
|
||
delete logconn;
|
||
}
|
||
}
|
||
|
||
|
||
void frmStatus::Go()
|
||
{
|
||
// Show the window
|
||
Show(true);
|
||
|
||
// Send RateChange event to launch each timer
|
||
wxScrollEvent nullScrollEvent;
|
||
if (viewMenu->IsChecked(MNU_STATUSPAGE))
|
||
{
|
||
currentPane = PANE_STATUS;
|
||
cbRate->SetValue(rateToCboString(statusRate));
|
||
OnRateChange(nullScrollEvent);
|
||
}
|
||
if (viewMenu->IsChecked(MNU_LOCKPAGE))
|
||
{
|
||
currentPane = PANE_LOCKS;
|
||
cbRate->SetValue(rateToCboString(locksRate));
|
||
OnRateChange(nullScrollEvent);
|
||
}
|
||
if (viewMenu->IsEnabled(MNU_XACTPAGE) && viewMenu->IsChecked(MNU_XACTPAGE))
|
||
{
|
||
currentPane = PANE_XACT;
|
||
cbRate->SetValue(rateToCboString(xactRate));
|
||
OnRateChange(nullScrollEvent);
|
||
}
|
||
if (viewMenu->IsEnabled(MNU_LOGPAGE) && viewMenu->IsChecked(MNU_LOGPAGE))
|
||
{
|
||
currentPane = PANE_LOG;
|
||
cbRate->SetValue(rateToCboString(logRate));
|
||
OnRateChange(nullScrollEvent);
|
||
}
|
||
if (viewMenu->IsEnabled(MNU_QUERYSTATEPAGE) && viewMenu->IsChecked(MNU_QUERYSTATEPAGE))
|
||
{
|
||
currentPane = PANE_QUERYSTATE;
|
||
cbRate->SetValue(rateToCboString(querystateRate));
|
||
OnRateChange(nullScrollEvent);
|
||
}
|
||
|
||
// Refresh all pages
|
||
wxCommandEvent nullEvent;
|
||
OnRefresh(nullEvent);
|
||
}
|
||
|
||
|
||
void frmStatus::OnClose(wxCloseEvent &event)
|
||
{
|
||
|
||
frm_exit = true;
|
||
queue_sql.Clear();
|
||
queue_sql.Post(-1);
|
||
bool ex=false;
|
||
{
|
||
wxCriticalSectionLocker lock(thread_execute);
|
||
while (!ex) {
|
||
int cnt=0;
|
||
{
|
||
wxCriticalSectionLocker lock(gs_critsect);
|
||
for(int i=0;i<4;i++) {
|
||
if (array_exec[i].conn!=NULL && array_exec[i].isExecute) cnt++;
|
||
if (array_exec[i].conn!=NULL && array_exec[i].result!=NULL) {
|
||
delete array_exec[i].result;
|
||
array_exec[i].result=NULL;
|
||
}
|
||
|
||
}
|
||
}
|
||
if (cnt>0) wxMilliSleep(10);
|
||
ex=true;
|
||
}
|
||
}
|
||
wxMilliSleep(20);
|
||
//if (q_thread) q_thread->Delete();
|
||
|
||
if (logThread && logisread) {
|
||
logThread->BreakRead();
|
||
event.Veto();
|
||
} else Destroy();
|
||
//Destroy();
|
||
}
|
||
|
||
|
||
void frmStatus::OnExit(wxCommandEvent &event)
|
||
{
|
||
wxCloseEvent e;
|
||
OnClose(e);
|
||
//Destroy();
|
||
}
|
||
|
||
|
||
void frmStatus::OnChangeDatabase(wxCommandEvent &ev)
|
||
{
|
||
wxString initquery;
|
||
|
||
if (locks_connection != connection)
|
||
{
|
||
delete locks_connection;
|
||
}
|
||
|
||
locks_connection = new pgConn(connection->GetHostName(), connection->GetService(), connection->GetHostAddr(), cbDatabase->GetValue(),
|
||
connection->GetUser(), connection->GetPassword(), connection->GetPort(), connection->GetRole(),"", connection->GetSslMode(),
|
||
0, connection->GetApplicationName(), connection->GetSSLCert(), connection->GetSSLKey(), connection->GetSSLRootCert(), connection->GetSSLCrl(),
|
||
connection->GetSSLCompression());
|
||
|
||
pgUser *user = new pgUser(locks_connection->GetUser());
|
||
if (user)
|
||
{
|
||
if (user->GetSuperuser())
|
||
{
|
||
if (locks_connection->BackendMinimumVersion(8, 0))
|
||
initquery = wxT("SET log_statement='none';SET log_duration='off';SET log_min_duration_statement=-1;");
|
||
else
|
||
initquery = wxT("SET log_statement='off';SET log_duration='off';SET log_min_duration_statement=-1;");
|
||
locks_connection->ExecuteVoid(initquery, false);
|
||
}
|
||
delete user;
|
||
}
|
||
}
|
||
|
||
void frmStatus::AddStatusPane()
|
||
{
|
||
// Create panel
|
||
wxPanel *pnlActivity = new wxPanel(this);
|
||
// Create flex grid
|
||
wxFlexGridSizer *grdActivity = new wxFlexGridSizer(1, 1, 5, 5);
|
||
grdActivity->AddGrowableCol(0);
|
||
grdActivity->AddGrowableRow(0);
|
||
|
||
// Add the list control
|
||
#ifdef __WXMAC__
|
||
// Switch to the generic list control.
|
||
// Disable sort on Mac.
|
||
wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), true);
|
||
#endif
|
||
ctlListView *lstStatus = new ctlListView(pnlActivity, CTL_STATUSLIST, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxSUNKEN_BORDER);
|
||
//lstStatus->SetDoubleBuffered(true);
|
||
//lstStatus->SetBackgroundStyle(wxBG_STYLE_COLOUR);
|
||
//lstStatus->SetBackgroundColour(*wxBLACK );
|
||
|
||
// Now switch back
|
||
#ifdef __WXMAC__
|
||
wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), false);
|
||
#endif
|
||
grdActivity->Add(lstStatus, 0, wxGROW, 3);
|
||
|
||
// Add the panel to the notebook
|
||
manager.AddPane(pnlActivity,
|
||
wxAuiPaneInfo().
|
||
Name(wxT("Activity")).Caption(_("Activity")).
|
||
CaptionVisible(true).CloseButton(true).MaximizeButton(true).
|
||
Dockable(true).Movable(true));
|
||
|
||
// Auto-sizing
|
||
pnlActivity->SetSizer(grdActivity);
|
||
grdActivity->Fit(pnlActivity);
|
||
|
||
// Add each column to the list control
|
||
statusList = (ctlListView *)lstStatus;
|
||
//statusList->Bind(wxEVT_ERASE_BACKGROUND, &frmStatus::OnEraseBackground, this);
|
||
// statusList->SetOwnBackgroundColour();
|
||
statusList->AddColumn(_("PID"), 35);
|
||
if (connection->BackendMinimumVersion(8, 5))
|
||
statusList->AddColumn(_("Application name"), 70);
|
||
statusList->AddColumn(_("Database"), 70);
|
||
statusList->AddColumn(_("User"), 70);
|
||
if (connection->BackendMinimumVersion(8, 1))
|
||
{
|
||
statusList->AddColumn(_("Client"), 70);
|
||
statusList->AddColumn(_("Client start"), 80);
|
||
}
|
||
if (connection->BackendMinimumVersion(7, 4))
|
||
statusList->AddColumn(_("Query start"), 50);
|
||
if (connection->BackendMinimumVersion(8, 3))
|
||
statusList->AddColumn(_("TX start"), 50);
|
||
if (connection->BackendMinimumVersion(9, 2))
|
||
{
|
||
statusList->AddColumn(_("State"), 35);
|
||
statusList->AddColumn(_("State change"), 35);
|
||
}
|
||
if (connection->BackendMinimumVersion(9, 4))
|
||
{
|
||
statusList->AddColumn(_("Backend XID"), 35);
|
||
statusList->AddColumn(_("Backend XMin"), 35);
|
||
}
|
||
if (connection->BackendMinimumVersion(9, 6))
|
||
{
|
||
statusList->AddColumn(_("W_Event_T"), 35);
|
||
statusList->AddColumn(_("W_Event"), 35);
|
||
}
|
||
statusList->AddColumn(_("Blocked by"), 35);
|
||
statusList->AddColumn(_("Query"), 500);
|
||
|
||
// Get through the list of columns to build the popup menu
|
||
// and reinitialize column's width if we find a saved width
|
||
statusPopupMenu = new wxMenu();
|
||
wxListItem item;
|
||
item.SetMask(wxLIST_MASK_TEXT);
|
||
int savedwidth;
|
||
for (int col = 0; col < statusList->GetColumnCount(); col++)
|
||
{
|
||
// Get column
|
||
statusList->GetColumn(col, item);
|
||
|
||
// Reinitialize column's width
|
||
settings->Read(wxT("frmStatus/StatusPane_") + item.GetText() + wxT("_Width"), &savedwidth, statusList->GetColumnWidth(col));
|
||
if (savedwidth > 0)
|
||
statusList->SetColumnWidth(col, savedwidth);
|
||
else
|
||
statusList->SetColumnWidth(col, 0);
|
||
statusColWidth[col] = savedwidth;
|
||
|
||
// Add new check item on the popup menu
|
||
statusPopupMenu->AppendCheckItem(1000 + col, item.GetText());
|
||
statusPopupMenu->Check(1000 + col, statusList->GetColumnWidth(col) > 0);
|
||
this->Connect(1000 + col, wxEVT_COMMAND_MENU_SELECTED,
|
||
wxCommandEventHandler(frmStatus::OnStatusMenu));
|
||
}
|
||
|
||
// Build image list
|
||
statusList->SetImageList(listimages, wxIMAGE_LIST_SMALL);
|
||
|
||
// Read statusRate configuration
|
||
settings->Read(wxT("frmStatus/RefreshStatusRate"), &statusRate, 10);
|
||
|
||
// Initialize sort order
|
||
statusSortColumn = 1;
|
||
statusSortOrder = wxT("ASC");
|
||
// Create the timer
|
||
statusTimer = new wxTimer(this, TIMER_STATUS_ID);
|
||
}
|
||
|
||
|
||
void frmStatus::AddLockPane()
|
||
{
|
||
// Create panel
|
||
wxPanel *pnlLock = new wxPanel(this);
|
||
|
||
// Create flex grid
|
||
wxFlexGridSizer *grdLock = new wxFlexGridSizer(1, 1, 5, 5);
|
||
grdLock->AddGrowableCol(0);
|
||
grdLock->AddGrowableRow(0);
|
||
|
||
// Add the list control
|
||
#ifdef __WXMAC__
|
||
// Switch to the generic list control.
|
||
// Disable sort on Mac.
|
||
wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), true);
|
||
#endif
|
||
wxListCtrl *lstLocks = new wxListCtrl(pnlLock, CTL_LOCKLIST, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxSUNKEN_BORDER);
|
||
// Now switch back
|
||
#ifdef __WXMAC__
|
||
wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), false);
|
||
#endif
|
||
grdLock->Add(lstLocks, 0, wxGROW, 3);
|
||
|
||
// Add the panel to the notebook
|
||
manager.AddPane(pnlLock,
|
||
wxAuiPaneInfo().
|
||
Name(wxT("Locks")).Caption(_("Locks")).
|
||
CaptionVisible(true).CloseButton(true).MaximizeButton(true).
|
||
Dockable(true).Movable(true));
|
||
|
||
// Auto-sizing
|
||
pnlLock->SetSizer(grdLock);
|
||
grdLock->Fit(pnlLock);
|
||
|
||
// Add each column to the list control
|
||
lockList = (ctlListView *)lstLocks;
|
||
lockList->AddColumn(wxT("PID"), 35);
|
||
lockList->AddColumn(_("Database"), 50);
|
||
lockList->AddColumn(_("Relation"), 50);
|
||
lockList->AddColumn(_("User"), 50);
|
||
if (locks_connection->BackendMinimumVersion(8, 3))
|
||
lockList->AddColumn(_("XID"), 50);
|
||
lockList->AddColumn(_("TX"), 50);
|
||
lockList->AddColumn(_("Mode"), 50);
|
||
lockList->AddColumn(_("Granted"), 50);
|
||
if (locks_connection->BackendMinimumVersion(7, 4))
|
||
lockList->AddColumn(_("Start"), 50);
|
||
lockList->AddColumn(_("Query"), 500);
|
||
|
||
// Get through the list of columns to build the popup menu
|
||
lockPopupMenu = new wxMenu();
|
||
wxListItem item;
|
||
item.SetMask(wxLIST_MASK_TEXT);
|
||
int savedwidth;
|
||
for (int col = 0; col < lockList->GetColumnCount(); col++)
|
||
{
|
||
// Get column
|
||
lockList->GetColumn(col, item);
|
||
int currwidth = lockList->GetColumnWidth(col);
|
||
// Reinitialize column's width
|
||
settings->Read(wxT("frmStatus/LockPane_") + item.GetText() + wxT("_Width"), &savedwidth, currwidth);
|
||
if (savedwidth > 0)
|
||
lockList->SetColumnWidth(col, savedwidth);
|
||
else
|
||
lockList->SetColumnWidth(col, 0);
|
||
lockColWidth[col] = savedwidth;
|
||
|
||
// Add new check item on the popup menu
|
||
lockPopupMenu->AppendCheckItem(2000 + col, item.GetText());
|
||
lockPopupMenu->Check(2000 + col, lockList->GetColumnWidth(col) > 0);
|
||
this->Connect(2000 + col, wxEVT_COMMAND_MENU_SELECTED,
|
||
wxCommandEventHandler(frmStatus::OnLockMenu));
|
||
}
|
||
|
||
// Build image list
|
||
lockList->SetImageList(listimages, wxIMAGE_LIST_SMALL);
|
||
|
||
// Read locksRate configuration
|
||
settings->Read(wxT("frmStatus/RefreshLockRate"), &locksRate, 10);
|
||
|
||
// Initialize sort order
|
||
lockSortColumn = 1;
|
||
lockSortOrder = wxT("ASC");
|
||
|
||
// Create the timer
|
||
locksTimer = new wxTimer(this, TIMER_LOCKS_ID);
|
||
}
|
||
|
||
|
||
void frmStatus::AddXactPane()
|
||
{
|
||
// Create panel
|
||
wxPanel *pnlXacts = new wxPanel(this);
|
||
|
||
// Create flex grid
|
||
wxFlexGridSizer *grdXacts = new wxFlexGridSizer(1, 1, 5, 5);
|
||
grdXacts->AddGrowableCol(0);
|
||
grdXacts->AddGrowableRow(0);
|
||
|
||
// Add the list control
|
||
#ifdef __WXMAC__
|
||
// Switch to the generic list control.
|
||
// Disable sort on Mac.
|
||
wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), true);
|
||
#endif
|
||
wxListCtrl *lstXacts = new wxListCtrl(pnlXacts, CTL_XACTLIST, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxSUNKEN_BORDER);
|
||
// Now switch back
|
||
#ifdef __WXMAC__
|
||
wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), false);
|
||
#endif
|
||
grdXacts->Add(lstXacts, 0, wxGROW, 3);
|
||
|
||
// Add the panel to the notebook
|
||
manager.AddPane(pnlXacts,
|
||
wxAuiPaneInfo().
|
||
Name(wxT("Transactions")).Caption(_("Transactions")).
|
||
CaptionVisible(true).CloseButton(true).MaximizeButton(true).
|
||
Dockable(true).Movable(true));
|
||
|
||
// Auto-sizing
|
||
pnlXacts->SetSizer(grdXacts);
|
||
grdXacts->Fit(pnlXacts);
|
||
|
||
// Add the xact list
|
||
xactList = (ctlListView *)lstXacts;
|
||
|
||
// We don't need this report if server release is less than 8.1
|
||
// GPDB doesn't have external global transactions.
|
||
// Perhaps we should use this display to show our
|
||
// global xid to local xid mappings?
|
||
if (!connection->BackendMinimumVersion(8, 1) || connection->GetIsGreenplum())
|
||
{
|
||
// manager.GetPane(wxT("Transactions")).Show(false);
|
||
lstXacts->InsertColumn(lstXacts->GetColumnCount(), _("Message"), wxLIST_FORMAT_LEFT, 800);
|
||
lstXacts->InsertItem(lstXacts->GetItemCount(), _("Prepared transactions not available on this server."), -1);
|
||
lstXacts->Enable(false);
|
||
xactTimer = NULL;
|
||
|
||
// We're done
|
||
return;
|
||
}
|
||
|
||
// Add each column to the list control
|
||
xactList->AddColumn(wxT("XID"), 50);
|
||
xactList->AddColumn(_("Global ID"), 200);
|
||
xactList->AddColumn(_("Time"), 100);
|
||
xactList->AddColumn(_("Owner"), 50);
|
||
xactList->AddColumn(_("Database"), 50);
|
||
|
||
// Get through the list of columns to build the popup menu
|
||
xactPopupMenu = new wxMenu();
|
||
wxListItem item;
|
||
item.SetMask(wxLIST_MASK_TEXT);
|
||
int savedwidth;
|
||
for (int col = 0; col < xactList->GetColumnCount(); col++)
|
||
{
|
||
// Get column
|
||
xactList->GetColumn(col, item);
|
||
int currwidth = xactList->GetColumnWidth(col);
|
||
// Reinitialize column's width
|
||
settings->Read(wxT("frmStatus/XactPane_") + item.GetText() + wxT("_Width"), &savedwidth, currwidth);
|
||
if (savedwidth > 0)
|
||
xactList->SetColumnWidth(col, savedwidth);
|
||
else
|
||
xactList->SetColumnWidth(col, 0);
|
||
xactColWidth[col] = savedwidth;
|
||
|
||
// Add new check item on the popup menu
|
||
xactPopupMenu->AppendCheckItem(3000 + col, item.GetText());
|
||
xactPopupMenu->Check(3000 + col, xactList->GetColumnWidth(col) > 0);
|
||
this->Connect(3000 + col, wxEVT_COMMAND_MENU_SELECTED,
|
||
wxCommandEventHandler(frmStatus::OnXactMenu));
|
||
}
|
||
|
||
// Build image list
|
||
xactList->SetImageList(listimages, wxIMAGE_LIST_SMALL);
|
||
|
||
// Read xactRate configuration
|
||
settings->Read(wxT("frmStatus/RefreshXactRate"), &xactRate, 10);
|
||
|
||
// Initialize sort order
|
||
xactSortColumn = 2;
|
||
xactSortOrder = wxT("ASC");
|
||
|
||
// Create the timer
|
||
xactTimer = new wxTimer(this, TIMER_XACT_ID);
|
||
}
|
||
void frmStatus::AddQuerystatePane()
|
||
{
|
||
// Create panel
|
||
wxPanel *pnlQuerystate = new wxPanel(this);
|
||
|
||
// Create flex grid
|
||
wxFlexGridSizer *grdQuerystate = new wxFlexGridSizer(1, 1, 5, 5);
|
||
grdQuerystate->AddGrowableCol(0);
|
||
grdQuerystate->AddGrowableRow(0);
|
||
|
||
// Add the list control
|
||
#ifdef __WXMAC__
|
||
// Switch to the generic list control.
|
||
// Disable sort on Mac.
|
||
wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), true);
|
||
#endif
|
||
wxListCtrl *lstQuerystate = new wxListCtrl(pnlQuerystate, CTL_QUERYSTATELIST, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxSUNKEN_BORDER);
|
||
// Now switch back
|
||
#ifdef __WXMAC__
|
||
wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), false);
|
||
#endif
|
||
grdQuerystate->Add(lstQuerystate, 0, wxGROW, 3);
|
||
|
||
// Add the panel to the notebook
|
||
manager.AddPane(pnlQuerystate,
|
||
wxAuiPaneInfo().Center().
|
||
Name(wxT("Querystate")).Caption(_("Query State")).
|
||
CaptionVisible(true).CloseButton(true).MaximizeButton(true).
|
||
Dockable(true).Movable(true));
|
||
|
||
// Auto-sizing
|
||
pnlQuerystate->SetSizer(grdQuerystate);
|
||
grdQuerystate->Fit(pnlQuerystate);
|
||
|
||
// Add the xact list
|
||
querystateList = (ctlListView *)lstQuerystate;
|
||
|
||
// Add each column to the list control
|
||
querystateList->AddColumn(wxT("Pid"), 20);
|
||
querystateList->AddColumn(wxT("Fn"), 20);
|
||
querystateList->AddColumn(_("Query Text"), 200);
|
||
querystateList->AddColumn(_("Plan"), 300);
|
||
querystateList->AddColumn(wxT("Leader_pid"), 20);
|
||
|
||
// Get through the list of columns to build the popup menu
|
||
querystatePopupMenu = new wxMenu();
|
||
wxListItem item;
|
||
item.SetMask(wxLIST_MASK_TEXT);
|
||
int savedwidth;
|
||
for (int col = 0; col < querystateList->GetColumnCount(); col++)
|
||
{
|
||
// Get column
|
||
querystateList->GetColumn(col, item);
|
||
wxString namec=item.GetText();
|
||
int currwidth=querystateList->GetColumnWidth(col);
|
||
// Reinitialize column's width
|
||
settings->Read(wxT("frmStatus/QuerystatePane_") + namec + wxT("_Width"), &savedwidth, currwidth);
|
||
if (savedwidth > 0)
|
||
querystateList->SetColumnWidth(col, savedwidth);
|
||
else
|
||
querystateList->SetColumnWidth(col, 0);
|
||
querystateColWidth[col] = savedwidth;
|
||
|
||
// Add new check item on the popup menu
|
||
querystatePopupMenu->AppendCheckItem(4000 + col, item.GetText());
|
||
querystatePopupMenu->Check(4000 + col, querystateList->GetColumnWidth(col) > 0);
|
||
this->Connect(4000 + col, wxEVT_COMMAND_MENU_SELECTED,
|
||
wxCommandEventHandler(frmStatus::OnQuerystateMenu));
|
||
}
|
||
|
||
// Build image list
|
||
querystateList->SetImageList(listimages, wxIMAGE_LIST_SMALL);
|
||
|
||
// Read querystateRate configuration
|
||
settings->Read(wxT("frmStatus/RefreshQuerystateRate"), &querystateRate, 10);
|
||
|
||
// Initialize sort order
|
||
//QuerystateortColumn = 2;
|
||
//QuerystateortOrder = wxT("ASC");
|
||
|
||
// Create the timer
|
||
querystateTimer = new wxTimer(this, TIMER_QUERYSTATE_ID);
|
||
{
|
||
wxCriticalSectionLocker lock(thread_execute);
|
||
pgSet *set = connection->ExecuteSet(wxT("SELECT 1 FROM pg_available_extensions WHERE installed_version is not null and name='pg_query_state'"));
|
||
if (set->NumRows() == 1)
|
||
viewMenu->Check(MNU_QUERYSTATEPAGE,true);
|
||
else
|
||
viewMenu->Check(MNU_QUERYSTATEPAGE,false);
|
||
delete set;
|
||
}
|
||
}
|
||
|
||
|
||
void frmStatus::AddLogPane()
|
||
{
|
||
int rc = -1;
|
||
wxString hint = HINT_INSTRUMENTATION;
|
||
|
||
// Create panel
|
||
wxPanel *pnlLog = new wxPanel(this);
|
||
//pnlLog->SetBackgroundColour(*wxRED);
|
||
// Create flex grid
|
||
wxFlexGridSizer *grdLog = new wxFlexGridSizer(1, 2, 2, 0);
|
||
//wxBoxSizer* grdLog = new wxBoxSizer(wxHORIZONTAL);
|
||
grdLog->AddGrowableCol(1);
|
||
grdLog->AddGrowableRow(0);
|
||
|
||
// Add the list control
|
||
#ifdef __WXMAC__
|
||
// Switch to the generic list control.
|
||
// Disable sort on Mac.
|
||
wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), true);
|
||
#endif
|
||
|
||
//wxListCtrl *lstLog = new wxListCtrl(pnlLog, CTL_LOGLIST, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxSUNKEN_BORDER);
|
||
logList = new ctlListView(pnlLog, CTL_LOGLIST, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
|
||
logList->SetToolTip(NULL);
|
||
// hide tooltip for windows
|
||
#ifdef __WXMSW__
|
||
HWND hwndList = (HWND)logList->GetHandle();
|
||
LPARAM style = ::SendMessage(hwndList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
|
||
::SendMessage(hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, style & ~LVS_EX_LABELTIP);
|
||
#endif
|
||
// Add the log list
|
||
//logList = (ctlListView*)lstLog;
|
||
logList->SetModeStoreLongString();
|
||
nav = new ctlNavigatePanel(pnlLog, logList);
|
||
logList->Bind(wxEVT_KEY_UP, &frmStatus::OnLogKeyUp, this);
|
||
//lstLog->Bind(wxEVT_MENU, &ctlNavigatePanel::OnContextMenu, this);
|
||
//Bind(wxEVT_THREAD, &frmStatus::OnAddLabelTextThread, this);
|
||
logList->Bind(wxEVT_MENU, &frmStatus::OnLogContextMenu, this);
|
||
logList->Bind(wxEVT_MOTION, &frmStatus::OnMoveMouseLog, this);
|
||
//Connect(wxID_ANY, wxEVT_THREAD, wxThreadEventHandler(frmLog::OnAddLabelTextThread), NULL, this);
|
||
// Now switch back
|
||
#ifdef __WXMAC__
|
||
wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), false);
|
||
#endif
|
||
delayHitLog = new wxTimer(this, TIMER_LOGHINT_ID);
|
||
//Bind(wxEVT_TIMER, &frmStatus::OnTimerHintLog, this);
|
||
///delayHitLog->Start(DELAYHITLOGPERIOD);
|
||
|
||
grdLog->Add(nav, 0, wxSHRINK, 3);
|
||
grdLog->Add(logList, 0, wxALL | wxEXPAND, 3);
|
||
// Add the panel to the notebook
|
||
manager.AddPane(pnlLog,
|
||
wxAuiPaneInfo().Center().
|
||
Name(wxT("Logfile")).Caption(_("Logfile")).
|
||
CaptionVisible(true).CloseButton(true).MaximizeButton(true).
|
||
Dockable(true).Movable(true));
|
||
|
||
// Auto-sizing
|
||
pnlLog->SetSizer(grdLog);
|
||
grdLog->Fit(pnlLog);
|
||
|
||
logcol[0] = logList->GetBackgroundColour();
|
||
logcol[1] = wxColour("#afafaf");
|
||
// We don't need this report (but we need the pane)
|
||
// if server release is less than 8.0 or if server has no adminpack
|
||
if (!is_read_log) {
|
||
logList->InsertColumn(logList->GetColumnCount(), _("Message"), wxLIST_FORMAT_LEFT, 700);
|
||
logList->AppendItemLong(-1, _("Functions pg_read_binary_file(text,bigint,bigint,boolean), pg_stat_file(text,boolean),pg_ls_logdir() permission denied."));
|
||
logList->Enable(false);
|
||
logTimer = NULL;
|
||
// We're done
|
||
return;
|
||
|
||
}
|
||
|
||
logList->AddColumn(_("Log entry"), 800);
|
||
// if (!connection->HasFeature(FEATURE_ROTATELOG))
|
||
btnRotateLog->Disable();
|
||
|
||
// Re-initialize variables
|
||
logfileLength = 0;
|
||
|
||
// Read logRate configuration
|
||
settings->Read(wxT("frmStatus/RefreshLogRate"), &logRate, 10);
|
||
|
||
// Create the timer
|
||
logTimer = new wxTimer(this, TIMER_LOG_ID);
|
||
}
|
||
|
||
void frmStatus::OnCopy(wxCommandEvent &ev)
|
||
{
|
||
ctlListView *list;
|
||
int row, col;
|
||
wxString text;
|
||
|
||
switch(currentPane)
|
||
{
|
||
case PANE_STATUS:
|
||
list = statusList;
|
||
break;
|
||
case PANE_LOCKS:
|
||
list = lockList;
|
||
break;
|
||
case PANE_XACT:
|
||
list = xactList;
|
||
break;
|
||
case PANE_LOG:
|
||
list = logList;
|
||
break;
|
||
case PANE_QUERYSTATE:
|
||
list = querystateList;
|
||
break;
|
||
default:
|
||
// This shouldn't happen.
|
||
// If it does, it's no big deal, we just need to get out.
|
||
return;
|
||
break;
|
||
}
|
||
if (currentPane==PANE_QUERYSTATE) {
|
||
wxString s;
|
||
for (row = 0; row < list->GetItemCount(); row++)
|
||
{
|
||
s=list->GetText(row, 2);
|
||
if (s.Length()>0) {
|
||
text.Append(wxT("SQL QUERY: ")).Append(s);
|
||
#ifdef __WXMSW__
|
||
text.Append(wxT("\r\n"));
|
||
#else
|
||
text.Append(wxT("\n"));
|
||
#endif
|
||
}
|
||
text.Append(list->GetText(row, 3));
|
||
#ifdef __WXMSW__
|
||
text.Append(wxT("\r\n"));
|
||
#else
|
||
text.Append(wxT("\n"));
|
||
#endif
|
||
}
|
||
// list->GetText(row,3);
|
||
} else
|
||
{
|
||
row = list->GetFirstSelected();
|
||
|
||
while (row >= 0)
|
||
{
|
||
for (col = 0; col < list->GetColumnCount(); col++)
|
||
{
|
||
text.Append(list->GetText(row, col) + wxT("\t"));
|
||
}
|
||
#ifdef __WXMSW__
|
||
text.Append(wxT("\r\n"));
|
||
#else
|
||
text.Append(wxT("\n"));
|
||
#endif
|
||
row = list->GetNextSelected(row);
|
||
}
|
||
}
|
||
if (text.Length() > 0 && wxTheClipboard->Open())
|
||
{
|
||
wxTheClipboard->SetData(new wxTextDataObject(text));
|
||
wxTheClipboard->Close();
|
||
}
|
||
}
|
||
|
||
|
||
void frmStatus::OnCopyQuery(wxCommandEvent &ev)
|
||
{
|
||
ctlListView *list;
|
||
int row, col;
|
||
wxString text = wxT("");
|
||
wxString dbname = wxT("");
|
||
unsigned int maxlength;
|
||
|
||
// Only the status list shows the query
|
||
list = statusList;
|
||
|
||
// Get the database
|
||
row = list->GetFirstSelected();
|
||
if (row != -1) {
|
||
col = BackendMinimumVersion(9, 0) ? 2 : 1;
|
||
dbname.Append(list->GetText(row, col));
|
||
|
||
// Get the actual query
|
||
row = list->GetFirstSelected();
|
||
text.Append(queries.Item(row));
|
||
}
|
||
else return;
|
||
// Check if we have a query whose length is maximum
|
||
maxlength = -1024;
|
||
|
||
// If we have some real query, launch the query tool
|
||
if (text.Length() > 0 && dbname.Length() > 0
|
||
&& text.Trim() != wxT("<IDLE>") && text.Trim() != wxT("<IDLE in transaction>"))
|
||
{
|
||
pgConn *conn = new pgConn(connection->GetHostName(), connection->GetService(), connection->GetHostAddr(), dbname,
|
||
connection->GetUser(), connection->GetPassword(),
|
||
connection->GetPort(), connection->GetRole(),"", connection->GetSslMode(), connection->GetDbOid(),
|
||
connection->GetApplicationName(),
|
||
connection->GetSSLCert(), connection->GetSSLKey(), connection->GetSSLRootCert(), connection->GetSSLCrl(),
|
||
connection->GetSSLCompression());
|
||
if (conn)
|
||
{
|
||
frmQuery *fq = new frmQuery(mainForm, wxEmptyString, conn, text);
|
||
fq->Go();
|
||
mainForm->AddFrame(fq);
|
||
}
|
||
}
|
||
}
|
||
|
||
void frmStatus::OnPaneActivated(wxAuiManagerEvent& evt) {
|
||
wxTimerEvent event;
|
||
OnRefreshUITimer(event);
|
||
}
|
||
void frmStatus::OnPaneClose(wxAuiManagerEvent &evt)
|
||
{
|
||
if (evt.pane->name == wxT("Activity"))
|
||
{
|
||
viewMenu->Check(MNU_STATUSPAGE, false);
|
||
statusTimer->Stop();
|
||
}
|
||
if (evt.pane->name == wxT("Locks"))
|
||
{
|
||
viewMenu->Check(MNU_LOCKPAGE, false);
|
||
locksTimer->Stop();
|
||
}
|
||
if (evt.pane->name == wxT("Transactions"))
|
||
{
|
||
viewMenu->Check(MNU_XACTPAGE, false);
|
||
if (xactTimer)
|
||
xactTimer->Stop();
|
||
}
|
||
if (evt.pane->name == wxT("Logfile"))
|
||
{
|
||
viewMenu->Check(MNU_LOGPAGE, false);
|
||
|
||
if (logThread) logThread->BreakRead();
|
||
if (logTimer)
|
||
logTimer->Stop();
|
||
}
|
||
if (evt.pane->name == wxT("Querystate"))
|
||
{
|
||
viewMenu->Check(MNU_QUERYSTATEPAGE, false);
|
||
if (querystateTimer)
|
||
querystateTimer->Stop();
|
||
}
|
||
}
|
||
|
||
|
||
void frmStatus::OnToggleStatusPane(wxCommandEvent &event)
|
||
{
|
||
if (viewMenu->IsChecked(MNU_STATUSPAGE))
|
||
{
|
||
manager.GetPane(wxT("Activity")).Show(true);
|
||
cbRate->SetValue(rateToCboString(statusRate));
|
||
if (statusRate > 0)
|
||
statusTimer->Start(statusRate * 1000L);
|
||
}
|
||
else
|
||
{
|
||
manager.GetPane(wxT("Activity")).Show(false);
|
||
statusTimer->Stop();
|
||
}
|
||
|
||
// Tell the manager to "commit" all the changes just made
|
||
manager.Update();
|
||
}
|
||
|
||
|
||
void frmStatus::OnToggleLockPane(wxCommandEvent &event)
|
||
{
|
||
if (viewMenu->IsChecked(MNU_LOCKPAGE))
|
||
{
|
||
manager.GetPane(wxT("Locks")).Show(true);
|
||
cbRate->SetValue(rateToCboString(locksRate));
|
||
if (locksRate > 0)
|
||
locksTimer->Start(locksRate * 1000L);
|
||
}
|
||
else
|
||
{
|
||
manager.GetPane(wxT("Locks")).Show(false);
|
||
locksTimer->Stop();
|
||
}
|
||
|
||
// Tell the manager to "commit" all the changes just made
|
||
manager.Update();
|
||
}
|
||
|
||
|
||
void frmStatus::OnToggleXactPane(wxCommandEvent &event)
|
||
{
|
||
if (viewMenu->IsEnabled(MNU_XACTPAGE) && viewMenu->IsChecked(MNU_XACTPAGE))
|
||
{
|
||
manager.GetPane(wxT("Transactions")).Show(true);
|
||
cbRate->SetValue(rateToCboString(xactRate));
|
||
if (xactRate > 0 && xactTimer)
|
||
xactTimer->Start(xactRate * 1000L);
|
||
}
|
||
else
|
||
{
|
||
manager.GetPane(wxT("Transactions")).Show(false);
|
||
if (xactTimer)
|
||
xactTimer->Stop();
|
||
}
|
||
|
||
// Tell the manager to "commit" all the changes just made
|
||
manager.Update();
|
||
}
|
||
|
||
|
||
void frmStatus::OnToggleLogPane(wxCommandEvent &event)
|
||
{
|
||
if (viewMenu->IsEnabled(MNU_LOGPAGE) && viewMenu->IsChecked(MNU_LOGPAGE))
|
||
{
|
||
manager.GetPane(wxT("Logfile")).Show(true);
|
||
cbRate->SetValue(rateToCboString(logRate));
|
||
if (logRate > 0 && logTimer)
|
||
logTimer->Start(logRate * 1000L);
|
||
wxTimerEvent e;
|
||
OnRefreshLogTimer(e);
|
||
}
|
||
else
|
||
{
|
||
manager.GetPane(wxT("Logfile")).Show(false);
|
||
if (logThread) logThread->BreakRead();
|
||
if (logTimer)
|
||
logTimer->Stop();
|
||
}
|
||
|
||
// Tell the manager to "commit" all the changes just made
|
||
manager.Update();
|
||
}
|
||
void frmStatus::OnToggleWaitEnable(wxCommandEvent& event) {
|
||
|
||
}
|
||
void frmStatus::OnToggleQuerystatePane(wxCommandEvent &event)
|
||
{
|
||
if (viewMenu->IsEnabled(MNU_QUERYSTATEPAGE) && viewMenu->IsChecked(MNU_QUERYSTATEPAGE))
|
||
{
|
||
manager.GetPane(wxT("Querystate")).Show(true);
|
||
cbRate->SetValue(rateToCboString(querystateRate));
|
||
if (querystateRate > 0 && querystateTimer)
|
||
querystateTimer->Start(querystateRate * 1000L);
|
||
}
|
||
else
|
||
{
|
||
manager.GetPane(wxT("Querystate")).Show(false);
|
||
if (querystateTimer)
|
||
querystateTimer->Stop();
|
||
}
|
||
|
||
// Tell the manager to "commit" all the changes just made
|
||
manager.Update();
|
||
}
|
||
|
||
|
||
void frmStatus::OnToggleToolBar(wxCommandEvent &event)
|
||
{
|
||
if (viewMenu->IsChecked(MNU_TOOLBAR))
|
||
{
|
||
manager.GetPane(wxT("toolBar")).Show(true);
|
||
}
|
||
else
|
||
{
|
||
manager.GetPane(wxT("toolBar")).Show(false);
|
||
}
|
||
|
||
// Tell the manager to "commit" all the changes just made
|
||
manager.Update();
|
||
}
|
||
|
||
|
||
void frmStatus::OnDefaultView(wxCommandEvent &event)
|
||
{
|
||
manager.LoadPerspective(FRMSTATUS_DEFAULT_PERSPECTIVE, true);
|
||
|
||
// Reset the captions for the current language
|
||
manager.GetPane(wxT("toolBar")).Caption(_("Tool bar"));
|
||
manager.GetPane(wxT("Activity")).Caption(_("Activity"));
|
||
manager.GetPane(wxT("Locks")).Caption(_("Locks"));
|
||
manager.GetPane(wxT("Transactions")).Caption(_("Prepared Transactions"));
|
||
manager.GetPane(wxT("Logfile")).Caption(_("Logfile"));
|
||
manager.GetPane(wxT("Querystate")).Caption(_("Query State"));
|
||
|
||
// tell the manager to "commit" all the changes just made
|
||
manager.Update();
|
||
|
||
// Sync the View menu options
|
||
viewMenu->Check(MNU_TOOLBAR, manager.GetPane(wxT("toolBar")).IsShown());
|
||
viewMenu->Check(MNU_STATUSPAGE, manager.GetPane(wxT("Activity")).IsShown());
|
||
viewMenu->Check(MNU_LOCKPAGE, manager.GetPane(wxT("Locks")).IsShown());
|
||
viewMenu->Check(MNU_XACTPAGE, manager.GetPane(wxT("Transactions")).IsShown());
|
||
viewMenu->Check(MNU_LOGPAGE, manager.GetPane(wxT("Logfile")).IsShown());
|
||
viewMenu->Check(MNU_QUERYSTATEPAGE, manager.GetPane(wxT("Querystate")).IsShown());
|
||
}
|
||
|
||
|
||
void frmStatus::OnHighlightStatus(wxCommandEvent &event)
|
||
{
|
||
wxTimerEvent evt;
|
||
|
||
OnRefreshStatusTimer(evt);
|
||
}
|
||
void frmStatus::OnEmptyAction(wxCommandEvent &event)
|
||
{
|
||
}
|
||
|
||
|
||
void frmStatus::OnHelp(wxCommandEvent &ev)
|
||
{
|
||
DisplayHelp(wxT("status"), HELP_PGADMIN);
|
||
}
|
||
|
||
|
||
void frmStatus::OnContents(wxCommandEvent &ev)
|
||
{
|
||
DisplayHelp(wxT("index"), HELP_PGADMIN);
|
||
}
|
||
|
||
void frmStatus::OnRateChange(wxCommandEvent &event)
|
||
{
|
||
wxTimer *timer;
|
||
int rate;
|
||
|
||
switch(currentPane)
|
||
{
|
||
case PANE_STATUS:
|
||
timer = statusTimer;
|
||
rate = cboToRate();
|
||
statusRate = rate;
|
||
break;
|
||
case PANE_LOCKS:
|
||
timer = locksTimer;
|
||
rate = cboToRate();
|
||
locksRate = rate;
|
||
break;
|
||
case PANE_XACT:
|
||
timer = xactTimer;
|
||
rate = cboToRate();
|
||
xactRate = rate;
|
||
break;
|
||
case PANE_LOG:
|
||
timer = logTimer;
|
||
rate = cboToRate();
|
||
logRate = rate;
|
||
break;
|
||
case PANE_QUERYSTATE:
|
||
timer = querystateTimer;
|
||
rate = cboToRate();
|
||
querystateRate = rate;
|
||
break;
|
||
default:
|
||
// This shouldn't happen.
|
||
// If it does, it's no big deal, we just need to get out.
|
||
return;
|
||
break;
|
||
}
|
||
|
||
if (timer)
|
||
{
|
||
timer->Stop();
|
||
if (rate > 0)
|
||
timer->Start(rate * 1000L);
|
||
}
|
||
OnRefresh(event);
|
||
}
|
||
|
||
|
||
void frmStatus::OnRefreshUITimer(wxTimerEvent &event)
|
||
{
|
||
wxListEvent evt;
|
||
refreshUITimer->Stop();
|
||
if (frm_exit && !logisread) Destroy();
|
||
for (unsigned int i = 0; i < manager.GetAllPanes().GetCount(); i++)
|
||
{
|
||
wxAuiPaneInfo &pane = manager.GetAllPanes()[i];
|
||
|
||
if (pane.HasFlag(wxAuiPaneInfo::optionActive))
|
||
{
|
||
if (pane.name == wxT("Activity") && currentPane != PANE_STATUS)
|
||
{
|
||
OnSelStatusItem(evt);
|
||
}
|
||
if (pane.name == wxT("Locks") && currentPane != PANE_LOCKS)
|
||
{
|
||
OnSelLockItem(evt);
|
||
}
|
||
if (pane.name == wxT("Transactions") && currentPane != PANE_XACT)
|
||
{
|
||
OnSelXactItem(evt);
|
||
}
|
||
if (pane.name == wxT("Logfile") && currentPane != PANE_LOG)
|
||
{
|
||
OnSelLogItem(evt);
|
||
}
|
||
if (pane.name == wxT("Querystate") && currentPane != PANE_QUERYSTATE)
|
||
{
|
||
OnSelQuerystateItem(evt);
|
||
}
|
||
}
|
||
}
|
||
|
||
refreshUITimer->Start(250);
|
||
}
|
||
|
||
bool frmStatus::BackendMinimumVersion(int ma, int mi) {
|
||
return major > ma || (major == ma && minor >= mi);
|
||
}
|
||
void frmStatus::OnRefreshStatusTimer(wxTimerEvent &event)
|
||
{
|
||
int slot = 0;
|
||
wxString pidcol = BackendMinimumVersion(9, 2) ? wxT("p.pid") : wxT("p.procpid");
|
||
wxString querycol = BackendMinimumVersion(9, 2) ? wxT("query") : wxT("current_query");
|
||
|
||
if (! viewMenu->IsChecked(MNU_STATUSPAGE))
|
||
return;
|
||
|
||
checkConnection();
|
||
if (!connection)
|
||
{
|
||
statusTimer->Stop();
|
||
locksTimer->Stop();
|
||
if (xactTimer)
|
||
xactTimer->Stop();
|
||
if (logTimer)
|
||
logTimer->Stop();
|
||
if (querystateTimer)
|
||
querystateTimer->Stop();
|
||
return;
|
||
}
|
||
{
|
||
wxCriticalSectionLocker lock(gs_critsect);
|
||
if (array_exec[slot].conn!=NULL) {
|
||
wxString msg=_("Activity query long execute");
|
||
wxLongLong startTime = array_exec[slot].start;
|
||
if (array_exec[slot].start==0) {
|
||
statusBar->SetStatusText(wxString::Format("Activity connection busy."));
|
||
return;
|
||
}
|
||
wxString run_interval = ElapsedTimeToStr(
|
||
wxGetLocalTimeMillis() - startTime);
|
||
statusBar->SetStatusText(wxString::Format("%s %s",msg,run_interval));
|
||
return;
|
||
};
|
||
}
|
||
|
||
wxString q = wxT("SELECT ");
|
||
wait_enable = waitMenu->IsChecked(MNU_WAITENABLE);
|
||
// PID
|
||
q += pidcol + wxT(" AS pid, ");
|
||
|
||
// Application name (when available)
|
||
if (BackendMinimumVersion(8, 5))
|
||
q += wxT("application_name, ");
|
||
if (BackendMinimumVersion(14, 0))
|
||
q += wxT("query_id, ");
|
||
|
||
// Database, and user name
|
||
q += wxT("p.datname, usename,\n");
|
||
|
||
// Client connection method
|
||
if (BackendMinimumVersion(8, 1))
|
||
{
|
||
q += wxT("CASE WHEN client_port=-1 THEN 'local pipe' ");
|
||
if (BackendMinimumVersion(9, 1))
|
||
q += wxT("WHEN length(client_hostname)>0 THEN client_hostname||':'||client_port ");
|
||
q += wxT("ELSE textin(inet_out(client_addr))||':'||client_port END AS client,\n");
|
||
}
|
||
|
||
// Backend start timestamp
|
||
if (BackendMinimumVersion(8, 1))
|
||
q += wxT("date_trunc('second', backend_start) AS backend_start, ");
|
||
|
||
// Query start timestamp (when available)
|
||
if (BackendMinimumVersion(9, 2))
|
||
{
|
||
q += wxT("CASE WHEN state='active' THEN date_trunc('second', query_start)::text ELSE '' END ");
|
||
}
|
||
else if (BackendMinimumVersion(7, 4))
|
||
{
|
||
q += wxT("CASE WHEN ") + querycol + wxT("='' OR ") + querycol + wxT("='<IDLE>' THEN '' ")
|
||
wxT(" ELSE date_trunc('second', query_start)::text END ");
|
||
}
|
||
else
|
||
{
|
||
q += wxT("'' ");
|
||
}
|
||
q += wxT("AS query_start,\n");
|
||
|
||
// Transaction start timestamp
|
||
if (BackendMinimumVersion(8, 3))
|
||
q += wxT("xact_start AS xact_start_full,date_trunc('second', xact_start) AS xact_start, ");
|
||
|
||
// State
|
||
if (BackendMinimumVersion(9, 2))
|
||
q += wxT("state, date_trunc('second', state_change) AS state_change, ");
|
||
|
||
// Xmin and XID
|
||
if (BackendMinimumVersion(9, 4))
|
||
q += wxT("backend_xid::text, backend_xmin::text, ");
|
||
|
||
// Blocked by...
|
||
//q += wxT("(SELECT min(l1.pid) FROM pg_locks l1 WHERE GRANTED AND (")
|
||
// wxT("relation IN (SELECT relation FROM pg_locks l2 WHERE l2.pid=") + pidcol + wxT(" AND NOT granted)")
|
||
// wxT(" OR ")
|
||
// wxT("transactionid IN (SELECT transactionid FROM pg_locks l3 WHERE l3.pid=") + pidcol + wxT(" AND NOT granted)")
|
||
// wxT(")) AS blockedby,\n");
|
||
q += "pg_blocking_pids(p.pid) AS blockedby,\n";
|
||
// Query
|
||
q += querycol + wxT(" AS query,\n");
|
||
|
||
// Slow query?
|
||
if (BackendMinimumVersion(9, 2))
|
||
{
|
||
q += wxT("CASE WHEN query_start IS NULL OR state<>'active' THEN false ELSE query_start < now() - '10 seconds'::interval END ");
|
||
}
|
||
else if (BackendMinimumVersion(7, 4))
|
||
{
|
||
q += wxT("CASE WHEN query_start IS NULL OR ") + querycol + wxT(" LIKE '<IDLE>%' THEN false ELSE query_start < now() - '10 seconds'::interval END ");
|
||
}
|
||
else
|
||
{
|
||
q += wxT("false");
|
||
}
|
||
q += wxT("AS slowquery\n");
|
||
wxString progress13="(select format('%s %s',phase,pr) progress_info,pid from (\
|
||
select case phase\
|
||
when 'scanning heap' then\
|
||
Round(100 * heap_blks_scanned / greatest(heap_blks_total, 1), 1) || '%'\
|
||
else\
|
||
Round(100 * heap_blks_vacuumed / greatest(heap_blks_total, 1), 1) || '%'\
|
||
end pr\
|
||
, phase, pid from pg_stat_progress_vacuum\
|
||
union all\
|
||
select \
|
||
Round(100 * backup_streamed / greatest(backup_total, backup_streamed,1)) || '% (' || pg_size_pretty(backup_streamed) || ')'\
|
||
pr\
|
||
, phase, pid from pg_stat_progress_basebackup\
|
||
union all\
|
||
select case phase\
|
||
when 'writing new heap' then\
|
||
Round(100 * heap_tuples_written / greatest(heap_tuples_scanned, 1), 1) || '%'\
|
||
else\
|
||
pg_size_pretty(heap_tuples_scanned) || ' rows'\
|
||
end pr\
|
||
, phase, pid from pg_stat_progress_cluster\
|
||
union all\
|
||
select\
|
||
round(100 * sample_blks_scanned / greatest(sample_blks_total, 1), 2) || '%' pr\
|
||
, phase, pid from pg_stat_progress_analyze\
|
||
union all\
|
||
select Round(100 * blocks_done / greatest(blocks_total, 1), 1) || '%' pr\
|
||
, phase, pid from pg_stat_progress_create_index\
|
||
) v) v\
|
||
";
|
||
bool iswalsend = false;
|
||
if (BackendMinimumVersion(10, 0))
|
||
{
|
||
if (BackendMinimumVersion(13, 0))
|
||
{
|
||
q += wxT(",backend_type,wait_event_type,wait_event,v.progress_info,case when backend_type='autovacuum launcher' then (select min(xmin::text::bigint) from pg_replication_slots) end av_replica\n");
|
||
iswalsend = true;
|
||
if (wait_sample && wait_enable) {
|
||
q += ",transaction_timestamp() tt,hs.wait_sample,hs.maxts";
|
||
}
|
||
}
|
||
else
|
||
q += wxT(",backend_type,wait_event_type,wait_event,v.heap_blks_total,v.heap_blks_vacuumed,v.heap_blks_scanned,v.phase\n");
|
||
|
||
if (!track_commit_timestamp)
|
||
q += wxT(",coalesce(sl.xmin,sl.catalog_xmin)::text xmin_slot,':'||slot_name||'['||sl.slot_type||']' slotinfo,'LagSent:'||pg_size_pretty(pg_wal_lsn_diff(pg_last_wal_receive_lsn(),coalesce(confirmed_flush_lsn,restart_lsn)))||' LagXmin: -1'||' s' xminlag,-1 xminslotdelta\n");
|
||
else if (isrecovery)
|
||
q += wxT(",coalesce(sl.xmin,sl.catalog_xmin)::text xmin_slot,':'||slot_name||'['||sl.slot_type||']' slotinfo,'LagSent:'||pg_size_pretty(pg_wal_lsn_diff(pg_last_wal_receive_lsn(),coalesce(confirmed_flush_lsn,restart_lsn)))||' LagXmin: '||coalesce(extract(epoch from (pg_last_committed_xact()).timestamp - pg_xact_commit_timestamp(xmin))::int,0)||' s' xminlag,coalesce(extract(epoch from (pg_last_committed_xact()).timestamp - pg_xact_commit_timestamp(xmin))::int,0) xminslotdelta\n");
|
||
else
|
||
q += wxT(",coalesce(sl.xmin,sl.catalog_xmin)::text xmin_slot,':'||slot_name||'['||sl.slot_type||']' slotinfo,'LagSent:'||pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(),coalesce(confirmed_flush_lsn,restart_lsn)))||' LagXmin: '||coalesce(extract(epoch from (pg_last_committed_xact()).timestamp - pg_xact_commit_timestamp(xmin))::int,0)||' s' xminlag,coalesce(extract(epoch from (pg_last_committed_xact()).timestamp - pg_xact_commit_timestamp(xmin))::int,0) xminslotdelta\n");
|
||
if (BackendMinimumVersion(13, 0))
|
||
q += "FROM pg_stat_activity p LEFT JOIN "+progress13+" ON p.pid=v.pid\n";
|
||
else
|
||
q += wxT("FROM pg_stat_activity p LEFT JOIN pg_stat_progress_vacuum v ON p.pid=v.pid\n");
|
||
q += wxT("LEFT JOIN pg_replication_slots sl ON p.pid=sl.active_pid\n");
|
||
if (wait_sample && wait_enable)
|
||
{
|
||
q += " left join ( \
|
||
select pid, string_agg(format('%s:%s', coalesce(event_type,'CPU') || ':' || coalesce(event,'CPU')||':'||queryid, cnt), ';') wait_sample, max(maxts) maxts from( \
|
||
select pid,queryid, event_type, event, max(ts) maxts, count(*) cnt from pg_wait_sampling_history h \
|
||
where h.event not in('ArchiverMain', 'WalWriterMain', 'CheckpointerMain', 'Extension', 'LogicalLauncherMain', 'CfsGcEnable', 'WalSenderMain' \
|
||
, 'AutoVacuumMain', '-ClientRead', 'CheckpointWriteDelay', 'BgWriterMain', 'BgWriterHibernate') \
|
||
or h.event is null\
|
||
";
|
||
|
||
if (!first_tt.IsEmpty()) q += "and h.ts > '"+first_tt+"'";
|
||
|
||
q+="group by pid, event_type, event,queryid \
|
||
) l group by pid) hs on p.pid = hs.pid\n";
|
||
}
|
||
|
||
//backend_type
|
||
} else
|
||
{
|
||
q += wxT("FROM pg_stat_activity p ");
|
||
}
|
||
|
||
// And the rest of the query...
|
||
|
||
q += wxT(" ORDER BY ") + NumToStr((long)statusSortColumn) + wxT(" ") + statusSortOrder;
|
||
SendQueryExecute(0,q,connection);
|
||
if (onlyhightligth) statusList->Enable(false);
|
||
}
|
||
void frmStatus::OnRefreshStatusTimer_After()
|
||
{
|
||
long row=0;
|
||
long pid=0;
|
||
bool iswalsend = false;
|
||
int slot=0;
|
||
pgSet *dataSet1 = NULL;
|
||
long long endtime;
|
||
long long starttime;
|
||
wxString msgerror;
|
||
if (BackendMinimumVersion(13, 0)) iswalsend = true;
|
||
|
||
{
|
||
wxCriticalSectionLocker lock(gs_critsect);
|
||
dataSet1=array_exec[slot].result;
|
||
endtime=array_exec[slot].end;
|
||
starttime=array_exec[slot].start;
|
||
if (array_exec[slot].isError) msgerror="Error query activity";
|
||
|
||
}
|
||
wxLongLong startTime = wxGetLocalTimeMillis();
|
||
|
||
statusList->Freeze();
|
||
//pgSet *dataSet1 = connection->ExecuteSet(q,false);
|
||
//statusList->SetEvtHandlerEnabled(false);
|
||
//pgSet *dataSet1 = connection->ExecuteSetAndNoBlock(q,false,wxGetTopLevelParent(this));
|
||
|
||
if (dataSet1)
|
||
{
|
||
//msgerror = connection->GetLastError();
|
||
statusBar->SetStatusText(_("Refreshing status list."));
|
||
|
||
|
||
// Clear the queries array content
|
||
queries.Clear();
|
||
wxString blocked=wxT("");
|
||
int countsenders=0;
|
||
long pidAV=-1;
|
||
wxArrayLong pids;
|
||
wxDateTime tt;
|
||
while (!dataSet1->Eof())
|
||
{
|
||
pid = dataSet1->GetLong(wxT("pid"));
|
||
wxString slinfo=wxEmptyString;
|
||
wxString backend_xid;
|
||
wxDateTime start_transaction;
|
||
wxTimeSpan deltaidle;
|
||
if (iswalsend) {
|
||
slinfo = dataSet1->GetVal(wxT("slotinfo"));
|
||
}
|
||
if (!tt.IsValid()&&wait_sample && wait_enable) {
|
||
tt = dataSet1->GetDateTime("tt");
|
||
WS.BeginSeriosSample(tt.GetValue().GetValue());
|
||
first_tt = dataSet1->GetVal("tt");
|
||
|
||
}
|
||
// Update the UI
|
||
if (pid != backend_pid)
|
||
{
|
||
|
||
if (row >= statusList->GetItemCount())
|
||
{
|
||
statusList->InsertItem(row, NumToStr(pid), -1);
|
||
row = statusList->GetItemCount() - 1;
|
||
}
|
||
else
|
||
{
|
||
statusList->SetItem(row, 0, NumToStr(pid),-1);
|
||
}
|
||
|
||
wxString qry = dataSet1->GetVal(wxT("query"));
|
||
wxString app_name = dataSet1->GetVal(wxT("application_name"));
|
||
wxString backend_type;
|
||
if (BackendMinimumVersion(13, 0)) {
|
||
backend_type = dataSet1->GetVal(wxT("backend_type"));
|
||
if (app_name.IsEmpty() && backend_type != "client backend") app_name = backend_type;
|
||
}
|
||
if (BackendMinimumVersion(9, 6))
|
||
{
|
||
if (BackendMinimumVersion(13, 0)) {
|
||
wxString progress_info = dataSet1->GetVal(wxT("progress_info"));
|
||
if (!progress_info.IsEmpty()) app_name = progress_info;
|
||
} else
|
||
{
|
||
wxString heap_blks_total = dataSet1->GetVal(wxT("heap_blks_total"));
|
||
if (!heap_blks_total.IsEmpty()) {
|
||
wxString heap_blks_vacuumed = dataSet1->GetVal(wxT("heap_blks_vacuumed"));
|
||
wxString heap_blks_scanned = dataSet1->GetVal(wxT("heap_blks_scanned"));
|
||
wxString phase = dataSet1->GetVal(wxT("phase"));
|
||
double total;
|
||
double vac = 0;
|
||
double proc;
|
||
heap_blks_vacuumed.ToDouble(&vac);
|
||
if (!phase.CmpNoCase(wxT("scanning heap"))) {
|
||
heap_blks_scanned.ToDouble(&vac);
|
||
}
|
||
heap_blks_total.ToDouble(&total);
|
||
proc = vac * 100 / total;
|
||
wxString str;
|
||
str.Printf(wxT("%s %5.2f%%"), phase, proc);
|
||
app_name = str;
|
||
}
|
||
}
|
||
if (!slinfo.IsEmpty()) app_name += slinfo;
|
||
}
|
||
int colpos = 1;
|
||
if (BackendMinimumVersion(8, 5))
|
||
statusList->SetItem(row, colpos++, app_name);
|
||
statusList->SetItem(row, colpos++, dataSet1->GetVal(wxT("datname")));
|
||
statusList->SetItem(row, colpos++, dataSet1->GetVal(wxT("usename")));
|
||
|
||
if (BackendMinimumVersion(8, 1))
|
||
{
|
||
statusList->SetItem(row, colpos++, dataSet1->GetVal(wxT("client")));
|
||
statusList->SetItem(row, colpos++, dataSet1->GetVal(wxT("backend_start")));
|
||
}
|
||
if (BackendMinimumVersion(7, 4))
|
||
{
|
||
statusList->SetItem(row, colpos++, dataSet1->GetVal(wxT("query_start")));
|
||
}
|
||
|
||
if (BackendMinimumVersion(8, 3)) {
|
||
start_transaction= dataSet1->GetDateTime("xact_start_full");
|
||
statusList->SetItem(row, colpos++, dataSet1->GetVal(wxT("xact_start")));
|
||
if (start_transaction.IsValid()) {
|
||
deltaidle = wxDateTime::Now() - start_transaction;
|
||
}
|
||
}
|
||
|
||
if (BackendMinimumVersion(9, 2))
|
||
{
|
||
statusList->SetItem(row, colpos++, dataSet1->GetVal(wxT("state")));
|
||
statusList->SetItem(row, colpos++, dataSet1->GetVal(wxT("state_change")));
|
||
}
|
||
|
||
if (BackendMinimumVersion(9, 4))
|
||
{
|
||
backend_xid= dataSet1->GetVal(wxT("backend_xid"));
|
||
statusList->SetItem(row, colpos++, backend_xid);
|
||
if (!slinfo.IsEmpty()) {
|
||
statusList->SetItem(row, colpos++, dataSet1->GetVal(wxT("xmin_slot")));
|
||
countsenders++;
|
||
}
|
||
else
|
||
{
|
||
wxString av_replica;
|
||
if (iswalsend) av_replica= dataSet1->GetVal(wxT("av_replica"));
|
||
if (av_replica.IsEmpty())
|
||
statusList->SetItem(row, colpos++, dataSet1->GetVal(wxT("backend_xmin")));
|
||
else {
|
||
statusList->SetItem(row, colpos++, av_replica);
|
||
pidAV=pid;
|
||
}
|
||
|
||
}
|
||
}
|
||
if (BackendMinimumVersion(9, 6))
|
||
{
|
||
wait_event_type_col=colpos;
|
||
statusList->SetItem(row, colpos++, dataSet1->GetVal(wxT("wait_event_type")));
|
||
statusList->SetItem(row, colpos++, dataSet1->GetVal(wxT("wait_event")));
|
||
}
|
||
wxString blockedby = dataSet1->GetVal(wxT("blockedby"));
|
||
blockedby=blockedby.substr(1, blockedby.Length() - 2);
|
||
if (wait_sample && wait_enable) {
|
||
bool isClientReadTransaction = false;
|
||
//if ( spt.count>1 && ll!=0) isClientReadTransaction = true;
|
||
if (start_transaction.IsValid()
|
||
&& start_transaction < tt
|
||
&& !backend_xid.IsEmpty()
|
||
)isClientReadTransaction = true;
|
||
|
||
WS.AddSample(pid, isClientReadTransaction, backend_type, dataSet1->GetVal("wait_sample"));
|
||
//wxULongLong qid = dataSet1->GetLongLong("query_id");
|
||
//WS.AddQuery(qid.GetValue(), qry);
|
||
}
|
||
statusList->SetItem(row, colpos++, blockedby);
|
||
if (!slinfo.IsEmpty()) {
|
||
statusList->SetItem(row, colpos, dataSet1->GetVal(wxT("xminlag")));
|
||
}
|
||
else
|
||
statusList->SetItem(row, colpos, qry);
|
||
|
||
// Colorize the new line
|
||
if (viewMenu->IsChecked(MNU_HIGHLIGHTSTATUS))
|
||
{
|
||
statusList->SetItemBackgroundColour(row,
|
||
wxColour(settings->GetActiveProcessColour()));
|
||
if (qry == wxT("<IDLE>") || qry == wxT("<IDLE> in transaction0"))
|
||
statusList->SetItemBackgroundColour(row,
|
||
wxColour(settings->GetIdleProcessColour()));
|
||
if (BackendMinimumVersion(9, 2))
|
||
{
|
||
if (dataSet1->GetVal(wxT("state")) != wxT("active"))
|
||
statusList->SetItemBackgroundColour(row,
|
||
wxColour(settings->GetIdleProcessColour()));
|
||
}
|
||
|
||
if (dataSet1->GetBool(wxT("slowquery")))
|
||
statusList->SetItemBackgroundColour(row,
|
||
wxColour(settings->GetSlowProcessColour()));
|
||
if (blockedby.Length() > 0) {
|
||
statusList->SetItemBackgroundColour(row,
|
||
wxColour(settings->GetBlockedProcessColour()));
|
||
blocked += blockedby;
|
||
blocked += wxT(",");
|
||
}
|
||
else if (deltaidle.GetSeconds() > idle_in_transaction_session_timeout) {
|
||
statusList->SetItemBackgroundColour(row,
|
||
wxColour(settings->GetIdle_in_transaction_session_timeoutProcessColour()));
|
||
|
||
}
|
||
if (!slinfo.IsEmpty()) {
|
||
// walsender
|
||
long xmindelta = dataSet1->GetLong(wxT("xminslotdelta"));
|
||
|
||
if (xmindelta>=1800)
|
||
statusList->SetItemBackgroundColour(row,wxColour(wxT("#FF8028"))); // orange
|
||
else
|
||
statusList->SetItemBackgroundColour(row, wxColour(settings->GetIdleProcessColour())); // idle
|
||
}
|
||
if (app_name.StartsWith(wxT("pgp-s super"))||app_name.StartsWith(wxT("pgp-s manager"))) statusList->SetItemBackgroundColour(row, wxColour(settings->GetIdleProcessColour())); // idle
|
||
|
||
}
|
||
else
|
||
statusList->SetItemBackgroundColour(row, *wxWHITE);
|
||
|
||
// filter apply
|
||
bool flt = false;
|
||
for (int i = 0; i < filterColumn.size(); i++) {
|
||
int col = filterColumn[i];
|
||
wxListItem listitem;
|
||
listitem.SetMask(wxLIST_MASK_TEXT);
|
||
statusList->GetColumn(col, listitem);
|
||
wxString label = listitem.GetText();
|
||
wxString tabval=statusList->GetItemText(row, col);
|
||
wxString fval = filterValue[i];
|
||
if (label == _("Client")) {
|
||
tabval = tabval.BeforeLast(':');
|
||
fval = fval.BeforeLast(':');
|
||
}
|
||
if (tabval != fval) {
|
||
flt = true;
|
||
break;
|
||
}
|
||
}
|
||
if (!flt) {
|
||
// Add the query content to the queries array
|
||
queries.Add(qry);
|
||
pids.Add(pid);
|
||
if (pid == s_pid_HIGHLIGH) {
|
||
statusList->SetItemBackgroundColour(row, wxColour(wxT("#FF8028")));
|
||
statusList->EnsureVisible(row);
|
||
}
|
||
|
||
row++;
|
||
}
|
||
}
|
||
dataSet1->MoveNext();
|
||
}
|
||
delete dataSet1;
|
||
if (viewMenu->IsChecked(MNU_HIGHLIGHTSTATUS))
|
||
{
|
||
if (countsenders == 0 && pidAV>0) {
|
||
// all walsender active='f'
|
||
for(long i = 0; i < pids.size(); i++)
|
||
{
|
||
if (pids[i]==pidAV)
|
||
statusList->SetItemBackgroundColour(i,
|
||
wxColour(settings->GetBlockedProcessColour()));
|
||
}
|
||
}
|
||
|
||
// who blocking
|
||
wxString numstr;
|
||
wxString str;
|
||
numstr=blocked.BeforeFirst(',',&str);
|
||
while (!numstr.IsEmpty()) {
|
||
int number = wxAtoi(numstr);
|
||
for(long i = 0; i < pids.size(); i++)
|
||
{
|
||
if (pids[i]==number) {
|
||
statusList->SetItemBackgroundColour(i,
|
||
wxColour(settings->GetBlockedbyProcessColour()));
|
||
|
||
}
|
||
}
|
||
blocked=str.Clone();
|
||
numstr=blocked.BeforeFirst(',',&str);
|
||
}
|
||
if (onlyhightligth) {
|
||
wxArrayString newquerys;
|
||
long r = statusList->GetItemCount();
|
||
//wxColour bg = *WHITE;
|
||
wxColour bgidle=wxColour(settings->GetIdleProcessColour());
|
||
long rr = 0;
|
||
int nquery = 0;
|
||
//long selrow = -1;
|
||
//selrow = statusList->GetFirstSelected();
|
||
|
||
while ((rr) < statusList->GetItemCount() && rr<row)
|
||
{
|
||
if (statusList->GetItemBackgroundColour(rr) != bgidle) {
|
||
newquerys.Add(queries[nquery]);
|
||
rr++;
|
||
}
|
||
else {
|
||
if (row==-11) {
|
||
for(int cc=0;cc<statusList->GetColumnCount();cc++)
|
||
statusList->SetItem(row, cc, " ");
|
||
|
||
} else {
|
||
statusList->DeleteItem(rr);
|
||
row--;
|
||
}
|
||
}
|
||
nquery++;
|
||
}
|
||
if (newquerys.Count() < queries.Count()) queries = newquerys;
|
||
} else if (!statusList->IsEnabled()) statusList->Enable(true);
|
||
|
||
}
|
||
if (tt.IsValid() && wait_sample && wait_enable) {
|
||
WS.EndSeriosSample();
|
||
}
|
||
bool selverify=true;
|
||
long r = statusList->GetItemCount();
|
||
long fuck_rows=0;
|
||
while ((row) < statusList->GetItemCount()) {
|
||
statusList->Select(row,false);
|
||
long item = -1;
|
||
item = statusList->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
|
||
if (item>=row && row>0) statusList->Focus(row-1);
|
||
if (statusList->GetItemCount()>row)
|
||
{
|
||
#ifdef __WXGTK__
|
||
//DeleteItem in GTK flicker problem
|
||
|
||
if (row+1 == r && filterColumn.size()>0) {
|
||
for(int cc=0;cc<statusList->GetColumnCount();cc++)
|
||
statusList->SetItem(row, cc, " ");
|
||
fuck_rows=1;
|
||
break;
|
||
} else statusList->DeleteItem(row);
|
||
#else
|
||
statusList->DeleteItem(row);
|
||
#endif
|
||
}
|
||
}
|
||
r = statusList->GetItemCount()-fuck_rows;
|
||
wxString tit = _("Activity") + "(" + NumToStr(r) + ")";
|
||
wxString old = manager.GetPane(wxT("Activity")).caption;
|
||
if (tit != old) {
|
||
manager.GetPane(wxT("Activity")).Caption(tit);
|
||
manager.Update();
|
||
}
|
||
|
||
if (wait_sample && wait_enable && top_small) top_small->Refresh();
|
||
|
||
wxListEvent ev;
|
||
//OnSelStatusItem(ev);
|
||
wxLongLong delta=wxGetLocalTimeMillis()-startTime;
|
||
delta=delta+(endtime-starttime);
|
||
wxString run_interval = ElapsedTimeToStr(delta);
|
||
//run_interval += wxString::Format(" %lld", (endtime-starttime));
|
||
|
||
statusBar->SetStatusText(wxString::Format("%s Activity:%s", _("Done."),run_interval));
|
||
|
||
if (msgerror.length() > 0) {
|
||
statusBar->SetStatusText(msgerror);
|
||
}
|
||
else
|
||
{
|
||
statusBar->SetStatusText(wxString::Format("%s Activity:%s", _("Done."),run_interval));
|
||
}
|
||
{
|
||
wxCriticalSectionLocker lock(gs_critsect);
|
||
array_exec[slot]={};
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
{
|
||
wxCriticalSectionLocker lock(gs_critsect);
|
||
array_exec[slot]={};
|
||
}
|
||
checkConnection();
|
||
}
|
||
//statusList->SetEvtHandlerEnabled(true);
|
||
statusList->Thaw();
|
||
//statusList->Refresh(false);
|
||
|
||
}
|
||
//// return true = Ok - Add query
|
||
//// return false = fail - conn busy
|
||
bool frmStatus::SendQueryExecute(int index,wxString &sql,pgConn *c) {
|
||
|
||
{
|
||
wxCriticalSectionLocker lock(gs_critsect);
|
||
SQL_exec sq=array_exec[index];
|
||
if (sq.conn==NULL) {
|
||
// is ready
|
||
sq.conn=c;
|
||
sq.query=sql;
|
||
array_exec[index]=sq;
|
||
} else return false; //is_busy
|
||
queue_sql.Post(index);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
void * ExecuteThread::Entry() {
|
||
while (!TestDestroy())
|
||
{
|
||
int index=-1;
|
||
if (q->Receive(index)==wxMSGQUEUE_NO_ERROR) {
|
||
if (index==-1) break;
|
||
SQL_exec sq;
|
||
SQL_exec *ppp;
|
||
{
|
||
wxCriticalSectionLocker lock(gs_critsect);
|
||
ppp=arr_point+index;
|
||
sq.conn=ppp->conn;
|
||
sq.query=ppp->query;
|
||
ppp->isExecute=true;
|
||
ppp->start=wxGetLocalTimeMillis().GetValue();
|
||
}
|
||
pgSet *dataSet1 = NULL;
|
||
{
|
||
wxCriticalSectionLocker lock(thread_execute);
|
||
dataSet1 = sq.conn->ExecuteSet(sq.query,false);
|
||
if (TestDestroy()) {
|
||
if (dataSet1) delete dataSet1;
|
||
dataSet1 = NULL;
|
||
}
|
||
}
|
||
|
||
{
|
||
wxCriticalSectionLocker lock(gs_critsect);
|
||
ppp->end=wxGetLocalTimeMillis().GetValue();
|
||
ppp->result=dataSet1;
|
||
ppp->isExecute=false;
|
||
if (!dataSet1) ppp->isError=true;
|
||
}
|
||
wxThreadEvent event( wxEVT_THREAD );
|
||
event.SetString("@@");
|
||
event.SetInt( index );
|
||
//theParent->GetEventHandler()->AddPendingEvent(event);
|
||
wxQueueEvent( theParent, event.Clone() );
|
||
|
||
} else break;
|
||
//wxQueueEvent( theParent, event.Clone() );
|
||
//wxThread::Sleep(100);
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
void frmStatus::OnRefreshLocksTimer(wxTimerEvent &event)
|
||
{
|
||
long pid = 0;
|
||
|
||
if (! viewMenu->IsChecked(MNU_LOCKPAGE))
|
||
return;
|
||
wxCriticalSectionLocker lock(thread_execute);
|
||
checkConnection();
|
||
if (!locks_connection)
|
||
{
|
||
statusTimer->Stop();
|
||
locksTimer->Stop();
|
||
if (xactTimer)
|
||
xactTimer->Stop();
|
||
if (logTimer)
|
||
logTimer->Stop();
|
||
if (querystateTimer)
|
||
querystateTimer->Stop();
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
// There are no sort operator for xid before 8.3
|
||
if (!connection->BackendMinimumVersion(8, 3) && lockSortColumn == 5)
|
||
{
|
||
wxLogError(_("You cannot sort by transaction id on your PostgreSQL release. You need at least 8.3."));
|
||
lockSortColumn = 1;
|
||
}
|
||
|
||
long row = 0;
|
||
wxString sql;
|
||
if (locks_connection->BackendMinimumVersion(8, 3))
|
||
{
|
||
sql = wxT("SELECT pg_stat_get_backend_pid(svrid) AS pid, ")
|
||
wxT("(SELECT datname FROM pg_database WHERE oid = pgl.database) AS dbname, ")
|
||
wxT("coalesce(pgc.relname, pgl.relation::text) AS class, ")
|
||
wxT("pg_get_userbyid(pg_stat_get_backend_userid(svrid)) as user, ")
|
||
wxT("pgl.virtualxid::text, pgl.virtualtransaction::text AS transaction, pgl.mode, pgl.granted, ")
|
||
wxT("date_trunc('second', pg_stat_get_backend_activity_start(svrid)) AS query_start, ")
|
||
wxT("pg_stat_get_backend_activity(svrid) AS query ")
|
||
wxT("FROM pg_stat_get_backend_idset() svrid, pg_locks pgl ")
|
||
wxT("LEFT JOIN pg_class pgc ON pgl.relation=pgc.oid ")
|
||
wxT("WHERE pgl.pid = pg_stat_get_backend_pid(svrid) ")
|
||
wxT("ORDER BY ") + NumToStr((long)lockSortColumn) + wxT(" ") + lockSortOrder;
|
||
}
|
||
else if (locks_connection->BackendMinimumVersion(7, 4))
|
||
{
|
||
sql = wxT("SELECT pg_stat_get_backend_pid(svrid) AS pid, ")
|
||
wxT("(SELECT datname FROM pg_database WHERE oid = pgl.database) AS dbname, ")
|
||
wxT("coalesce(pgc.relname, pgl.relation::text) AS class, ")
|
||
wxT("pg_get_userbyid(pg_stat_get_backend_userid(svrid)) as user, ")
|
||
wxT("pgl.transaction, pgl.mode, pgl.granted, ")
|
||
wxT("date_trunc('second', pg_stat_get_backend_activity_start(svrid)) AS query_start, ")
|
||
wxT("pg_stat_get_backend_activity(svrid) AS query ")
|
||
wxT("FROM pg_stat_get_backend_idset() svrid, pg_locks pgl ")
|
||
wxT("LEFT JOIN pg_class pgc ON pgl.relation=pgc.oid ")
|
||
wxT("WHERE pgl.pid = pg_stat_get_backend_pid(svrid) ")
|
||
wxT("ORDER BY ") + NumToStr((long)lockSortColumn) + wxT(" ") + lockSortOrder;
|
||
}
|
||
else
|
||
{
|
||
sql = wxT("SELECT pg_stat_get_backend_pid(svrid) AS pid, ")
|
||
wxT("(SELECT datname FROM pg_database WHERE oid = pgl.database) AS dbname, ")
|
||
wxT("coalesce(pgc.relname, pgl.relation::text) AS class, ")
|
||
wxT("pg_get_userbyid(pg_stat_get_backend_userid(svrid)) as user, ")
|
||
wxT("pgl.transaction, pgl.mode, pgl.granted, ")
|
||
wxT("pg_stat_get_backend_activity(svrid) AS query ")
|
||
wxT("FROM pg_stat_get_backend_idset() svrid, pg_locks pgl ")
|
||
wxT("LEFT JOIN pg_class pgc ON pgl.relation=pgc.oid ")
|
||
wxT("WHERE pgl.pid = pg_stat_get_backend_pid(svrid) ")
|
||
wxT("ORDER BY ") + NumToStr((long)lockSortColumn) + wxT(" ") + lockSortOrder;
|
||
}
|
||
|
||
pgSet *dataSet2 = locks_connection->ExecuteSet(sql);
|
||
if (dataSet2)
|
||
{
|
||
statusBar->SetStatusText(_("Refreshing locks list."));
|
||
lockList->Freeze();
|
||
|
||
while (!dataSet2->Eof())
|
||
{
|
||
pid = dataSet2->GetLong(wxT("pid"));
|
||
|
||
if (pid != backend_pid)
|
||
{
|
||
if (row >= lockList->GetItemCount())
|
||
{
|
||
lockList->InsertItem(row, NumToStr(pid), -1);
|
||
row = lockList->GetItemCount() - 1;
|
||
}
|
||
else
|
||
{
|
||
lockList->SetItem(row, 0, NumToStr(pid));
|
||
}
|
||
|
||
int colpos = 1;
|
||
lockList->SetItem(row, colpos++, dataSet2->GetVal(wxT("dbname")));
|
||
lockList->SetItem(row, colpos++, dataSet2->GetVal(wxT("class")));
|
||
lockList->SetItem(row, colpos++, dataSet2->GetVal(wxT("user")));
|
||
if (locks_connection->BackendMinimumVersion(8, 3))
|
||
lockList->SetItem(row, colpos++, dataSet2->GetVal(wxT("virtualxid")));
|
||
lockList->SetItem(row, colpos++, dataSet2->GetVal(wxT("transaction")));
|
||
lockList->SetItem(row, colpos++, dataSet2->GetVal(wxT("mode")));
|
||
|
||
if (dataSet2->GetVal(wxT("granted")) == wxT("t"))
|
||
{
|
||
lockList->SetItem(row, colpos++, _("Yes"));
|
||
lockList->SetItemBackgroundColour(row,lockList->GetBackgroundColour());
|
||
}
|
||
else {
|
||
lockList->SetItem(row, colpos++, _("No"));
|
||
lockList->SetItemBackgroundColour(row, wxColour(settings->GetBlockedProcessColour()));
|
||
|
||
}
|
||
|
||
wxString qry = dataSet2->GetVal(wxT("query"));
|
||
|
||
if (locks_connection->BackendMinimumVersion(7, 4))
|
||
{
|
||
if (qry.IsEmpty() || qry == wxT("<IDLE>"))
|
||
lockList->SetItem(row, colpos++, wxEmptyString);
|
||
else
|
||
lockList->SetItem(row, colpos++, dataSet2->GetVal(wxT("query_start")));
|
||
}
|
||
lockList->SetItem(row, colpos++, qry.Left(250));
|
||
|
||
row++;
|
||
}
|
||
dataSet2->MoveNext();
|
||
}
|
||
|
||
delete dataSet2;
|
||
|
||
while (row < lockList->GetItemCount())
|
||
lockList->DeleteItem(row);
|
||
|
||
lockList->Thaw();
|
||
wxListEvent ev;
|
||
//OnSelLockItem(ev);
|
||
statusBar->SetStatusText(_("Done."));
|
||
}
|
||
else
|
||
checkConnection();
|
||
}
|
||
|
||
|
||
void frmStatus::OnRefreshXactTimer(wxTimerEvent &event)
|
||
{
|
||
if (! viewMenu->IsEnabled(MNU_XACTPAGE) || ! viewMenu->IsChecked(MNU_XACTPAGE) || !xactTimer)
|
||
return;
|
||
wxCriticalSectionLocker lock(thread_execute);
|
||
checkConnection();
|
||
if (!connection)
|
||
{
|
||
statusTimer->Stop();
|
||
locksTimer->Stop();
|
||
xactTimer->Stop();
|
||
querystateTimer->Stop();
|
||
if (logTimer)
|
||
logTimer->Stop();
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
// There are no sort operator for xid before 8.3
|
||
if (!connection->BackendMinimumVersion(8, 3) && xactSortColumn == 1)
|
||
{
|
||
wxLogError(_("You cannot sort by transaction id on your PostgreSQL release. You need at least 8.3."));
|
||
xactSortColumn = 2;
|
||
}
|
||
|
||
long row = 0;
|
||
wxString sql;
|
||
if (connection->BackendMinimumVersion(8, 3))
|
||
sql = wxT("SELECT transaction::text, gid, prepared, owner, database ")
|
||
wxT("FROM pg_prepared_xacts ")
|
||
wxT("ORDER BY ") + NumToStr((long)xactSortColumn) + wxT(" ") + xactSortOrder;
|
||
else
|
||
sql = wxT("SELECT transaction, gid, prepared, owner, database ")
|
||
wxT("FROM pg_prepared_xacts ")
|
||
wxT("ORDER BY ") + NumToStr((long)xactSortColumn) + wxT(" ") + xactSortOrder;
|
||
|
||
pgSet *dataSet3 = connection->ExecuteSet(sql);
|
||
if (dataSet3)
|
||
{
|
||
statusBar->SetStatusText(_("Refreshing transactions list."));
|
||
xactList->Freeze();
|
||
|
||
while (!dataSet3->Eof())
|
||
{
|
||
long xid = dataSet3->GetLong(wxT("transaction"));
|
||
|
||
if (row >= xactList->GetItemCount())
|
||
{
|
||
xactList->InsertItem(row, NumToStr(xid), -1);
|
||
row = xactList->GetItemCount() - 1;
|
||
}
|
||
else
|
||
{
|
||
xactList->SetItem(row, 0, NumToStr(xid));
|
||
}
|
||
|
||
int colpos = 1;
|
||
xactList->SetItem(row, colpos++, dataSet3->GetVal(wxT("gid")));
|
||
xactList->SetItem(row, colpos++, dataSet3->GetVal(wxT("prepared")));
|
||
xactList->SetItem(row, colpos++, dataSet3->GetVal(wxT("owner")));
|
||
xactList->SetItem(row, colpos++, dataSet3->GetVal(wxT("database")));
|
||
|
||
row++;
|
||
dataSet3->MoveNext();
|
||
}
|
||
delete dataSet3;
|
||
|
||
while (row < xactList->GetItemCount())
|
||
xactList->DeleteItem(row);
|
||
|
||
xactList->Thaw();
|
||
wxListEvent ev;
|
||
//OnSelXactItem(ev);
|
||
statusBar->SetStatusText(_("Done."));
|
||
}
|
||
else
|
||
checkConnection();
|
||
}
|
||
long frmStatus::getlongvalue(wxString source,wxString match_str) {
|
||
long aa=0;
|
||
wxRegEx foundstr(match_str);
|
||
if (foundstr.Matches(source)) {
|
||
wxString v=foundstr.GetMatch(source,1);
|
||
v.ToLong(&aa);
|
||
}
|
||
return aa;
|
||
}
|
||
|
||
|
||
void frmStatus::OnRefreshQuerystateTimer(wxTimerEvent &event)
|
||
{
|
||
if (! viewMenu->IsEnabled(MNU_QUERYSTATEPAGE) || ! viewMenu->IsChecked(MNU_QUERYSTATEPAGE) || !querystateTimer)
|
||
return;
|
||
|
||
checkConnection();
|
||
if (!connection)
|
||
{
|
||
statusTimer->Stop();
|
||
locksTimer->Stop();
|
||
xactTimer->Stop();
|
||
if (querystateTimer)
|
||
querystateTimer->Stop();
|
||
if (logTimer)
|
||
logTimer->Stop();
|
||
return;
|
||
}
|
||
int row = statusList->GetFirstSelected();
|
||
if (row<0)
|
||
return;
|
||
wxString pid=statusList->GetText(row, 0);
|
||
wxString dbname=statusList->GetText(row, 2); // dbname
|
||
wxString wait_event_type= statusList->GetText(row, wait_event_type_col);
|
||
if (dbname.IsEmpty()||wait_event_type==wxT("Extension")) return;
|
||
|
||
wxString flags=wxT("");
|
||
if (viewMenu->IsChecked(MNU_QUERYSTATEVERBOSE))
|
||
flags += wxT(",true,false");
|
||
else
|
||
flags += wxT(",false,false");
|
||
if (viewMenu->IsChecked(MNU_QUERYSTATETIME))
|
||
flags += wxT(",true");
|
||
else
|
||
flags += wxT(",false");
|
||
if (viewMenu->IsChecked(MNU_QUERYSTATEBUFFER))
|
||
flags += wxT(",true");
|
||
else
|
||
flags += wxT(",false");
|
||
if (viewMenu->IsChecked(MNU_QUERYSTATETRIGGER))
|
||
flags += wxT(",true");
|
||
else
|
||
flags += wxT(",false");
|
||
|
||
flags += wxT(",'text'::text");
|
||
int slot=1;
|
||
{
|
||
wxCriticalSectionLocker lock(gs_critsect);
|
||
if (array_exec[slot].conn!=NULL) {
|
||
wxString msg=_("Query state status long execute");
|
||
wxLongLong startTime = array_exec[slot].start;
|
||
if (array_exec[slot].start==0) {
|
||
statusBar->SetStatusText(wxString::Format("connection busy."));
|
||
return;
|
||
}
|
||
wxString run_interval = ElapsedTimeToStr(
|
||
wxGetLocalTimeMillis() - startTime);
|
||
statusBar->SetStatusText(wxString::Format("%s %s",msg,run_interval));
|
||
return;
|
||
};
|
||
}
|
||
wxString sql;
|
||
sql = wxT("select pid,frame_number,query_text,unnest(string_to_array(plan, E'\n')) pln,leader_pid from pg_query_state(")
|
||
+pid+flags+wxT(") s");
|
||
SendQueryExecute(slot,sql,connection);
|
||
}
|
||
void frmStatus::OnRefreshQuerystateTimer_After()
|
||
{
|
||
// wxCriticalSectionLocker lock(gs_critsect);
|
||
|
||
long row = 0;
|
||
//pgSet *dataSet3 = connection->ExecuteSet(sql,false);
|
||
int slot=1;
|
||
long long endtime;
|
||
long long starttime;
|
||
pgSet *dataSet3 = NULL;
|
||
{
|
||
wxCriticalSectionLocker lock(gs_critsect);
|
||
dataSet3=array_exec[slot].result;
|
||
endtime=array_exec[slot].end;
|
||
starttime=array_exec[slot].start;
|
||
}
|
||
|
||
if (dataSet3)
|
||
{
|
||
statusBar->SetStatusText(_("Refreshing query state list."));
|
||
wxLongLong startTime=wxGetLocalTimeMillis();
|
||
querystateList->Freeze();
|
||
long prev_fn=100000000;
|
||
while (!dataSet3->Eof()&&dataSet3->NumCols()>0)
|
||
{
|
||
long pid = dataSet3->GetLong(wxT("pid"));
|
||
|
||
if (row >= querystateList->GetItemCount())
|
||
{
|
||
querystateList->InsertItem(row, NumToStr(pid), -1);
|
||
row = querystateList->GetItemCount() - 1;
|
||
}
|
||
else
|
||
{
|
||
querystateList->SetItem(row, 0, NumToStr(pid));
|
||
}
|
||
|
||
int colpos = 1;
|
||
long fn=dataSet3->GetLong(wxT("frame_number"));
|
||
querystateList->SetItem(row, colpos++, NumToStr(fn));
|
||
querystateList->SetItem(row, colpos++, dataSet3->GetVal(wxT("query_text")));
|
||
wxString p=dataSet3->GetVal(wxT("pln"));
|
||
querystateList->SetItem(row, colpos++, p);
|
||
querystateList->SetItem(row, colpos++, dataSet3->GetVal(wxT("leader_pid")));
|
||
if (prev_fn==fn) {
|
||
querystateList->SetItem(row, 1, wxT(""));
|
||
querystateList->SetItem(row, 2, wxT(""));
|
||
}
|
||
wxColour wc;
|
||
if (p.Find(wxT("->"))<0) {
|
||
wc=*wxWHITE;
|
||
if (getlongvalue(p,wxT("Rows Removed by Join Filter: ([0-9]+)"))>1000000) {
|
||
wc=wxColour(201,83,2);
|
||
//querystateList->SetItemBackgroundColour(row, wxColour(201,83,2));
|
||
}
|
||
|
||
querystateList->SetItemBackgroundColour(row, wc);
|
||
//querystateList->SetItemBackgroundColour(row, );
|
||
} else
|
||
{
|
||
if (getlongvalue(p,wxT("actual rows=([0-9]+)"))>1000000) {
|
||
querystateList->SetItemBackgroundColour(row, wxColour(255,174,200)); // red
|
||
} else
|
||
querystateList->SetItemBackgroundColour(row, wxColour(224,255,224)); // gren
|
||
}
|
||
|
||
row++;
|
||
prev_fn=fn;
|
||
dataSet3->MoveNext();
|
||
}
|
||
delete dataSet3;
|
||
|
||
while (row < querystateList->GetItemCount())
|
||
querystateList->DeleteItem(row);
|
||
|
||
querystateList->Thaw();
|
||
wxLongLong delta=wxGetLocalTimeMillis()-startTime;
|
||
delta=delta+(endtime-starttime);
|
||
wxString run_interval = ElapsedTimeToStr(delta);
|
||
statusBar->SetStatusText(wxString::Format("%s Qstate:%s", _("Done."),run_interval));
|
||
{
|
||
wxCriticalSectionLocker lock(gs_critsect);
|
||
array_exec[slot]={}; // free slot
|
||
}
|
||
|
||
}
|
||
else {
|
||
{
|
||
wxCriticalSectionLocker lock(gs_critsect);
|
||
array_exec[slot]={}; // free slot
|
||
}
|
||
checkConnection();
|
||
}
|
||
}
|
||
|
||
|
||
void frmStatus::OnRefreshLogTimer(wxTimerEvent &event)
|
||
{
|
||
if (logisread) return;
|
||
if (! viewMenu->IsEnabled(MNU_LOGPAGE) || ! viewMenu->IsChecked(MNU_LOGPAGE) || !logTimer)
|
||
return;
|
||
|
||
checkConnection();
|
||
if (!connection)
|
||
{
|
||
statusTimer->Stop();
|
||
locksTimer->Stop();
|
||
if (xactTimer)
|
||
xactTimer->Stop();
|
||
logTimer->Stop();
|
||
|
||
if (logThread) {
|
||
logThread->BreakRead();
|
||
wxMilliSleep(50);
|
||
logThread->DoTerminate();
|
||
wxMilliSleep(5);
|
||
//s_CloseLog.Wait();
|
||
while (logThread != NULL) wxMilliSleep(5);
|
||
}
|
||
return;
|
||
}
|
||
if (!logThread) {
|
||
wxString applicationname = "pgAdmin III LogReader";
|
||
logconn = new pgConn(connection->GetHostName(), connection->GetService(), connection->GetHostAddr(), connection->GetDbname(),
|
||
connection->GetUser(), connection->GetPassword(), connection->GetPort(), connection->GetRole(), "", connection->GetSslMode(),
|
||
0, applicationname, connection->GetSSLCert(), connection->GetSSLKey(), connection->GetSSLRootCert(), connection->GetSSLCrl(),
|
||
connection->GetSSLCompression());
|
||
|
||
if (!logconn->IsAlive()) {
|
||
wxString err=logconn->GetLastError();
|
||
//wxMessageBox(err);
|
||
statusBar->SetStatusText(err);
|
||
delete logconn;
|
||
logconn = NULL;
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
}
|
||
if (log_queue.IsOk()) log_queue.Clear();
|
||
|
||
logThread = new ReadLogThread(logconn, this,&log_queue);
|
||
if (logThread->Create() != wxTHREAD_NO_ERROR)
|
||
{
|
||
wxLogError(wxT("Can’t create log thread!"));
|
||
delete logThread;
|
||
logThread = NULL;
|
||
} else
|
||
logThread->Run();
|
||
}
|
||
else
|
||
if (logThread) // The thread
|
||
{
|
||
// Recive lines
|
||
if (logThread->isBreak()) return;
|
||
wxString sstr;
|
||
long lastrow = logList->GetItemCount();
|
||
bool remote = lastrow - 1 == logList->GetFocusedItem();
|
||
long cnt = 0;
|
||
float pr = 0;
|
||
long timeout = logTimer->GetInterval();
|
||
const wxMilliClock_t waitUntil = wxGetLocalTimeMillis() + timeout;
|
||
logisread = true;
|
||
if (!logList->IsFrozen()) logList->Freeze();
|
||
while (logThread && log_queue.ReceiveTimeout(1, sstr) == wxMSGQUEUE_NO_ERROR) {
|
||
if (logThread->isBreak()) break;
|
||
addLogLine(sstr, true, true);
|
||
if (logThread->isBreak()) break;
|
||
if ((cnt++ % 1000) == 0) {
|
||
//pr = 100 * cnt / total;
|
||
wxString ll = wxString::Format("append rows %ld ...", cnt+ lastrow);
|
||
statusBar->SetStatusText(ll);
|
||
wxYield();
|
||
if (frm_exit) { logisread = false; return; }
|
||
}
|
||
//if (logThread->isBreak()) return;
|
||
const wxMilliClock_t now = wxGetLocalTimeMillis();
|
||
if (now >= waitUntil) break;
|
||
|
||
};
|
||
if (logList->IsFrozen())
|
||
{
|
||
logList->Thaw();
|
||
nav->Refresh();
|
||
}
|
||
logisread = false;
|
||
if (logThread && logThread->isBreak()) {
|
||
return;
|
||
}
|
||
if (cnt > 0) {
|
||
cnt += lastrow;
|
||
//wxString ll = wxString::Format("append rows GUI %ld ...", cnt);
|
||
//statusBar->SetStatusText(ll);
|
||
addodd++;
|
||
if (remote) {
|
||
logList->Focus(logList->GetItemCount() - 1);
|
||
}
|
||
logList->Refresh();
|
||
}
|
||
//statusBar->SetStatusText(s);
|
||
if (logThread && logThread->isReadyRows()) {
|
||
long read = logThread->GetReadByteFile(savedPartialLine); // result last read
|
||
logfileLength = read;
|
||
// Ready next lines
|
||
}
|
||
else {
|
||
return; /// not ready next lines
|
||
}
|
||
}
|
||
|
||
|
||
|
||
//wxCriticalSectionLocker lock(gs_critsect);
|
||
|
||
|
||
if (logList->IsFrozen()) logList->Thaw();
|
||
|
||
if (logconn->GetLastResultError().sql_state == wxT("42501"))
|
||
{
|
||
// Don't have superuser privileges, so can't do anything with the log display
|
||
logTimer->Stop();
|
||
cbLogfiles->Disable();
|
||
btnRotateLog->Disable();
|
||
manager.GetPane(wxT("Logfile")).Show(false);
|
||
manager.Update();
|
||
return;
|
||
}
|
||
|
||
long newlen = 0;
|
||
|
||
if (logDirectory.IsEmpty())
|
||
{
|
||
// freshly started
|
||
logDirectory = logconn->ExecuteScalar(wxT("SHOW log_directory"));
|
||
if (logconn->GetLastResultError().sql_state == wxT("42501"))
|
||
{
|
||
// Don't have superuser privileges, so can't do anything with the log display
|
||
logTimer->Stop();
|
||
cbLogfiles->Disable();
|
||
btnRotateLog->Disable();
|
||
manager.GetPane(wxT("Logfile")).Show(false);
|
||
manager.Update();
|
||
return;
|
||
}
|
||
if (fillLogfileCombo())
|
||
{
|
||
savedPartialLine.Clear();
|
||
cbLogfiles->SetSelection(0);
|
||
wxCommandEvent ev;
|
||
OnLoadLogfile(ev);
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
//logDirectory = wxEmptyString;
|
||
return;
|
||
logDirectory = wxT("-");
|
||
if (logconn->BackendMinimumVersion(8, 3))
|
||
logList->AppendItemLong(-1, wxString(_("logging_collector not enabled or log_filename misconfigured")));
|
||
else
|
||
logList->AppendItemLong(-1, wxString(_("redirect_stderr not enabled or log_filename misconfigured")));
|
||
cbLogfiles->Disable();
|
||
btnRotateLog->Disable();
|
||
}
|
||
}
|
||
|
||
if (logDirectory == wxT("-"))
|
||
return;
|
||
|
||
if (isCurrent && logfileName.Len()>0)
|
||
{
|
||
// check if the current logfile changed
|
||
|
||
pgSet* set;
|
||
if ((logconn->BackendMinimumVersion(10, 0)))
|
||
set = logconn->ExecuteSet(wxT("select size len from pg_stat_file(") + logconn->qtDbString(logfileName) + wxT(",true)"),false);
|
||
else
|
||
set = logconn->ExecuteSet(wxT("SELECT pg_file_length(") + logconn->qtDbString(logfileName) + wxT(") AS len"));
|
||
if (set )
|
||
{
|
||
if (set->NumCols() == 0) {
|
||
// error server
|
||
// continue after
|
||
wxString errtext=logconn->GetLastError();
|
||
statusBar->SetStatusText("Error db: "+ errtext);
|
||
return;
|
||
}
|
||
if (set->NumCols()>0 && !set->IsNull(0)) newlen = set->GetLong(wxT("len"));
|
||
else {
|
||
logDirectory = ""; // reRead directory
|
||
logfileName = "";
|
||
newlen = 0;
|
||
showCurrent = true;
|
||
}
|
||
delete set;
|
||
}
|
||
else
|
||
{
|
||
checkConnection();
|
||
logDirectory = ""; // reRead directory
|
||
logfileName = "";
|
||
return;
|
||
}
|
||
if (newlen > logfileLength)
|
||
{
|
||
|
||
statusBar->SetStatusText(_("Refreshing log list."));
|
||
addLogFile(logfileName, logfileTimestamp, newlen, logfileLength, false);
|
||
statusBar->SetStatusText(_("Wait..."));
|
||
// as long as there was new data, the logfile is probably the current
|
||
// one so we don't need to check for rotation
|
||
return;
|
||
}
|
||
}
|
||
|
||
//
|
||
wxString newDirectory = logconn->ExecuteScalar(wxT("SHOW log_directory"));
|
||
|
||
int newfiles = 0;
|
||
if (newDirectory != logDirectory)
|
||
cbLogfiles->Clear();
|
||
|
||
newfiles = fillLogfileCombo();
|
||
|
||
if (newfiles)
|
||
{
|
||
if (!showCurrent)
|
||
isCurrent = false;
|
||
|
||
if (isCurrent)
|
||
{
|
||
wxCommandEvent ev;
|
||
if (cbLogfiles->GetCount() > 0) {
|
||
cbLogfiles->SetSelection(0);
|
||
OnLoadLogfile(ev);
|
||
}
|
||
else {
|
||
|
||
int pos = cbLogfiles->GetCount() - newfiles;
|
||
bool skipFirst = true;
|
||
|
||
while (newfiles--)
|
||
{
|
||
addLogLine(_("pgadmin:Logfile rotated."), false);
|
||
wxDateTime* ts = (wxDateTime*)cbLogfiles->wxItemContainer::GetClientData(pos++);
|
||
wxASSERT(ts != 0);
|
||
if (logThread) logThread->BreakRead();
|
||
addLogFile(ts, skipFirst);
|
||
skipFirst = false;
|
||
|
||
pos++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
void frmStatus::OnRefresh(wxCommandEvent &event)
|
||
{
|
||
wxTimerEvent evt;
|
||
|
||
OnRefreshStatusTimer(evt);
|
||
OnRefreshLocksTimer(evt);
|
||
OnRefreshXactTimer(evt);
|
||
OnRefreshLogTimer(evt);
|
||
OnRefreshQuerystateTimer(evt);
|
||
}
|
||
|
||
|
||
void frmStatus::checkConnection()
|
||
{
|
||
if (connection) {
|
||
{
|
||
wxCriticalSectionLocker lock(gs_critsect);
|
||
int countQuery=0;
|
||
for (int i=0;i<4;i++)
|
||
if (array_exec[i].conn!=NULL) countQuery++;
|
||
if (countQuery==0)
|
||
{
|
||
if (!locks_connection->IsAlive())
|
||
{
|
||
locks_connection = connection;
|
||
}
|
||
if (!connection->IsAlive())
|
||
{
|
||
if (locks_connection==connection) locks_connection = 0;
|
||
delete connection;
|
||
connection = 0;
|
||
statusTimer->Stop();
|
||
locksTimer->Stop();
|
||
if (xactTimer)
|
||
xactTimer->Stop();
|
||
if (logTimer)
|
||
logTimer->Stop();
|
||
if (querystateTimer)
|
||
querystateTimer->Stop();
|
||
actionMenu->Enable(MNU_REFRESH, false);
|
||
toolBar->EnableTool(MNU_REFRESH, false);
|
||
statusBar->SetStatusText(_("Connection broken."));
|
||
SetTitle(_("Connection broken."));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
void frmStatus::addLogFile(wxDateTime *dt, bool skipFirst)
|
||
{
|
||
pgSet* set;
|
||
if (settings->GetASUTPstyle()) {
|
||
wxString sql = "select current_setting('log_directory')||'/'||name filename,modification filetime,size len\n"
|
||
" FROM pg_ls_logdir() where name ~ '.csv' and modification >= '" + DateToAnsiStr(*dt) + "'::timestamp order by modification-'" + DateToAnsiStr(*dt) + "'::timestamp limit 1";
|
||
set = logconn->ExecuteSet(sql);
|
||
} else
|
||
set = logconn->ExecuteSet(
|
||
wxT("SELECT modification filetime, name filename, size AS len ")
|
||
wxT(" FROM pg_ls_logdir()")
|
||
wxT(" WHERE modification = '") + DateToAnsiStr(*dt) + wxT("'::timestamp"),false);
|
||
if (set)
|
||
{
|
||
logfileName = set->GetVal(wxT("filename"));
|
||
logfileTimestamp = set->GetDateTime(wxT("filetime"));
|
||
long len = set->GetLong(wxT("len"));
|
||
//if (logThread) logThread->BreakRead();
|
||
logfileLength = 0;
|
||
addLogFile(logfileName, logfileTimestamp, len, logfileLength, skipFirst);
|
||
|
||
delete set;
|
||
}
|
||
}
|
||
|
||
|
||
void frmStatus::addLogFile(const wxString &filename, const wxDateTime timestamp, long len, long &read, bool skipFirst)
|
||
{
|
||
wxString line;
|
||
|
||
if (skipFirst)
|
||
{
|
||
long maxServerLogSize = settings->GetMaxServerLogSize();
|
||
|
||
if (!logfileLength && maxServerLogSize && logfileLength > maxServerLogSize)
|
||
{
|
||
long maxServerLogSize = settings->GetMaxServerLogSize();
|
||
len = read - maxServerLogSize;
|
||
}
|
||
else
|
||
skipFirst = false;
|
||
}
|
||
|
||
// If GPDB 3.3 and later, log is normally in CSV format. Let's get a whole log line before calling addLogLine,
|
||
// so we can do things smarter.
|
||
|
||
// PostgreSQL can log in CSV format, as well as regular format. Normally, we'd only see
|
||
// the regular format logs here, because pg_logdir_ls only returns those. But if pg_logdir_ls is
|
||
// changed to return the csv format log files, we should handle it.
|
||
|
||
bool csv_log_format = filename.Right(4) == wxT(".csv");
|
||
|
||
if (csv_log_format && savedPartialLine.length() > 0)
|
||
{
|
||
if (read == 0) // Starting at beginning of log file
|
||
savedPartialLine.clear();
|
||
else
|
||
line = savedPartialLine;
|
||
}
|
||
if (logThread) {
|
||
if (logThread->isReadyRows()) {
|
||
logThread->SetParameters(filename,len,read,savedPartialLine);
|
||
logThread->GoReadRows();
|
||
return;
|
||
}
|
||
}
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
|
||
void frmStatus::addLogLine(const wxString &str, bool formatted, bool csv_log_format)
|
||
{
|
||
int row = logList->GetItemCount();
|
||
|
||
int idxTimeStampCol = -1, idxLevelCol = -1;
|
||
int idxLogEntryCol = 0;
|
||
|
||
|
||
if (!logFormatKnown) {
|
||
logList->AppendItemLong(-1, str);
|
||
int colorindex = nav->TryMarkItem(row, str);
|
||
if (colorindex>=0)
|
||
logList->SetItemBackgroundColour(row, nav->GetColorByIndex(colorindex));
|
||
else
|
||
logList->SetItemBackgroundColour(row, logcol[addodd % 2]);
|
||
}
|
||
else if ((!csv_log_format) && str.Find(':') < 0)
|
||
{
|
||
// Must be a continuation of a previous line.
|
||
logList->InsertItem(row, wxEmptyString, -1);
|
||
logList->SetItem(row, idxLogEntryCol, str);
|
||
}
|
||
else if (!formatted)
|
||
{
|
||
// Not from a log, from pgAdmin itself.
|
||
if (logHasTimestamp)
|
||
{
|
||
logList->InsertItem(row, wxEmptyString, -1);
|
||
logList->SetItem(row, idxLevelCol, str.BeforeFirst(':'));
|
||
}
|
||
else
|
||
{
|
||
logList->InsertItem(row, str.BeforeFirst(':'), -1);
|
||
}
|
||
logList->SetItem(row, idxLogEntryCol, str.AfterFirst(':'));
|
||
}
|
||
else // formatted log
|
||
{
|
||
if (csv_log_format)
|
||
{
|
||
// Log is in CSV format (GPDB 3.3 and later, or Postgres if only csv log enabled)
|
||
// In this case, we are always supposed to have a complete log line in csv format in str when called.
|
||
|
||
if (logHasTimestamp && (str.Length() < 20 || (logHasTimestamp && (str[0] != wxT('2') || str[1] != wxT('0')))))
|
||
{
|
||
// Log line too short or does not start with an expected timestamp...
|
||
// Must be a continuation of the previous line or garbage,
|
||
// or we are out of sync in our CSV handling.
|
||
// We shouldn't ever get here.
|
||
logList->InsertItem(row, wxEmptyString, -1);
|
||
logList->SetItem(row, 2, str);
|
||
}
|
||
else
|
||
{
|
||
CSVTokenizer tk(str);
|
||
|
||
bool gpdb = connection->GetIsGreenplum();
|
||
|
||
// Get the fields from the CSV log.
|
||
wxString logTime = tk.GetNextToken();
|
||
wxString logUser = tk.GetNextToken();
|
||
wxString logDatabase = tk.GetNextToken();
|
||
wxString logPid = tk.GetNextToken();
|
||
|
||
wxString logSession;
|
||
wxString logCmdcount;
|
||
wxString logSegment;
|
||
|
||
if (gpdb)
|
||
{
|
||
wxString logThread = tk.GetNextToken(); // GPDB specific
|
||
wxString logHost = tk.GetNextToken();
|
||
wxString logPort = tk.GetNextToken(); // GPDB (Postgres puts port with Host)
|
||
wxString logSessiontime = tk.GetNextToken();
|
||
wxString logTransaction = tk.GetNextToken();
|
||
logSession = tk.GetNextToken();
|
||
logCmdcount = tk.GetNextToken();
|
||
logSegment = tk.GetNextToken();
|
||
wxString logSlice = tk.GetNextToken();
|
||
wxString logDistxact = tk.GetNextToken();
|
||
wxString logLocalxact = tk.GetNextToken();
|
||
wxString logSubxact = tk.GetNextToken();
|
||
}
|
||
else
|
||
{
|
||
wxString logHost = tk.GetNextToken(); // Postgres puts port with Hostname
|
||
logSession = tk.GetNextToken();
|
||
wxString logLineNumber = tk.GetNextToken();
|
||
wxString logPsDisplay = tk.GetNextToken();
|
||
wxString logSessiontime = tk.GetNextToken();
|
||
wxString logVXid = tk.GetNextToken();
|
||
wxString logTransaction = tk.GetNextToken();
|
||
}
|
||
|
||
wxString logSeverity = tk.GetNextToken();
|
||
wxString logState = tk.GetNextToken();
|
||
wxString logMessage = tk.GetNextToken();
|
||
wxString logDetail = tk.GetNextToken();
|
||
wxString logHint = tk.GetNextToken();
|
||
wxString logQuery = tk.GetNextToken();
|
||
wxString logQuerypos = tk.GetNextToken();
|
||
wxString logContext = tk.GetNextToken();
|
||
wxString logDebug = tk.GetNextToken();
|
||
wxString logCursorpos = tk.GetNextToken();
|
||
|
||
wxString logStack;
|
||
if (gpdb)
|
||
{
|
||
wxString logFunction = tk.GetNextToken(); // GPDB. Postgres puts func, file, and line together
|
||
wxString logFile = tk.GetNextToken();
|
||
wxString logLine = tk.GetNextToken();
|
||
logStack = tk.GetNextToken(); // GPDB only.
|
||
}
|
||
else
|
||
wxString logFuncFileLine = tk.GetNextToken();
|
||
|
||
logList->InsertItem(row, logTime, -1); // Insert timestamp (with time zone)
|
||
|
||
logList->SetItem(row, 1, logSeverity);
|
||
|
||
// Display the logMessage, breaking it into lines
|
||
wxStringTokenizer lm(logMessage, wxT("\n"));
|
||
logList->SetItem(row, 2, lm.GetNextToken());
|
||
|
||
logList->SetItem(row, 3, logSession);
|
||
logList->SetItem(row, 4, logCmdcount);
|
||
logList->SetItem(row, 5, logDatabase);
|
||
if ((!gpdb) || (logSegment.length() > 0 && logSegment != wxT("seg-1")))
|
||
{
|
||
logList->SetItem(row, 6, logSegment);
|
||
}
|
||
else
|
||
{
|
||
// If we are reading the masterDB log only, the logSegment won't
|
||
// have anything useful in it. Look in the logMessage, and see if the
|
||
// segment info exists in there. It will always be at the end.
|
||
if (logMessage.length() > 0 && logMessage[logMessage.length() - 1] == wxT(')'))
|
||
{
|
||
int segpos = -1;
|
||
segpos = logMessage.Find(wxT("(seg"));
|
||
if (segpos <= 0)
|
||
segpos = logMessage.Find(wxT("(mir"));
|
||
if (segpos > 0)
|
||
{
|
||
logSegment = logMessage.Mid(segpos + 1);
|
||
if (logSegment.Find(wxT(' ')) > 0)
|
||
logSegment = logSegment.Mid(0, logSegment.Find(wxT(' ')));
|
||
logList->SetItem(row, 6, logSegment);
|
||
}
|
||
}
|
||
}
|
||
|
||
// The rest of the lines from the logMessage
|
||
while (lm.HasMoreTokens())
|
||
{
|
||
int controw = logList->GetItemCount();
|
||
logList->InsertItem(controw, wxEmptyString, -1);
|
||
logList->SetItem(controw, 2, lm.GetNextToken());
|
||
}
|
||
|
||
// Add the detail
|
||
wxStringTokenizer ld(logDetail, wxT("\n"));
|
||
while (ld.HasMoreTokens())
|
||
{
|
||
int controw = logList->GetItemCount();
|
||
logList->InsertItem(controw, wxEmptyString, -1);
|
||
logList->SetItem(controw, 2, ld.GetNextToken());
|
||
}
|
||
|
||
// And the hint
|
||
wxStringTokenizer lh(logHint, wxT("\n"));
|
||
while (lh.HasMoreTokens())
|
||
{
|
||
int controw = logList->GetItemCount();
|
||
logList->InsertItem(controw, wxEmptyString, -1);
|
||
logList->SetItem(controw, 2, lh.GetNextToken());
|
||
}
|
||
|
||
if (logDebug.length() > 0)
|
||
{
|
||
wxString logState3 = logState.Mid(0, 3);
|
||
if (logState3 == wxT("426") || logState3 == wxT("22P") || logState3 == wxT("427")
|
||
|| logState3 == wxT("42P") || logState3 == wxT("458")
|
||
|| logMessage.Mid(0, 9) == wxT("duration:") || logSeverity == wxT("FATAL") || logSeverity == wxT("PANIC"))
|
||
{
|
||
// If not redundant, add the statement from the debug_string
|
||
wxStringTokenizer lh(logDebug, wxT("\n"));
|
||
if (lh.HasMoreTokens())
|
||
{
|
||
int controw = logList->GetItemCount();
|
||
logList->InsertItem(controw, wxEmptyString, -1);
|
||
logList->SetItem(controw, 2, wxT("statement: ") + lh.GetNextToken());
|
||
}
|
||
while (lh.HasMoreTokens())
|
||
{
|
||
int controw = logList->GetItemCount();
|
||
logList->InsertItem(controw, wxEmptyString, -1);
|
||
logList->SetItem(controw, 2, lh.GetNextToken());
|
||
}
|
||
}
|
||
}
|
||
|
||
if (gpdb)
|
||
if (logSeverity == wxT("PANIC") ||
|
||
(logSeverity == wxT("FATAL") && logState != wxT("57P03") && logState != wxT("53300")))
|
||
{
|
||
// If this is a severe error, add the stack trace.
|
||
wxStringTokenizer ls(logStack, wxT("\n"));
|
||
if (ls.HasMoreTokens())
|
||
{
|
||
int controw = logList->GetItemCount();
|
||
logList->InsertItem(controw, wxEmptyString, -1);
|
||
logList->SetItem(controw, 1, wxT("STACK"));
|
||
logList->SetItem(controw, 2, ls.GetNextToken());
|
||
}
|
||
while (ls.HasMoreTokens())
|
||
{
|
||
int controw = logList->GetItemCount();
|
||
logList->InsertItem(controw, wxEmptyString, -1);
|
||
logList->SetItem(controw, 2, ls.GetNextToken());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else if (connection->GetIsGreenplum())
|
||
{
|
||
// Greenplum 3.2 and before. log_line_prefix = "%m|%u|%d|%p|%I|%X|:-"
|
||
|
||
wxString logSeverity;
|
||
// Skip prefix, get message. In GPDB, always follows ":-".
|
||
wxString rest = str.Mid(str.Find(wxT(":-")) + 1) ;
|
||
if (rest.Length() > 0 && rest[0] == wxT('-'))
|
||
rest = rest.Mid(1);
|
||
|
||
// Separate loglevel from message
|
||
|
||
if (rest.Length() > 1 && rest[0] != wxT(' ') && rest.Find(':') > 0)
|
||
{
|
||
logSeverity = rest.BeforeFirst(':');
|
||
rest = rest.AfterFirst(':').Mid(2);
|
||
}
|
||
|
||
wxString ts = str.BeforeFirst(logFormat.c_str()[logFmtPos + 2]);
|
||
if (ts.Length() < 20 || (logHasTimestamp && (ts.Left(2) != wxT("20") || str.Find(':') < 0)))
|
||
{
|
||
// No Timestamp? Must be a continuation of a previous line?
|
||
// Not sure if it is possible to get here.
|
||
logList->InsertItem(row, wxEmptyString, -1);
|
||
logList->SetItem(row, 2, rest);
|
||
}
|
||
else if (logSeverity.Length() > 1)
|
||
{
|
||
// Normal case: Start of a new log record.
|
||
logList->InsertItem(row, ts, -1);
|
||
logList->SetItem(row, 1, logSeverity);
|
||
logList->SetItem(row, 2, rest);
|
||
}
|
||
else
|
||
{
|
||
// Continuation of previous line
|
||
logList->InsertItem(row, wxEmptyString, -1);
|
||
logList->SetItem(row, 2, rest);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// All Non-csv-format non-GPDB PostgreSQL systems.
|
||
|
||
wxString rest;
|
||
|
||
if (logHasTimestamp)
|
||
{
|
||
if (formatted)
|
||
{
|
||
rest = str.Mid(logFmtPos + 22).AfterFirst(':');
|
||
wxString ts = str.Mid(logFmtPos, str.Length() - rest.Length() - logFmtPos - 1);
|
||
|
||
int pos = ts.Find(logFormat.c_str()[logFmtPos + 2], true);
|
||
logList->InsertItem(row, ts.Left(pos), -1);
|
||
logList->SetItem(row, idxLevelCol, ts.Mid(pos + logFormat.Length() - logFmtPos - 2));
|
||
logList->SetItem(row, idxLogEntryCol, rest.Mid(2));
|
||
}
|
||
else
|
||
{
|
||
logList->InsertItem(row, wxEmptyString, -1);
|
||
logList->SetItem(row, idxLevelCol, str.BeforeFirst(':'));
|
||
logList->SetItem(row, idxLogEntryCol, str.AfterFirst(':').Mid(2));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (formatted)
|
||
rest = str.Mid(logFormat.Length());
|
||
else
|
||
rest = str;
|
||
|
||
int pos = rest.Find(':');
|
||
|
||
if (pos < 0) {
|
||
logList->InsertItem(row, rest, -1);
|
||
}
|
||
else
|
||
{
|
||
logList->InsertItem(row, rest.BeforeFirst(':'), -1);
|
||
logList->SetItem(row, idxLogEntryCol, rest.AfterFirst(':').Mid(2));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void frmStatus::OnLogKeyUp(wxKeyEvent& event)
|
||
{
|
||
if (currentPane == PANE_LOG) {
|
||
if (nav->RunKeyCommand(event)) return;
|
||
}
|
||
event.Skip();
|
||
}
|
||
|
||
void frmStatus::emptyLogfileCombo()
|
||
{
|
||
if (cbLogfiles->GetCount()) // first entry has no client data
|
||
cbLogfiles->Delete(0);
|
||
|
||
while (cbLogfiles->GetCount())
|
||
{
|
||
wxDateTime *dt = (wxDateTime *)cbLogfiles->wxItemContainer::GetClientData(0);
|
||
if (dt)
|
||
delete dt;
|
||
cbLogfiles->Delete(0);
|
||
}
|
||
}
|
||
|
||
|
||
int frmStatus::fillLogfileCombo()
|
||
{
|
||
int count = cbLogfiles->GetCount();
|
||
if (!count)
|
||
cbLogfiles->Append(_("Current log"));
|
||
else
|
||
count--;
|
||
pgSet* set;
|
||
if (settings->GetASUTPstyle())
|
||
set = logconn->ExecuteSet(
|
||
wxT("select name filename,modification filetime\n")
|
||
wxT(" FROM pg_ls_logdir() where name ~ '.csv'\n")
|
||
wxT(" ORDER BY modification DESC"),false);
|
||
|
||
else set = logconn->ExecuteSet(
|
||
wxT("SELECT name filename,modification filetime\n")
|
||
wxT(" FROM pg_ls_logdir()\n")
|
||
wxT(" ORDER BY filetime DESC"),false);
|
||
|
||
|
||
if (set)
|
||
{
|
||
if (set->NumRows() <= count)
|
||
{
|
||
delete set;
|
||
return 0;
|
||
}
|
||
|
||
set->Locate(count + 1);
|
||
count = 0;
|
||
|
||
while (!set->Eof())
|
||
{
|
||
count++;
|
||
wxString fn = set->GetVal(wxT("filename"));
|
||
wxDateTime ts = set->GetDateTime(wxT("filetime"));
|
||
|
||
cbLogfiles->Append(DateToAnsiStr(ts), (void *)new wxDateTime(ts));
|
||
|
||
set->MoveNext();
|
||
}
|
||
|
||
delete set;
|
||
}
|
||
if (count > 0) {
|
||
unsigned int i;
|
||
int maxWidth(0), width;
|
||
for (i = 0; i < cbLogfiles->GetCount(); i++)
|
||
{
|
||
cbLogfiles->GetTextExtent(cbLogfiles->GetString(i), &width, NULL);
|
||
if (width > maxWidth)
|
||
maxWidth = width;
|
||
}
|
||
|
||
//cbLogfiles->SetMinSize(wxSize(maxWidth + 2, -1));
|
||
//int sz = wxSystemSettings::GetMetric(wxSYS_VSCROLL_X, cbLogfiles);
|
||
int sz = 24;
|
||
cbLogfiles->SetSize(wxSize(maxWidth + sz, -1));
|
||
toolBar->Realize();
|
||
|
||
wxSize newszT = toolBar->GetBestSize();
|
||
manager.GetPane(wxT("toolBar")).BestSize(newszT);
|
||
//manager.GetPane(wxT("toolBar")).MinSize(newszT);
|
||
manager.Update();
|
||
}
|
||
return count;
|
||
}
|
||
|
||
|
||
void frmStatus::OnLoadLogfile(wxCommandEvent &event)
|
||
{
|
||
int pos = cbLogfiles->GetCurrentSelection();
|
||
if (pos >= 0)
|
||
{
|
||
showCurrent = (pos == 0);
|
||
isCurrent = showCurrent || (pos == 1);
|
||
|
||
wxDateTime *ts = (wxDateTime *)cbLogfiles->wxItemContainer::GetClientData(showCurrent ? 1 : pos);
|
||
wxASSERT(ts != 0);
|
||
|
||
if (ts != NULL && (!logfileTimestamp.IsValid() || *ts != logfileTimestamp))
|
||
{
|
||
if (logThread) logThread->BreakRead();
|
||
|
||
logList->DeleteAllItemsWithLong();
|
||
nav->ClearMark();
|
||
//bgColor = wxColour("#afafaf");
|
||
//bgColor = logList->GetBackgroundColour();
|
||
addodd = 0;
|
||
addLogFile(ts, true);
|
||
nav->Refresh();
|
||
}
|
||
}
|
||
}
|
||
ReadLogThread::~ReadLogThread() {
|
||
//s_CloseLog.Post();
|
||
((frmStatus *) theParent)->logThread = NULL;
|
||
}
|
||
void ReadLogThread::BreakRead() {
|
||
if (!isReadyRows()) {
|
||
m_break = true;
|
||
while (!isReadyRows()) {
|
||
wxMilliSleep(20);
|
||
}
|
||
}
|
||
log_queue->Clear();
|
||
}
|
||
void ReadLogThread::DoTerminate() {
|
||
m_exit = true;
|
||
if (isReadyRows()) {
|
||
s_goReadLog.Post();
|
||
}
|
||
return;
|
||
}
|
||
|
||
void* ReadLogThread::Entry() {
|
||
int size_rows = 0;
|
||
while (!m_exit)
|
||
{
|
||
{
|
||
wxMutexLocker lock(s_mutexDBLogReading);
|
||
//s_mutexDBLogReading.Lock();
|
||
//rows.clear();
|
||
getFilename();
|
||
}
|
||
if (m_exit) break;
|
||
s_goReadLog.Wait();
|
||
}
|
||
return NULL;
|
||
}
|
||
void ReadLogThread::getFilename() {
|
||
pgSet* set;
|
||
if (logfileName.length() == 0) return;
|
||
if (m_exit || m_break) return;
|
||
if (!conn->IsAlive()) {
|
||
wxDateTime n = wxDateTime::Now();
|
||
if (!nextrun.IsValid() || nextrun < n) {
|
||
if (!conn->Reconnect(false))
|
||
{
|
||
wxTimeSpan sp(0, 2);
|
||
nextrun = wxDateTime::Now() + sp;
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
readLogFile(logfileName, len, logfileLength, savedPartialLine);
|
||
|
||
//if (namepage.IsEmpty()) namepage = "not connect";
|
||
//if (m_notebook->GetPageText(0) != namepage) m_notebook->SetPageText(0, namepage);
|
||
}
|
||
void ReadLogThread::readLogFile(wxString logfileName, long& lenfile, long& logfileLength, wxString& savedPartialLine) {
|
||
wxString line;
|
||
|
||
// If GPDB 3.3 and later, log is normally in CSV format. Let's get a whole log line before calling addLogLine,
|
||
// so we can do things smarter.
|
||
|
||
// PostgreSQL can log in CSV format, as well as regular format. Normally, we'd only see
|
||
// the regular format logs here, because pg_logdir_ls only returns those. But if pg_logdir_ls is
|
||
// changed to return the csv format log files, we should handle it.
|
||
|
||
bool csv_log_format = logfileName.Right(4) == wxT(".csv");
|
||
if (csv_log_format && savedPartialLine.length() > 0)
|
||
{
|
||
if (logfileLength == 0) // Starting at beginning of log file
|
||
savedPartialLine.clear();
|
||
line = savedPartialLine;
|
||
}
|
||
wxString funcname = "pg_read_binary_file(";
|
||
int countLine = 0;
|
||
long logf = logfileLength;
|
||
while (lenfile > logfileLength)
|
||
{
|
||
//statusBar->SetStatusText(_("Reading log from server..."));
|
||
if (m_exit) return;
|
||
|
||
#define PG_READ_BUFFER 500000
|
||
wxString readsql = wxString::Format("select %s%s,%s, %d,true)", funcname, conn->qtDbString(logfileName), NumToStr(logfileLength), PG_READ_BUFFER);
|
||
pgSet* set = conn->ExecuteSet(readsql,false);
|
||
if (!set)
|
||
{
|
||
conn->IsAlive();
|
||
return;
|
||
}
|
||
if (set->NumRows() == 0 || set->NumCols() ==0 || set->GetVal(0).IsNull()) {
|
||
delete set;
|
||
break;
|
||
}
|
||
char* raw1 = set->GetCharPtr(0);
|
||
if (!raw1 || !*raw1)
|
||
{
|
||
delete set;
|
||
break;
|
||
}
|
||
char* rawbuff;
|
||
char m[PG_READ_BUFFER + 1];
|
||
if (true) {
|
||
|
||
rawbuff = &m[0];
|
||
unsigned char c;
|
||
unsigned char* startChar;
|
||
unsigned char* startLine= (unsigned char*)&m[0];
|
||
int pos = 0;
|
||
raw1 = raw1 + 2; // bytea data \x01cf23 ....
|
||
int utf8charLen = 0;
|
||
unsigned int unichar = 0;
|
||
unsigned int unicharcurrent = 0;
|
||
int shift;
|
||
while (*raw1 != 0) {
|
||
if (m_exit) return;
|
||
if (m_break) {
|
||
log_queue->Clear();
|
||
return;
|
||
}
|
||
c = *raw1;
|
||
c = c - '0';
|
||
if (c > 9) c = *raw1 - 'a' + 10;
|
||
raw1++;
|
||
m[pos] = c << 4;
|
||
c = *raw1 - '0';
|
||
if (c > 9) c = *raw1 - 'a' + 10;
|
||
c = c | m[pos]; // hex string -> byte
|
||
m[pos] = c;
|
||
// check utf-8 char
|
||
if (utf8charLen == 0) {
|
||
startChar = (unsigned char*) &m[pos];
|
||
|
||
if (c >> 7 == 0)
|
||
utf8charLen = 1;
|
||
else if (c >> 5 == 0x6)
|
||
utf8charLen = 2;
|
||
else if (c >> 4 == 0xE)
|
||
utf8charLen = 3;
|
||
else if (c >> 5 == 0x1E)
|
||
utf8charLen = 4;
|
||
else
|
||
utf8charLen = 0;
|
||
// bad utf8 format
|
||
shift = 0;
|
||
unichar = c;
|
||
}
|
||
unicharcurrent = c << shift;
|
||
shift += 8;
|
||
unichar = unichar | unicharcurrent;
|
||
pos++;
|
||
raw1++;
|
||
utf8charLen--;
|
||
if (utf8charLen == 0) {
|
||
// utf-8 char complite
|
||
if (unichar == '\"' && csv_log_format)
|
||
inquote = !inquote;
|
||
//wxString linebuff(startChar, lencsvstr);
|
||
if (unichar == '\n' && !inquote) {
|
||
// end line
|
||
size_t lencsvstr = (unsigned char*)&m[pos] - startLine;
|
||
wxString linebuff(startLine, set->GetConversion(),lencsvstr); // include '\n'
|
||
if (line.length() > 0) {
|
||
linebuff = line + linebuff;
|
||
line.clear();
|
||
}
|
||
startLine = (unsigned char*)&m[pos];
|
||
//rows.push_back(linebuff.Trim());
|
||
log_queue->Post(linebuff.Trim());
|
||
countLine++;
|
||
}
|
||
|
||
}
|
||
}
|
||
//
|
||
m[pos] = 0;
|
||
if (utf8charLen != 0) {
|
||
//read = startChar - &m[0];
|
||
// remove bad utf-8 char
|
||
*startChar = 0;
|
||
pos = startChar- (unsigned char*)&m[0];
|
||
// start position bad utf-8 char
|
||
} else
|
||
m[pos] = 0;
|
||
if (startLine != (unsigned char*)&m[pos]) {
|
||
// partial line
|
||
size_t lencsvstr = (unsigned char*)&m[pos] - startLine;
|
||
wxString linebuff(startLine, lencsvstr); // include '\n'
|
||
if (line.length() > 0) {
|
||
linebuff = line + linebuff;
|
||
line.clear();
|
||
}
|
||
line = linebuff;
|
||
}
|
||
}
|
||
else {
|
||
rawbuff = raw1;
|
||
}
|
||
int l = strlen(rawbuff);
|
||
logfileLength += l;
|
||
//status->SetLabelText(wxString::Format("%s Load bytes %ld", host, logfileLength));
|
||
|
||
wxString str;
|
||
//str = line + wxTextBuffer::Translate(wxString(rawbuff, set->GetConversion()), wxTextFileType_Unix);
|
||
sendText(wxString::Format("@Load log line %d ...", countLine));
|
||
#undef PG_READ_BUFFER
|
||
delete set;
|
||
|
||
if (countLine == 0)
|
||
{
|
||
wxString msgstr = "@ The server log contains entries in multiple encodings and cannot be displayed by pgAdmin.";
|
||
//wxMessageBox(msgstr);
|
||
sendText(msgstr);
|
||
return;
|
||
}
|
||
|
||
}
|
||
|
||
savedPartialLine.clear();
|
||
|
||
if (!line.IsEmpty())
|
||
{
|
||
// We finished reading to the end of the log file, but still have some data left
|
||
if (csv_log_format)
|
||
{
|
||
savedPartialLine = line; // Save partial log line for next read of the data file.
|
||
line.Clear();
|
||
}
|
||
else
|
||
//my_view->AddRow(line.Trim());
|
||
log_queue->Post(line.Trim());
|
||
//rows.push_back(line.Trim());
|
||
|
||
}
|
||
if (logf==0) sendText(wxString::Format("Done %d", countLine));
|
||
}
|
||
|
||
void frmStatus::OnAddLabelTextThread(wxThreadEvent& event) {
|
||
wxString s = event.GetString();
|
||
if (s.Len()>2 && s[0] == '@') {
|
||
s = s.substr(1);
|
||
statusBar->SetStatusText(s);
|
||
return;
|
||
}
|
||
if (s=="@@") {
|
||
if (event.GetInt()==0) {
|
||
//OnRefreshStatusTimer_After(); //slot==0
|
||
OnRefreshStatusTimer_After();
|
||
CallAfter(&frmStatus::OnRefreshStatusTimer_After);
|
||
}
|
||
if (event.GetInt()==1) OnRefreshQuerystateTimer_After(); //slot==0
|
||
return;
|
||
}
|
||
{
|
||
wxTimerEvent event;
|
||
OnRefreshLogTimer(event);
|
||
}
|
||
|
||
}
|
||
///////////////////////////////
|
||
|
||
void frmStatus::OnRotateLogfile(wxCommandEvent &event)
|
||
{
|
||
if (wxMessageBox(_("Are you sure the logfile should be rotated?"), _("Logfile rotation"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION) == wxYES)
|
||
connection->ExecuteVoid(wxT("select pg_logfile_rotate()"));
|
||
}
|
||
|
||
|
||
void frmStatus::OnCancelBtn(wxCommandEvent &event)
|
||
{
|
||
switch(currentPane)
|
||
{
|
||
case PANE_STATUS:
|
||
OnStatusCancelBtn(event);
|
||
break;
|
||
case PANE_LOCKS:
|
||
OnLocksCancelBtn(event);
|
||
break;
|
||
default:
|
||
// This shouldn't happen. If it does, it's no big deal
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
void frmStatus::OnStatusCancelBtn(wxCommandEvent &event)
|
||
{
|
||
long item = statusList->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||
if (item < 0)
|
||
return;
|
||
|
||
if (wxMessageBox(_("Are you sure you wish to cancel the selected query(s)?"), _("Cancel query?"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION) != wxYES)
|
||
return;
|
||
{
|
||
wxCriticalSectionLocker lock(thread_execute);
|
||
while (item >= 0)
|
||
{
|
||
wxString pid = statusList->GetItemText(item);
|
||
wxString sql = wxT("SELECT pg_cancel_backend(") + pid + wxT(");");
|
||
connection->ExecuteScalar(sql);
|
||
|
||
item = statusList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||
}
|
||
}
|
||
wxMessageBox(_("A cancel signal was sent to the selected server process(es)."), _("Cancel query"), wxOK | wxICON_INFORMATION, this);
|
||
OnRefresh(event);
|
||
wxListEvent ev;
|
||
OnSelStatusItem(ev);
|
||
}
|
||
|
||
|
||
void frmStatus::OnLocksCancelBtn(wxCommandEvent &event)
|
||
{
|
||
long item = lockList->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||
if (item < 0)
|
||
return;
|
||
|
||
if (wxMessageBox(_("Are you sure you wish to cancel the selected query(s)?"), _("Cancel query?"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION) != wxYES)
|
||
return;
|
||
{
|
||
wxCriticalSectionLocker lock(thread_execute);
|
||
while (item >= 0)
|
||
{
|
||
wxString pid = lockList->GetItemText(item);
|
||
wxString sql = wxT("SELECT pg_cancel_backend(") + pid + wxT(");");
|
||
connection->ExecuteScalar(sql);
|
||
|
||
item = lockList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||
}
|
||
}
|
||
wxMessageBox(_("A cancel signal was sent to the selected server process(es)."), _("Cancel query"), wxOK | wxICON_INFORMATION);
|
||
OnRefresh(event);
|
||
wxListEvent ev;
|
||
OnSelLockItem(ev);
|
||
}
|
||
|
||
|
||
void frmStatus::OnTerminateBtn(wxCommandEvent &event)
|
||
{
|
||
switch(currentPane)
|
||
{
|
||
case PANE_STATUS:
|
||
OnStatusTerminateBtn(event);
|
||
break;
|
||
case PANE_LOCKS:
|
||
OnLocksTerminateBtn(event);
|
||
break;
|
||
default:
|
||
// This shouldn't happen. If it does, it's no big deal
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
void frmStatus::OnStatusTerminateBtn(wxCommandEvent &event)
|
||
{
|
||
long item = statusList->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||
if (item < 0)
|
||
return;
|
||
|
||
if (wxMessageBox(_("Are you sure you wish to terminate the selected server process(es)?"), _("Terminate process?"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION) != wxYES)
|
||
return;
|
||
{
|
||
wxCriticalSectionLocker lock(thread_execute);
|
||
while (item >= 0)
|
||
{
|
||
wxString pid = statusList->GetItemText(item);
|
||
wxString sql = wxT("SELECT pg_terminate_backend(") + pid + wxT(");");
|
||
connection->ExecuteScalar(sql);
|
||
|
||
item = statusList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||
}
|
||
}
|
||
wxMessageBox(_("A terminate signal was sent to the selected server process(es)."), _("Terminate process"), wxOK | wxICON_INFORMATION);
|
||
OnRefresh(event);
|
||
wxListEvent ev;
|
||
OnSelStatusItem(ev);
|
||
}
|
||
|
||
|
||
void frmStatus::OnLocksTerminateBtn(wxCommandEvent &event)
|
||
{
|
||
long item = lockList->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||
if (item < 0)
|
||
return;
|
||
|
||
if (wxMessageBox(_("Are you sure you wish to terminate the selected server process(es)?"), _("Terminate process?"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION) != wxYES)
|
||
return;
|
||
{
|
||
wxCriticalSectionLocker lock(thread_execute);
|
||
while (item >= 0)
|
||
{
|
||
wxString pid = lockList->GetItemText(item);
|
||
wxString sql = wxT("SELECT pg_terminate_backend(") + pid + wxT(");");
|
||
connection->ExecuteScalar(sql);
|
||
|
||
item = lockList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||
}
|
||
}
|
||
wxMessageBox(_("A terminate signal was sent to the selected server process(es)."), _("Terminate process"), wxOK | wxICON_INFORMATION);
|
||
OnRefresh(event);
|
||
wxListEvent ev;
|
||
OnSelLockItem(ev);
|
||
}
|
||
|
||
|
||
void frmStatus::OnStatusMenu(wxCommandEvent &event)
|
||
{
|
||
wxListItem column;
|
||
column.SetMask(wxLIST_MASK_TEXT);
|
||
|
||
for (unsigned int i = 0; i < statusPopupMenu->GetMenuItemCount(); i++)
|
||
{
|
||
// Save column's width in a variable so that we can restore the old width
|
||
// if we make this column "invisible"
|
||
int currwidth= statusList->GetColumnWidth(i);
|
||
if (statusList->GetColumnWidth(i) > 0)
|
||
statusColWidth[i] = statusList->GetColumnWidth(i);
|
||
|
||
wxMenuItem *menu = statusPopupMenu->FindItemByPosition(i);
|
||
if (menu && menu->IsChecked())
|
||
statusList->SetColumnWidth(i, statusColWidth[i]);
|
||
else if (statusList->GetColumnWidth(i) > 0)
|
||
statusList->SetColumnWidth(i, 0);
|
||
|
||
// Save current width to restore it at next launch
|
||
statusList->GetColumn(i, column);
|
||
if (currwidth > 0)
|
||
settings->WriteInt(wxT("frmStatus/StatusPane_") + column.GetText() + wxT("_Width"),
|
||
statusColWidth[i]);
|
||
else
|
||
settings->WriteInt(wxT("frmStatus/StatusPane_") + column.GetText() + wxT("_Width"),
|
||
-statusColWidth[i]);
|
||
}
|
||
}
|
||
|
||
|
||
void frmStatus::OnLockMenu(wxCommandEvent &event)
|
||
{
|
||
wxListItem column;
|
||
column.SetMask(wxLIST_MASK_TEXT);
|
||
|
||
for (unsigned int i = 0; i < lockPopupMenu->GetMenuItemCount(); i++)
|
||
{
|
||
// Save column's width in a variable so that we can restore the old width
|
||
// if we make this column "invisible"
|
||
int currwidth = lockList->GetColumnWidth(i);
|
||
if (lockList->GetColumnWidth(i) > 0)
|
||
lockColWidth[i] = lockList->GetColumnWidth(i);
|
||
|
||
wxMenuItem *menu = lockPopupMenu->FindItemByPosition(i);
|
||
if (menu && menu->IsChecked())
|
||
lockList->SetColumnWidth(i, lockColWidth[i]);
|
||
else if (lockList->GetColumnWidth(i) > 0)
|
||
lockList->SetColumnWidth(i, 0);
|
||
|
||
// Save current width to restore it at next launch
|
||
lockList->GetColumn(i, column);
|
||
if (currwidth > 0)
|
||
settings->WriteInt(wxT("frmStatus/LockPane_") + column.GetText() + wxT("_Width"),
|
||
lockColWidth[i]);
|
||
else
|
||
settings->WriteInt(wxT("frmStatus/LockPane_") + column.GetText() + wxT("_Width"),
|
||
-lockColWidth[i]);
|
||
}
|
||
}
|
||
|
||
|
||
void frmStatus::OnXactMenu(wxCommandEvent &event)
|
||
{
|
||
wxListItem column;
|
||
column.SetMask(wxLIST_MASK_TEXT);
|
||
|
||
for (unsigned int i = 0; i < xactPopupMenu->GetMenuItemCount(); i++)
|
||
{
|
||
// Save column's width in a variable so that we can restore the old width
|
||
// if we make this column "invisible"
|
||
int currwidth = xactList->GetColumnWidth(i);
|
||
if (xactList->GetColumnWidth(i) > 0)
|
||
xactColWidth[i] = xactList->GetColumnWidth(i);
|
||
|
||
wxMenuItem *menu = xactPopupMenu->FindItemByPosition(i);
|
||
if (menu && menu->IsChecked())
|
||
xactList->SetColumnWidth(i, xactColWidth[i]);
|
||
else if (xactList->GetColumnWidth(i) > 0)
|
||
xactList->SetColumnWidth(i, 0);
|
||
|
||
// Save current width to restore it at next launch
|
||
xactList->GetColumn(i, column);
|
||
if (currwidth > 0)
|
||
settings->WriteInt(wxT("frmStatus/XactPane_") + column.GetText() + wxT("_Width"),
|
||
xactColWidth[i]);
|
||
else
|
||
settings->WriteInt(wxT("frmStatus/XactPane_") + column.GetText() + wxT("_Width"),
|
||
-xactColWidth[i]);
|
||
}
|
||
}
|
||
void frmStatus::OnQuerystateMenu(wxCommandEvent &event)
|
||
{
|
||
wxListItem column;
|
||
column.SetMask(wxLIST_MASK_TEXT);
|
||
|
||
for (unsigned int i = 0; i < querystatePopupMenu->GetMenuItemCount(); i++)
|
||
{
|
||
// Save column's width in a variable so that we can restore the old width
|
||
// if we make this column "invisible"
|
||
int currwidth=querystateList->GetColumnWidth(i);
|
||
if (querystateList->GetColumnWidth(i) > 0)
|
||
querystateColWidth[i] = querystateList->GetColumnWidth(i);
|
||
|
||
wxMenuItem *menu = querystatePopupMenu->FindItemByPosition(i);
|
||
if (menu && menu->IsChecked())
|
||
querystateList->SetColumnWidth(i, querystateColWidth[i]);
|
||
else if (querystateList->GetColumnWidth(i) > 0)
|
||
querystateList->SetColumnWidth(i, 0);
|
||
|
||
// Save current width to restore it at next launch
|
||
querystateList->GetColumn(i, column);
|
||
if (currwidth > 0)
|
||
settings->WriteInt(wxT("frmStatus/QuerystatePane_") + column.GetText() + wxT("_Width"),
|
||
querystateColWidth[i]);
|
||
else
|
||
settings->WriteInt(wxT("frmStatus/QuerystatePane_") + column.GetText() + wxT("_Width"),
|
||
-querystateColWidth[i]);
|
||
}
|
||
}
|
||
|
||
|
||
void frmStatus::OnCommit(wxCommandEvent &event)
|
||
{
|
||
long item = xactList->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||
if (item < 0)
|
||
return;
|
||
|
||
if (wxMessageBox(_("Are you sure you wish to commit the selected prepared transactions?"), _("Commit transaction?"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION) != wxYES)
|
||
return;
|
||
{
|
||
wxCriticalSectionLocker lock(thread_execute);
|
||
|
||
while (item >= 0)
|
||
{
|
||
wxString xid = xactList->GetText(item, 1);
|
||
wxString sql = wxT("COMMIT PREPARED ") + connection->qtDbString(xid);
|
||
|
||
// We must execute this in the database in which the prepared transaction originated.
|
||
if (connection->GetDbname() != xactList->GetText(item, 4))
|
||
{
|
||
pgConn *tmpConn = new pgConn(connection->GetHost(),
|
||
connection->GetService(),
|
||
connection->GetHostAddr(),
|
||
xactList->GetText(item, 4),
|
||
connection->GetUser(),
|
||
connection->GetPassword(),
|
||
connection->GetPort(),
|
||
connection->GetRole(),
|
||
"",
|
||
connection->GetSslMode(),
|
||
0,
|
||
connection->GetApplicationName(),
|
||
connection->GetSSLCert(),
|
||
connection->GetSSLKey(),
|
||
connection->GetSSLRootCert(),
|
||
connection->GetSSLCrl(),
|
||
connection->GetSSLCompression());
|
||
if (tmpConn)
|
||
{
|
||
if (tmpConn->GetStatus() != PGCONN_OK)
|
||
{
|
||
wxMessageBox(wxT("Connection failed: ") + tmpConn->GetLastError());
|
||
return ;
|
||
}
|
||
tmpConn->ExecuteScalar(sql);
|
||
|
||
tmpConn->Close();
|
||
delete tmpConn;
|
||
}
|
||
}
|
||
else
|
||
connection->ExecuteScalar(sql);
|
||
|
||
item = xactList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||
}
|
||
}
|
||
OnRefresh(event);
|
||
wxListEvent ev;
|
||
OnSelXactItem(ev);
|
||
}
|
||
|
||
void frmStatus::OnRollback(wxCommandEvent &event)
|
||
{
|
||
long item = xactList->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||
if (item < 0)
|
||
return;
|
||
|
||
if (wxMessageBox(_("Are you sure you wish to rollback the selected prepared transactions?"), _("Rollback transaction?"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION) != wxYES)
|
||
return;
|
||
{
|
||
wxCriticalSectionLocker lock(thread_execute);
|
||
|
||
while (item >= 0)
|
||
{
|
||
wxString xid = xactList->GetText(item, 1);
|
||
wxString sql = wxT("ROLLBACK PREPARED ") + connection->qtDbString(xid);
|
||
|
||
// We must execute this in the database in which the prepared transaction originated.
|
||
if (connection->GetDbname() != xactList->GetText(item, 4))
|
||
{
|
||
pgConn *tmpConn = new pgConn(connection->GetHost(),
|
||
connection->GetService(),
|
||
connection->GetHostAddr(),
|
||
xactList->GetText(item, 4),
|
||
connection->GetUser(),
|
||
connection->GetPassword(),
|
||
connection->GetPort(),
|
||
connection->GetRole(),
|
||
"",
|
||
connection->GetSslMode(),
|
||
0,
|
||
connection->GetApplicationName(),
|
||
connection->GetSSLCert(),
|
||
connection->GetSSLKey(),
|
||
connection->GetSSLRootCert(),
|
||
connection->GetSSLCrl(),
|
||
connection->GetSSLCompression());
|
||
if (tmpConn)
|
||
{
|
||
if (tmpConn->GetStatus() != PGCONN_OK)
|
||
{
|
||
wxMessageBox(wxT("Connection failed: ") + tmpConn->GetLastError());
|
||
return ;
|
||
}
|
||
tmpConn->ExecuteScalar(sql);
|
||
|
||
tmpConn->Close();
|
||
delete tmpConn;
|
||
}
|
||
}
|
||
else
|
||
connection->ExecuteScalar(sql);
|
||
|
||
item = xactList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||
}
|
||
}
|
||
OnRefresh(event);
|
||
wxListEvent ev;
|
||
OnSelXactItem(ev);
|
||
}
|
||
|
||
|
||
void frmStatus::OnSelStatusItem(wxListEvent &event)
|
||
{
|
||
#ifdef __WXGTK__1
|
||
manager.GetPane(wxT("Activity")).SetFlag(wxAuiPaneInfo::optionActive, true);
|
||
manager.GetPane(wxT("Locks")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Transactions")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Logfile")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Querystate")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.Update();
|
||
#endif
|
||
currentPane = PANE_STATUS;
|
||
cbRate->SetValue(rateToCboString(statusRate));
|
||
statusList->SetFocus();
|
||
ActivatePane("Activity");
|
||
if (connection && connection->BackendMinimumVersion(8, 0))
|
||
{
|
||
if(statusList->GetSelectedItemCount() > 0)
|
||
{
|
||
toolBar->EnableTool(MNU_CANCEL, true);
|
||
actionMenu->Enable(MNU_CANCEL, true);
|
||
if (connection->HasFeature(FEATURE_TERMINATE_BACKEND))
|
||
{
|
||
toolBar->EnableTool(MNU_TERMINATE, true);
|
||
actionMenu->Enable(MNU_TERMINATE, true);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
toolBar->EnableTool(MNU_CANCEL, false);
|
||
actionMenu->Enable(MNU_CANCEL, false);
|
||
toolBar->EnableTool(MNU_TERMINATE, false);
|
||
actionMenu->Enable(MNU_TERMINATE, false);
|
||
}
|
||
}
|
||
toolBar->EnableTool(MNU_COMMIT, false);
|
||
actionMenu->Enable(MNU_COMMIT, false);
|
||
toolBar->EnableTool(MNU_ROLLBACK, false);
|
||
actionMenu->Enable(MNU_ROLLBACK, false);
|
||
cbLogfiles->Enable(false);
|
||
btnRotateLog->Enable(false);
|
||
|
||
editMenu->Enable(MNU_COPY, statusList->GetFirstSelected() >= 0);
|
||
actionMenu->Enable(MNU_COPY_QUERY, statusList->GetFirstSelected() >= 0);
|
||
toolBar->EnableTool(MNU_COPY_QUERY, statusList->GetFirstSelected() >= 0);
|
||
|
||
//OnRefresh(event);
|
||
wxTimerEvent evt;
|
||
OnRefreshStatusTimer(evt);
|
||
OnRefreshLocksTimer(evt);
|
||
OnRefreshXactTimer(evt);
|
||
OnRefreshQuerystateTimer(evt);
|
||
|
||
}
|
||
|
||
|
||
void frmStatus::OnSelLockItem(wxListEvent &event)
|
||
{
|
||
#ifdef __WXGTK__1
|
||
manager.GetPane(wxT("Activity")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Locks")).SetFlag(wxAuiPaneInfo::optionActive, true);
|
||
manager.GetPane(wxT("Transactions")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Logfile")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Querystate")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.Update();
|
||
#endif
|
||
currentPane = PANE_LOCKS;
|
||
lockList->SetFocus();
|
||
ActivatePane("Locks");
|
||
cbRate->SetValue(rateToCboString(locksRate));
|
||
if (connection && connection->BackendMinimumVersion(8, 0))
|
||
{
|
||
if(lockList->GetSelectedItemCount() > 0)
|
||
{
|
||
toolBar->EnableTool(MNU_CANCEL, true);
|
||
actionMenu->Enable(MNU_CANCEL, true);
|
||
if (connection->HasFeature(FEATURE_TERMINATE_BACKEND))
|
||
{
|
||
toolBar->EnableTool(MNU_TERMINATE, true);
|
||
actionMenu->Enable(MNU_TERMINATE, true);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
toolBar->EnableTool(MNU_CANCEL, false);
|
||
actionMenu->Enable(MNU_CANCEL, false);
|
||
toolBar->EnableTool(MNU_TERMINATE, false);
|
||
actionMenu->Enable(MNU_TERMINATE, false);
|
||
}
|
||
}
|
||
toolBar->EnableTool(MNU_COMMIT, false);
|
||
actionMenu->Enable(MNU_COMMIT, false);
|
||
toolBar->EnableTool(MNU_ROLLBACK, false);
|
||
actionMenu->Enable(MNU_ROLLBACK, false);
|
||
cbLogfiles->Enable(false);
|
||
btnRotateLog->Enable(false);
|
||
|
||
editMenu->Enable(MNU_COPY, lockList->GetFirstSelected() >= 0);
|
||
actionMenu->Enable(MNU_COPY_QUERY, false);
|
||
toolBar->EnableTool(MNU_COPY_QUERY, false);
|
||
}
|
||
|
||
|
||
void frmStatus::OnSelXactItem(wxListEvent &event)
|
||
{
|
||
#ifdef __WXGTK__1
|
||
manager.GetPane(wxT("Activity")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Locks")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Transactions")).SetFlag(wxAuiPaneInfo::optionActive, true);
|
||
manager.GetPane(wxT("Logfile")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Querystate")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.Update();
|
||
#endif
|
||
currentPane = PANE_XACT;
|
||
xactList->SetFocus();
|
||
ActivatePane("Transactions");
|
||
cbRate->SetValue(rateToCboString(xactRate));
|
||
if(xactList->GetSelectedItemCount() > 0)
|
||
{
|
||
toolBar->EnableTool(MNU_COMMIT, true);
|
||
actionMenu->Enable(MNU_COMMIT, true);
|
||
toolBar->EnableTool(MNU_ROLLBACK, true);
|
||
actionMenu->Enable(MNU_ROLLBACK, true);
|
||
}
|
||
else
|
||
{
|
||
toolBar->EnableTool(MNU_COMMIT, false);
|
||
actionMenu->Enable(MNU_COMMIT, false);
|
||
toolBar->EnableTool(MNU_ROLLBACK, false);
|
||
actionMenu->Enable(MNU_ROLLBACK, false);
|
||
}
|
||
toolBar->EnableTool(MNU_CANCEL, false);
|
||
actionMenu->Enable(MNU_CANCEL, false);
|
||
toolBar->EnableTool(MNU_TERMINATE, false);
|
||
actionMenu->Enable(MNU_TERMINATE, false);
|
||
cbLogfiles->Enable(false);
|
||
btnRotateLog->Enable(false);
|
||
|
||
editMenu->Enable(MNU_COPY, xactList->GetFirstSelected() >= 0);
|
||
actionMenu->Enable(MNU_COPY_QUERY, false);
|
||
toolBar->EnableTool(MNU_COPY_QUERY, false);
|
||
}
|
||
|
||
void frmStatus::OnSelQuerystateItem(wxListEvent &event)
|
||
{
|
||
#ifdef __WXGTK__1
|
||
manager.GetPane(wxT("Activity")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Locks")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Transactions")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Logfile")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Querystate")).SetFlag(wxAuiPaneInfo::optionActive, true);
|
||
manager.Update();
|
||
#endif
|
||
currentPane = PANE_QUERYSTATE;
|
||
querystateList->SetFocus();
|
||
ActivatePane("Querystate");
|
||
cbRate->SetValue(rateToCboString(querystateRate));
|
||
{
|
||
toolBar->EnableTool(MNU_COMMIT, false);
|
||
actionMenu->Enable(MNU_COMMIT, false);
|
||
toolBar->EnableTool(MNU_ROLLBACK, false);
|
||
actionMenu->Enable(MNU_ROLLBACK, false);
|
||
}
|
||
toolBar->EnableTool(MNU_CANCEL, false);
|
||
actionMenu->Enable(MNU_CANCEL, false);
|
||
toolBar->EnableTool(MNU_TERMINATE, false);
|
||
actionMenu->Enable(MNU_TERMINATE, false);
|
||
cbLogfiles->Enable(false);
|
||
btnRotateLog->Enable(false);
|
||
|
||
editMenu->Enable(MNU_COPY, querystateList->GetFirstSelected() >= 0);
|
||
actionMenu->Enable(MNU_COPY_QUERY, false);
|
||
toolBar->EnableTool(MNU_COPY_QUERY, false);
|
||
}
|
||
|
||
void frmStatus::ActivatePane(wxString name) {
|
||
if (!manager.GetPane(name).HasFlag(wxAuiPaneInfo::optionActive)) {
|
||
//manager.GetPane("Logfile").HasFlag(wxAuiPaneInfo::optionActive);
|
||
int i, pane_count;
|
||
wxAuiPaneInfo* active_paneinfo = NULL;
|
||
for (unsigned int i = 0; i < manager.GetAllPanes().GetCount(); i++)
|
||
{
|
||
wxAuiPaneInfo& pane = manager.GetAllPanes()[i];
|
||
pane.state &= ~wxAuiPaneInfo::optionActive;
|
||
if (pane.name == name)
|
||
{
|
||
pane.state |= wxAuiPaneInfo::optionActive;
|
||
active_paneinfo = &pane;
|
||
}
|
||
}
|
||
if (active_paneinfo) manager.Update();
|
||
}
|
||
}
|
||
|
||
|
||
void frmStatus::OnSelLogItem(wxListEvent &event)
|
||
{
|
||
#ifdef __WXGTK__1
|
||
manager.GetPane(wxT("Activity")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Locks")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Transactions")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.GetPane(wxT("Logfile")).SetFlag(wxAuiPaneInfo::optionActive, true);
|
||
manager.GetPane(wxT("Querystate")).SetFlag(wxAuiPaneInfo::optionActive, false);
|
||
manager.Update();
|
||
#endif
|
||
currentPane = PANE_LOG;
|
||
cbRate->SetValue(rateToCboString(logRate));
|
||
logList->SetFocus();
|
||
ActivatePane("Logfile");
|
||
// if there's no log, don't enable items
|
||
if (logDirectory != wxT("-"))
|
||
{
|
||
cbLogfiles->Enable(true);
|
||
btnRotateLog->Enable(true);
|
||
toolBar->EnableTool(MNU_CANCEL, false);
|
||
toolBar->EnableTool(MNU_TERMINATE, false);
|
||
toolBar->EnableTool(MNU_COMMIT, false);
|
||
toolBar->EnableTool(MNU_ROLLBACK, false);
|
||
actionMenu->Enable(MNU_CANCEL, false);
|
||
actionMenu->Enable(MNU_TERMINATE, false);
|
||
actionMenu->Enable(MNU_COMMIT, false);
|
||
actionMenu->Enable(MNU_ROLLBACK, false);
|
||
}
|
||
|
||
editMenu->Enable(MNU_COPY, logList->GetFirstSelected() >= 0);
|
||
actionMenu->Enable(MNU_COPY_QUERY, false);
|
||
toolBar->EnableTool(MNU_COPY_QUERY, false);
|
||
event.Skip();
|
||
}
|
||
|
||
|
||
void frmStatus::SetColumnImage(ctlListView *list, int col, int image)
|
||
{
|
||
wxListItem item;
|
||
item.SetMask(wxLIST_MASK_IMAGE);
|
||
item.SetImage(image);
|
||
list->SetColumn(col, item);
|
||
}
|
||
|
||
void frmStatus::OnRightClickStatusItem(wxListEvent& event)
|
||
{
|
||
int row = event.GetIndex();
|
||
//wxString txt = event.GetText();
|
||
if ((row<0) || (row>=statusList->GetItemCount())) return;
|
||
wxRect r;
|
||
//statusList->GetItemRect(row, r);
|
||
wxString ss = wxEmptyString;
|
||
int col = -1;
|
||
for (int cc = 0; cc < statusList->GetColumnCount();cc++) {
|
||
statusList->GetSubItemRect(row, cc, r, wxLIST_RECT_BOUNDS);
|
||
if (r.Contains(event.GetPoint())) {
|
||
ss = wxString::Format("\rBounding rect of item %d column %d is (%d, %d)-(%d, %d)", row,cc, r.x, r.y, r.x + r.width, r.y + r.height);
|
||
col = cc;
|
||
break;
|
||
}
|
||
}
|
||
if (col == -1) return;
|
||
wxString val=statusList->GetItemText(row, col);
|
||
wxString txt = wxString::Format("gettext=%s\r index=%d\r column=%d", val.c_str(), row, col);
|
||
txt = txt + ss;
|
||
|
||
wxListItem listitem;
|
||
listitem.SetMask(wxLIST_MASK_TEXT);
|
||
statusList->GetColumn(col, listitem);
|
||
wxString label = listitem.GetText()+" = "+val;
|
||
//wxMessageBox(txt, "test", wxICON_WARNING | wxOK);
|
||
wxString hint=label;
|
||
if (filterColumn.size() > 0) hint = toolBar->GetToolShortHelp(MNU_CLEAR_FILTER_SERVER_STATUS)+"\n"+label;
|
||
filterColumn.Add(col);
|
||
filterValue.Add(val);
|
||
toolBar->SetToolShortHelp(MNU_CLEAR_FILTER_SERVER_STATUS, hint);
|
||
toolBar->EnableTool(MNU_CLEAR_FILTER_SERVER_STATUS, true);
|
||
toolBar->EnableTool(MNU_SET_FILTER_HIGHLIGHT_STATUS, false);
|
||
|
||
wxTimerEvent evt;
|
||
OnRefreshStatusTimer(evt);
|
||
}
|
||
|
||
void frmStatus::OnSetHighlightFilter(wxCommandEvent& event) {
|
||
toolBar->SetToolShortHelp(MNU_CLEAR_FILTER_SERVER_STATUS, "");
|
||
toolBar->EnableTool(MNU_CLEAR_FILTER_SERVER_STATUS, true);
|
||
toolBar->EnableTool(MNU_SET_FILTER_HIGHLIGHT_STATUS, false);
|
||
onlyhightligth = true;
|
||
}
|
||
void frmStatus::OnClearFilter(wxCommandEvent& event) {
|
||
toolBar->EnableTool(MNU_CLEAR_FILTER_SERVER_STATUS, false);
|
||
toolBar->EnableTool(MNU_SET_FILTER_HIGHLIGHT_STATUS, true);
|
||
|
||
toolBar->SetToolShortHelp(MNU_CLEAR_FILTER_SERVER_STATUS, "Clear filter");
|
||
filterColumn.Clear();
|
||
filterValue.Clear();
|
||
onlyhightligth = false;
|
||
wxTimerEvent evt;
|
||
OnRefreshStatusTimer(evt);
|
||
|
||
}
|
||
|
||
void frmStatus::OnSortStatusGrid(wxListEvent &event)
|
||
{
|
||
// Get the information for the SQL ORDER BY
|
||
if (event.GetColumn()<0) return;
|
||
if (statusSortColumn == event.GetColumn() + 1)
|
||
{
|
||
if (statusSortOrder == wxT("ASC"))
|
||
statusSortOrder = wxT("DESC");
|
||
else
|
||
statusSortOrder = wxT("ASC");
|
||
}
|
||
else
|
||
{
|
||
statusSortColumn = event.GetColumn() + 1;
|
||
statusSortOrder = wxT("ASC");
|
||
}
|
||
|
||
|
||
// Re-initialize all columns' image
|
||
for (int i = 0; i < statusList->GetColumnCount(); i++)
|
||
{
|
||
SetColumnImage(statusList, i, -1);
|
||
}
|
||
|
||
// Set the up/down image
|
||
if (statusSortOrder == wxT("ASC"))
|
||
SetColumnImage(statusList, statusSortColumn - 1, 0);
|
||
else
|
||
SetColumnImage(statusList, statusSortColumn - 1, 1);
|
||
|
||
// Refresh grid
|
||
wxTimerEvent evt;
|
||
OnRefreshStatusTimer(evt);
|
||
}
|
||
|
||
|
||
void frmStatus::OnSortLockGrid(wxListEvent &event)
|
||
{
|
||
// Get the information for the SQL ORDER BY
|
||
if (lockSortColumn == event.GetColumn() + 1)
|
||
{
|
||
if (lockSortOrder == wxT("ASC"))
|
||
lockSortOrder = wxT("DESC");
|
||
else
|
||
lockSortOrder = wxT("ASC");
|
||
}
|
||
else
|
||
{
|
||
lockSortColumn = event.GetColumn() + 1;
|
||
lockSortOrder = wxT("ASC");
|
||
}
|
||
|
||
// There are no sort operator for xid before 8.3
|
||
if (!connection->BackendMinimumVersion(8, 3) && lockSortColumn == 5)
|
||
{
|
||
wxLogError(_("You cannot sort by transaction id on your PostgreSQL release. You need at least 8.3."));
|
||
lockSortColumn = 1;
|
||
}
|
||
|
||
// Re-initialize all columns' image
|
||
for (int i = 0; i < lockList->GetColumnCount(); i++)
|
||
{
|
||
SetColumnImage(lockList, i, -1);
|
||
}
|
||
|
||
// Set the up/down image
|
||
if (lockSortOrder == wxT("ASC"))
|
||
SetColumnImage(lockList, lockSortColumn - 1, 0);
|
||
else
|
||
SetColumnImage(lockList, lockSortColumn - 1, 1);
|
||
|
||
// Refresh grid
|
||
wxTimerEvent evt;
|
||
OnRefreshLocksTimer(evt);
|
||
}
|
||
|
||
|
||
void frmStatus::OnSortXactGrid(wxListEvent &event)
|
||
{
|
||
// Get the information for the SQL ORDER BY
|
||
if (xactSortColumn == event.GetColumn() + 1)
|
||
{
|
||
if (xactSortOrder == wxT("ASC"))
|
||
xactSortOrder = wxT("DESC");
|
||
else
|
||
xactSortOrder = wxT("ASC");
|
||
}
|
||
else
|
||
{
|
||
xactSortColumn = event.GetColumn() + 1;
|
||
xactSortOrder = wxT("ASC");
|
||
}
|
||
|
||
// There are no sort operator for xid before 8.3
|
||
if (!connection->BackendMinimumVersion(8, 3) && xactSortColumn == 1)
|
||
{
|
||
wxLogError(_("You cannot sort by transaction id on your PostgreSQL release. You need at least 8.3."));
|
||
xactSortColumn = 2;
|
||
}
|
||
|
||
// Re-initialize all columns' image
|
||
for (int i = 0; i < xactList->GetColumnCount(); i++)
|
||
{
|
||
SetColumnImage(xactList, i, -1);
|
||
}
|
||
|
||
// Set the up/down image
|
||
if (xactSortOrder == wxT("ASC"))
|
||
SetColumnImage(xactList, xactSortColumn - 1, 0);
|
||
else
|
||
SetColumnImage(xactList, xactSortColumn - 1, 1);
|
||
|
||
// Refresh grid
|
||
wxTimerEvent evt;
|
||
OnRefreshXactTimer(evt);
|
||
}
|
||
|
||
|
||
void frmStatus::OnRightClickStatusGrid(wxListEvent &event)
|
||
{
|
||
statusList->PopupMenu(statusPopupMenu, event.GetPoint());
|
||
}
|
||
|
||
void frmStatus::OnRightClickLockGrid(wxListEvent &event)
|
||
{
|
||
lockList->PopupMenu(lockPopupMenu, event.GetPoint());
|
||
}
|
||
|
||
void frmStatus::OnRightClickXactGrid(wxListEvent &event)
|
||
{
|
||
xactList->PopupMenu(xactPopupMenu, event.GetPoint());
|
||
}
|
||
void frmStatus::OnRightClickQuerystateGrid(wxListEvent &event)
|
||
{
|
||
querystateList->PopupMenu(querystatePopupMenu, event.GetPoint());
|
||
}
|
||
void frmStatus::OnLogContextMenu(wxCommandEvent& event) {
|
||
nav->OnContextMenu(event);
|
||
}
|
||
int count = 0;
|
||
void frmStatus::OnTimerHintLog(wxTimerEvent& event)
|
||
{
|
||
delayHitLog->Stop();
|
||
wxPoint pm = logList->GetScreenPosition();
|
||
wxRect rc = logList->GetSize();
|
||
wxPoint m = wxGetMousePosition();
|
||
rc.x = pm.x;
|
||
rc.y = pm.y;
|
||
count++;
|
||
//statusBar->SetStatusText(wxString::Format(" TIMER COUNT %d x:%d,y:%d",count, m.x, m.y));
|
||
if (!rc.Contains(m)) {
|
||
}
|
||
else {
|
||
wxPoint curr = logList->ScreenToClient(m);
|
||
if (lastmouse == m && lastlogitem != -1 && lastlogitemShow != lastlogitem) {
|
||
{
|
||
wxString s;
|
||
if (m_Popup != NULL) {
|
||
delete m_Popup;
|
||
m_Popup = NULL;
|
||
}
|
||
else {
|
||
}
|
||
s = logList->GetTextLong(lastlogitem);
|
||
lastlogitemShow = lastlogitem;
|
||
lastlogitem = -1;
|
||
wxSize rr(350, 25);
|
||
//
|
||
wxString key = "content";
|
||
int x, y;
|
||
wxPoint p = m;
|
||
p.x = p.x + 5;
|
||
p.y = p.y + 5;
|
||
PreviewHtml v;
|
||
wxString tt = v.Preview(s, fmtpreview::CSV);
|
||
s = tt;
|
||
FunctionPGHelper fh(s);
|
||
fh.SetTimerClose(1500);
|
||
//m_Popup = new popuphelp((wxWindow*)winMain, key, &fh, p, rr);
|
||
m_Popup = new popuphelp(this, key, &fh, p, rr);
|
||
if (m_Popup && m_Popup->IsValid() && rr != m_Popup->GetSizePopup()) {
|
||
// recreate with new size
|
||
rr = m_Popup->GetSizePopup();
|
||
delete m_Popup;
|
||
m_Popup = new popuphelp(this, key, &fh, p, rr);
|
||
}
|
||
if (m_Popup && m_Popup->IsValid()) {
|
||
//m_PopupHelp->UpdateWindowUI(true);
|
||
wxSize top_sz = m_Popup->GetSizePopup();
|
||
wxPoint posScreen;
|
||
wxSize sizeScreen;
|
||
const int displayNum = wxDisplay::GetFromPoint(p);
|
||
if (displayNum != wxNOT_FOUND)
|
||
{
|
||
const wxRect rectScreen = wxDisplay(displayNum).GetGeometry();
|
||
posScreen = rectScreen.GetPosition();
|
||
sizeScreen = rectScreen.GetSize();
|
||
}
|
||
else // outside of any display?
|
||
{
|
||
// just use the primary one then
|
||
posScreen = wxPoint(0, 0);
|
||
sizeScreen = wxGetDisplaySize();
|
||
}
|
||
wxSize top_new(top_sz);
|
||
wxPoint oldp(p);
|
||
if (p.x + top_new.x > sizeScreen.x) p.x = sizeScreen.x - top_new.x - 20;
|
||
if (p.y + top_new.y > sizeScreen.y) p.y = sizeScreen.y - top_new.y - 20;
|
||
if (oldp == p) p.x = p.x + 20;
|
||
m_Popup->Move(p);
|
||
wxRect r = m_Popup->GetScreenRect();
|
||
//m_PopupHelp->Position(p, wxSize(0, 17));
|
||
m_Popup->Popup();
|
||
//wxPopupTransientWindow
|
||
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|
||
void frmStatus::OnCmdFindStrLog(wxCommandEvent& event) {
|
||
wxString s = event.GetString();
|
||
//statusBar->SetStatusText(wxString::Format(" FIND CMD: %s",s));
|
||
nav->SetFindString(s);
|
||
}
|
||
void frmStatus::OnMoveMouseLog(wxMouseEvent& event)
|
||
{
|
||
// wxMenu* logListPopupMenu;
|
||
// logListPopupMenu = nav->GetPopupMenu();
|
||
wxPoint mp = event.GetPosition();
|
||
lastmouse = wxGetMousePosition();
|
||
int flags = wxLIST_HITTEST_ONITEMLABEL;
|
||
long item=logList->HitTest(mp,flags);
|
||
//logList->PopupMenu(logListPopupMenu, event.GetPoint());
|
||
// statusBar->SetStatusText(wxString::Format("x:%d,y:%d",lastmouse.x,lastmouse.y));
|
||
wxString s;
|
||
|
||
if (lastlogitem != -1 || lastlogitem != item) {
|
||
#define DELAYHITLOGPERIOD 1000
|
||
delayHitLog->Stop();
|
||
if (logList->GetAutoHint()) delayHitLog->StartOnce(DELAYHITLOGPERIOD);
|
||
}
|
||
else
|
||
delayHitLog->Stop();
|
||
lastlogitem = item;
|
||
event.Skip();
|
||
return;
|
||
}
|
||
|
||
void frmStatus::OnRightClickLogGrid(wxListEvent& event)
|
||
{
|
||
delayHitLog->Stop();
|
||
lastmouse = wxGetMousePosition();
|
||
wxTimerEvent tm;
|
||
//logList->GetItem();
|
||
//int flags = wxLIST_HITTEST_ONITEMLABEL;
|
||
//long item=logList->HitTest(mp,flags);
|
||
long item=event.GetIndex();
|
||
lastlogitem=item;
|
||
lastlogitemShow=-1;
|
||
OnTimerHintLog(tm);
|
||
// wxMenu* logListPopupMenu;
|
||
// logListPopupMenu = nav->GetPopupMenu();
|
||
// logList->PopupMenu(logListPopupMenu, event.GetPoint());
|
||
}
|
||
|
||
|
||
void frmStatus::OnChgColSizeStatusGrid(wxListEvent &event)
|
||
{
|
||
wxCommandEvent ev;
|
||
OnStatusMenu(ev);
|
||
}
|
||
|
||
void frmStatus::OnChgColSizeLockGrid(wxListEvent &event)
|
||
{
|
||
wxCommandEvent ev;
|
||
OnLockMenu(ev);
|
||
}
|
||
|
||
void frmStatus::OnChgColSizeXactGrid(wxListEvent &event)
|
||
{
|
||
wxCommandEvent ev;
|
||
OnXactMenu(ev);
|
||
}
|
||
|
||
void frmStatus::OnChgColSizeQuerystateGrid(wxListEvent &event)
|
||
{
|
||
wxCommandEvent ev;
|
||
OnQuerystateMenu(ev);
|
||
}
|
||
|
||
|
||
serverStatusFactory::serverStatusFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : actionFactory(list)
|
||
{
|
||
mnu->Append(id, _("&Server Status\tCtrl-S"), _("Displays the current database status."));
|
||
}
|
||
|
||
|
||
wxWindow *serverStatusFactory::StartDialog(frmMain *form, pgObject *obj)
|
||
{
|
||
|
||
pgServer *server = obj->GetServer();
|
||
wxString applicationname = appearanceFactory->GetLongAppName() + wxT(" - Server Status");
|
||
|
||
pgConn *conn = server->CreateConn(wxEmptyString, 0, applicationname);
|
||
if (conn)
|
||
{
|
||
wxString txt = server->GetDescription()
|
||
+ wxT(" (") + server->GetName() + wxT(":") + NumToStr((long)server->GetPort()) + wxT(")");
|
||
|
||
frmStatus *status = new frmStatus(form, txt, conn);
|
||
status->Go();
|
||
return status;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
bool serverStatusFactory::CheckEnable(pgObject *obj)
|
||
{
|
||
return obj && obj->GetServer() != 0;
|
||
}
|