~ubuntu-branches/ubuntu/utopic/pgadmin3/utopic-proposed

« back to all changes in this revision

Viewing changes to pgadmin/debugger/dlgDirectDbg.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Gerfried Fuchs
  • Date: 2011-06-07 23:03:54 UTC
  • mfrom: (1.3.1 upstream) (13 sid)
  • mto: This revision was merged to the branch mainline in revision 14.
  • Revision ID: james.westby@ubuntu.com-20110607230354-3td4j9y71u4ahcvj
Tags: 1.14.0~beta1-1
* New upstream development release, adding Build-Depends on
  postgresql-server-dev-all >= 117~.
* Add Build-Depends on quilt, (un)patch to debian/rules and patch for fixing
  the include for kwlist.h in pgadmin/db/keywords.c.
* Add pg_config --includedir-server output to CPPFLAGS.
* Remove unrecognized configure options: --with-wx-config,
  --with-pgsql-include, --enable-gtk2, --enable-unicode.
* Clean up manually the files that are left behind after the broken
  distclean.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
//////////////////////////////////////////////////////////////////////////
2
2
//
3
3
// pgAdmin III - PostgreSQL Tools
4
 
// 
5
 
// Copyright (C) 2002 - 2010, The pgAdmin Development Team
 
4
//
 
5
// Copyright (C) 2002 - 2011, The pgAdmin Development Team
6
6
// This software is released under the PostgreSQL Licence
7
7
//
8
 
// dlgDirectDbg.cpp - debugger 
 
8
// dlgDirectDbg.cpp - debugger
9
9
//
10
10
//////////////////////////////////////////////////////////////////////////
11
11
 
26
26
#include "debugger/dbgDbResult.h"
27
27
#include "debugger/ctlCodeWindow.h"
28
28
 
29
 
#include "images/debugger.xpm"
 
29
#include "images/debugger.pngc"
30
30
 
31
31
#include <stdexcept>
32
32
 
37
37
IMPLEMENT_CLASS( dlgDirectDbg, pgDialog )
38
38
 
39
39
BEGIN_EVENT_TABLE( dlgDirectDbg, pgDialog )
40
 
    EVT_BUTTON( wxID_OK,                    dlgDirectDbg::OnOk )
41
 
    EVT_BUTTON( wxID_CANCEL,                dlgDirectDbg::OnCancel )    
42
 
    EVT_BUTTON( MENU_ID_SPAWN_DEBUGGER,  dlgDirectDbg::OnDebug )
43
 
    EVT_BUTTON( MENU_ID_NOTICE_RECEIVED, dlgDirectDbg::OnNoticeReceived )
44
 
 
45
 
    EVT_MENU( RESULT_ID_DIRECT_TARGET_COMPLETE, dlgDirectDbg::OnTargetComplete )
46
 
 
47
 
    EVT_CLOSE( dlgDirectDbg::OnClose )
 
40
        EVT_BUTTON( wxID_OK,                    dlgDirectDbg::OnOk )
 
41
        EVT_BUTTON( wxID_CANCEL,                dlgDirectDbg::OnCancel )
 
42
        EVT_BUTTON( MENU_ID_SPAWN_DEBUGGER,  dlgDirectDbg::OnDebug )
 
43
        EVT_BUTTON( MENU_ID_NOTICE_RECEIVED, dlgDirectDbg::OnNoticeReceived )
 
44
 
 
45
        EVT_MENU( RESULT_ID_DIRECT_TARGET_COMPLETE, dlgDirectDbg::OnTargetComplete )
 
46
 
 
47
        EVT_CLOSE( dlgDirectDbg::OnClose )
48
48
 
49
49
END_EVENT_TABLE()
50
50
 
51
51
////////////////////////////////////////////////////////////////////////////////
52
52
// dlgDirectDbg constructor
53
53
//
54
 
//    This class implements 'direct-debugging'. In direct-debugging, the user 
 
54
//    This class implements 'direct-debugging'. In direct-debugging, the user
55
55
//  provides a function signature, procedure signature, or OID on the command
56
 
//  line (this identifies the debug target).  We query the server for the 
 
56
//  line (this identifies the debug target).  We query the server for the
57
57
//  names, types, and in/out modes for each target parameter and then prompt
58
58
//    the user to enter a value for each of the IN (and IN/OUT) parameters.
59
59
//
60
 
//  When the user fills in the parameter values and clicks OK, we set a 
61
 
//  breakpoint at the target and then execute a SELECT statement or an 
62
 
//  EXEC statement that invokes the target (with the parameter values 
 
60
//  When the user fills in the parameter values and clicks OK, we set a
 
61
//  breakpoint at the target and then execute a SELECT statement or an
 
62
//  EXEC statement that invokes the target (with the parameter values
63
63
//  provided by the user).
64
64
 
65
 
dlgDirectDbg::dlgDirectDbg( frmDebugger *parent, wxWindowID id, const dbgConnProp & connProp )
66
 
  : m_connProp(connProp),
67
 
    m_targetInfo(NULL),
68
 
    m_conn(NULL),
69
 
    m_codeWindow(NULL),
70
 
    m_parent (parent),
71
 
    m_cancelled (false)
 
65
dlgDirectDbg::dlgDirectDbg( frmDebugger *parent, wxWindowID id, const dbgConnProp &connProp )
 
66
        : m_connProp(connProp),
 
67
          m_targetInfo(NULL),
 
68
          m_conn(NULL),
 
69
          m_codeWindow(NULL),
 
70
          m_parent (parent),
 
71
          m_cancelled (false)
72
72
{
73
 
    wxWindowBase::SetFont(settings->GetSystemFont());
74
 
    LoadResource(m_parent, wxT("dlgDirectDbg"));
 
73
        wxWindowBase::SetFont(settings->GetSystemFont());
 
74
        LoadResource(m_parent, wxT("dlgDirectDbg"));
75
75
 
76
 
    // Icon
77
 
    SetIcon(wxIcon(debugger_xpm));
78
 
    RestorePosition();
 
76
        // Icon
 
77
        SetIcon(*debugger_png_ico);
 
78
        RestorePosition();
79
79
}
80
80
 
81
81
////////////////////////////////////////////////////////////////////////////////
88
88
 
89
89
void dlgDirectDbg::setupParamWindow( )
90
90
{
91
 
    // Add three columns to the grid control:
92
 
    //   (Parameter) Name, Type, and Value
93
 
    grdParams->CreateGrid( 0, 3 );
94
 
    grdParams->SetColLabelValue( COL_NAME,  _( "Name" ));
95
 
    grdParams->SetColLabelValue( COL_TYPE,  _( "Type" ));
96
 
    grdParams->SetColLabelValue( COL_VALUE, _( "Value" ));
97
 
    grdParams->SetRowLabelSize( 25 );
98
 
    grdParams->SetColSize( 0, 75 );
99
 
    grdParams->SetColSize( 1, 100 );
100
 
    grdParams->SetColSize( 2, grdParams->GetClientSize().x - 210 );
101
 
    grdParams->SetColLabelSize( 18 );
 
91
        // Add three columns to the grid control:
 
92
        //   (Parameter) Name, Type, and Value
 
93
        grdParams->CreateGrid( 0, 3 );
 
94
        grdParams->SetColLabelValue( COL_NAME,  _( "Name" ));
 
95
        grdParams->SetColLabelValue( COL_TYPE,  _( "Type" ));
 
96
        grdParams->SetColLabelValue( COL_VALUE, _( "Value" ));
 
97
        grdParams->SetRowLabelSize( 25 );
 
98
        grdParams->SetColSize( 0, 75 );
 
99
        grdParams->SetColSize( 1, 100 );
 
100
        grdParams->SetColSize( 2, grdParams->GetClientSize().x - 210 );
 
101
        grdParams->SetColLabelSize( 18 );
102
102
 
103
 
    chkPkgInit->SetValue(false);
104
 
    chkPkgInit->Disable();
 
103
        chkPkgInit->SetValue(false);
 
104
        chkPkgInit->Disable();
105
105
}
106
106
 
107
107
////////////////////////////////////////////////////////////////////////////////
115
115
 
