mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 06:05:49 -06:00
1073 lines
30 KiB
C++
1073 lines
30 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// pgAdmin III - PostgreSQL Tools
|
|
//
|
|
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
// dlgDirectDbg.cpp - debugger
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "pgAdmin3.h"
|
|
|
|
// wxWindows headers
|
|
#include <wx/wx.h>
|
|
#include <wx/grid.h>
|
|
|
|
// App headers
|
|
#include "ctl/ctlAuiNotebook.h"
|
|
#include "db/pgConn.h"
|
|
#include "db/pgQueryThread.h"
|
|
#include "db/pgQueryResultEvent.h"
|
|
#include "schema/pgObject.h"
|
|
#include "debugger/dbgConst.h"
|
|
#include "debugger/dbgBreakPoint.h"
|
|
#include "debugger/dbgController.h"
|
|
#include "debugger/dbgModel.h"
|
|
#include "debugger/ctlStackWindow.h"
|
|
#include "debugger/ctlMessageWindow.h"
|
|
#include "debugger/ctlTabWindow.h"
|
|
#include "debugger/frmDebugger.h"
|
|
#include "debugger/dlgDirectDbg.h"
|
|
|
|
#include "images/debugger.pngc"
|
|
|
|
#define lblMessage CTRL_STATIC("lblMessage")
|
|
#define grdParams CTRL("grdParams", wxGrid)
|
|
#define chkPkgInit CTRL_CHECKBOX("chkPkgInit")
|
|
#define btnDebug CTRL_BUTTON("wxID_OK")
|
|
|
|
IMPLEMENT_CLASS(dlgDirectDbg, pgDialog)
|
|
|
|
BEGIN_EVENT_TABLE(dlgDirectDbg, pgDialog)
|
|
EVT_BUTTON(wxID_OK, dlgDirectDbg::OnOk)
|
|
EVT_BUTTON(wxID_CANCEL, dlgDirectDbg::OnCancel)
|
|
EVT_GRID_CMD_LABEL_LEFT_CLICK(XRCID("grdParams"), dlgDirectDbg::OnClickGridLabel)
|
|
EVT_MENU(RESULT_ID_ARGS_UPDATED, dlgDirectDbg::ResultArgsUpdated)
|
|
EVT_MENU(RESULT_ID_ARGS_UPDATE_ERROR, dlgDirectDbg::ResultArgsUpdateError)
|
|
END_EVENT_TABLE()
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// dlgDirectDbg constructor
|
|
//
|
|
// This class implements 'direct-debugging'. In direct-debugging, the user
|
|
// provides a function signature, procedure signature, or OID on the command
|
|
// line (this identifies the debug target). We query the server for the
|
|
// names, types, and in/out modes for each target parameter and then prompt
|
|
// the user to enter a value for each of the IN (and IN/OUT) parameters.
|
|
//
|
|
// When the user fills in the parameter values and clicks OK, we set a
|
|
// breakpoint at the target and then execute a SELECT statement or an
|
|
// EXEC statement that invokes the target (with the parameter values
|
|
// provided by the user).
|
|
|
|
dlgDirectDbg::dlgDirectDbg(frmDebugger *_parent, dbgController *_controller,
|
|
pgConn *_conn)
|
|
: m_controller(_controller), m_thread(NULL), m_conn(_conn)
|
|
{
|
|
int width, height, totalWidth = 0;
|
|
|
|
SetFont(settings->GetSystemFont());
|
|
LoadResource(_parent, wxT("dlgDirectDbg"));
|
|
|
|
// Icon
|
|
SetIcon(*debugger_png_ico);
|
|
RestorePosition();
|
|
|
|
grdParams->SetRowLabelSize(wxGRID_AUTOSIZE);
|
|
grdParams->SetColLabelSize(20);
|
|
grdParams->AutoSizeColumns(true);
|
|
|
|
chkPkgInit->SetValue(false);
|
|
|
|
PopulateParamGrid();
|
|
|
|
LoadSettings();
|
|
|
|
for(int i = 0; i < grdParams->GetNumberCols(); i++)
|
|
grdParams->AutoSizeColumn(i, true);
|
|
|
|
if (grdParams->GetNumberCols() > 1)
|
|
{
|
|
// Extend grid to it's parent width
|
|
grdParams->GetClientSize(&width, &height);
|
|
for (int i = 0; i < grdParams->GetNumberCols(); i++)
|
|
{
|
|
totalWidth += grdParams->GetColSize(i);
|
|
}
|
|
// Total client width - total six column widths - the first (an empty) column
|
|
// width
|
|
grdParams->SetColSize(COL_DEF_VAL, width - totalWidth - 100);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// PopulateParamGrid()
|
|
//
|
|
// This function reads parameter descriptions from m_targetInfo and adds a
|
|
// new row to the grid control for each IN (or IN/OUT, VARAIADIC) parameter.
|
|
// Each row displays the parameter name, the data type, and an entry box
|
|
// where the user can type in a value for that parameter
|
|
//
|
|
void dlgDirectDbg::PopulateParamGrid()
|
|
{
|
|
pgDbgArgs *args = m_controller->GetTargetInfo()->GetArgs();
|
|
|
|
// If the target is defined within package, offer the user
|
|
// a chance to debug the initializer (there may or may not
|
|
// be an initializer, we don't really know at this point)
|
|
if(m_controller->GetTargetInfo()->GetPkgOid() == 0)
|
|
chkPkgInit->Disable();
|
|
else
|
|
chkPkgInit->Enable();
|
|
|
|
if (!args)
|
|
{
|
|
grdParams->CreateGrid(0, 1);
|
|
grdParams->SetColLabelValue(COL_NAME, _("No arguments required"));
|
|
grdParams->SetColSize(0, 350);
|
|
|
|
return;
|
|
}
|
|
|
|
// Add seven columns to the grid control:
|
|
// - Name, Type, NULL?, EXPR?, Value, Default?, And Default Value
|
|
grdParams->CreateGrid(0, 7);
|
|
|
|
grdParams->SetColLabelValue(COL_NAME, _("Name"));
|
|
grdParams->SetColLabelValue(COL_TYPE, _("Type"));
|
|
grdParams->SetColLabelValue(COL_NULL, _("Null?"));
|
|
grdParams->SetColLabelValue(COL_EXPR, _("Expression?"));
|
|
grdParams->SetColLabelValue(COL_VALUE, _("Value"));
|
|
grdParams->SetColLabelValue(COL_USE_DEF, _("Use default?"));
|
|
grdParams->SetColLabelValue(COL_DEF_VAL, _("Default Value"));
|
|
|
|
size_t idx = 0;
|
|
|
|
for(size_t pIdx = 0; pIdx < args->Count(); pIdx++)
|
|
{
|
|
dbgArgInfo *arg = (*args)[pIdx];
|
|
|
|
// If this is an IN parameter (or an IN/OUT parameter), add
|
|
// a new row to the grid
|
|
if(arg->GetMode() != pgParam::PG_PARAM_OUT)
|
|
{
|
|
grdParams->AppendRows(1);
|
|
grdParams->SetCellValue(idx, COL_NAME, arg->GetName());
|
|
|
|
// Make it obvious which are variadics
|
|
if (arg->GetMode() != pgParam::PG_PARAM_VARIADIC)
|
|
{
|
|
grdParams->SetRowLabelValue(idx, wxEmptyString);
|
|
grdParams->SetCellValue(idx, COL_TYPE, arg->GetTypeName());
|
|
|
|
if (!arg->IsArray())
|
|
{
|
|
// Is the value an expression?
|
|
grdParams->SetCellEditor(idx, COL_EXPR, new ctlGridCellBoolEditor());
|
|
grdParams->SetCellRenderer(idx, COL_EXPR, new wxGridCellBoolRenderer());
|
|
grdParams->SetCellValue(idx, COL_EXPR, wxT(""));
|
|
}
|
|
else
|
|
{
|
|
grdParams->SetCellBackgroundColour(idx, COL_EXPR, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(idx, COL_VALUE, wxColour(235, 235, 235, 90));
|
|
}
|
|
|
|
// Use the default value?
|
|
grdParams->SetCellRenderer(idx, COL_USE_DEF, new wxGridCellBoolRenderer());
|
|
grdParams->SetCellEditor(idx, COL_USE_DEF, new ctlGridCellBoolEditor());
|
|
}
|
|
else
|
|
{
|
|
grdParams->SetCellValue(idx, COL_TYPE, wxT("VARIADIC ") + arg->GetTypeName());
|
|
grdParams->SetRowLabelValue(idx, wxEmptyString);
|
|
|
|
grdParams->AppendRows(1);
|
|
grdParams->SetRowLabelValue(idx + 1, wxT("+"));
|
|
grdParams->SetCellValue(idx + 1, COL_NAME, _("Click '+/-' to add/remove value to variadic"));
|
|
|
|
grdParams->SetCellBackgroundColour(idx + 1, COL_EXPR, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(idx + 1, COL_VALUE, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(idx + 1, COL_USE_DEF, wxColour(235, 235, 235, 90));
|
|
}
|
|
|
|
// Set value to NULL?
|
|
grdParams->SetCellEditor(idx, COL_NULL, new ctlGridCellBoolEditor(arg));
|
|
grdParams->SetCellRenderer(idx, COL_NULL, new wxGridCellBoolRenderer());
|
|
grdParams->SetCellValue(idx, COL_NULL, wxT(""));
|
|
|
|
if (arg->HasDefault())
|
|
{
|
|
// Whenever the default value is available, use that by default
|
|
grdParams->SetCellValue(idx, COL_USE_DEF, wxT("1"));
|
|
grdParams->SetCellValue(idx, COL_DEF_VAL, arg->Default());
|
|
|
|
// When "Use Defalut?" is enabled, disable VALUE, NULL? and
|
|
// EXPR? columns
|
|
grdParams->SetReadOnly(idx, COL_USE_DEF, false);
|
|
grdParams->SetReadOnly(idx, COL_VALUE, false);
|
|
grdParams->SetReadOnly(idx, COL_EXPR, false);
|
|
}
|
|
else
|
|
{
|
|
grdParams->SetCellValue(idx, COL_USE_DEF, wxT(""));
|
|
grdParams->SetCellValue(idx, COL_DEF_VAL, _("<No default value>"));
|
|
|
|
// When default value is not available, we should ask the user
|
|
// to enter them
|
|
grdParams->SetReadOnly(idx, COL_USE_DEF, true);
|
|
grdParams->SetReadOnly(idx, COL_VALUE, arg->IsArray());
|
|
grdParams->SetReadOnly(idx, COL_EXPR, arg->IsArray());
|
|
|
|
grdParams->SetCellBackgroundColour(idx, COL_USE_DEF, wxColour(235, 235, 235, 90));
|
|
if (arg->IsArray())
|
|
{
|
|
grdParams->SetCellBackgroundColour(idx, COL_VALUE, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(idx, COL_EXPR, wxColour(235, 235, 235, 90));
|
|
}
|
|
}
|
|
|
|
grdParams->SetReadOnly(idx, COL_NULL, false);
|
|
grdParams->SetReadOnly(idx, COL_NAME, true);
|
|
grdParams->SetReadOnly(idx, COL_TYPE, true);
|
|
grdParams->SetReadOnly(idx, COL_DEF_VAL, true);
|
|
grdParams->SetCellBackgroundColour(idx, COL_NAME, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(idx, COL_TYPE, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(idx, COL_DEF_VAL, wxColour(235, 235, 235, 90));
|
|
|
|
idx++;
|
|
|
|
if (arg->GetMode() != pgParam::PG_PARAM_VARIADIC &&
|
|
arg->IsArray())
|
|
{
|
|
grdParams->AppendRows(1);
|
|
|
|
grdParams->SetRowLabelValue(idx, wxT("+"));
|
|
grdParams->SetCellValue(idx, COL_NAME, _("Click '+/-' to add/remove value to the array"));
|
|
|
|
grdParams->SetReadOnly(idx, COL_NAME, true);
|
|
grdParams->SetReadOnly(idx, COL_TYPE, true);
|
|
grdParams->SetReadOnly(idx, COL_NULL, true);
|
|
grdParams->SetReadOnly(idx, COL_EXPR, true);
|
|
grdParams->SetReadOnly(idx, COL_VALUE, true);
|
|
grdParams->SetReadOnly(idx, COL_USE_DEF, true);
|
|
grdParams->SetReadOnly(idx, COL_DEF_VAL, true);
|
|
|
|
grdParams->SetCellBackgroundColour(idx, COL_NAME, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(idx, COL_TYPE, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(idx, COL_NULL, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(idx, COL_EXPR, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(idx, COL_VALUE, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(idx, COL_USE_DEF, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(idx, COL_DEF_VAL, wxColour(235, 235, 235, 90));
|
|
|
|
idx++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Move the cursor to the first value (so that the user
|
|
// can just start typing)
|
|
|
|
grdParams->SetGridCursor(0, COL_VALUE);
|
|
grdParams->SetFocus();
|
|
}
|
|
|
|
void dlgDirectDbg::LoadLastCellSetting(int row_number, int parameter_index,
|
|
int index_array_bound, bool isArray)
|
|
{
|
|
wxString lastValue, valKey;
|
|
dbgTargetInfo *target = m_controller->GetTargetInfo();
|
|
long num;
|
|
|
|
settings->Read(wxT("Debugger/Proc/OID"), &num, -1L);
|
|
if(num != target->GetOid())
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if(!isArray)
|
|
{
|
|
// Non array elements cell index is 0
|
|
valKey = wxString::Format(wxT("Debugger/Proc/%d/0/"), parameter_index);
|
|
settings->Read(valKey + wxT("VAL"), &lastValue, wxEmptyString);
|
|
grdParams->SetCellValue(row_number, COL_VALUE, lastValue);
|
|
}
|
|
else
|
|
{
|
|
long arrCnt;
|
|
|
|
settings->Read(
|
|
wxString::Format(
|
|
wxT("Debugger/Proc/%d/"), parameter_index)
|
|
+ wxT("ArrCnt"), &arrCnt, 0L);
|
|
|
|
// Refresh an entire array element
|
|
for( int i = 0; i <= index_array_bound && i <= arrCnt - 1; i++ )
|
|
{
|
|
valKey = wxString::Format(wxT("Debugger/Proc/%d/%d/"), parameter_index, i);
|
|
settings->Read(valKey + wxT("VAL"), &lastValue, wxEmptyString);
|
|
grdParams->SetCellValue(row_number - index_array_bound + i, COL_VALUE,
|
|
lastValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// LoadSettings()
|
|
//
|
|
// Loads default values from our .ini file. We save the OID of the most
|
|
// recent direct-debugging target when close a session. If we're direct-
|
|
// debugging the same target this time around, we load the argument values
|
|
// from the .ini file.
|
|
void dlgDirectDbg::LoadSettings()
|
|
{
|
|
long num, arrCnt;
|
|
wxString tmp, key;
|
|
bool initPkgCon = false;
|
|
|
|
settings->Read(wxT("Debugger/Proc/OID"), &num, -1L);
|
|
|
|
dbgTargetInfo *target = m_controller->GetTargetInfo();
|
|
pgDbgArgs *args = m_controller->GetTargetInfo()->GetArgs();
|
|
|
|
if (num != target->GetOid())
|
|
{
|
|
chkPkgInit->SetValue(target->GetPkgInitOid() != 0L);
|
|
chkPkgInit->Enable(target->GetPkgInitOid() != 0L);
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
settings->Read(wxT("Debugger/Proc/initialize_package_constructor"), &initPkgCon, true);
|
|
|
|
chkPkgInit->SetValue(&initPkgCon && target->GetPkgInitOid() != 0L);
|
|
chkPkgInit->Enable(target->GetPkgInitOid() != 0L);
|
|
}
|
|
|
|
settings->Read(wxT("Debugger/Proc/args"), &num, 0L);
|
|
|
|
if (num <= 0L)
|
|
return;
|
|
|
|
if (!args)
|
|
return;
|
|
|
|
for (int cnt = 0, row = 0; cnt < num && cnt < (int)args->Count();)
|
|
{
|
|
ctlGridCellBoolEditor *editor =
|
|
dynamic_cast<ctlGridCellBoolEditor *>(
|
|
grdParams->GetCellEditor(row, COL_NULL));
|
|
dbgArgInfo *arg
|
|
= editor != NULL ? editor->GetArg() : NULL;
|
|
|
|
if (arg == NULL)
|
|
{
|
|
row++;
|
|
|
|
continue;
|
|
}
|
|
|
|
key = wxString::Format(wxT("Debugger/Proc/%d/"), cnt);
|
|
|
|
// Use NULL?
|
|
settings->Read(key + wxT("NULL"), &tmp, wxEmptyString);
|
|
grdParams->SetCellValue(row, COL_NULL, tmp);
|
|
|
|
// Use Default (if available)
|
|
settings->Read(key + wxT("USE_DEF"), &tmp, wxEmptyString);
|
|
grdParams->SetCellValue(row, COL_USE_DEF, tmp);
|
|
|
|
// Is Array/VARIADIC?
|
|
settings->Read(key + wxT("ArrCnt"), &arrCnt, 0L);
|
|
|
|
if (arrCnt > 0L)
|
|
{
|
|
// An individual variable can be an expression or can be the 'NULL' value
|
|
wxString valKey, strVal, strExpr, strNull;
|
|
|
|
for (int idx = 0; idx < arrCnt; idx++, row++)
|
|
{
|
|
valKey = wxString::Format(wxT("Debugger/Proc/%d/%d/"), cnt, idx);
|
|
|
|
// Use 'NULL'?
|
|
settings->Read(valKey + wxT("NULL"), &strNull, wxEmptyString);
|
|
|
|
// Use EXPR?
|
|
settings->Read(valKey + wxT("EXPR"), &strExpr, wxEmptyString);
|
|
|
|
// Value
|
|
settings->Read(valKey + wxT("VAL"), &strVal, wxEmptyString);
|
|
|
|
if (arg->IsArray())
|
|
{
|
|
int arrRow = row + 1;
|
|
|
|
if (idx == 0)
|
|
{
|
|
grdParams->SetReadOnly(row, COL_EXPR, true);
|
|
grdParams->SetReadOnly(row, COL_VALUE, true);
|
|
|
|
grdParams->SetCellBackgroundColour(row, COL_EXPR, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(row, COL_VALUE, wxColour(235, 235, 235, 90));
|
|
|
|
grdParams->SetRowLabelValue(
|
|
row, wxString::Format(wxT("%d"), cnt + 1));
|
|
}
|
|
grdParams->InsertRows(arrRow, 1, false);
|
|
grdParams->SetRowLabelValue(arrRow, wxT("-"));
|
|
|
|
grdParams->SetCellValue(arrRow, COL_TYPE, arg->GetBaseType());
|
|
|
|
// Is the value an expression?
|
|
grdParams->SetCellEditor(arrRow, COL_EXPR, new ctlGridCellBoolEditor());
|
|
grdParams->SetCellRenderer(arrRow, COL_EXPR,
|
|
new wxGridCellBoolRenderer());
|
|
grdParams->SetCellValue(arrRow, COL_EXPR, strExpr);
|
|
|
|
// Set value to NULL?
|
|
grdParams->SetCellEditor(arrRow, COL_NULL,
|
|
new ctlGridCellBoolEditor(arg));
|
|
grdParams->SetCellRenderer(arrRow, COL_NULL,
|
|
new wxGridCellBoolRenderer());
|
|
grdParams->SetCellValue(arrRow, COL_NULL, strNull);
|
|
|
|
// Set value
|
|
grdParams->SetCellValue(arrRow, COL_VALUE, strVal);
|
|
|
|
grdParams->SetReadOnly(arrRow, COL_NULL, false);
|
|
grdParams->SetReadOnly(arrRow, COL_EXPR, false);
|
|
grdParams->SetReadOnly(arrRow, COL_VALUE, false);
|
|
|
|
grdParams->SetCellBackgroundColour(arrRow, COL_NAME, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(arrRow, COL_TYPE, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(arrRow, COL_USE_DEF, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(arrRow, COL_DEF_VAL, wxColour(235, 235, 235, 90));
|
|
|
|
grdParams->SetReadOnly(arrRow + 1, COL_NAME, true);
|
|
grdParams->SetReadOnly(arrRow + 1, COL_TYPE, true);
|
|
grdParams->SetReadOnly(arrRow + 1, COL_NULL, true);
|
|
grdParams->SetReadOnly(arrRow + 1, COL_EXPR, true);
|
|
grdParams->SetReadOnly(arrRow + 1, COL_VALUE, true);
|
|
grdParams->SetReadOnly(arrRow + 1, COL_USE_DEF, true);
|
|
grdParams->SetReadOnly(arrRow + 1, COL_DEF_VAL, true);
|
|
|
|
grdParams->SetCellBackgroundColour(arrRow + 1, COL_NAME, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(arrRow + 1, COL_TYPE, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(arrRow + 1, COL_NULL, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(arrRow + 1, COL_EXPR, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(arrRow + 1, COL_VALUE, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(arrRow + 1, COL_USE_DEF,
|
|
wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(arrRow + 1, COL_DEF_VAL,
|
|
wxColour(235, 235, 235, 90));
|
|
|
|
grdParams->SetRowLabelValue(arrRow + 1, wxT("+"));
|
|
}
|
|
else
|
|
{
|
|
grdParams->SetCellValue(row, COL_VALUE, strVal);
|
|
grdParams->SetCellValue(row, COL_EXPR, strExpr);
|
|
grdParams->SetCellValue(row, COL_NULL, strNull);
|
|
|
|
grdParams->SetReadOnly(row, COL_NULL, false);
|
|
grdParams->SetReadOnly(row, COL_EXPR, false);
|
|
grdParams->SetReadOnly(row, COL_VALUE, false);
|
|
|
|
grdParams->SetRowLabelValue(
|
|
row, wxString::Format(wxT("%d"), cnt + 1));
|
|
}
|
|
}
|
|
if (arg->IsArray())
|
|
row++;
|
|
}
|
|
cnt++;
|
|
}
|
|
}
|
|
|
|
|
|
void dlgDirectDbg::OnOk(wxCommandEvent &_ev)
|
|
{
|
|
if (m_thread)
|
|
return;
|
|
|
|
grdParams->Enable(false);
|
|
btnDebug->Enable(false);
|
|
|
|
m_thread = new dbgArgValueEvaluator(m_conn, this);
|
|
|
|
if (m_thread->Create() != wxTHREAD_NO_ERROR)
|
|
{
|
|
delete m_thread;
|
|
m_thread = NULL;
|
|
|
|
wxLogError(_("Failed to create a debugging thread."));
|
|
EndModal(wxID_CANCEL);
|
|
|
|
return;
|
|
}
|
|
|
|
m_thread->Run();
|
|
}
|
|
|
|
|
|
void dlgDirectDbg::OnCancel(wxCommandEvent &_ev)
|
|
{
|
|
if (m_thread)
|
|
{
|
|
if (m_thread->IsRunning())
|
|
{
|
|
m_thread->CancelEval();
|
|
m_thread->Wait();
|
|
}
|
|
|
|
delete m_thread;
|
|
m_thread = NULL;
|
|
}
|
|
_ev.Skip();
|
|
}
|
|
|
|
void dlgDirectDbg::OnClickGridLabel(wxGridEvent &_ev)
|
|
{
|
|
if (_ev.AltDown() || _ev.ControlDown() || _ev.ShiftDown())
|
|
{
|
|
_ev.Skip();
|
|
|
|
return;
|
|
}
|
|
|
|
int row = _ev.GetRow();
|
|
int col = _ev.GetCol();
|
|
|
|
if (row < 0 || col > 0)
|
|
{
|
|
_ev.Skip();
|
|
|
|
return;
|
|
}
|
|
|
|
wxString strLabel = grdParams->GetRowLabelValue(row);
|
|
|
|
if (strLabel == wxT("+"))
|
|
{
|
|
wxASSERT(row != 0);
|
|
|
|
ctlGridCellBoolEditor *editor =
|
|
dynamic_cast<ctlGridCellBoolEditor *>(
|
|
grdParams->GetCellEditor(row - 1, COL_NULL));
|
|
dbgArgInfo *arg
|
|
= editor != NULL ? editor->GetArg() : NULL;
|
|
|
|
grdParams->InsertRows(row, 1, false);
|
|
grdParams->SetRowLabelValue(row, wxT("-"));
|
|
|
|
grdParams->SetCellValue(row, COL_TYPE, arg->GetBaseType());
|
|
grdParams->SetCellBackgroundColour(row, COL_TYPE, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(row, COL_NAME, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(row, COL_USE_DEF, wxColour(235, 235, 235, 90));
|
|
grdParams->SetCellBackgroundColour(row, COL_DEF_VAL, wxColour(235, 235, 235, 90));
|
|
|
|
// Is the value an expression?
|
|
grdParams->SetCellEditor(row, COL_EXPR, new ctlGridCellBoolEditor());
|
|
grdParams->SetCellRenderer(row, COL_EXPR, new wxGridCellBoolRenderer());
|
|
grdParams->SetCellValue(row, COL_EXPR, wxT(""));
|
|
|
|
// Set value to NULL?
|
|
grdParams->SetCellEditor(row, COL_NULL, new ctlGridCellBoolEditor(arg));
|
|
grdParams->SetCellRenderer(row, COL_NULL, new wxGridCellBoolRenderer());
|
|
grdParams->SetCellValue(row, COL_NULL, wxT("1"));
|
|
|
|
row++;
|
|
grdParams->SetRowLabelValue(row, wxT("+"));
|
|
}
|
|
else if (strLabel == wxT("-"))
|
|
{
|
|
dbgArgInfo *arg = NULL;
|
|
grdParams->DeleteRows(row, 1, false);
|
|
}
|
|
else
|
|
return;
|
|
|
|
// Update the row labels
|
|
ctlGridCellBoolEditor *editor = NULL;
|
|
dbgArgInfo *arg = NULL,
|
|
*prev = NULL;
|
|
wxString strName;
|
|
|
|
int totalRows = grdParams->GetNumberRows(),
|
|
idx = 0;
|
|
row = 0;
|
|
|
|
while (row < totalRows)
|
|
{
|
|
editor =
|
|
dynamic_cast<ctlGridCellBoolEditor *>(
|
|
grdParams->GetCellEditor(row, COL_NULL));
|
|
arg = editor != NULL ? editor->GetArg() : NULL;
|
|
strName = grdParams->GetCellValue(row, COL_NAME);
|
|
|
|
if (strName.IsEmpty() && arg)
|
|
grdParams->SetRowLabelValue(row, wxT("-"));
|
|
else if (!strName.IsEmpty() && !arg)
|
|
grdParams->SetRowLabelValue(row, wxT("+"));
|
|
else
|
|
{
|
|
idx++;
|
|
grdParams->SetRowLabelValue(row, wxString::Format(wxT("%d"), idx));
|
|
}
|
|
|
|
row++;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// SaveSettings()
|
|
//
|
|
// Save default values to our .ini file. We save the OID of the most
|
|
// recent direct-debugging target when close a session. We also save the
|
|
// value of each argument - if you debug the same target again next time,
|
|
// loadSettings() will initialize the parameter-values window with the
|
|
// same parameter values that you entered in this session.
|
|
//
|
|
void dlgDirectDbg::SaveSettings()
|
|
{
|
|
wxString strName, strExpr, strVal, strNull, strDef, strKey, strValExpr;
|
|
dbgArgInfo *prev = NULL,
|
|
*arg = NULL;
|
|
int row = 0,
|
|
idx = -1,
|
|
arrCnt = 1;
|
|
|
|
// Save the current function/procedure/trigger OID
|
|
settings->WriteLong(wxT("Debugger/Proc/OID"),
|
|
m_controller->GetTargetInfo()->GetOid());
|
|
|
|
// Save - whether we need to debug the package constructor
|
|
settings->WriteBool(wxT("Debugger/Proc/initialize_package_constructor"),
|
|
(chkPkgInit->IsEnabled() && chkPkgInit->GetValue()));
|
|
|
|
for (; row < grdParams->GetNumberRows(); row++)
|
|
{
|
|
ctlGridCellBoolEditor *editor =
|
|
dynamic_cast<ctlGridCellBoolEditor *>(
|
|
grdParams->GetCellEditor(row, COL_NULL));
|
|
arg = editor != NULL ? editor->GetArg() : NULL;
|
|
|
|
// This should be the information for add/remove values for an array
|
|
if (arg == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
else if (prev != arg)
|
|
{
|
|
idx++;
|
|
prev = arg;
|
|
|
|
if (arg->IsArray())
|
|
{
|
|
arrCnt = 0;
|
|
}
|
|
else
|
|
{
|
|
arrCnt = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
arrCnt++;
|
|
}
|
|
|
|
settings->WriteInt(wxString::Format(wxT("Debugger/Proc/%d/ArrCnt"), idx), arrCnt);
|
|
|
|
if ((arrCnt == 0 && arg->IsArray()) ||
|
|
(arrCnt == 1 && !arg->IsArray()))
|
|
{
|
|
// Use Default (if available)
|
|
settings->Write(wxString::Format(wxT("Debugger/Proc/%d/USE_DEF"), idx),
|
|
grdParams->GetCellValue(row, COL_USE_DEF));
|
|
|
|
// Use NULL?
|
|
settings->Write(wxString::Format(wxT("Debugger/Proc/%d/NULL"), idx),
|
|
grdParams->GetCellValue(row, COL_NULL));
|
|
|
|
if (arrCnt == 0 && arg->IsArray())
|
|
continue;
|
|
}
|
|
|
|
strKey = wxString::Format(wxT("Debugger/Proc/%d/%d/"), idx, arrCnt - 1);
|
|
|
|
// Use NULL?
|
|
settings->Write(strKey + wxT("NULL"),
|
|
grdParams->GetCellValue(row, COL_NULL));
|
|
|
|
// Is value EXPR?
|
|
settings->Write(strKey + wxT("EXPR"),
|
|
grdParams->GetCellValue(row, COL_EXPR));
|
|
|
|
// Value
|
|
settings->Write(strKey + wxT("VAL"),
|
|
grdParams->GetCellValue(row, COL_VALUE));
|
|
}
|
|
|
|
// Save the number of arguments
|
|
settings->WriteLong(wxT("Debugger/Proc/args"), (long)(idx + 1));
|
|
}
|
|
|
|
|
|
ctlGridCellBoolEditor::ctlGridCellBoolEditor(dbgArgInfo *_arg)
|
|
: m_arg(_arg)
|
|
{}
|
|
|
|
|
|
void ctlGridCellBoolEditor::BeginEdit(int _row, int _col, wxGrid *_grid)
|
|
{
|
|
wxGridCellBoolEditor::BeginEdit(_row, _col, _grid);
|
|
|
|
wxFocusEvent event (wxEVT_KILL_FOCUS);
|
|
if (m_control)
|
|
{
|
|
m_control->GetEventHandler()->AddPendingEvent(event);
|
|
}
|
|
}
|
|
|
|
|
|
wxGrid *dlgDirectDbg::GetParamsGrid()
|
|
{
|
|
return grdParams;
|
|
}
|
|
|
|
bool dlgDirectDbg::DebugPkgConstructor()
|
|
{
|
|
return chkPkgInit->IsEnabled() && chkPkgInit->GetValue();
|
|
}
|
|
|
|
|
|
wxGridCellEditor *ctlGridCellBoolEditor::Clone() const
|
|
{
|
|
return new ctlGridCellBoolEditor(m_arg);
|
|
}
|
|
|
|
|
|
void dlgDirectDbg::ResultArgsUpdated(wxCommandEvent &_ev)
|
|
{
|
|
SaveSettings();
|
|
SavePosition();
|
|
|
|
if (m_thread)
|
|
{
|
|
if (m_thread->IsRunning())
|
|
{
|
|
m_thread->CancelEval();
|
|
m_thread->Wait();
|
|
}
|
|
|
|
delete m_thread;
|
|
m_thread = NULL;
|
|
}
|
|
|
|
if (IsModal())
|
|
EndModal(wxID_OK);
|
|
else
|
|
Destroy();
|
|
}
|
|
|
|
|
|
void dlgDirectDbg::ResultArgsUpdateError(wxCommandEvent &_ev)
|
|
{
|
|
if (_ev.GetInt() == pgQueryResultEvent::PGQ_CONN_LOST)
|
|
{
|
|
if(wxMessageBox(
|
|
_("Connection to the database server lost!\nDo you want to try to reconnect to the server?"),
|
|
_("Connection Lost"), wxICON_ERROR | wxICON_QUESTION | wxYES_NO) == wxID_YES)
|
|
{
|
|
if (m_thread)
|
|
{
|
|
if (m_thread->IsRunning())
|
|
{
|
|
m_thread->CancelEval();
|
|
m_thread->Wait();
|
|
}
|
|
|
|
delete m_thread;
|
|
m_thread = NULL;
|
|
}
|
|
m_conn->Reconnect();
|
|
|
|
return;
|
|
}
|
|
EndModal(wxID_CANCEL);
|
|
|
|
return;
|
|
}
|
|
|
|
if (m_thread)
|
|
{
|
|
if (m_thread->IsRunning())
|
|
{
|
|
m_thread->CancelEval();
|
|
m_thread->Wait();
|
|
}
|
|
|
|
delete m_thread;
|
|
m_thread = NULL;
|
|
}
|
|
|
|
wxLogError(_ev.GetString());
|
|
|
|
grdParams->Enable(true);
|
|
btnDebug->Enable(true);
|
|
}
|
|
|
|
|
|
void dbgArgValueEvaluator::NoticeHandler(void *, const char *)
|
|
{
|
|
// Ignore the notices
|
|
}
|
|
|
|
|
|
void *dbgArgValueEvaluator::Entry()
|
|
{
|
|
bool argNull, nullVal, useDef;
|
|
wxString strVal, strValExpr;
|
|
dbgArgInfo *prev = NULL,
|
|
*arg = NULL;
|
|
|
|
wxGrid *grd = m_dlg->GetParamsGrid();
|
|
|
|
m_dlg->m_controller->GetTargetInfo()->DebugPackageConstructor()
|
|
= m_dlg->DebugPkgConstructor();
|
|
|
|
m_conn->RegisterNoticeProcessor(dbgArgValueEvaluator::NoticeHandler, NULL);
|
|
|
|
for (int row = 0, idx = 0, arrCnt = 1, arr_idx_bound = 0;
|
|
row < grd->GetNumberRows() && !m_cancelled; row++)
|
|
{
|
|
ctlGridCellBoolEditor *editor =
|
|
dynamic_cast<ctlGridCellBoolEditor *>(
|
|
grd->GetCellEditor(row, dlgDirectDbg::COL_NULL));
|
|
arg = editor != NULL ? editor->GetArg() : NULL;
|
|
|
|
// This should be the information for add/remove values for an array
|
|
if (arg == NULL)
|
|
{
|
|
// prev was an array, can we fetch value for the same
|
|
if (prev && !prev->Null())
|
|
{
|
|
wxString res =
|
|
m_conn->ExecuteScalar(
|
|
wxT("SELECT ARRAY[") + strValExpr + wxT("]::") + prev->GetTypeName(),
|
|
false);
|
|
|
|
if (m_cancelled)
|
|
{
|
|
m_conn->RegisterNoticeProcessor(NULL, NULL);
|
|
|
|
return (void *)NULL;
|
|
}
|
|
if (m_conn->GetStatus() == PGCONN_BAD)
|
|
{
|
|
wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, RESULT_ID_ARGS_UPDATE_ERROR);
|
|
|
|
ev.SetInt(pgQueryResultEvent::PGQ_CONN_LOST);
|
|
|
|
m_dlg->GetEventHandler()->AddPendingEvent(ev);
|
|
|
|
m_conn->RegisterNoticeProcessor(NULL, NULL);
|
|
|
|
return (void *)NULL;
|
|
}
|
|
if (m_conn->GetLastResultStatus() == PGRES_TUPLES_OK)
|
|
{
|
|
prev->Value() = res;
|
|
}
|
|
else
|
|
{
|
|
wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, RESULT_ID_ARGS_UPDATE_ERROR);
|
|
wxString strName = prev->GetName();
|
|
wxString strMsg;
|
|
|
|
if (strName.IsEmpty())
|
|
{
|
|
ev.SetString(
|
|
wxString::Format(
|
|
_("The specified value for argument #%d is not valid.\nPlease re-enter the value for it."),
|
|
idx));
|
|
}
|
|
else
|
|
{
|
|
ev.SetString(
|
|
wxString::Format(
|
|
_("Specified value for argument '%s' is not valid.\nPlease re-enter the value for it."),
|
|
strName.c_str()));
|
|
}
|
|
ev.SetInt(pgQueryResultEvent::PGQ_RESULT_ERROR);
|
|
m_dlg->LoadLastCellSetting(row - 1, idx - 1, arr_idx_bound - 1, true);
|
|
m_dlg->GetEventHandler()->AddPendingEvent(ev);
|
|
|
|
m_conn->RegisterNoticeProcessor(NULL, NULL);
|
|
|
|
return (void *)NULL;
|
|
|
|
}
|
|
prev = NULL;
|
|
arr_idx_bound = 0;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
else if (prev != arg)
|
|
{
|
|
idx++;
|
|
argNull = false;
|
|
nullVal = false;
|
|
useDef = false;
|
|
|
|
strValExpr = wxEmptyString;
|
|
}
|
|
|
|
if (prev != arg)
|
|
{
|
|
prev = arg;
|
|
|
|
// Use Default (if available)
|
|
arg->UseDefault() = wxGridCellBoolEditor::IsTrueValue(
|
|
grd->GetCellValue(row, dlgDirectDbg::COL_USE_DEF));
|
|
// NULL?
|
|
arg->Null() = wxGridCellBoolEditor::IsTrueValue(
|
|
grd->GetCellValue(row, dlgDirectDbg::COL_NULL));
|
|
|
|
if (arg->UseDefault())
|
|
strValExpr = arg->Default();
|
|
|
|
if (arg->IsArray())
|
|
continue;
|
|
}
|
|
|
|
// Use NULL?
|
|
//
|
|
// Keep this just before 'Use Default' column as - we may have non-empty
|
|
// value in the 'VAL' column
|
|
|
|
if (!arg->UseDefault() || !arg->Null())
|
|
{
|
|
if (!strValExpr.IsEmpty())
|
|
{
|
|
strValExpr += wxT(", ");
|
|
}
|
|
|
|
if (wxGridCellBoolEditor::IsTrueValue(
|
|
grd->GetCellValue(row, dlgDirectDbg::COL_NULL)))
|
|
{
|
|
strValExpr += wxT("NULL");
|
|
}
|
|
else if (wxGridCellBoolEditor::IsTrueValue(
|
|
grd->GetCellValue(row, dlgDirectDbg::COL_EXPR)))
|
|
{
|
|
strValExpr += wxT("(") + grd->GetCellValue(row, dlgDirectDbg::COL_VALUE) + wxT(")");
|
|
}
|
|
else
|
|
{
|
|
strValExpr += m_conn->qtDbString(
|
|
grd->GetCellValue(row, dlgDirectDbg::COL_VALUE));
|
|
}
|
|
strValExpr.Append(wxT("::"))
|
|
.Append(arg->IsArray() ?
|
|
arg->GetBaseType() : arg->GetTypeName());
|
|
|
|
if(arg->IsArray())
|
|
{
|
|
arr_idx_bound ++;
|
|
}
|
|
}
|
|
|
|
if (!arg->IsArray() && !arg->Null())
|
|
{
|
|
pgSet *set =
|
|
m_conn->ExecuteSet(wxT("SELECT ") + strValExpr, false);
|
|
|
|
if (m_cancelled)
|
|
{
|
|
return (void *)NULL;
|
|
}
|
|
if (m_conn->GetStatus() == PGCONN_BAD)
|
|
{
|
|
wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, RESULT_ID_ARGS_UPDATE_ERROR);
|
|
|
|
ev.SetString(_("Connection to the database server lost!"));
|
|
ev.SetInt(pgQueryResultEvent::PGQ_CONN_LOST);
|
|
|
|
m_dlg->GetEventHandler()->AddPendingEvent(ev);
|
|
|
|
m_conn->RegisterNoticeProcessor(NULL, NULL);
|
|
|
|
if (set)
|
|
delete set;
|
|
|
|
return (void *)NULL;
|
|
}
|
|
if (m_conn->GetLastResultStatus() == PGRES_TUPLES_OK &&
|
|
set && set->NumRows() > 0L)
|
|
{
|
|
if (set->IsNull(0))
|
|
{
|
|
arg->Null() = true;
|
|
}
|
|
else
|
|
{
|
|
arg->Null() = false;
|
|
arg->Value() = set->GetVal(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wxString strName = arg->GetName();
|
|
|
|
if (strName.IsEmpty())
|
|
strName = wxString::Format(_("Param#%d"), idx);
|
|
|
|
wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, RESULT_ID_ARGS_UPDATE_ERROR);
|
|
|
|
ev.SetString(
|
|
wxString::Format(_("Please re-enter the value for argument '%s'."),
|
|
strName.c_str()));
|
|
ev.SetInt(pgQueryResultEvent::PGQ_RESULT_ERROR);
|
|
|
|
m_dlg->GetEventHandler()->AddPendingEvent(ev);
|
|
m_dlg->LoadSettings();
|
|
// For scalar variable, always index of array bound is 0.
|
|
m_dlg->LoadLastCellSetting(row, idx - 1, 0, false);
|
|
m_conn->RegisterNoticeProcessor(NULL, NULL);
|
|
|
|
return (void *)NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, RESULT_ID_ARGS_UPDATED);
|
|
m_dlg->GetEventHandler()->AddPendingEvent(ev);
|
|
|
|
m_conn->RegisterNoticeProcessor(NULL, NULL);
|
|
|
|
return (void *)NULL;
|
|
}
|
|
|
|
|
|
void dbgArgValueEvaluator::CancelEval()
|
|
{
|
|
m_cancelled = true;
|
|
|
|
if (m_conn->GetTxStatus() == PGCONN_TXSTATUS_ACTIVE)
|
|
m_conn->CancelExecution();
|
|
}
|
|
|
|
dbgArgValueEvaluator::dbgArgValueEvaluator(pgConn *_conn, dlgDirectDbg *_dlg)
|
|
: wxThread(wxTHREAD_JOINABLE), m_conn(_conn), m_dlg(_dlg), m_cancelled(false)
|
|
{}
|