116
116
bool dlgDirectDbg::startDebugging( void )
117
117
{
118
 
    // First, figure out what kind of target we are going to debug.
119
 
    // The caller filled in our m_breakpoint list with the name and
120
 
    // type of each target that he's interested in.
121
 
    //
122
 
    // FIXME: For now, we only allow one initial breakpoint for direct
123
 
    //          debugging - you can create other breakpoints once you see
124
 
    //          the source code.
125
 
 
126
 
    dbgBreakPointList::Node * node = m_breakpoints.GetFirst(); 
127
 
 
128
 
    wxASSERT_MSG( node != NULL, wxT( "Expected to find at least one target on the command line" ));
129
 
 
130
 
    dbgBreakPoint * breakpoint = node->GetData();
131
 
 
132
 
    m_target = breakpoint->getTarget();
133
 
 
134
 
    char    targetType=0;
135
 
 
136
 
    switch( breakpoint->getTargetType())
137
 
    {
138
 
        case dbgBreakPoint::TRIGGER:     targetType = 't'; break;
139
 
        case dbgBreakPoint::FUNCTION:    targetType = 'f'; break;
140
 
        case dbgBreakPoint::PROCEDURE:   targetType = 'p'; break;
141
 
        case dbgBreakPoint::OID:         targetType = 'o'; break;
142
 
        default:
143
 
        {
144
 
            wxASSERT_MSG( false, wxT( "Unexpected target type" ));
145
 
            break;
146
 
        }
147
 
    }
148
 
 
149
 
    if (!loadTargetInfo( m_target, m_connProp, targetType ))
150
 
        return false;
151
 
 
152
 
    populateParamGrid();
153
 
    return true;
 
118
        // First, figure out what kind of target we are going to debug.
 
119
        // The caller filled in our m_breakpoint list with the name and
 
120
        // type of each target that he's interested in.
 
121
        //
 
122
        // FIXME: For now, we only allow one initial breakpoint for direct
 
123
        //          debugging - you can create other breakpoints once you see
 
124
        //          the source code.
 
125
 
 
126
        dbgBreakPointList::Node *node = m_breakpoints.GetFirst();
 
127
 
 
128
        wxASSERT_MSG( node != NULL, wxT( "Expected to find at least one target on the command line" ));
 
129
 
 
130
        dbgBreakPoint *breakpoint = node->GetData();
 
131
 
 
132
        m_target = breakpoint->getTarget();
 
133
 
 
134
        char    targetType = 0;
 
135
 
 
136
        switch( breakpoint->getTargetType())
 
137
        {
 
138
                case dbgBreakPoint::TRIGGER:
 
139
                        targetType = 't';
 
140
                        break;
 
141
                case dbgBreakPoint::FUNCTION:
 
142
                        targetType = 'f';
 
143
                        break;
 
144
                case dbgBreakPoint::PROCEDURE:
 
145
                        targetType = 'p';
 
146
                        break;
 
147
                case dbgBreakPoint::OID:
 
148
                        targetType = 'o';
 
149
                        break;
 
150
                default:
 
151
                {
 
152
                        wxASSERT_MSG( false, wxT( "Unexpected target type" ));
 
153
                        break;
 
154
                }
 
155
        }
 
156
 
 
157
        if (!loadTargetInfo( m_target, m_connProp, targetType ))
 
158
                return false;
 
159
 
 
160
        populateParamGrid();
 
161
        return true;
154
162
}
155
163
 
156
164
////////////////////////////////////////////////////////////////////////////////
160
168
//  dbgTargetInfo object that loads information about the debug target (that is,
161
169
//  the function or procedure of interest).  Call this function with two
162
170
//  arguments: target should contain the signature of a function or procedure
163
 
//  or the OID of a function or procedure and connProp should contain the 
 
171
//  or the OID of a function or procedure and connProp should contain the
164
172
//  information required to connect to the server (like the hostname, port number,
165
173
//  and user name).
166
174
 
167
 
bool dlgDirectDbg::loadTargetInfo( const wxString &target, const dbgConnProp & connProp, char targetType )
 
175
bool dlgDirectDbg::loadTargetInfo( const wxString &target, const dbgConnProp &connProp, char targetType )
168
176
{
169
 
    // Connect to the server using the connection properties contained in connProp
170
 
 
171
 
    m_conn = new dbgPgConn(m_parent, connProp);
172
 
 
173
 
    if( m_conn && m_conn->isConnected())
174
 
    {
175
 
        if( getenv( "DEBUGGER_INIT" ))
176
 
        {
177
 
            PQclear( m_conn->waitForCommand( wxString(getenv( "DEBUGGER_INIT" ), wxConvUTF8 )));
178
 
        }
179
 
 
180
 
        // Our proxy API may throw (perfectly legitimate) errors at us (for example,
181
 
        // if the target process ends while we are waiting for a breakpoint) - apparently
182
 
        // those error messages scare the user when they show up in the log, so we'll
183
 
        // just suppress logging for this session
184
 
 
185
 
        PQclear( m_conn->waitForCommand( wxT( "SET log_min_messages TO fatal" )));
186
 
 
187
 
        // Now load information about the target into m_targetInfo (note:
188
 
        // the dbgTargetInfo() constructor queries the server for all 
189
 
        // required information)
190
 
 
191
 
        try
192
 
        {
193
 
            m_targetInfo = new dbgTargetInfo( target, m_conn, targetType );
194
 
        }
195
 
        catch( const std::runtime_error & error )
196
 
        {
197
 
            wxLogError(wxT("%s"), wxString(error.what(), wxConvUTF8).c_str());
198
 
            m_conn->Close();
199
 
            return false;
200
 
        }
201
 
 
202
 
        this->SetTitle(m_targetInfo->getName());
203
 
    }
204
 
 
205
 
    return true;
 
177
        // Connect to the server using the connection properties contained in connProp
 
178
 
 
179
        m_conn = new dbgPgConn(m_parent, connProp);
 
180
 
 
181
        if( m_conn && m_conn->isConnected())
 
182
        {
 
183
                if( getenv( "DEBUGGER_INIT" ))
 
184
                {
 
185
                        PQclear( m_conn->waitForCommand( wxString(getenv( "DEBUGGER_INIT" ), wxConvUTF8 )));
 
186
                }
 
187
 
 
188
                // Our proxy API may throw (perfectly legitimate) errors at us (for example,
 
189
                // if the target process ends while we are waiting for a breakpoint) - apparently
 
190
                // those error messages scare the user when they show up in the log, so we'll
 
191
                // just suppress logging for this session
 
192
 
 
193
                PQclear( m_conn->waitForCommand( wxT( "SET log_min_messages TO fatal" )));
 
194
 
 
195
                // Now load information about the target into m_targetInfo (note:
 
196
                // the dbgTargetInfo() constructor queries the server for all
 
197
                // required information)
 
198
 
 
199
                try
 
200
                {
 
201
                        m_targetInfo = new dbgTargetInfo( target, m_conn, targetType );
 
202
                }
 
203
                catch( const std::runtime_error &error )
 
204
                {
 
205
                        wxLogError(wxT("%s"), wxString(error.what(), wxConvUTF8).c_str());
 
206
                        m_conn->Close();
 
207
                        return false;
 
208
                }
 
209
 
 
210
                this->SetTitle(m_targetInfo->getName());
 
211
        }
 
212
 
 
213
        return true;
206
214
}
207
215
 
208
216
////////////////////////////////////////////////////////////////////////////////
215
223
 
216
224
void dlgDirectDbg::populateParamGrid( )
217
225
{
218
 
    // First, try to load default values from a previous invocation into 
219
 
    // m_targetInfo (assuming that we're debugging the same target this 
220
 
    // time around)
221
 
 
222
 
    loadSettings();
223
 
 
224
 
    int i = 0;
225
 
 
226
 
    for( int count = 0; count < m_targetInfo->getArgCount(); ++count )
227
 
    {
228
 
        wsArgInfo & arg = ((*m_targetInfo)[count] );
229
 
 
230
 
        // If this is an IN parameter (or an IN/OUT parameter), add 
231
 
        // a new row to the grid
232
 
 
233
 
        if( arg.getMode() != wxT( "o" ))
234
 
        {
235
 
            grdParams->AppendRows( 1 );
236
 
            grdParams->SetCellValue( i, COL_NAME,  arg.getName());
 
226
        // First, try to load default values from a previous invocation into
 
227
        // m_targetInfo (assuming that we're debugging the same target this
 
228
        // time around)
 
229
 
 
230
        loadSettings();
 
231
 
 
232
        int i = 0;
 
233
 
 
234
        for( int count = 0; count < m_targetInfo->getArgCount(); ++count )
 
235
        {
 
236
                wsArgInfo &arg = ((*m_targetInfo)[count] );
 
237
 
 
238
                // If this is an IN parameter (or an IN/OUT parameter), add
 
239
                // a new row to the grid
 
240
 
 
241
                if( arg.getMode() != wxT( "o" ))
 
242
                {
 
243
                        grdParams->AppendRows( 1 );
 
244
                        grdParams->SetCellValue( i, COL_NAME,  arg.getName());
237
245
 
238
246
                        // Make it obvious which are variadics
239
247
                        if (arg.getMode() != wxT( "v" ))
240
 
                grdParams->SetCellValue( i, COL_TYPE,  arg.getType());
 
248
                                grdParams->SetCellValue( i, COL_TYPE,  arg.getType());
241
249
                        else
242
 
                grdParams->SetCellValue( i, COL_TYPE, arg.getType() + wxT(" VARIADIC"));
243
 
 
244
 
            grdParams->SetCellValue( i, COL_VALUE, arg.getValue());
245
 
        
246
 
            grdParams->SetReadOnly( i, COL_NAME,  true );
247
 
            grdParams->SetReadOnly( i, COL_TYPE,  true );
248
 
            grdParams->SetReadOnly( i, COL_VALUE, false );
249
 
        
250
 
            i++;
251
 
        }
252
 
    }
253
 
 
254
 
    // Move the cursor to the first value (so that the user
255
 
    // can just start typing)
256
 
 
257
 
    grdParams->SetGridCursor( 0, COL_VALUE );
258
 
    grdParams->SetFocus();
259
 
 
260
 
    // If the target is defined within package, offer the user
261
 
    // a chance to debug the initializer (there may or may not
262
 
    // be an initializer, we don't really know at this point)
263
 
 
264
 
    if( m_targetInfo->getPkgOid() == 0 )
265
 
        chkPkgInit->Disable();
266
 
    else
267
 
        chkPkgInit->Enable();
268
 
 
269
 
    // If the target function has no parameters (and it's not defined within
270
 
    // a package), there's no good reason to wait for the user to hit the Ok
271
 
    // button before we invoke the target...
272
 
 
273
 
    if((m_targetInfo->getArgInCount() + m_targetInfo->getArgInOutCount() == 0 ) && ( m_targetInfo->getPkgOid() == 0))
274
 
    {
275
 
        grdParams->AppendRows( 1 );
276
 
        grdParams->SetReadOnly( i, COL_NAME,  true );
277
 
        grdParams->SetReadOnly( i, COL_TYPE,  true );
278
 
        grdParams->SetReadOnly( i, COL_VALUE, true );
279
 
 
280
 
        grdParams->SetCellValue( 0, COL_NAME, _( "No arguments required" ));
281
 
        wxFont font = grdParams->GetCellFont( 0, COL_NAME );
282
 
        font.SetStyle( wxFONTSTYLE_ITALIC );
283
 
        grdParams->SetCellFont( 0, COL_NAME, font );
284
 
 
285
 
        grdParams->SetColSize(COL_NAME, 200);
286
 
        activateDebugger();
287
 
    }
288
 
    else
289
 
        this->ShowModal();
 
250
                                grdParams->SetCellValue( i, COL_TYPE, arg.getType() + wxT(" VARIADIC"));
 
251
 
 
252
                        grdParams->SetCellValue( i, COL_VALUE, arg.getValue());
 
253
 
 
254
                        grdParams->SetReadOnly( i, COL_NAME,  true );
 
255
                        grdParams->SetReadOnly( i, COL_TYPE,  true );
 
256
                        grdParams->SetReadOnly( i, COL_VALUE, false );
 
257
 
 
258
                        i++;
 
259
                }
 
260
        }
 
261
 
 
262
        // Move the cursor to the first value (so that the user
 
263
        // can just start typing)
 
264
 
 
265
        grdParams->SetGridCursor( 0, COL_VALUE );
 
266
        grdParams->SetFocus();
 
267
 
 
268
        // If the target is defined within package, offer the user
 
269
        // a chance to debug the initializer (there may or may not
 
270
        // be an initializer, we don't really know at this point)
 
271
 
 
272
        if( m_targetInfo->getPkgOid() == 0 )
 
273
                chkPkgInit->Disable();
 
274
        else
 
275
                chkPkgInit->Enable();
 
276
 
 
277
        // If the target function has no parameters (and it's not defined within
 
278
        // a package), there's no good reason to wait for the user to hit the Ok
 
279
        // button before we invoke the target...
 
280
 
 
281
        if((m_targetInfo->getArgInCount() + m_targetInfo->getArgInOutCount() == 0 ) && ( m_targetInfo->getPkgOid() == 0))
 
282
        {
 
283
                grdParams->AppendRows( 1 );
 
284
                grdParams->SetReadOnly( i, COL_NAME,  true );
 
285
                grdParams->SetReadOnly( i, COL_TYPE,  true );
 
286
                grdParams->SetReadOnly( i, COL_VALUE, true );
 
287
 
 
288
                grdParams->SetCellValue( 0, COL_NAME, _( "No arguments required" ));
 
289
                wxFont font = grdParams->GetCellFont( 0, COL_NAME );
 
290
                font.SetStyle( wxFONTSTYLE_ITALIC );
 
291
                grdParams->SetCellFont( 0, COL_NAME, font );
 
292
 
 
293
                grdParams->SetColSize(COL_NAME, 200);
 
294
                activateDebugger();
 
295
        }
 
296
        else
 
297
                this->ShowModal();
290
298
}
291
299
 
292
300
////////////////////////////////////////////////////////////////////////////////
293
301
// OnOk()
294
302
//
295
303
//    This event handler is called when the user clicks the OK button - we call the
296
 
//  activateDebugger() function to set the required breakpoint and invoke the 
 
304
//  activateDebugger() function to set the required breakpoint and invoke the
297
305
//  target (after nabbing any parameter values from the prompt dialog)
298
306
 
299
 
void dlgDirectDbg::OnOk( wxCommandEvent & event )
 
307
void dlgDirectDbg::OnOk( wxCommandEvent &event )
300
308
{
301
 
    activateDebugger();
 
309
        activateDebugger();
302
310
}
303
311
 
304
312
////////////////////////////////////////////////////////////////////////////////
305
313
// loadSettings()
306
314
//
307
 
//    Loads default values from our .ini file. We save the OID of the most 
 
315
//    Loads default values from our .ini file. We save the OID of the most
308
316
//    recent direct-debugging target when close a session. If we're direct-
309
317
//    debugging the same target this time around, we load the argument values
310
318
//    from the .ini file.
311
319
 
312
320
void dlgDirectDbg::loadSettings()
313
321
{
314
 
    long        lastOID;
315
 
    
316
 
    settings->Read( wxT( "Debugger/Proc/OID" ), &lastOID, -1 );
317
 
 
318
 
    if( lastOID == m_targetInfo->getOid())
319
 
    {
320
 
        int    count = 0;
321
 
 
322
 
        for( int i = 0; i < m_targetInfo->getArgCount(); ++i )
323
 
        {
324
 
            wsArgInfo & arg = (*m_targetInfo)[i];
325
 
 
326
 
            if( arg.getMode() != wxT( "o" ))
327
 
            {
328
 
                settings->Read( wxString::Format( wxT( "Debugger/Proc/argValue%d" ), ++count ), &(arg.getValue()), wxT( "" ));
329
 
            }
330
 
        }
331
 
    }
 
322
        long        lastOID;
 
323
 
 
324
        settings->Read( wxT( "Debugger/Proc/OID" ), &lastOID, -1 );
 
325
 
 
326
        if( lastOID == m_targetInfo->getOid())
 
327
        {
 
328
                int    count = 0;
 
329
 
 
330
                for( int i = 0; i < m_targetInfo->getArgCount(); ++i )
 
331
                {
 
332
                        wsArgInfo &arg = (*m_targetInfo)[i];
 
333
 
 
334
                        if( arg.getMode() != wxT( "o" ))
 
335
                        {
 
336
                                settings->Read( wxString::Format( wxT( "Debugger/Proc/argValue%d" ), ++count ), &(arg.getValue()), wxT( "" ));
 
337
                        }
 
338
                }
 
339
        }
332
340
}
333
341
 
334
342
////////////////////////////////////////////////////////////////////////////////
335
343
// saveSettings()
336
344
//
337
 
//    Save default values to our .ini file. We save the OID of the most 
338
 
//    recent direct-debugging target when close a session. We also save the 
 
345
//    Save default values to our .ini file. We save the OID of the most
 
346
//    recent direct-debugging target when close a session. We also save the
339
347
//  value of each argument - if you debug the same target again next time,
340
 
//    loadSettings() will initialize the parameter-values window with the 
 
348
//    loadSettings() will initialize the parameter-values window with the
341
349
//    same parameter values that you entered in this session.
342
350
 
343
351
void dlgDirectDbg::saveSettings()
344
352
{
345
 
    settings->Write( wxT( "Debugger/Proc/OID" ), m_targetInfo->getOid());
346
 
 
347
 
    int    count = 0;
348
 
 
349
 
    for( int i = 0; i < m_targetInfo->getArgCount(); ++i )
350
 
    {
351
 
        wsArgInfo & arg = ( *m_targetInfo)[i];
352
 
 
353
 
        if( arg.getMode() != wxT( "o" ))
354
 
        {
355
 
            settings->Write( wxString::Format( wxT( "Debugger/Proc/argName%d" ), ++count ), arg.getName());
356
 
            settings->Write( wxString::Format( wxT( "Debugger/Proc/argType%d" ),   count ), arg.getType());
357
 
            settings->Write( wxString::Format( wxT( "Debugger/Proc/argValue%d" ),  count ), (arg.getValue() == wxT("NULL") ? wxEmptyString : arg.getValue().c_str()));
358
 
        }
359
 
    }
 
353
        settings->WriteLong( wxT( "Debugger/Proc/OID" ), m_targetInfo->getOid());
 
354
 
 
355
        int    count = 0;
 
356
 
 
357
        for( int i = 0; i < m_targetInfo->getArgCount(); ++i )
 
358
        {
 
359
                wsArgInfo &arg = ( *m_targetInfo)[i];
 
360
 
 
361
                if( arg.getMode() != wxT( "o" ))
 
362
                {
 
363
                        settings->Write( wxString::Format( wxT( "Debugger/Proc/argName%d" ), ++count ), arg.getName());
 
364
                        settings->Write( wxString::Format( wxT( "Debugger/Proc/argType%d" ),   count ), arg.getType());
 
365
                        settings->Write( wxString::Format( wxT( "Debugger/Proc/argValue%d" ),  count ), wxString((arg.getValue() == wxT("NULL") ? wxEmptyString : arg.getValue().c_str())));
 
366
                }
 
367
        }
360
368
}
361
369
 
362
370
////////////////////////////////////////////////////////////////////////////////
365
373
//    This event handler is called when the user clicks the Cancel button - we
366
374
//    close the connection to the server and then close ourself.
367
375
 
368
 
void dlgDirectDbg::OnCancel( wxCommandEvent & event )
 
376
void dlgDirectDbg::OnCancel( wxCommandEvent &event )
369
377
{
370
 
    // This will raise close event which is handled by 
371
 
    // dlgDirectDbg::OnClose().
372
 
    m_cancelled = true;
373
 
    Close();
 
378
        // This will raise close event which is handled by
 
379
        // dlgDirectDbg::OnClose().
 
380
        m_cancelled = true;
 
381
        Close();
374
382
}
375
383
 
376
384
////////////////////////////////////////////////////////////////////////////////
377
385
// OnClose()
378
386
//
379
387
//    wxWidgets invokes this event handler when the user closes the parameter
380
 
//    window. We close the connection with server and raise close event for 
 
388
//    window. We close the connection with server and raise close event for
381
389
//    MainFrame.
382
390
 
383
 
void dlgDirectDbg::OnClose( wxCloseEvent & event )
 
391
void dlgDirectDbg::OnClose( wxCloseEvent &event )
384
392
{
385
 
    // Destroy the grid - required as it seems to create threads in some cases
386
 
    if (grdParams)
387
 
    {
388
 
        grdParams->Destroy();
389
 
        delete grdParams;
390
 
    }
 
393
        // Destroy the grid - required as it seems to create threads in some cases
 
394
        if (grdParams)
 
395
        {
 
396
                grdParams->Destroy();
 
397
                delete grdParams;
 
398
        }
391
399
 
392
 
    // Close the debugger (proxy) connection
393
 
    if (m_conn)
394
 
    {
395
 
        m_conn->Close();
396
 
        delete m_conn;
397
 
        m_conn = NULL;
398
 
    }
 
400
        // Close the debugger (proxy) connection
 
401
        if (m_conn)
 
402
        {
 
403
                m_conn->Close();
 
404
                delete m_conn;
 
405
                m_conn = NULL;
 
406
        }
399
407
 
400
408
        // Closing frmMain from here leads to recursive call
401
 
    // to OnClose function on windows
 
409
        // to OnClose function on windows
402
410
#ifndef __WXWIN__
403
 
    // This will inform the MainWindow to close.
404
 
    // if it's not visible yet.
405
 
    if (m_parent->IsShown())
406
 
        event.Skip();
407
 
    else
408
 
        m_parent->Close();
 
411
        // This will inform the MainWindow to close.
 
412
        // if it's not visible yet.
 
413
        if (m_parent->IsShown())
 
414
                event.Skip();
 
415
        else
 
416
                m_parent->Close();
409
417
#endif // __WXWIN__
410
418
 
411
 
    if ( this->IsModal() )
412
 
    {
413
 
        if ( m_cancelled )
414
 
            EndModal( wxID_CANCEL );
415
 
        else
416
 
            EndModal( wxID_OK);
417
 
    }
 
419
        if ( this->IsModal() )
 
420
        {
 
421
                if ( m_cancelled )
 
422
                        EndModal( wxID_CANCEL );
 
423
                else
 
424
                        EndModal( wxID_OK);
 
425
        }
418
426
}
419
427
 
420
428
////////////////////////////////////////////////////////////////////////////////
423
431
//    This function is called after the user has filled in any parameter values
424
432
//  and clicked the Ok button.  activateDebugger() extracts the paramter values
425
433
//  from the grid control and copies those values into our dbgTargetInfo object
426
 
//  (m_targetInfo).  Next, we set a breakpoint at the target, and, finally, 
 
434
//  (m_targetInfo).  Next, we set a breakpoint at the target, and, finally,
427
435
//  we invoke the target function/procedure
428
436
 
429
437
bool dlgDirectDbg::activateDebugger( )
430
438
{
431
 
    // Unset the completed flag (if it exists)
432
 
    if (m_codeWindow)
433
 
        m_codeWindow->m_targetComplete = false;
434
 
 
435
 
    // Copy the parameter values from the grid into m_targetInfo
436
 
    int i = 0;
437
 
 
438
 
    for( int count = 0; count < m_targetInfo->getArgCount(); ++count )
439
 
    {
440
 
        wsArgInfo & arg = (*m_targetInfo)[count];
441
 
 
442
 
        // Populate the ArgInfo object's IN or INOUT variables only, OUT
443
 
        // variables will be assigned NULL later on.
444
 
 
445
 
        if(arg.getMode() != wxT("o"))
446
 
        {
447
 
            arg.setValue( grdParams->GetCellValue(i, COL_VALUE));
448
 
            i++;
449
 
        }    
450
 
    }
451
 
 
452
 
    // Write the target OID and argument values to our settings file
453
 
    // so that we can default them next time around
454
 
    saveSettings();
455
 
 
456
 
    // Now set a breakpoint at the target (note: the call to setBreakpoint()
457
 
    // will hang until the  server sends us a response)
458
 
    
459
 
    try
460
 
    {
461
 
        // Debug the initialiser. We can only do so once, so unset, and disable
462
 
        // the option after setting the breakpoint
463
 
        if( chkPkgInit->GetValue())
464
 
            setBreakpoint( m_targetInfo->getPkgOid(), m_targetInfo->getPkgInitOid());
465
 
 
466
 
        chkPkgInit->SetValue(false);
467
 
        chkPkgInit->Disable();
468
 
 
469
 
        setBreakpoint( m_targetInfo->getPkgOid(), m_targetInfo->getOid());
470
 
    }
471
 
    catch( const std::runtime_error & error )
472
 
    {
473
 
        wxMessageBox( wxString( error.what(), wxConvUTF8 ), _( "Cannot create breakpoint" ), wxOK | wxICON_ERROR );
474
 
        return( false );
475
 
    }
476
 
 
477
 
    // And invoke the target (note: the call to invokeTarget() will *NOT*
478
 
    // wait for a result set from the server - instead, OnResultReady() will
479
 
    // be called when the result set is ready)
480
 
 
481
 
    try
482
 
    {
483
 
        invokeTarget();
484
 
    }
485
 
    catch( const std::runtime_error & error )
486
 
    {
487
 
        wxMessageBox( wxString( error.what(), wxConvUTF8 ), _( "Cannot invoke target" ), wxOK | wxICON_ERROR );
488
 
        return( false );
489
 
    }
490
 
 
491
 
    return( true );
 
439
        // Unset the completed flag (if it exists)
 
440
        if (m_codeWindow)
 
441
                m_codeWindow->m_targetComplete = false;
 
442
 
 
443
        // Copy the parameter values from the grid into m_targetInfo
 
444
        int i = 0;
 
445
 
 
446
        for( int count = 0; count < m_targetInfo->getArgCount(); ++count )
 
447
        {
 
448
                wsArgInfo &arg = (*m_targetInfo)[count];
 
449
 
 
450
                // Populate the ArgInfo object's IN or INOUT variables only, OUT
 
451
                // variables will be assigned NULL later on.
 
452
 
 
453
                if(arg.getMode() != wxT("o"))
 
454
                {
 
455
                        arg.setValue( grdParams->GetCellValue(i, COL_VALUE));
 
456
                        i++;
 
457
                }
 
458
        }
 
459
 
 
460
        // Write the target OID and argument values to our settings file
 
461
        // so that we can default them next time around
 
462
        saveSettings();
 
463
 
 
464
        // Now set a breakpoint at the target (note: the call to setBreakpoint()
 
465
        // will hang until the  server sends us a response)
 
466
 
 
467
        try
 
468
        {
 
469
                // Debug the initialiser. We can only do so once, so unset, and disable
 
470
                // the option after setting the breakpoint
 
471
                if( chkPkgInit->GetValue())
 
472
                        setBreakpoint( m_targetInfo->getPkgOid(), m_targetInfo->getPkgInitOid());
 
473
 
 
474
                chkPkgInit->SetValue(false);
 
475
                chkPkgInit->Disable();
 
476
 
 
477
                setBreakpoint( m_targetInfo->getPkgOid(), m_targetInfo->getOid());
 
478
        }
 
479
        catch( const std::runtime_error &error )
 
480
        {
 
481
                wxMessageBox( wxString( error.what(), wxConvUTF8 ), _( "Cannot create breakpoint" ), wxOK | wxICON_ERROR );
 
482
                return( false );
 
483
        }
 
484
 
 
485
        // And invoke the target (note: the call to invokeTarget() will *NOT*
 
486
        // wait for a result set from the server - instead, OnResultReady() will
 
487
        // be called when the result set is ready)
 
488
 
 
489
        try
 
490
        {
 
491
                invokeTarget();
 
492
        }
 
493
        catch( const std::runtime_error &error )
 
494
        {
 
495
                wxMessageBox( wxString( error.what(), wxConvUTF8 ), _( "Cannot invoke target" ), wxOK | wxICON_ERROR );
 
496
                return( false );
 
497
        }
 
498
 
 
499
        return( true );
492
500
}
493
501
 
494
502
////////////////////////////////////////////////////////////////////////////////
495
503
// setBreakpoint()
496
504
//
497
505
//    This function creates a breakpoint at the target.  For now, we always create
498
 
//  a breakpoint by calling edb_procoid_debug() or plpgsql_procoid_debug() with 
499
 
//  the OID of the target.  Later, we'll change this function to use the 
 
506
//  a breakpoint by calling edb_procoid_debug() or plpgsql_procoid_debug() with
 
507
//  the OID of the target.  Later, we'll change this function to use the
500
508
//  new CREATE BREAKPOINT command.
501
509
 
502
510
void dlgDirectDbg::setBreakpoint(long pkgOid, long funcOid)
503
511
{
504
 
    dbgResultset * result;
505
 
 
506
 
    if (m_conn->DebuggerApiVersion() <= DEBUGGER_V2_API)
507
 
    {
508
 
        if( m_targetInfo->getLanguage() == wxT( "edbspl" ))
509
 
            result = new dbgResultset(m_conn->waitForCommand(wxString::Format(wxT("select edb_oid_debug( %ld, %ld );"), pkgOid, funcOid)));
510
 
        else
511
 
            result = new dbgResultset(m_conn->waitForCommand(wxString::Format(wxT("select plpgsql_oid_debug( %ld, %ld );"),  pkgOid, funcOid)));
512
 
    }
513
 
    else
514
 
    {
515
 
        if( m_targetInfo->getLanguage() == wxT( "edbspl" ))
516
 
            result = new dbgResultset(m_conn->waitForCommand(wxString::Format(wxT("select edb_oid_debug(%ld);"), funcOid)));
517
 
        else
518
 
            result = new dbgResultset(m_conn->waitForCommand(wxString::Format(wxT("select plpgsql_oid_debug(%ld);"), funcOid)));
519
 
    }
520
 
 
521
 
    if( result->getCommandStatus() != PGRES_TUPLES_OK )
522
 
        throw( std::runtime_error( result->getRawErrorMessage()));
 
512
        dbgResultset *result;
 
513
 
 
514
        if (m_conn->DebuggerApiVersion() <= DEBUGGER_V2_API)
 
515
        {
 
516
                if( m_targetInfo->getLanguage() == wxT( "edbspl" ))
 
517
                        result = new dbgResultset(m_conn->waitForCommand(wxString::Format(wxT("select edb_oid_debug( %ld, %ld );"), pkgOid, funcOid)));
 
518
                else
 
519
                        result = new dbgResultset(m_conn->waitForCommand(wxString::Format(wxT("select plpgsql_oid_debug( %ld, %ld );"),  pkgOid, funcOid)));
 
520
        }
 
521
        else
 
522
        {
 
523
                if( m_targetInfo->getLanguage() == wxT( "edbspl" ))
 
524
                        result = new dbgResultset(m_conn->waitForCommand(wxString::Format(wxT("select edb_oid_debug(%ld);"), funcOid)));
 
525
                else
 
526
                        result = new dbgResultset(m_conn->waitForCommand(wxString::Format(wxT("select plpgsql_oid_debug(%ld);"), funcOid)));
 
527
        }
 
528
 
 
529
        if( result->getCommandStatus() != PGRES_TUPLES_OK )
 
530
                throw( std::runtime_error( result->getRawErrorMessage()));
523
531
}
524
532
 
525
533
////////////////////////////////////////////////////////////////////////////////
526
534
// invokeTarget()
527
535
//
528
536
//    This function invokes the debugger target (that is, the function or procedure
529
 
//  that the user wants to debug).  If the target is a function, we generate a 
 
537
//  that the user wants to debug).  If the target is a function, we generate a
530
538
//  SELECT statement; if the target is a procedure, we generate an EXEC statement.
531
539
//  In either case, we build the argument list from the argument values found
532
540
//  in m_targetInfo
533
541
 
534
542
void dlgDirectDbg::invokeTarget()
535
543
{
536
 
    // If we have access the the EDB extended libpq functions,
537
 
    // and this is a stored procedure, we should execute the
538
 
    // procedure using the callable statement interface to allow
539
 
    // us to retrieve the OUT/INOUT parameter results.
540
 
    // Otherwise, just SELECT/EXEC it as per normal.
 
544
        // If we have access the the EDB extended libpq functions,
 
545
        // and this is a stored procedure, we should execute the
 
546
        // procedure using the callable statement interface to allow
 
547
        // us to retrieve the OUT/INOUT parameter results.
 
548
        // Otherwise, just SELECT/EXEC it as per normal.
541
549
#ifdef __WXMSW__
542
 
    if (!m_targetInfo->getIsFunction() &&
543
 
        PQiGetOutResult && 
544
 
        PQiPrepareOut && 
545
 
        PQiSendQueryPreparedOut)
546
 
        invokeTargetCallable();
547
 
    else
 
550
        if (!m_conn->EdbMinimumVersion(9, 0) &&
 
551
                !m_targetInfo->getIsFunction() &&
 
552
                PQiGetOutResult &&
 
553
                PQiPrepareOut &&
 
554
                PQiSendQueryPreparedOut)
 
555
                invokeTargetCallable();
 
556
        else
548
557
#else
549
558
#ifdef EDB_LIBPQ
550
 
    if (!m_targetInfo->getIsFunction())
551
 
        invokeTargetCallable();
552
 
    else
553
 
#endif
554
 
#endif
555
 
        invokeTargetStatement();
556
 
 
557
 
    // Since parameter window has done its job, we need to hide
558
 
    // it and let code window come in front.
559
 
    if (m_codeWindow) 
560
 
    {
561
 
        m_codeWindow->enableTools();
562
 
        m_codeWindow->resumeLocalDebugging();
563
 
    }
564
 
    
565
 
    this->Show( false );
 
559
        if (!m_conn->EdbMinimumVersion(9, 0) &&
 
560
                !m_targetInfo->getIsFunction())
 
561
                invokeTargetCallable();
 
562
        else
 
563
#endif
 
564
#endif
 
565
                invokeTargetStatement();
 
566
 
 
567
        // Since parameter window has done its job, we need to hide
 
568
        // it and let code window come in front.
 
569
        if (m_codeWindow)
 
570
        {
 
571
                m_codeWindow->enableTools();
 
572
                m_codeWindow->resumeLocalDebugging();
 
573
        }
 
574
 
 
575
        this->Show( false );
566
576
}
567
577
 
568
578
void dlgDirectDbg::invokeTargetCallable()
569
579
{
570
 
    dbgPgParams *params = new dbgPgParams();
571
 
 
572
 
    wxString query = wxT("CALL ") + m_targetInfo->getFQName() + wxT("(");
573
 
 
574
 
    // Setup the param struct.
575
 
    params->nParams = m_targetInfo->getArgCount();
576
 
    params->paramTypes = new Oid[params->nParams];
577
 
    params->paramValues = new char*[params->nParams];
578
 
    params->paramModes = new int[params->nParams];
579
 
 
580
 
    // Iterate through the parameters, adding them to the param 
581
 
    // struct and the statement as we go.
582
 
    for( int i = 0; i < params->nParams; ++i )
583
 
    {
584
 
        wsArgInfo &arg = (*m_targetInfo)[i];
585
 
 
586
 
        params->paramTypes[i] = arg.getTypeOid();
587
 
 
588
 
        if(arg.getMode() == wxT("o")) // OUT
589
 
        {
590
 
            params->paramModes[i] = 2;
591
 
            params->paramValues[i] = 0;
592
 
        }
593
 
        else if(arg.getMode() == wxT("b")) // IN OUT
594
 
        {
595
 
            params->paramModes[i] = 3;
596
 
 
597
 
            int len = arg.getValue().Length() + 1;
598
 
            char *tmp = new char[len];
599
 
            snprintf(tmp, len, "%s", (const char *)arg.getValue().mb_str(wxConvUTF8));
600
 
            if (strcmp(tmp, "") == 0)
601
 
                params->paramValues[i] = 0;
602
 
            else if (strcmp(tmp, "''") == 0)
603
 
                params->paramValues[i] = (char *)"";
604
 
            else if (strcmp(tmp, "\\'\\'") == 0)
605
 
                params->paramValues[i] = (char *)"''";
606
 
            else
607
 
                params->paramValues[i] = tmp;
608
 
        }
609
 
        else // IN
610
 
        {
611
 
            params->paramModes[i] = 1;
612
 
 
613
 
            int len = arg.getValue().Length() + 1;
614
 
            char *tmp = new char[len];
615
 
            snprintf(tmp, len, "%s", (const char *)arg.getValue().mb_str(wxConvUTF8));
616
 
            if (strcmp(tmp, "") == 0)
617
 
                params->paramValues[i] = 0;
618
 
            else if (strcmp(tmp, "''") == 0)
619
 
                params->paramValues[i] = (char *)"";
620
 
            else if (strcmp(tmp, "\\'\\'") == 0)
621
 
                params->paramValues[i] = (char *)"''";
622
 
            else
623
 
                params->paramValues[i] = tmp;
624
 
        }
625
 
 
626
 
            if (i)
627
 
                query += wxT(", ");
628
 
            query += wxString::Format(wxT("$%d::"), i + 1) + arg.getType();
629
 
 
630
 
    }
631
 
 
632
 
    query += wxT(");");
633
 
 
634
 
    // And send the completed command to the server - we'll get 
635
 
    // a dbgDbResult event when the command completes (and that 
636
 
    // event will get routed to dlgDirectDbg::OnResultReady())
637
 
    m_conn->startCommand( query, GetEventHandler(), RESULT_ID_DIRECT_TARGET_COMPLETE, params );
 
580
        dbgPgParams *params = new dbgPgParams();
 
581
 
 
582
        wxString query = wxT("CALL ") + m_targetInfo->getFQName() + wxT("(");
 
583
 
 
584
        // Setup the param struct.
 
585
        params->nParams = m_targetInfo->getArgCount();
 
586
        params->paramTypes = new Oid[params->nParams];
 
587
        params->paramValues = new char*[params->nParams];
 
588
        params->paramModes = new int[params->nParams];
 
589
 
 
590
        // Iterate through the parameters, adding them to the param
 
591
        // struct and the statement as we go.
 
592
        for( int i = 0; i < params->nParams; ++i )
 
593
        {
 
594
                wsArgInfo &arg = (*m_targetInfo)[i];
 
595
 
 
596
                params->paramTypes[i] = arg.getTypeOid();
 
597
 
 
598
                if(arg.getMode() == wxT("o")) // OUT
 
599
                {
 
600
                        params->paramModes[i] = 2;
 
601
                        params->paramValues[i] = 0;
 
602
                }
 
603
                else if(arg.getMode() == wxT("b")) // IN OUT
 
604
                {
 
605
                        params->paramModes[i] = 3;
 
606
 
 
607
                        int len = arg.getValue().Length() + 1;
 
608
                        char *tmp = new char[len];
 
609
                        snprintf(tmp, len, "%s", (const char *)arg.getValue().mb_str(wxConvUTF8));
 
610
                        if (strcmp(tmp, "") == 0)
 
611
                                params->paramValues[i] = 0;
 
612
                        else if (strcmp(tmp, "''") == 0)
 
613
                                params->paramValues[i] = (char *)"";
 
614
                        else if (strcmp(tmp, "\\'\\'") == 0)
 
615
                                params->paramValues[i] = (char *)"''";
 
616
                        else
 
617
                                params->paramValues[i] = tmp;
 
618
                }
 
619
                else // IN
 
620
                {
 
621
                        params->paramModes[i] = 1;
 
622
 
 
623
                        int len = arg.getValue().Length() + 1;
 
624
                        char *tmp = new char[len];
 
625
                        snprintf(tmp, len, "%s", (const char *)arg.getValue().mb_str(wxConvUTF8));
 
626
                        if (strcmp(tmp, "") == 0)
 
627
                                params->paramValues[i] = 0;
 
628
                        else if (strcmp(tmp, "''") == 0)
 
629
                                params->paramValues[i] = (char *)"";
 
630
                        else if (strcmp(tmp, "\\'\\'") == 0)
 
631
                                params->paramValues[i] = (char *)"''";
 
632
                        else
 
633
                                params->paramValues[i] = tmp;
 
634
                }
 
635
 
 
636
                if (i)
 
637
                        query += wxT(", ");
 
638
                query += wxString::Format(wxT("$%d::"), i + 1) + arg.getType();
 
639
 
 
640
        }
 
641
 
 
642
        query += wxT(");");
 
643
 
 
644
        // And send the completed command to the server - we'll get
 
645
        // a dbgDbResult event when the command completes (and that
 
646
        // event will get routed to dlgDirectDbg::OnResultReady())
 
647
        m_conn->startCommand( query, GetEventHandler(), RESULT_ID_DIRECT_TARGET_COMPLETE, params );
638
648
}
639
649
 
640
650
void dlgDirectDbg::invokeTargetStatement()
641
651
{
642
 
    wxString query, declareStatement;
643
 
    if (!m_conn->EdbMinimumVersion(8, 4))
644
 
        query = m_targetInfo->getIsFunction() ? wxT( "SELECT " ) : wxT( "EXEC " );
645
 
    else
646
 
    {
647
 
        query = wxT("SELECT");
648
 
        if (!m_targetInfo->getIsFunction())
649
 
            query = wxT("EXEC ");
650
 
        else if (m_targetInfo->getLanguage() == wxT("edbspl"))
651
 
            query = wxT("PERFORM ");
652
 
    }
653
 
 
654
 
    // If this is a function, and the return type is not record, or
655
 
    // we have at least one OUT/INOUT param, we should select from
656
 
    // the function to get a full resultset.
657
 
    if (m_targetInfo->getIsFunction() && m_targetInfo->getLanguage() != wxT("edbspl") &&
658
 
        (m_targetInfo->getReturnType() != wxT("record") ||
659
 
         m_targetInfo->getArgInOutCount() > 0 ||
660
 
         m_targetInfo->getArgOutCount() > 0))
661
 
         query.Append(wxT("* FROM "));
662
 
 
663
 
    // Stuff the verb (SELECT or EXEC), schema, and target name into the query
664
 
    query.Append(m_targetInfo->getFQName());
665
 
 
666
 
    // Now append the argument list
667
 
    query.Append(wxT("("));
668
 
 
669
 
    for(int i = 0; i < m_targetInfo->getArgCount(); ++i)
670
 
    {
671
 
        wsArgInfo & arg = (*m_targetInfo)[i];
672
 
 
673
 
        if(arg.getMode() == wxT("o") && !m_conn->EdbMinimumVersion(8, 4))
674
 
        {
675
 
            if (!m_targetInfo->getIsFunction() || m_targetInfo->getLanguage() == wxT("edbspl"))
676
 
                query.Append( wxT("NULL::") + arg.getType() + wxT(", "));
677
 
        }
678
 
        else if (m_conn->EdbMinimumVersion(8, 4) && (arg.getMode() == wxT("o") || arg.getMode() == wxT("b")))
679
 
        {
680
 
            if (!m_targetInfo->getIsFunction() || m_targetInfo->getLanguage() == wxT("edbspl"))
681
 
            {
682
 
                wxString strParam = wxString::Format(wxT("param%d"), i);
683
 
                declareStatement +=  strParam + wxT(" ") + arg.getType();
684
 
                if (arg.getMode() == wxT("b"))
685
 
                    declareStatement += wxT(" := ") + arg.quoteValue() + wxT("::") + arg.getType();
686
 
                declareStatement += wxT(";\n");
687
 
                query.Append(strParam + wxT(", "));
688
 
            }
689
 
            else if (arg.getMode() != wxT("o"))
690
 
                query.Append( arg.quoteValue() + wxT("::") + arg.getType() + wxT(", "));
691
 
        }
692
 
        else if(arg.getMode() == wxT("v"))
693
 
            query.Append( arg.getValue() + wxT(", "));
694
 
        else
695
 
            query.Append( arg.quoteValue() + wxT("::") + arg.getType() + wxT(", "));
696
 
    }
697
 
 
698
 
    if (query.EndsWith(wxT(", ")))
699
 
        query = query.Left(query.Length() - 2);
700
 
    else if (query.EndsWith(wxT("(")))
701
 
        query = query.Left(query.Length() - 1);
702
 
 
703
 
    // And terminate the argument list
704
 
    if(m_targetInfo->getArgInCount() + m_targetInfo->getArgInOutCount() == 0)
705
 
    {
706
 
        /*
707
 
         * edbspl function/procedure with OUT parameter takes value/variable as an input
708
 
         */
709
 
        if (m_conn->GetIsEdb())
710
 
        {
711
 
            if (m_targetInfo->getArgCount() == 0)
712
 
            {
713
 
                if (m_targetInfo->getIsFunction() || m_targetInfo->getLanguage() != wxT("edbspl"))
714
 
                    query.Append(wxT("()"));
715
 
            }
716
 
            else if (m_targetInfo->getLanguage() != wxT("edbspl"))
717
 
                query.Append(wxT("()"));
718
 
            else
719
 
                query.Append(wxT(")"));
720
 
        }
721
 
        else if (m_targetInfo->getIsFunction())
722
 
            query.Append(wxT("()"));
723
 
    }
724
 
    else
725
 
    {
726
 
        query.Append(wxT(")"));
727
 
    }
728
 
 
729
 
    if (m_conn->EdbMinimumVersion(8, 4) && (m_targetInfo->getLanguage() == wxT("edbspl") || !m_targetInfo->getIsFunction()))
730
 
    {
731
 
        wxString tmpQuery = wxT("DECLARE\n")
732
 
                          + declareStatement
733
 
                          + wxT("BEGIN\n")
734
 
                          + query + wxT(";\n")
735
 
                          + wxT("END;");
736
 
        query = tmpQuery;
737
 
    }
738
 
 
739
 
    // And send the completed command to the server - we'll get
740
 
    // a dbgDbResult event when the command completes (and that
741
 
    // event will get routed to dlgDirectDbg::OnResultReady())
742
 
    m_conn->startCommand( query, GetEventHandler(), RESULT_ID_DIRECT_TARGET_COMPLETE );
 
652
        wxString query, declareStatement;
 
653
        if (!m_conn->EdbMinimumVersion(8, 4))
 
654
                query = m_targetInfo->getIsFunction() ? wxT( "SELECT " ) : wxT( "EXEC " );
 
655
        else
 
656
        {
 
657
                query = wxT("SELECT");
 
658
                if (!m_targetInfo->getIsFunction())
 
659
                        query = wxT("EXEC ");
 
660
                else if (m_targetInfo->getLanguage() == wxT("edbspl"))
 
661
                        query = wxT("PERFORM ");
 
662
        }
 
663
 
 
664
        // If this is a function, and the return type is not record, or
 
665
        // we have at least one OUT/INOUT param, we should select from
 
666
        // the function to get a full resultset.
 
667
        if (m_targetInfo->getIsFunction() && m_targetInfo->getLanguage() != wxT("edbspl") &&
 
668
                (m_targetInfo->getReturnType() != wxT("record") ||
 
669
                 m_targetInfo->getArgInOutCount() > 0 ||
 
670
                 m_targetInfo->getArgOutCount() > 0))
 
671
                query.Append(wxT("* FROM "));
 
672
 
 
673
        // Stuff the verb (SELECT or EXEC), schema, and target name into the query
 
674
        query.Append(m_targetInfo->getFQName());
 
675
 
 
676
        // Now append the argument list
 
677
        query.Append(wxT("("));
 
678
 
 
679
        for(int i = 0; i < m_targetInfo->getArgCount(); ++i)
 
680
        {
 
681
                wsArgInfo &arg = (*m_targetInfo)[i];
 
682
 
 
683
                if(arg.getMode() == wxT("o") && !m_conn->EdbMinimumVersion(8, 4))
 
684
                {
 
685
                        if (!m_targetInfo->getIsFunction() || m_targetInfo->getLanguage() == wxT("edbspl"))
 
686
                                query.Append( wxT("NULL::") + arg.getType() + wxT(", "));
 
687
                }
 
688
                else if (m_conn->EdbMinimumVersion(8, 4) && (arg.getMode() == wxT("o") || arg.getMode() == wxT("b")))
 
689
                {
 
690
                        if (!m_targetInfo->getIsFunction() || m_targetInfo->getLanguage() == wxT("edbspl"))
 
691
                        {
 
692
                                wxString strParam = wxString::Format(wxT("param%d"), i);
 
693
                                declareStatement +=  strParam + wxT(" ") + arg.getType();
 
694
                                if (arg.getMode() == wxT("b"))
 
695
                                {
 
696
                                        declareStatement += wxT(" := ") + arg.quoteValue();
 
697
                                        if (!arg.quoteValue().Contains(wxT("::")))
 
698
                                                declareStatement += wxT("::") + arg.getType();
 
699
                                }
 
700
                                declareStatement += wxT(";\n");
 
701
                                query.Append(strParam + wxT(", "));
 
702
                        }
 
703
                        else if (arg.getMode() != wxT("o"))
 
704
                        {
 
705
                                if (!arg.quoteValue().Contains(wxT("::")))
 
706
                                        query.Append( arg.quoteValue() + wxT("::") + arg.getType() + wxT(", "));
 
707
                                else
 
708
                                        query.Append( arg.quoteValue() + wxT(", "));
 
709
                        }
 
710
                }
 
711
                else if(arg.getMode() == wxT("v"))
 
712
                        query.Append( arg.getValue() + wxT(", "));
 
713
                else
 
714
                {
 
715
                        if (!arg.quoteValue().Contains(wxT("::")))
 
716
                                query.Append( arg.quoteValue() + wxT("::") + arg.getType() + wxT(", "));
 
717
                        else
 
718
                                query.Append( arg.quoteValue() + wxT(", "));
 
719
                }
 
720
        }
 
721
 
 
722
        if (query.EndsWith(wxT(", ")))
 
723
                query = query.Left(query.Length() - 2);
 
724
        else if (query.EndsWith(wxT("(")))
 
725
                query = query.Left(query.Length() - 1);
 
726
 
 
727
        // And terminate the argument list
 
728
        if(m_targetInfo->getArgInCount() + m_targetInfo->getArgInOutCount() == 0)
 
729
        {
 
730
                /*
 
731
                 * edbspl function/procedure with OUT parameter takes value/variable as an input
 
732
                 */
 
733
                if (m_conn->GetIsEdb())
 
734
                {
 
735
                        if (m_targetInfo->getArgCount() == 0)
 
736
                        {
 
737
                                if (m_targetInfo->getIsFunction() || m_targetInfo->getLanguage() != wxT("edbspl"))
 
738
                                        query.Append(wxT("()"));
 
739
                        }
 
740
                        else if (m_targetInfo->getLanguage() != wxT("edbspl"))
 
741
                                query.Append(wxT("()"));
 
742
                        else
 
743
                                query.Append(wxT(")"));
 
744
                }
 
745
                else if (m_targetInfo->getIsFunction())
 
746
                        query.Append(wxT("()"));
 
747
        }
 
748
        else
 
749
        {
 
750
                query.Append(wxT(")"));
 
751
        }
 
752
 
 
753
        if (m_conn->EdbMinimumVersion(8, 4) && (m_targetInfo->getLanguage() == wxT("edbspl") || !m_targetInfo->getIsFunction()))
 
754
        {
 
755
                wxString tmpQuery = wxT("DECLARE\n")
 
756
                                    + declareStatement
 
757
                                    + wxT("BEGIN\n")
 
758
                                    + query + wxT(";\n")
 
759
                                    + wxT("END;");
 
760
                query = tmpQuery;
 
761
        }
 
762
 
 
763
        // And send the completed command to the server - we'll get
 
764
        // a dbgDbResult event when the command completes (and that
 
765
        // event will get routed to dlgDirectDbg::OnResultReady())
 
766
        m_conn->startCommand( query, GetEventHandler(), RESULT_ID_DIRECT_TARGET_COMPLETE );
743
767
}
744
768
 
745
769
 
755
779
//
756
780
//  We should really display the complete result set somewhere too.
757
781
 
758
 
void dlgDirectDbg::OnTargetComplete( wxCommandEvent & event )
 
782
void dlgDirectDbg::OnTargetComplete( wxCommandEvent &event )
759
783
{
760
 
    // Extract the result set handle from the event and log the status info
761
 
 
762
 
    PGresult   * result = (PGresult *)event.GetClientData();
763
 
 
764
 
    wxLogInfo( wxT( "OnTargetComplete() called\n" ));
765
 
    wxLogInfo( wxT( "%s\n" ), wxString(PQresStatus( PQresultStatus( result )), wxConvUTF8).c_str());
766
 
 
767
 
    // If the query failed, write the error message to the status line, otherwise, copy the result set into the grid
768
 
    if(( PQresultStatus( result ) == PGRES_NONFATAL_ERROR ) || ( PQresultStatus( result ) == PGRES_FATAL_ERROR ))
769
 
    {
770
 
        wxString    message( PQresultErrorMessage( result ), wxConvUTF8 );
771
 
 
772
 
        message.Replace( wxT( "\n" ), wxT( " " ));
773
 
 
774
 
        m_parent->getStatusBar()->SetStatusText( message, 1 );
775
 
        char *state = PQresultErrorField(result,PG_DIAG_SQLSTATE);
776
 
 
777
 
        // Don't bother telling the user that he aborted - he already knows!
778
 
        if (state != NULL && strcmp(state, "57014"))
779
 
            wxLogError( wxT( "%s\n" ), wxString(PQerrorMessage(m_conn->getConnection()), wxConvUTF8).c_str());
780
 
        else
781
 
            wxLogInfo( wxT( "%s\n" ), wxString(PQerrorMessage(m_conn->getConnection()), wxConvUTF8).c_str());
782
 
    }
783
 
    else
784
 
    {
785
 
        wxString message( PQcmdStatus( result ), wxConvUTF8 );
786
 
 
787
 
        message.Replace( wxT( "\r" ), wxT( "" ));
788
 
        message.Replace( wxT( "\n" ), wxT( " " ));
789
 
 
790
 
        m_parent->getStatusBar()->SetStatusText( message, 1 );
791
 
 
792
 
        // If this result set has any columns, add a result grid to the code window so
793
 
        // we can show the results to the user
794
 
 
795
 
        if( m_codeWindow && PQnfields( result ))
796
 
        {
797
 
            m_codeWindow->OnResultSet( result );
798
 
        }
799
 
    }
800
 
 
801
 
    if (m_codeWindow)
802
 
    {
803
 
        m_codeWindow->m_targetComplete = true;
804
 
        m_codeWindow->disableTools( );
805
 
    }
806
 
 
807
 
    // Do not show if aborted
808
 
    if ( m_codeWindow && m_codeWindow->m_targetAborted )
809
 
        return;
810
 
 
811
 
    this->Show( true );
 
784
        // Extract the result set handle from the event and log the status info
 
785
 
 
786
        PGresult    *result = (PGresult *)event.GetClientData();
 
787
 
 
788
        wxLogInfo( wxT( "OnTargetComplete() called\n" ));
 
789
        wxLogInfo( wxT( "%s\n" ), wxString(PQresStatus( PQresultStatus( result )), wxConvUTF8).c_str());
 
790
 
 
791
        // If the query failed, write the error message to the status line, otherwise, copy the result set into the grid
 
792
        if(( PQresultStatus( result ) == PGRES_NONFATAL_ERROR ) || ( PQresultStatus( result ) == PGRES_FATAL_ERROR ))
 
793
        {
 
794
                wxString    message( PQresultErrorMessage( result ), wxConvUTF8 );
 
795
 
 
796
                message.Replace( wxT( "\n" ), wxT( " " ));
 
797
 
 
798
                m_parent->getStatusBar()->SetStatusText( message, 1 );
 
799
                char *state = PQresultErrorField(result, PG_DIAG_SQLSTATE);
 
800
 
 
801
                // Don't bother telling the user that he aborted - he already knows!
 
802
                // Depending on the stage, m_conn might not be set all! so check for
 
803
                // that first
 
804
                if (m_conn)
 
805
                {
 
806
                        if (state != NULL && strcmp(state, "57014"))
 
807
                                wxLogError( wxT( "%s\n" ), wxString(PQerrorMessage(m_conn->getConnection()), wxConvUTF8).c_str());
 
808
                        else
 
809
                                wxLogInfo( wxT( "%s\n" ), wxString(PQerrorMessage(m_conn->getConnection()), wxConvUTF8).c_str());
 
810
                }
 
811
        }
 
812
        else
 
813
        {
 
814
                wxString message( PQcmdStatus( result ), wxConvUTF8 );
 
815
 
 
816
                message.Replace( wxT( "\r" ), wxT( "" ));
 
817
                message.Replace( wxT( "\n" ), wxT( " " ));
 
818
 
 
819
                m_parent->getStatusBar()->SetStatusText( message, 1 );
 
820
 
 
821
                // If this result set has any columns, add a result grid to the code window so
 
822
                // we can show the results to the user
 
823
 
 
824
                if( m_codeWindow && PQnfields( result ))
 
825
                {
 
826
                        m_codeWindow->OnResultSet( result );
 
827
                }
 
828
        }
 
829
 
 
830
        if (m_codeWindow)
 
831
        {
 
832
                m_codeWindow->m_targetComplete = true;
 
833
                m_codeWindow->disableTools( );
 
834
        }
 
835
 
 
836
        // Do not show if aborted
 
837
        if ( m_codeWindow && m_codeWindow->m_targetAborted )
 
838
                return;
 
839
 
 
840
        this->Show( true );
812
841
}
813
842
 
814
843
////////////////////////////////////////////////////////////////////////////////
817
846
//    This event handler is called when a notice is received from the server (in
818
847
//  response to our invoking the target).  For now, we just forward this event
819
848
//  to the debugger window (m_codeWindow) and the notification message is added
820
 
//  to the debugger's message window.  
 
849
//  to the debugger's message window.
821
850
//
822
851
//  When/if we get around to adding a result set window to this class, we should
823
852
//  also add a message window too and display notice messages here instead of in
824
853
//  the debugger window.
825
854
 
826
 
void dlgDirectDbg::OnNoticeReceived( wxCommandEvent & event )
827
 
{   
828
 
    if( m_codeWindow )
829
 
        m_codeWindow->OnNoticeReceived( event );
 
855
void dlgDirectDbg::OnNoticeReceived( wxCommandEvent &event )
 
856
{
 
857
        if( m_codeWindow )
 
858
                m_codeWindow->OnNoticeReceived( event );
830
859
}
831
860
 
832
861
////////////////////////////////////////////////////////////////////////////////
833
862
// OnDebug()
834
863
//
835
864
//    This event handler is called when a PLDBGBREAK notice is received from the
836
 
//  server.  A quick review:  we've already set a breakpoint at the target and 
 
865
//  server.  A quick review:  we've already set a breakpoint at the target and
837
866
//  then we invoked the target (using the parameter values entered by the user).
838
867
//  Now we're waiting for a result set from the target.  Since we set a breakpoint
839
 
//  inside of the target, the server will send us a specially crafted NOTICE 
840
 
//  that tells use which port to attach to in order to contact the debugger 
 
868
//  inside of the target, the server will send us a specially crafted NOTICE
 
869
//  that tells use which port to attach to in order to contact the debugger
841
870
//  server - that's what 'event' contains.
842
871
//
843
872
//  When we get the PLDBGBREAK message (inside of 'event'), we create a new
844
 
//  debugger window by calling glMainFrame->addDebug() and let that window 
845
 
//  take over for a while.  When the target finally completes, we'll get a 
 
873
//  debugger window by calling glMainFrame->addDebug() and let that window
 
874
//  take over for a while.  When the target finally completes, we'll get a
846
875
//  a dbgDbResult event and handle the result set inside of OnResultReady()
847
876
 
848
 
void dlgDirectDbg::OnDebug( wxCommandEvent & event )
 
877
void dlgDirectDbg::OnDebug( wxCommandEvent &event )
849
878
{
850
 
    // This event contains a string of the form:
851
 
    //     /path/debugger -k --database=db --host=host --port=port --user=user &"
852
 
    // We can use that string to launch a separate debugger client.
853
 
    //
854
 
    // The event also contains a pointer to a map that contains keyword=value
855
 
    // pairs for the debugger connection properties.  To get to that map, we
856
 
    // call event.GetClientData().  Once we have the map, we can look for the
857
 
    // debugger connection properties such as "database", "host", "port", ...
858
 
 
859
 
    dbgConnProp * debugProps = (dbgConnProp *)event.GetClientData();
860
 
 
861
 
    m_codeWindow = m_parent->addDebug( *debugProps );
862
 
 
863
 
    if (m_codeWindow)
864
 
        m_codeWindow->startLocalDebugging();
865
 
 
866
 
    this->Show( false );
 
879
        // This event contains a string of the form:
 
880
        //     /path/debugger -k --database=db --host=host --port=port --user=user &"
 
881
        // We can use that string to launch a separate debugger client.
 
882
        //
 
883
        // The event also contains a pointer to a map that contains keyword=value
 
884
        // pairs for the debugger connection properties.  To get to that map, we
 
885
        // call event.GetClientData().  Once we have the map, we can look for the
 
886
        // debugger connection properties such as "database", "host", "port", ...
 
887
 
 
888
        dbgConnProp *debugProps = (dbgConnProp *)event.GetClientData();
 
889
 
 
890
        m_codeWindow = m_parent->addDebug( *debugProps );
 
891
 
 
892
        if (m_codeWindow)
 
893
                m_codeWindow->startLocalDebugging();
 
894
 
 
895
        this->Show( false );
867
896
}
868
897
 
869
898
////////////////////////////////////////////////////////////////////////////////
873
902
//  caller typically populates this list before calling startDebugging() - we
874
903
//  set a breakpoint for each member of the list
875
904
 
876
 
dbgBreakPointList & dlgDirectDbg::getBreakpointList()
877
 
878
 
    return( m_breakpoints ); 
 
905
dbgBreakPointList &dlgDirectDbg::getBreakpointList()
 
906
{
 
907
        return( m_breakpoints );
879
908
}
880
909