Added buttons to allow a dump of DB DATATYPES and DB DIAGNOSTIC info via wxLogMessage...
[wxWidgets.git] / samples / db / dbtest.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: dbtest.cpp
3 // Purpose: wxWindows database demo app
4 // Author: George Tasker
5 // Modified by:
6 // Created: 1998
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Remstar International, Inc.
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 /*
13 * SYNOPSIS START
14
15 This sample program demonstrates the cross-platform ODBC database classes
16 donated by the development team at Remstar International.
17
18 The table this sample is based on is developer contact table, and shows
19 some of the simple uses of the database classes wxDb and wxDbTable.
20
21 * SYNOPSIS END
22 */
23
24 #ifdef __GNUG__
25 #pragma implementation "dbtest.h"
26 #endif
27
28 #include "wx/wxprec.h"
29
30 #ifdef __BORLANDC__
31 #pragma hdrstop
32 #endif //__BORLANDC__
33
34 #ifndef WX_PRECOMP
35 #include <wx/wx.h>
36 #endif //WX_PRECOMP
37
38 #ifdef __WXGTK__
39 #include "db.xpm"
40 #endif
41
42 #include <stdio.h> /* Included strictly for reading the text file with the database parameters */
43
44 //#include <wx/db.h> /* Required in the file which will get the data source connection */
45 //#include <wx/dbtable.h> /* Has the wxDbTable object from which all data objects will inherit their data table functionality */
46
47 //extern wxDbList WXDLLEXPORT *PtrBegDbList; /* from db.cpp, used in getting back error results from db connections */
48
49 #include "dbtest.h" /* Header file for this demonstration program */
50 #include "listdb.h" /* Code to support the "Lookup" button on the editor dialog */
51
52 IMPLEMENT_APP(DatabaseDemoApp)
53
54 extern wxChar ListDB_Selection[]; /* Used to return the first column value for the selected line from the listDB routines */
55 extern wxChar ListDB_Selection2[]; /* Used to return the second column value for the selected line from the listDB routines */
56
57 const char *GetExtendedDBErrorMsg(wxDb *pDb, char *ErrFile, int ErrLine)
58 {
59 static wxString msg;
60 msg = wxT("");
61
62 wxString tStr;
63
64 if (ErrFile || ErrLine)
65 {
66 msg += wxT("File: ");
67 msg += ErrFile;
68 msg += wxT(" Line: ");
69 tStr.Printf(wxT("%d"),ErrLine);
70 msg += tStr.c_str();
71 msg += wxT("\n");
72 }
73
74 msg.Append (wxT("\nODBC errors:\n"));
75 msg += wxT("\n");
76
77 // Display errors for this connection
78 int i;
79 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
80 {
81 if (pDb->errorList[i])
82 {
83 msg.Append(pDb->errorList[i]);
84 if (wxStrcmp(pDb->errorList[i],wxT("")) != 0)
85 msg.Append(wxT("\n"));
86 // Clear the errmsg buffer so the next error will not
87 // end up showing the previous error that have occurred
88 wxStrcpy(pDb->errorList[i],wxT(""));
89 }
90 }
91 msg += wxT("\n");
92
93 return msg.c_str();
94 } // GetExtendedDBErrorMsg
95
96
97 bool DataTypeSupported(wxDb *pDb, SWORD datatype)
98 {
99 wxDbSqlTypeInfo sqlTypeInfo;
100
101 bool breakpoint = FALSE;
102
103 if (pDb->GetDataTypeInfo(datatype, sqlTypeInfo))
104 breakpoint = TRUE;
105
106 return breakpoint;
107
108 } // GetDataTypesSupported();
109
110
111
112 void CheckSupportForAllDataTypes(wxDb *pDb)
113 {
114 wxLogMessage("\nThe following datatypes are supported by the\ndatabase you are currently connected to:");
115 #ifdef SQL_C_BINARY
116 if (DataTypeSupported(pDb,SQL_C_BINARY))
117 wxLogMessage("SQL_C_BINARY");
118 #endif
119 #ifdef SQL_C_BIT
120 if (DataTypeSupported(pDb,SQL_C_BIT))
121 wxLogMessage("SQL_C_BIT");
122 #endif
123 #ifdef SQL_C_BOOKMARK
124 if (DataTypeSupported(pDb,SQL_C_BOOKMARK))
125 wxLogMessage("SQL_C_BOOKMARK");
126 #endif
127 #ifdef SQL_C_CHAR
128 if (DataTypeSupported(pDb,SQL_C_CHAR))
129 wxLogMessage("SQL_C_CHAR");
130 #endif
131 #ifdef SQL_C_DATE
132 if (DataTypeSupported(pDb,SQL_C_DATE))
133 wxLogMessage("SQL_C_DATE");
134 #endif
135 #ifdef SQL_C_DEFAULT
136 if (DataTypeSupported(pDb,SQL_C_DEFAULT))
137 wxLogMessage("SQL_C_DEFAULT");
138 #endif
139 #ifdef SQL_C_DOUBLE
140 if (DataTypeSupported(pDb,SQL_C_DOUBLE))
141 wxLogMessage("SQL_C_DOUBLE");
142 #endif
143 #ifdef SQL_C_FLOAT
144 if (DataTypeSupported(pDb,SQL_C_FLOAT))
145 wxLogMessage("SQL_C_FLOAT");
146 #endif
147 #ifdef SQL_C_GUID
148 if (DataTypeSupported(pDb,SQL_C_GUID))
149 wxLogMessage("SQL_C_GUID");
150 #endif
151 #ifdef SQL_C_INTERVAL_DAY
152 if (DataTypeSupported(pDb,SQL_C_INTERVAL_DAY))
153 wxLogMessage("SQL_C_INTERVAL_DAY");
154 #endif
155 #ifdef SQL_C_INTERVAL_DAY_TO_HOUR
156 if (DataTypeSupported(pDb,SQL_C_INTERVAL_DAY_TO_HOUR))
157 wxLogMessage("SQL_C_INTERVAL_DAY_TO_HOUR");
158 #endif
159 #ifdef SQL_C_INTERVAL_DAY_TO_MINUTE
160 if (DataTypeSupported(pDb,SQL_C_INTERVAL_DAY_TO_MINUTE))
161 wxLogMessage("SQL_C_INTERVAL_DAY_TO_MINUTE");
162 #endif
163 #ifdef SQL_C_INTERVAL_DAY_TO_SECOND
164 if (DataTypeSupported(pDb,SQL_C_INTERVAL_DAY_TO_SECOND))
165 wxLogMessage("SQL_C_INTERVAL_DAY_TO_SECOND");
166 #endif
167 #ifdef SQL_C_INTERVAL_HOUR
168 if (DataTypeSupported(pDb,SQL_C_INTERVAL_HOUR))
169 wxLogMessage("SQL_C_INTERVAL_HOUR");
170 #endif
171 #ifdef SQL_C_INTERVAL_HOUR_TO_MINUTE
172 if (DataTypeSupported(pDb,SQL_C_INTERVAL_HOUR_TO_MINUTE))
173 wxLogMessage("SQL_C_INTERVAL_HOUR_TO_MINUTE");
174 #endif
175 #ifdef SQL_C_INTERVAL_HOUR_TO_SECOND
176 if (DataTypeSupported(pDb,SQL_C_INTERVAL_HOUR_TO_SECOND))
177 wxLogMessage("SQL_C_INTERVAL_HOUR_TO_SECOND");
178 #endif
179 #ifdef SQL_C_INTERVAL_MINUTE
180 if (DataTypeSupported(pDb,SQL_C_INTERVAL_MINUTE))
181 wxLogMessage("SQL_C_INTERVAL_MINUTE");
182 #endif
183 #ifdef SQL_C_INTERVAL_MINUTE_TO_SECOND
184 if (DataTypeSupported(pDb,SQL_C_INTERVAL_MINUTE_TO_SECOND))
185 wxLogMessage("SQL_C_INTERVAL_MINUTE_TO_SECOND");
186 #endif
187 #ifdef SQL_C_INTERVAL_MONTH
188 if (DataTypeSupported(pDb,SQL_C_INTERVAL_MONTH))
189 wxLogMessage("SQL_C_INTERVAL_MONTH");
190 #endif
191 #ifdef SQL_C_INTERVAL_SECOND
192 if (DataTypeSupported(pDb,SQL_C_INTERVAL_SECOND))
193 wxLogMessage("SQL_C_INTERVAL_SECOND");
194 #endif
195 #ifdef SQL_C_INTERVAL_YEAR
196 if (DataTypeSupported(pDb,SQL_C_INTERVAL_YEAR))
197 wxLogMessage("SQL_C_INTERVAL_YEAR");
198 #endif
199 #ifdef SQL_C_INTERVAL_YEAR_TO_MONTH
200 if (DataTypeSupported(pDb,SQL_C_INTERVAL_YEAR_TO_MONTH))
201 wxLogMessage("SQL_C_INTERVAL_YEAR_TO_MONTH");
202 #endif
203 #ifdef SQL_C_LONG
204 if (DataTypeSupported(pDb,SQL_C_LONG))
205 wxLogMessage("SQL_C_LONG");
206 #endif
207 #ifdef SQL_C_NUMERIC
208 if (DataTypeSupported(pDb,SQL_C_NUMERIC))
209 wxLogMessage("SQL_C_NUMERIC");
210 #endif
211 #ifdef SQL_C_SBIGINT
212 if (DataTypeSupported(pDb,SQL_C_SBIGINT))
213 wxLogMessage("SQL_C_SBIGINT");
214 #endif
215 #ifdef SQL_C_SHORT
216 if (DataTypeSupported(pDb,SQL_C_SHORT))
217 wxLogMessage("SQL_C_SHORT");
218 #endif
219 #ifdef SQL_C_SLONG
220 if (DataTypeSupported(pDb,SQL_C_SLONG))
221 wxLogMessage("SQL_C_SLONG");
222 #endif
223 #ifdef SQL_C_SSHORT
224 if (DataTypeSupported(pDb,SQL_C_SSHORT))
225 wxLogMessage("SQL_C_SSHORT");
226 #endif
227 #ifdef SQL_C_STINYINT
228 if (DataTypeSupported(pDb,SQL_C_STINYINT))
229 wxLogMessage("SQL_C_STINYINT");
230 #endif
231 #ifdef SQL_C_TIME
232 if (DataTypeSupported(pDb,SQL_C_TIME))
233 wxLogMessage("SQL_C_TIME");
234 #endif
235 #ifdef SQL_C_TIMESTAMP
236 if (DataTypeSupported(pDb,SQL_C_TIMESTAMP))
237 wxLogMessage("SQL_C_TIMESTAMP");
238 #endif
239 #ifdef SQL_C_TINYINT
240 if (DataTypeSupported(pDb,SQL_C_TINYINT))
241 wxLogMessage("SQL_C_TINYINT");
242 #endif
243 #ifdef SQL_C_TYPE_DATE
244 if (DataTypeSupported(pDb,SQL_C_TYPE_DATE))
245 wxLogMessage("SQL_C_TYPE_DATE");
246 #endif
247 #ifdef SQL_C_TYPE_TIME
248 if (DataTypeSupported(pDb,SQL_C_TYPE_TIME))
249 wxLogMessage("SQL_C_TYPE_TIME");
250 #endif
251 #ifdef SQL_C_TYPE_TIMESTAMP
252 if (DataTypeSupported(pDb,SQL_C_TYPE_TIMESTAMP))
253 wxLogMessage("SQL_C_TYPE_TIMESTAMP");
254 #endif
255 #ifdef SQL_C_UBIGINT
256 if (DataTypeSupported(pDb,SQL_C_UBIGINT))
257 wxLogMessage("SQL_C_UBIGINT");
258 #endif
259 #ifdef SQL_C_ULONG
260 if (DataTypeSupported(pDb,SQL_C_ULONG))
261 wxLogMessage("SQL_C_ULONG");
262 #endif
263 #ifdef SQL_C_USHORT
264 if (DataTypeSupported(pDb,SQL_C_USHORT))
265 wxLogMessage("SQL_C_USHORT");
266 #endif
267 #ifdef SQL_C_UTINYINT
268 if (DataTypeSupported(pDb,SQL_C_UTINYINT))
269 wxLogMessage("SQL_C_UTINYINT");
270 #endif
271 #ifdef SQL_C_VARBOOKMARK
272 if (DataTypeSupported(pDb,SQL_C_VARBOOKMARK))
273 wxLogMessage("SQL_C_VARBOOKMARK");
274 #endif
275
276 // Extended SQL types
277 #ifdef SQL_DATE
278 if (DataTypeSupported(pDb,SQL_DATE))
279 wxLogMessage("SQL_DATE");
280 #endif
281 #ifdef SQL_INTERVAL
282 if (DataTypeSupported(pDb,SQL_INTERVAL))
283 wxLogMessage("SQL_INTERVAL");
284 #endif
285 #ifdef SQL_TIME
286 if (DataTypeSupported(pDb,SQL_TIME))
287 wxLogMessage("SQL_TIME");
288 #endif
289 #ifdef SQL_TIMESTAMP
290 if (DataTypeSupported(pDb,SQL_TIMESTAMP))
291 wxLogMessage("SQL_TIMESTAMP");
292 #endif
293 #ifdef SQL_LONGVARCHAR
294 if (DataTypeSupported(pDb,SQL_LONGVARCHAR))
295 wxLogMessage("SQL_LONGVARCHAR");
296 #endif
297 #ifdef SQL_BINARY
298 if (DataTypeSupported(pDb,SQL_BINARY))
299 wxLogMessage("SQL_BINARY");
300 #endif
301 #ifdef SQL_VARBINARY
302 if (DataTypeSupported(pDb,SQL_VARBINARY))
303 wxLogMessage("SQL_VARBINARY");
304 #endif
305 #ifdef SQL_LONGVARBINARY
306 if (DataTypeSupported(pDb,SQL_LONGVARBINARY))
307 wxLogMessage("SQL_LONGVARBINARY");
308 #endif
309 #ifdef SQL_BIGINT
310 if (DataTypeSupported(pDb,SQL_BIGINT))
311 wxLogMessage("SQL_BIGINT");
312 #endif
313 #ifdef SQL_TINYINT
314 if (DataTypeSupported(pDb,SQL_TINYINT))
315 wxLogMessage("SQL_TINYINT");
316 #endif
317 #ifdef SQL_BIT
318 if (DataTypeSupported(pDb,SQL_BIT))
319 wxLogMessage("SQL_BIT");
320 #endif
321 #ifdef SQL_GUID
322 if (DataTypeSupported(pDb,SQL_GUID))
323 wxLogMessage("SQL_GUID");
324 #endif
325
326 #ifdef SQL_CHAR
327 if (DataTypeSupported(pDb,SQL_CHAR))
328 wxLogMessage("SQL_CHAR");
329 #endif
330 #ifdef SQL_INTEGER
331 if (DataTypeSupported(pDb,SQL_INTEGER))
332 wxLogMessage("SQL_INTEGER");
333 #endif
334 #ifdef SQL_SMALLINT
335 if (DataTypeSupported(pDb,SQL_SMALLINT))
336 wxLogMessage("SQL_SMALLINT");
337 #endif
338 #ifdef SQL_REAL
339 if (DataTypeSupported(pDb,SQL_REAL))
340 wxLogMessage("SQL_REAL");
341 #endif
342 #ifdef SQL_DOUBLE
343 if (DataTypeSupported(pDb,SQL_DOUBLE))
344 wxLogMessage("SQL_DOUBLE");
345 #endif
346 #ifdef SQL_NUMERIC
347 if (DataTypeSupported(pDb,SQL_NUMERIC))
348 wxLogMessage("SQL_NUMERIC");
349 #endif
350 #ifdef SQL_DATE
351 if (DataTypeSupported(pDb,SQL_DATE))
352 wxLogMessage("SQL_DATE");
353 #endif
354 #ifdef SQL_TIME
355 if (DataTypeSupported(pDb,SQL_TIME))
356 wxLogMessage("SQL_TIME");
357 #endif
358 #ifdef SQL_TIMESTAMP
359 if (DataTypeSupported(pDb,SQL_TIMESTAMP))
360 wxLogMessage("SQL_TIMESTAMP");
361 #endif
362 #ifdef SQL_VARCHAR
363 if (DataTypeSupported(pDb,SQL_VARCHAR))
364 wxLogMessage("SQL_VARCHAR");
365 #endif
366
367 // UNICODE
368 #ifdef SQL_C_TCHAR
369 if (DataTypeSupported(pDb,SQL_C_TCHAR))
370 wxLogMessage("SQL_C_TCHAR (Unicode support is possible)");
371 #endif
372
373 wxLogMessage("\n");
374 } // CheckSupportForAllDataTypes()
375
376
377 bool DatabaseDemoApp::OnInit()
378 {
379 DbConnectInf = NULL;
380 Contact = NULL;
381
382 // Create the main frame window
383 DemoFrame = new DatabaseDemoFrame(NULL, wxT("wxWindows Database Demo"), wxPoint(50, 50), wxSize(537, 480));
384
385 // Give it an icon
386 DemoFrame->SetIcon(wxICON(db));
387
388 // Make a menubar
389 wxMenu *file_menu = new wxMenu;
390 file_menu->Append(FILE_CREATE, wxT("&Create CONTACT table"));
391 file_menu->Append(FILE_RECREATE_TABLE, wxT("&Recreate CONTACT table"));
392 file_menu->Append(FILE_RECREATE_INDEXES, wxT("&Recreate CONTACT indexes"));
393 file_menu->Append(FILE_EXIT, wxT("E&xit"));
394
395 wxMenu *edit_menu = new wxMenu;
396 edit_menu->Append(EDIT_PARAMETERS, wxT("&Parameters..."));
397
398 wxMenu *help_menu = new wxMenu;
399 help_menu->Append(HELP_ABOUT, wxT("&About"));
400
401 wxMenuBar *menu_bar = new wxMenuBar;
402 menu_bar->Append(file_menu, wxT("&File"));
403 menu_bar->Append(edit_menu, wxT("&Edit"));
404 menu_bar->Append(help_menu, wxT("&Help"));
405 DemoFrame->SetMenuBar(menu_bar);
406
407 params.ODBCSource[0] = 0;
408 params.UserName[0] = 0;
409 params.Password[0] = 0;
410 params.DirPath[0] = 0;
411
412 // Show the frame
413 DemoFrame->Show(TRUE);
414
415 // Passing NULL for the SQL environment handle causes
416 // the wxDbConnectInf constructor to obtain a handle
417 // for you.
418 //
419 // WARNING: Be certain that you do not free this handle
420 // directly with SQLFreeEnv(). Use either the
421 // method ::FreeHenv() or delete the DbConnectInf.
422 DbConnectInf = new wxDbConnectInf(NULL, params.ODBCSource, params.UserName,
423 params.Password, params.DirPath);
424
425 if (!DbConnectInf || !DbConnectInf->GetHenv())
426 {
427 wxMessageBox(wxT("Unable to define data source connection info."), wxT("DB CONNECTION ERROR..."),wxOK | wxICON_EXCLAMATION);
428 wxDELETE(DbConnectInf);
429 }
430
431 if (!ReadParamFile(params))
432 DemoFrame->BuildParameterDialog(NULL);
433
434 if (!wxStrlen(params.ODBCSource))
435 {
436 wxDELETE(DbConnectInf);
437 return(FALSE);
438 }
439
440 DbConnectInf->SetDsn(params.ODBCSource);
441 DbConnectInf->SetUserID(params.UserName);
442 DbConnectInf->SetPassword(params.Password);
443 DbConnectInf->SetDefaultDir(params.DirPath);
444
445 READONLY_DB = wxDbGetConnection(DbConnectInf);
446 if (READONLY_DB == 0)
447 {
448 wxMessageBox(wxT("Unable to connect to the data source.\n\nCheck the name of your data source to verify it has been correctly entered/spelled.\n\nWith some databases, the user name and password must\nbe created with full rights to the CONTACT table prior to making a connection\n(using tools provided by the database manufacturer)"), wxT("DB CONNECTION ERROR..."),wxOK | wxICON_EXCLAMATION);
449 DemoFrame->BuildParameterDialog(NULL);
450 wxDELETE(DbConnectInf);
451 wxMessageBox(wxT("Now exiting program.\n\nRestart program to try any new settings."),wxT("Notice..."),wxOK | wxICON_INFORMATION);
452 return(FALSE);
453 }
454
455 DemoFrame->BuildEditorDialog();
456
457 // Show the frame
458 DemoFrame->Refresh();
459
460 return TRUE;
461 } // DatabaseDemoApp::OnInit()
462
463
464 bool DatabaseDemoApp::ReadParamFile(Cparameters &params)
465 {
466 FILE *paramFile;
467 if ((paramFile = fopen(PARAM_FILENAME, wxT("r"))) == NULL)
468 {
469 wxString tStr;
470 tStr.Printf(wxT("Unable to open the parameter file '%s' for reading.\n\nYou must specify the data source, user name, and\npassword that will be used and save those settings."),PARAM_FILENAME);
471 wxMessageBox(tStr,wxT("File I/O Error..."),wxOK | wxICON_EXCLAMATION);
472
473 return FALSE;
474 }
475
476 wxChar buffer[1000+1];
477 fgets(buffer, sizeof(params.ODBCSource), paramFile);
478 buffer[wxStrlen(buffer)-1] = wxT('\0');
479 wxStrcpy(params.ODBCSource,buffer);
480
481 fgets(buffer, sizeof(params.UserName), paramFile);
482 buffer[wxStrlen(buffer)-1] = wxT('\0');
483 wxStrcpy(params.UserName,buffer);
484
485 fgets(buffer, sizeof(params.Password), paramFile);
486 buffer[wxStrlen(buffer)-1] = wxT('\0');
487 wxStrcpy(params.Password,buffer);
488
489 fgets(buffer, sizeof(params.DirPath), paramFile);
490 buffer[wxStrlen(buffer)-1] = wxT('\0');
491 wxStrcpy(params.DirPath,buffer);
492
493 fclose(paramFile);
494
495 return TRUE;
496 } // DatabaseDemoApp::ReadParamFile()
497
498
499 bool DatabaseDemoApp::WriteParamFile(Cparameters &params)
500 {
501 FILE *paramFile;
502 if ((paramFile = fopen(PARAM_FILENAME, wxT("wt"))) == NULL)
503 {
504 wxString tStr;
505 tStr.Printf(wxT("Unable to write/overwrite '%s'."),PARAM_FILENAME);
506 wxMessageBox(tStr,wxT("File I/O Error..."),wxOK | wxICON_EXCLAMATION);
507 return FALSE;
508 }
509
510 fputs(wxGetApp().params.ODBCSource, paramFile);
511 fputc(wxT('\n'), paramFile);
512 fputs(wxGetApp().params.UserName, paramFile);
513 fputc(wxT('\n'), paramFile);
514 fputs(wxGetApp().params.Password, paramFile);
515 fputc(wxT('\n'), paramFile);
516 fputs(wxGetApp().params.DirPath, paramFile);
517 fputc(wxT('\n'), paramFile);
518 fclose(paramFile);
519
520 return TRUE;
521 } // DatabaseDemoApp::WriteParamFile()
522
523
524 void DatabaseDemoApp::CreateDataTable(bool recreate)
525 {
526 bool Ok = TRUE;
527 if (recreate)
528 Ok = (wxMessageBox(wxT("Any data currently residing in the table will be erased.\n\nAre you sure?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
529
530 if (!Ok)
531 return;
532
533 wxBeginBusyCursor();
534
535 bool success = TRUE;
536
537 Contact->GetDb()->RollbackTrans(); // Make sure the current cursor is in a known/stable state
538
539 if (!Contact->CreateTable(recreate))
540 {
541 wxEndBusyCursor();
542 wxString tStr;
543 tStr = wxT("Error creating CONTACTS table.\nTable was not created.\n\n");
544 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
545 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
546 success = FALSE;
547 }
548 else
549 {
550 if (!Contact->CreateIndexes())
551 {
552 wxEndBusyCursor();
553 wxString tStr;
554 tStr = wxT("Error creating CONTACTS indexes.\nIndexes will be unavailable.\n\n");
555 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
556 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
557 success = FALSE;
558 }
559 }
560 while (wxIsBusy())
561 wxEndBusyCursor();
562
563 if (success)
564 wxMessageBox(wxT("Table and index(es) were successfully created."),wxT("Notice..."),wxOK | wxICON_INFORMATION);
565 } // DatabaseDemoApp::CreateDataTable()
566
567
568 BEGIN_EVENT_TABLE(DatabaseDemoFrame, wxFrame)
569 EVT_MENU(FILE_CREATE, DatabaseDemoFrame::OnCreate)
570 EVT_MENU(FILE_RECREATE_TABLE, DatabaseDemoFrame::OnRecreateTable)
571 EVT_MENU(FILE_RECREATE_INDEXES, DatabaseDemoFrame::OnRecreateIndexes)
572 EVT_MENU(FILE_EXIT, DatabaseDemoFrame::OnExit)
573 EVT_MENU(EDIT_PARAMETERS, DatabaseDemoFrame::OnEditParameters)
574 EVT_MENU(HELP_ABOUT, DatabaseDemoFrame::OnAbout)
575 EVT_CLOSE(DatabaseDemoFrame::OnCloseWindow)
576 END_EVENT_TABLE()
577
578
579 // DatabaseDemoFrame constructor
580 DatabaseDemoFrame::DatabaseDemoFrame(wxFrame *frame, const wxString& title,
581 const wxPoint& pos, const wxSize& size):
582 wxFrame(frame, -1, title, pos, size)
583 {
584 // Put any code in necessary for initializing the main frame here
585 pEditorDlg = NULL;
586 pParamDlg = NULL;
587
588 delete wxLog::SetActiveTarget(new wxLogStderr);
589
590 } // DatabaseDemoFrame constructor
591
592 DatabaseDemoFrame::~DatabaseDemoFrame()
593 {
594 delete wxLog::SetActiveTarget(NULL);
595 } // DatabaseDemoFrame destructor
596
597
598 void DatabaseDemoFrame::OnCreate(wxCommandEvent& event)
599 {
600 wxGetApp().CreateDataTable(FALSE);
601 } // DatabaseDemoFrame::OnCreate()
602
603
604 void DatabaseDemoFrame::OnRecreateTable(wxCommandEvent& event)
605 {
606 wxGetApp().CreateDataTable(TRUE);
607 } // DatabaseDemoFrame::OnRecreate()
608
609
610 void DatabaseDemoFrame::OnRecreateIndexes(wxCommandEvent& event)
611 {
612 if (!wxGetApp().Contact->CreateIndexes())
613 {
614 while (wxIsBusy())
615 wxEndBusyCursor();
616 wxString tStr;
617 tStr = wxT("Error creating CONTACTS indexes.\nNew indexes will be unavailable.\n\n");
618 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
619 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
620 }
621 else
622 wxMessageBox(wxT("Index(es) were successfully recreated."),wxT("Notice..."),wxOK | wxICON_INFORMATION);
623
624 } // DatabaseDemoFrame::OnRecreateIndexes()
625
626
627 void DatabaseDemoFrame::OnExit(wxCommandEvent& event)
628 {
629 Close();
630 } // DatabaseDemoFrame::OnExit()
631
632
633 void DatabaseDemoFrame::OnEditParameters(wxCommandEvent& event)
634 {
635 if ((pEditorDlg->mode != mCreate) && (pEditorDlg->mode != mEdit))
636 BuildParameterDialog(this);
637 else
638 wxMessageBox(wxT("Cannot change database parameters while creating or editing a record"),wxT("Notice..."),wxOK | wxICON_INFORMATION);
639 } // DatabaseDemoFrame::OnEditParameters()
640
641
642 void DatabaseDemoFrame::OnAbout(wxCommandEvent& event)
643 {
644 wxMessageBox(wxT("wxWindows sample program for database classes\n\nContributed on 27 July 1998"),wxT("About..."),wxOK | wxICON_INFORMATION);
645 } // DatabaseDemoFrame::OnAbout()
646
647
648 // Put any additional checking necessary to make certain it is alright
649 // to close the program here that is not done elsewhere
650 void DatabaseDemoFrame::OnCloseWindow(wxCloseEvent& event)
651 {
652 // Clean up time
653 if (pEditorDlg && pEditorDlg->Close())
654 pEditorDlg = NULL;
655 else
656 {
657 if (pEditorDlg)
658 {
659 event.Veto();
660 return;
661 }
662 }
663
664 wxDELETE(wxGetApp().Contact);
665
666 // This function will close all the connections to the database that have been
667 // previously cached.
668 wxDbCloseConnections();
669
670 // Deletion of the wxDbConnectInf instance must be the LAST thing done that
671 // has anything to do with the database. Deleting this before disconnecting,
672 // freeing/closing connections, etc will result in a crash!
673 wxDELETE(wxGetApp().DbConnectInf);
674
675 this->Destroy();
676
677 } // DatabaseDemoFrame::OnCloseWindow()
678
679
680 void DatabaseDemoFrame::BuildEditorDialog()
681 {
682 pEditorDlg = NULL;
683 pEditorDlg = new CeditorDlg(this);
684 if (pEditorDlg)
685 {
686 pEditorDlg->Initialize();
687 if (!pEditorDlg->initialized)
688 {
689 pEditorDlg->Close();
690 pEditorDlg = NULL;
691 wxMessageBox(wxT("Unable to initialize the editor dialog for some reason"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
692 Close();
693 }
694 }
695 else
696 {
697 wxMessageBox(wxT("Unable to create the editor dialog for some reason"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
698 Close();
699 }
700 } // DatabaseDemoFrame::BuildEditorDialog()
701
702
703 void DatabaseDemoFrame::BuildParameterDialog(wxWindow *parent)
704 {
705 pParamDlg = new CparameterDlg(parent);
706
707 if (!pParamDlg)
708 wxMessageBox(wxT("Unable to create the parameter dialog for some reason"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
709 } // DatabaseDemoFrame::BuildParameterDialog()
710
711
712 /*
713 * Constructor note: If no wxDb object is passed in, a new connection to the database
714 * is created for this instance of Ccontact. This can be a slow process depending
715 * on the database engine being used, and some database engines have a limit on the
716 * number of connections (either hard limits, or license restricted) so care should
717 * be used to use as few connections as is necessary.
718 *
719 * IMPORTANT: Objects which share a wxDb pointer are ALL acted upon whenever a member
720 * function of pDb is called (i.e. CommitTrans() or RollbackTrans(), so if modifying
721 * or creating a table objects which use the same pDb, know that all the objects
722 * will be committed or rolled back when any of the objects has this function call made.
723 */
724 Ccontact::Ccontact (wxDb *pwxDb) : wxDbTable(pwxDb ? pwxDb : wxDbGetConnection(wxGetApp().DbConnectInf),
725 CONTACT_TABLE_NAME, CONTACT_NO_COLS, wxT(""),
726 !wxDB_QUERY_ONLY, wxGetApp().DbConnectInf->GetDefaultDir())
727 {
728 // This is used to represent whether the database connection should be released
729 // when this instance of the object is deleted. If using the same connection
730 // for multiple instance of database objects, then the connection should only be
731 // released when the last database instance using the connection is deleted
732 freeDbConn = !pwxDb;
733
734 if (GetDb())
735 GetDb()->SetSqlLogging(sqlLogON);
736
737 SetupColumns();
738
739 } // Ccontact Constructor
740
741
742 void Ccontact::Initialize()
743 {
744 Name[0] = 0;
745 Addr1[0] = 0;
746 Addr2[0] = 0;
747 City[0] = 0;
748 State[0] = 0;
749 PostalCode[0] = 0;
750 Country[0] = 0;
751 JoinDate.year = 1980;
752 JoinDate.month = 1;
753 JoinDate.day = 1;
754 JoinDate.hour = 0;
755 JoinDate.minute = 0;
756 JoinDate.second = 0;
757 JoinDate.fraction = 0;
758 NativeLanguage = langENGLISH;
759 IsDeveloper = FALSE;
760 Contributions = 0;
761 LinesOfCode = 0L;
762 } // Ccontact::Initialize
763
764
765 Ccontact::~Ccontact()
766 {
767 if (freeDbConn)
768 {
769 if (!wxDbFreeConnection(GetDb()))
770 {
771 wxString tStr;
772 tStr = wxT("Unable to Free the Ccontact data table handle\n\n");
773 tStr += GetExtendedDBErrorMsg(GetDb(),__FILE__,__LINE__);
774 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
775 }
776 }
777 } // Ccontract destructor
778
779
780 /*
781 * Handles setting up all the connections for the interface from the wxDbTable
782 * functions to interface to the data structure used to store records in
783 * memory, and for all the column definitions that define the table structure
784 */
785 void Ccontact::SetupColumns()
786 {
787 // NOTE: Columns now are 8 character names, as that is all dBase can support. Longer
788 // names can be used for other database engines
789 SetColDefs ( 0,wxT("NAME"), DB_DATA_TYPE_VARCHAR, Name, SQL_C_CHAR, sizeof(Name), TRUE, TRUE); // Primary index
790 SetColDefs ( 1,wxT("ADDRESS1"), DB_DATA_TYPE_VARCHAR, Addr1, SQL_C_CHAR, sizeof(Addr1), FALSE,TRUE);
791 SetColDefs ( 2,wxT("ADDRESS2"), DB_DATA_TYPE_VARCHAR, Addr2, SQL_C_CHAR, sizeof(Addr2), FALSE,TRUE);
792 SetColDefs ( 3,wxT("CITY"), DB_DATA_TYPE_VARCHAR, City, SQL_C_CHAR, sizeof(City), FALSE,TRUE);
793 SetColDefs ( 4,wxT("STATE"), DB_DATA_TYPE_VARCHAR, State, SQL_C_CHAR, sizeof(State), FALSE,TRUE);
794 SetColDefs ( 5,wxT("POSTCODE"), DB_DATA_TYPE_VARCHAR, PostalCode, SQL_C_CHAR, sizeof(PostalCode), FALSE,TRUE);
795 SetColDefs ( 6,wxT("COUNTRY"), DB_DATA_TYPE_VARCHAR, Country, SQL_C_CHAR, sizeof(Country), FALSE,TRUE);
796 SetColDefs ( 7,wxT("JOINDATE"), DB_DATA_TYPE_DATE, &JoinDate, SQL_C_TIMESTAMP, sizeof(JoinDate), FALSE,TRUE);
797 SetColDefs ( 8,wxT("IS_DEV"), DB_DATA_TYPE_INTEGER, &IsDeveloper, SQL_C_BOOLEAN(IsDeveloper), sizeof(IsDeveloper), FALSE,TRUE);
798 SetColDefs ( 9,wxT("CONTRIBS"), DB_DATA_TYPE_INTEGER, &Contributions, SQL_C_USHORT, sizeof(Contributions), FALSE,TRUE);
799 SetColDefs (10,wxT("LINE_CNT"), DB_DATA_TYPE_INTEGER, &LinesOfCode, SQL_C_ULONG, sizeof(LinesOfCode), FALSE,TRUE);
800 SetColDefs (11,wxT("LANGUAGE"), DB_DATA_TYPE_INTEGER, &NativeLanguage, SQL_C_ENUM, sizeof(NativeLanguage), FALSE,TRUE);
801 #if wxODBC_BLOB_EXPERIMENT > 0
802 SetColDefs (12,wxT("PICTURE"), DB_DATA_TYPE_BLOB, Picture, SQL_LONGVARBINARY, sizeof(Picture), FALSE,TRUE);
803 #endif
804 } // Ccontact::SetupColumns
805
806
807 bool Ccontact::CreateIndexes(void)
808 {
809 // This index could easily be accomplished with an "orderBy" clause,
810 // but is done to show how to construct a non-primary index.
811 wxString indexName;
812 wxDbIdxDef idxDef[2];
813
814 bool Ok = TRUE;
815
816 wxStrcpy(idxDef[0].ColName, "IS_DEV");
817 idxDef[0].Ascending = TRUE;
818
819 wxStrcpy(idxDef[1].ColName, "NAME");
820 idxDef[1].Ascending = TRUE;
821
822 indexName = GetTableName();
823 indexName += "_IDX1";
824 Ok = CreateIndex(indexName.c_str(), TRUE, 2, idxDef);
825
826 return Ok;
827 } // Ccontact::CreateIndexes()
828
829
830 /*
831 * Having a function to do a query on the primary key (and possibly others) is
832 * very efficient and tighter coding so that it is available where ever the object
833 * is. Great for use with multiple tables when not using views or outer joins
834 */
835 bool Ccontact::FetchByName(const wxString &name)
836 {
837 whereStr.Printf(wxT("NAME = '%s'"),name.c_str());
838 SetWhereClause(whereStr.c_str());
839 SetOrderByClause(wxT(""));
840
841 if (!Query())
842 return(FALSE);
843
844 // Fetch the record
845 return(GetNext());
846
847 } // Ccontact::FetchByName()
848
849
850 /*
851 *
852 * ************* DIALOGS ***************
853 *
854 */
855
856
857 /* CeditorDlg constructor
858 *
859 * Creates the dialog used for creating/editing/deleting/copying a Ccontact object.
860 * This dialog actually is drawn in the main frame of the program
861 *
862 * An instance of Ccontact is created - "Contact" - which is used to hold the Ccontact
863 * object that is currently being worked with.
864 */
865
866 BEGIN_EVENT_TABLE(CeditorDlg, wxPanel)
867 EVT_BUTTON(-1, CeditorDlg::OnButton)
868 EVT_CLOSE(CeditorDlg::OnCloseWindow)
869 END_EVENT_TABLE()
870
871 CeditorDlg::CeditorDlg(wxWindow *parent) : wxPanel (parent, 0, 0, 537, 480)
872 {
873 // Since the ::OnCommand() function is overridden, this prevents the widget
874 // detection in ::OnCommand() until all widgets have been initialized to prevent
875 // uninitialized pointers from crashing the program
876 widgetPtrsSet = FALSE;
877
878 initialized = FALSE;
879
880 SetMode(mView);
881
882 Show(FALSE);
883 } // CeditorDlg constructor
884
885
886 void CeditorDlg::OnCloseWindow(wxCloseEvent& event)
887 {
888 // Clean up time
889 if ((mode != mCreate) && (mode != mEdit))
890 {
891 this->Destroy();
892 }
893 else
894 {
895 wxMessageBox(wxT("Must finish processing the current record being created/modified before exiting"),wxT("Notice..."),wxOK | wxICON_INFORMATION);
896 event.Veto();
897 }
898 } // CeditorDlg::OnCloseWindow()
899
900
901 void CeditorDlg::OnButton(wxCommandEvent &event)
902 {
903 wxWindow *win = (wxWindow*) event.GetEventObject();
904 OnCommand( *win, event );
905 } // CeditorDlg::OnButton()
906
907
908 void CeditorDlg::OnCommand(wxWindow& win, wxCommandEvent& event)
909 {
910 wxString widgetName;
911
912 widgetName = win.GetName();
913
914 if (!widgetPtrsSet)
915 return;
916
917 if (widgetName == pCreateBtn->GetName())
918 {
919 wxGetApp().Contact->Initialize();
920 PutData();
921 SetMode( mCreate );
922 pNameTxt->SetValue(wxT(""));
923 pNameTxt->SetFocus();
924 return;
925 }
926
927 if (widgetName == pEditBtn->GetName())
928 {
929 saveName = wxGetApp().Contact->Name;
930 SetMode( mEdit );
931 pNameTxt->SetFocus();
932 return;
933 }
934
935 if (widgetName == pCopyBtn->GetName())
936 {
937 SetMode(mCreate);
938 pNameTxt->SetValue(wxT(""));
939 pNameTxt->SetFocus();
940 return;
941 }
942
943 if (widgetName == pDeleteBtn->GetName())
944 {
945 bool Ok = (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
946
947 if (!Ok)
948 return;
949
950 if (Ok && wxGetApp().Contact->Delete())
951 {
952 // NOTE: Deletions are not finalized until a CommitTrans() is performed.
953 // If the commit were not performed, the program will continue to
954 // show the table contents as if they were deleted until this instance
955 // of Ccontact is deleted. If the Commit wasn't performed, the
956 // database will automatically Rollback the changes when the database
957 // connection is terminated
958 wxGetApp().Contact->GetDb()->CommitTrans();
959
960 // Try to get the row that followed the just deleted row in the orderBy sequence
961 if (!GetNextRec())
962 {
963 // There was now row (in sequence) after the just deleted row, so get the
964 // row which preceded the just deleted row
965 if (!GetPrevRec())
966 {
967 // There are now no rows remaining, so clear the dialog widgets
968 wxGetApp().Contact->Initialize();
969 PutData();
970 }
971 }
972 SetMode(mode); // force reset of button enable/disable
973 }
974 else
975 // Delete failed
976 wxGetApp().Contact->GetDb()->RollbackTrans();
977
978 SetMode(mView);
979 return;
980 }
981
982 if (widgetName == pSaveBtn->GetName())
983 {
984 Save();
985 return;
986 }
987
988 if (widgetName == pCancelBtn->GetName())
989 {
990 bool Ok = (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
991
992 if (!Ok)
993 return;
994
995 if (saveName.IsEmpty())
996 {
997 wxGetApp().Contact->Initialize();
998 PutData();
999 SetMode(mView);
1000 return;
1001 }
1002 else
1003 {
1004 // Requery previous record
1005 if (wxGetApp().Contact->FetchByName(saveName))
1006 {
1007 PutData();
1008 SetMode(mView);
1009 return;
1010 }
1011 }
1012
1013 // Previous record not available, retrieve first record in table
1014 if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
1015 wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
1016 {
1017 wxGetApp().Contact->whereStr = wxT("NAME = (SELECT MIN(NAME) FROM ");
1018 wxGetApp().Contact->whereStr += wxGetApp().Contact->GetTableName();
1019 wxGetApp().Contact->whereStr += wxT(")");
1020 wxGetApp().Contact->SetWhereClause(wxGetApp().Contact->whereStr.c_str());
1021 }
1022 else
1023 wxGetApp().Contact->SetWhereClause(wxT(""));
1024
1025 if (!wxGetApp().Contact->Query())
1026 {
1027 wxString tStr;
1028 tStr = wxT("ODBC error during Query()\n\n");
1029 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1030 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1031 SetMode(mView);
1032 return;
1033 }
1034 if (wxGetApp().Contact->GetNext()) // Successfully read first record
1035 {
1036 PutData();
1037 SetMode(mView);
1038 return;
1039 }
1040 // No contacts are available, clear dialog
1041 wxGetApp().Contact->Initialize();
1042 PutData();
1043 SetMode(mView);
1044 return;
1045 } // Cancel Button
1046
1047 if (widgetName == pPrevBtn->GetName())
1048 {
1049 if (!GetPrevRec())
1050 wxBell();
1051 return;
1052 } // Prev Button
1053
1054 if (widgetName == pNextBtn->GetName())
1055 {
1056 if (!GetNextRec())
1057 wxBell();
1058 return;
1059 } // Next Button
1060
1061 if (widgetName == pQueryBtn->GetName())
1062 {
1063 // Display the query dialog box
1064 wxChar qryWhere[DB_MAX_WHERE_CLAUSE_LEN+1];
1065 wxStrcpy(qryWhere, (const wxChar*) wxGetApp().Contact->qryWhereStr);
1066 wxChar *tblName[] = {(wxChar *)CONTACT_TABLE_NAME, 0};
1067 new CqueryDlg(GetParent(), wxGetApp().Contact->GetDb(), tblName, qryWhere);
1068
1069 // Query the first record in the new record set and
1070 // display it, if the query string has changed.
1071 if (wxStrcmp(qryWhere, (const wxChar*) wxGetApp().Contact->qryWhereStr))
1072 {
1073 wxGetApp().Contact->whereStr.Empty();
1074 wxGetApp().Contact->SetOrderByClause("NAME");
1075
1076 if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
1077 wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
1078 {
1079 wxGetApp().Contact->whereStr = wxT("NAME = (SELECT MIN(NAME) FROM ");
1080 wxGetApp().Contact->whereStr += CONTACT_TABLE_NAME;
1081 }
1082
1083 // Append the query where string (if there is one)
1084 wxGetApp().Contact->qryWhereStr = qryWhere;
1085 if (wxStrlen(qryWhere))
1086 {
1087 wxGetApp().Contact->whereStr += wxT(" WHERE ");
1088 wxGetApp().Contact->whereStr += wxGetApp().Contact->qryWhereStr;
1089 }
1090 // Close the expression with a right paren
1091 wxGetApp().Contact->whereStr += wxT(")");
1092 // Requery the table
1093 wxGetApp().Contact->SetWhereClause(wxGetApp().Contact->whereStr.c_str());
1094 if (!wxGetApp().Contact->Query())
1095 {
1096 wxString tStr;
1097 tStr = wxT("ODBC error during Query()\n\n");
1098 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1099 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1100 return;
1101 }
1102 // Display the first record from the query set
1103 if (!wxGetApp().Contact->GetNext())
1104 wxGetApp().Contact->Initialize();
1105 PutData();
1106 }
1107
1108 // Enable/Disable the reset button
1109 pResetBtn->Enable(!wxGetApp().Contact->qryWhereStr.IsEmpty());
1110
1111 return;
1112 } // Query button
1113
1114
1115 if (widgetName == pResetBtn->GetName())
1116 {
1117 // Clear the additional where criteria established by the query feature
1118 wxGetApp().Contact->qryWhereStr = wxT("");
1119 wxGetApp().Contact->SetOrderByClause(wxT("NAME"));
1120
1121 if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
1122 wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
1123 {
1124 wxGetApp().Contact->whereStr = wxT("NAME = (SELECT MIN(NAME) FROM ");
1125 wxGetApp().Contact->whereStr += CONTACT_TABLE_NAME;
1126 wxGetApp().Contact->whereStr += wxT(")");
1127 }
1128
1129 wxGetApp().Contact->SetWhereClause(wxGetApp().Contact->whereStr.c_str());
1130 if (!wxGetApp().Contact->Query())
1131 {
1132 wxString tStr;
1133 tStr = wxT("ODBC error during Query()\n\n");
1134 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1135 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1136 return;
1137 }
1138 if (!wxGetApp().Contact->GetNext())
1139 wxGetApp().Contact->Initialize();
1140 PutData();
1141 pResetBtn->Enable(FALSE);
1142
1143 return;
1144 } // Reset button
1145
1146
1147 if (widgetName == pNameListBtn->GetName())
1148 {
1149 new ClookUpDlg(/* wxWindow *parent */ this,
1150 /* wxChar *windowTitle */ wxT("Select contact name"),
1151 /* wxChar *tableName */ (wxChar *) CONTACT_TABLE_NAME,
1152 /* wxChar *dispCol1 */ wxT("NAME"),
1153 /* wxChar *dispCol2 */ wxT("JOINDATE"),
1154 /* wxChar *where */ wxT(""),
1155 /* wxChar *orderBy */ wxT("NAME"),
1156 /* wxDb *pDb */ wxGetApp().READONLY_DB,
1157 /* const wxString &defDir */ wxGetApp().DbConnectInf->GetDefaultDir(),
1158 /* bool distinctValues */ TRUE);
1159
1160 if (ListDB_Selection && wxStrlen(ListDB_Selection))
1161 {
1162 wxString w = wxT("NAME = '");
1163 w += ListDB_Selection;
1164 w += wxT("'");
1165 GetRec(w);
1166 }
1167
1168 return;
1169 }
1170
1171 if (widgetName == pDataTypesBtn->GetName())
1172 {
1173 CheckSupportForAllDataTypes(wxGetApp().READONLY_DB);
1174 return;
1175 } // Data types Button
1176
1177 if (widgetName == pDbDiagsBtn->GetName())
1178 {
1179 DisplayDbDiagnostics(wxGetApp().READONLY_DB);
1180 return;
1181 }
1182
1183 } // CeditorDlg::OnCommand()
1184
1185
1186 bool CeditorDlg::Initialize()
1187 {
1188 // Create the data structure and a new database connection.
1189 // (As there is not a pDb being passed in the constructor, a new database
1190 // connection is created)
1191 wxGetApp().Contact = new Ccontact();
1192
1193 if (!wxGetApp().Contact)
1194 {
1195 wxMessageBox(wxT("Unable to instantiate an instance of Ccontact"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
1196 return FALSE;
1197 }
1198
1199 // Check if the table exists or not. If it doesn't, ask the user if they want to
1200 // create the table. Continue trying to create the table until it exists, or user aborts
1201 while (!wxGetApp().Contact->GetDb()->TableExists((wxChar *)CONTACT_TABLE_NAME,
1202 wxGetApp().DbConnectInf->GetUserID(),
1203 wxGetApp().DbConnectInf->GetDefaultDir()))
1204 {
1205 wxString tStr;
1206 tStr.Printf(wxT("Unable to open the table '%s'.\n\nTable may need to be created...?\n\n"),CONTACT_TABLE_NAME);
1207 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1208 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1209
1210 bool createTable = (wxMessageBox(wxT("Do you wish to try to create/clear the CONTACTS table?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
1211
1212 if (!createTable)
1213 {
1214 // Close();
1215 return FALSE;
1216 }
1217 else
1218 wxGetApp().CreateDataTable(FALSE);
1219 }
1220
1221 // Tables must be "opened" before anything other than creating/deleting table can be done
1222 if (!wxGetApp().Contact->Open())
1223 {
1224 // Table does exist, or there was some problem opening it. Currently this should
1225 // never fail, except in the case of the table not exisiting or the current
1226 // user has insufficent privileges to access the table
1227 #if 1
1228 // This code is experimenting with a new function that will hopefully be available
1229 // in the 2.4 release. This check will determine whether the open failing was due
1230 // to the table not existing, or the users privileges being insufficient to
1231 // open the table.
1232 if (!wxGetApp().Contact->GetDb()->TablePrivileges(CONTACT_TABLE_NAME, wxT("SELECT"),
1233 wxGetApp().Contact->GetDb()->GetUsername(),
1234 wxGetApp().Contact->GetDb()->GetUsername(),
1235 wxGetApp().DbConnectInf->GetDefaultDir()))
1236 {
1237 wxString tStr;
1238 tStr.Printf(wxT("Unable to open the table '%s' (likely due to\ninsufficient privileges of the logged in user).\n\n"),CONTACT_TABLE_NAME);
1239 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1240 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1241 }
1242 else
1243 #endif
1244 if (!wxGetApp().Contact->GetDb()->TableExists(CONTACT_TABLE_NAME,
1245 wxGetApp().Contact->GetDb()->GetUsername(),
1246 wxGetApp().DbConnectInf->GetDefaultDir()))
1247 {
1248 wxString tStr;
1249 tStr.Printf(wxT("Unable to open the table '%s' as the table\ndoes not appear to exist in the tablespace available\nto the currently logged in user.\n\n"),CONTACT_TABLE_NAME);
1250 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1251 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1252 }
1253
1254 return FALSE;
1255 }
1256
1257 // Build the dialog
1258
1259 (void)new wxStaticBox(this, EDITOR_DIALOG_FN_GROUP, wxT(""), wxPoint(15, 1), wxSize(497, 69), 0, wxT("FunctionGrp"));
1260 (void)new wxStaticBox(this, EDITOR_DIALOG_SEARCH_GROUP, wxT(""), wxPoint(417, 1), wxSize(95, 242), 0, wxT("SearchGrp"));
1261
1262 pCreateBtn = new wxButton(this, EDITOR_DIALOG_CREATE, wxT("&Create"), wxPoint( 25, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("CreateBtn"));
1263 pEditBtn = new wxButton(this, EDITOR_DIALOG_EDIT, wxT("&Edit"), wxPoint(102, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("EditBtn"));
1264 pDeleteBtn = new wxButton(this, EDITOR_DIALOG_DELETE, wxT("&Delete"), wxPoint(179, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("DeleteBtn"));
1265 pCopyBtn = new wxButton(this, EDITOR_DIALOG_COPY, wxT("Cop&y"), wxPoint(256, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("CopyBtn"));
1266 pSaveBtn = new wxButton(this, EDITOR_DIALOG_SAVE, wxT("&Save"), wxPoint(333, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("SaveBtn"));
1267 pCancelBtn = new wxButton(this, EDITOR_DIALOG_CANCEL, wxT("C&ancel"), wxPoint(430, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("CancelBtn"));
1268 pPrevBtn = new wxButton(this, EDITOR_DIALOG_PREV, wxT("<< &Prev"), wxPoint(430, 81), wxSize( 70, 35), 0, wxDefaultValidator, wxT("PrevBtn"));
1269 pNextBtn = new wxButton(this, EDITOR_DIALOG_NEXT, wxT("&Next >>"), wxPoint(430, 121), wxSize( 70, 35), 0, wxDefaultValidator, wxT("NextBtn"));
1270 pQueryBtn = new wxButton(this, EDITOR_DIALOG_QUERY, wxT("&Query"), wxPoint(430, 161), wxSize( 70, 35), 0, wxDefaultValidator, wxT("QueryBtn"));
1271 pResetBtn = new wxButton(this, EDITOR_DIALOG_RESET, wxT("&Reset"), wxPoint(430, 200), wxSize( 70, 35), 0, wxDefaultValidator, wxT("ResetBtn"));
1272 pNameMsg = new wxStaticText(this, EDITOR_DIALOG_NAME_MSG, wxT("Name:"), wxPoint( 17, 80), wxSize( -1, -1), 0, wxT("NameMsg"));
1273 pNameTxt = new wxTextCtrl(this, EDITOR_DIALOG_NAME_TEXT, wxT(""), wxPoint( 17, 97), wxSize(308, 25), 0, wxDefaultValidator, wxT("NameTxt"));
1274 pNameListBtn = new wxButton(this, EDITOR_DIALOG_LOOKUP, wxT("&Lookup"), wxPoint(333, 97), wxSize( 70, 24), 0, wxDefaultValidator, wxT("LookupBtn"));
1275 pAddress1Msg = new wxStaticText(this, EDITOR_DIALOG_ADDRESS1_MSG, wxT("Address:"), wxPoint( 17, 130), wxSize( -1, -1), 0, wxT("Address1Msg"));
1276 pAddress1Txt = new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT, wxT(""), wxPoint( 17, 147), wxSize(308, 25), 0, wxDefaultValidator, wxT("Address1Txt"));
1277 pAddress2Msg = new wxStaticText(this, EDITOR_DIALOG_ADDRESS2_MSG, wxT("Address:"), wxPoint( 17, 180), wxSize( -1, -1), 0, wxT("Address2Msg"));
1278 pAddress2Txt = new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT, wxT(""), wxPoint( 17, 197), wxSize(308, 25), 0, wxDefaultValidator, wxT("Address2Txt"));
1279 pCityMsg = new wxStaticText(this, EDITOR_DIALOG_CITY_MSG, wxT("City:"), wxPoint( 17, 230), wxSize( -1, -1), 0, wxT("CityMsg"));
1280 pCityTxt = new wxTextCtrl(this, EDITOR_DIALOG_CITY_TEXT, wxT(""), wxPoint( 17, 247), wxSize(225, 25), 0, wxDefaultValidator, wxT("CityTxt"));
1281 pStateMsg = new wxStaticText(this, EDITOR_DIALOG_STATE_MSG, wxT("State:"), wxPoint(250, 230), wxSize( -1, -1), 0, wxT("StateMsg"));
1282 pStateTxt = new wxTextCtrl(this, EDITOR_DIALOG_STATE_TEXT, wxT(""), wxPoint(250, 247), wxSize(153, 25), 0, wxDefaultValidator, wxT("StateTxt"));
1283 pCountryMsg = new wxStaticText(this, EDITOR_DIALOG_COUNTRY_MSG, wxT("Country:"), wxPoint( 17, 280), wxSize( -1, -1), 0, wxT("CountryMsg"));
1284 pCountryTxt = new wxTextCtrl(this, EDITOR_DIALOG_COUNTRY_TEXT, wxT(""), wxPoint( 17, 297), wxSize(225, 25), 0, wxDefaultValidator, wxT("CountryTxt"));
1285 pPostalCodeMsg = new wxStaticText(this, EDITOR_DIALOG_POSTAL_MSG, wxT("Postal Code:"),wxPoint(250, 280), wxSize( -1, -1), 0, wxT("PostalCodeMsg"));
1286 pPostalCodeTxt = new wxTextCtrl(this, EDITOR_DIALOG_POSTAL_TEXT, wxT(""), wxPoint(250, 297), wxSize(153, 25), 0, wxDefaultValidator, wxT("PostalCodeTxt"));
1287
1288 wxString choice_strings[5];
1289 choice_strings[0] = wxT("English");
1290 choice_strings[1] = wxT("French");
1291 choice_strings[2] = wxT("German");
1292 choice_strings[3] = wxT("Spanish");
1293 choice_strings[4] = wxT("Other");
1294
1295 pNativeLangChoice = new wxChoice(this, EDITOR_DIALOG_LANG_CHOICE, wxPoint( 17, 346), wxSize(277, -1), 5, choice_strings);
1296 pNativeLangMsg = new wxStaticText(this, EDITOR_DIALOG_LANG_MSG, wxT("Native language:"), wxPoint( 17, 330), wxSize( -1, -1), 0, wxT("NativeLangMsg"));
1297
1298 wxString radio_strings[2];
1299 radio_strings[0] = wxT("No");
1300 radio_strings[1] = wxT("Yes");
1301 pDeveloperRadio = new wxRadioBox(this,EDITOR_DIALOG_DEVELOPER, wxT("Developer:"), wxPoint(303, 330), wxSize( -1, -1), 2, radio_strings, 2, wxHORIZONTAL);
1302 pJoinDateMsg = new wxStaticText(this, EDITOR_DIALOG_JOIN_MSG, wxT("Date joined:"), wxPoint( 17, 380), wxSize( -1, -1), 0, wxT("JoinDateMsg"));
1303 pJoinDateTxt = new wxTextCtrl(this, EDITOR_DIALOG_JOIN_TEXT, wxT(""), wxPoint( 17, 397), wxSize(150, 25), 0, wxDefaultValidator, wxT("JoinDateTxt"));
1304 pContribMsg = new wxStaticText(this, EDITOR_DIALOG_CONTRIB_MSG,wxT("Contributions:"), wxPoint(175, 380), wxSize( -1, -1), 0, wxT("ContribMsg"));
1305 pContribTxt = new wxTextCtrl(this, EDITOR_DIALOG_CONTRIB_TEXT, wxT(""), wxPoint(175, 397), wxSize(120, 25), 0, wxDefaultValidator, wxT("ContribTxt"));
1306 pLinesMsg = new wxStaticText(this, EDITOR_DIALOG_LINES_MSG, wxT("Lines of code:"), wxPoint(303, 380), wxSize( -1, -1), 0, wxT("LinesMsg"));
1307 pLinesTxt = new wxTextCtrl(this, EDITOR_DIALOG_LINES_TEXT, wxT(""), wxPoint(303, 397), wxSize(100, 25), 0, wxDefaultValidator, wxT("LinesTxt"));
1308
1309 pDataTypesBtn = new wxButton(this, EDITOR_DIALOG_DATATYPES, wxT("Data&types"), wxPoint(430, 337), wxSize( 70, 35), 0, wxDefaultValidator, wxT("DataTypesBtn"));
1310 pDbDiagsBtn = new wxButton(this, EDITOR_DIALOG_DB_DIAGS, wxT("DB Dia&gs"), wxPoint(430, 387), wxSize( 70, 35), 0, wxDefaultValidator, wxT("DbDiagsBtn"));
1311
1312 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1313 // handle all widget processing
1314 widgetPtrsSet = TRUE;
1315
1316 // Setup the orderBy and where clauses to return back a single record as the result set,
1317 // as there will only be one record being shown on the dialog at a time, this optimizes
1318 // network traffic by only returning a one row result
1319
1320 wxGetApp().Contact->SetOrderByClause(wxT("NAME")); // field name to sort by
1321
1322 // The wxString "whereStr" is not a member of the wxDbTable object, it is a member variable
1323 // specifically in the Ccontact class. It is used here for simpler construction of a varying
1324 // length string, and then after the string is built, the wxDbTable member variable "where" is
1325 // assigned the pointer to the constructed string.
1326 //
1327 // The constructed where clause below has a sub-query within it "SELECT MIN(NAME) FROM %s"
1328 // to achieve a single row (in this case the first name in alphabetical order).
1329
1330 if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
1331 wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
1332 {
1333 wxGetApp().Contact->whereStr.Printf(wxT("NAME = (SELECT MIN(NAME) FROM %s)"),
1334 wxGetApp().Contact->GetTableName().c_str());
1335 // NOTE: (const wxChar*) returns a pointer which may not be valid later, so this is short term use only
1336 wxGetApp().Contact->SetWhereClause(wxGetApp().Contact->whereStr);
1337 }
1338 else
1339 wxGetApp().Contact->SetWhereClause(wxT(""));
1340
1341 // Perform the Query to get the result set.
1342 // NOTE: If there are no rows returned, that is a valid result, so Query() would return TRUE.
1343 // Only if there is a database error will Query() come back as FALSE
1344 if (!wxGetApp().Contact->Query())
1345 {
1346 wxString tStr;
1347 tStr = wxT("ODBC error during Query()\n\n");
1348 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1349 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1350 return FALSE;
1351 }
1352
1353 // Since Query succeeded, now get the row that was returned
1354 if (!wxGetApp().Contact->GetNext())
1355 // If the GetNext() failed at this point, then there are no rows to retrieve,
1356 // so clear the values in the members of "Contact" so that PutData() blanks the
1357 // widgets on the dialog
1358 wxGetApp().Contact->Initialize();
1359 /*
1360 wxGetApp().Contact->GetDb()->RollbackTrans();
1361 */
1362 SetMode(mView);
1363 PutData();
1364
1365 Show(TRUE);
1366
1367 initialized = TRUE;
1368 return TRUE;
1369 } // CeditorDlg::Initialize()
1370
1371
1372 void CeditorDlg::FieldsEditable()
1373 {
1374 if (!widgetPtrsSet)
1375 return;
1376
1377 pNameTxt->Enable((mode == mCreate) || (mode == mEdit));
1378 pAddress1Txt->Enable((mode == mCreate) || (mode == mEdit));
1379 pAddress2Txt->Enable((mode == mCreate) || (mode == mEdit));
1380 pCityTxt->Enable((mode == mCreate) || (mode == mEdit));
1381 pStateTxt->Enable((mode == mCreate) || (mode == mEdit));
1382 pPostalCodeTxt->Enable((mode == mCreate) || (mode == mEdit));
1383 pCountryTxt->Enable((mode == mCreate) || (mode == mEdit));
1384
1385 pJoinDateTxt->Enable((mode == mCreate) || (mode == mEdit));
1386 pContribTxt->Enable((mode == mCreate) || (mode == mEdit));
1387 pLinesTxt->Enable((mode == mCreate) || (mode == mEdit));
1388 pNativeLangChoice->Enable((mode == mCreate) || (mode == mEdit));
1389 pDeveloperRadio->Enable((mode == mCreate) || (mode == mEdit));
1390
1391 } // CeditorDlg::FieldsEditable()
1392
1393
1394 void CeditorDlg::SetMode(enum DialogModes m)
1395 {
1396 bool edit = FALSE;
1397
1398 mode = m;
1399 switch (mode)
1400 {
1401 case mCreate:
1402 case mEdit:
1403 edit = TRUE;
1404 break;
1405 case mView:
1406 case mSearch:
1407 edit = FALSE;
1408 break;
1409 default:
1410 break;
1411 };
1412
1413 if (widgetPtrsSet)
1414 {
1415 pCreateBtn->Enable( !edit );
1416 pEditBtn->Enable( !edit && (wxStrcmp(wxGetApp().Contact->Name,wxT(""))!=0) );
1417 pDeleteBtn->Enable( !edit && (wxStrcmp(wxGetApp().Contact->Name,wxT(""))!=0) );
1418 pCopyBtn->Enable( !edit && (wxStrcmp(wxGetApp().Contact->Name,wxT(""))!=0) );
1419 pSaveBtn->Enable( edit );
1420 pCancelBtn->Enable( edit );
1421 pPrevBtn->Enable( !edit );
1422 pNextBtn->Enable( !edit );
1423 pQueryBtn->Enable( !edit );
1424 pResetBtn->Enable( !edit && !wxGetApp().Contact->qryWhereStr.IsEmpty() );
1425 pNameListBtn->Enable( !edit );
1426 }
1427
1428 FieldsEditable();
1429 } // CeditorDlg::SetMode()
1430
1431
1432 bool CeditorDlg::PutData()
1433 {
1434 wxString tStr;
1435
1436 pNameTxt->SetValue(wxGetApp().Contact->Name);
1437 pAddress1Txt->SetValue(wxGetApp().Contact->Addr1);
1438 pAddress2Txt->SetValue(wxGetApp().Contact->Addr2);
1439 pCityTxt->SetValue(wxGetApp().Contact->City);
1440 pStateTxt->SetValue(wxGetApp().Contact->State);
1441 pCountryTxt->SetValue(wxGetApp().Contact->Country);
1442 pPostalCodeTxt->SetValue(wxGetApp().Contact->PostalCode);
1443
1444 tStr.Printf(wxT("%d/%d/%d"),wxGetApp().Contact->JoinDate.month,wxGetApp().Contact->JoinDate.day,wxGetApp().Contact->JoinDate.year);
1445 pJoinDateTxt->SetValue(tStr);
1446
1447 tStr.Printf(wxT("%d"),wxGetApp().Contact->Contributions);
1448 pContribTxt->SetValue(tStr);
1449
1450 tStr.Printf(wxT("%lu"),wxGetApp().Contact->LinesOfCode);
1451 pLinesTxt->SetValue(tStr);
1452
1453 pNativeLangChoice->SetSelection(wxGetApp().Contact->NativeLanguage);
1454
1455 pDeveloperRadio->SetSelection(wxGetApp().Contact->IsDeveloper);
1456
1457 return TRUE;
1458 } // Ceditor::PutData()
1459
1460
1461 /*
1462 * Reads the data out of all the widgets on the dialog. Some data evaluation is done
1463 * to ensure that there is a name entered and that the date field is valid.
1464 *
1465 * A return value of TRUE means that valid data was retrieved from the dialog, otherwise
1466 * invalid data was found (and a message was displayed telling the user what to fix), and
1467 * the data was not placed into the appropraite fields of Ccontact
1468 */
1469 bool CeditorDlg::GetData()
1470 {
1471 // Validate that the data currently entered into the widgets is valid data
1472
1473 wxString tStr;
1474 tStr = pNameTxt->GetValue();
1475 if (!wxStrcmp((const wxChar*) tStr,wxT("")))
1476 {
1477 wxMessageBox(wxT("A name is required for entry into the contact table"),wxT("Notice..."),wxOK | wxICON_INFORMATION);
1478 return FALSE;
1479 }
1480
1481 bool invalid = FALSE;
1482 int mm,dd,yyyy;
1483 int first, second;
1484
1485 tStr = pJoinDateTxt->GetValue();
1486 if (tStr.Freq(wxT('/')) != 2)
1487 invalid = TRUE;
1488
1489 // Find the month, day, and year tokens
1490 if (!invalid)
1491 {
1492 first = tStr.First(wxT('/'));
1493 second = tStr.Last(wxT('/'));
1494
1495 mm = atoi(tStr.SubString(0,first));
1496 dd = atoi(tStr.SubString(first+1,second));
1497 yyyy = atoi(tStr.SubString(second+1,tStr.Length()-1));
1498
1499 invalid = !(mm && dd && yyyy);
1500 }
1501
1502 // Force Year 2000 compliance
1503 if (!invalid && (yyyy < 1000))
1504 invalid = TRUE;
1505
1506 // Check the token ranges for validity
1507 if (!invalid)
1508 {
1509 if (yyyy > 9999)
1510 invalid = TRUE;
1511 else if ((mm < 1) || (mm > 12))
1512 invalid = TRUE;
1513 else
1514 {
1515 if (dd < 1)
1516 invalid = TRUE;
1517 else
1518 {
1519 int days[12] = {31,28,31,30,31,30,
1520 31,31,30,31,30,31};
1521 if (dd > days[mm-1])
1522 {
1523 invalid = TRUE;
1524 if ((dd == 29) && (mm == 2))
1525 {
1526 if (((yyyy % 4) == 0) && (((yyyy % 100) != 0) || ((yyyy % 400) == 0)))
1527 invalid = FALSE;
1528 }
1529 }
1530 }
1531 }
1532 }
1533
1534 if (!invalid)
1535 {
1536 wxGetApp().Contact->JoinDate.month = mm;
1537 wxGetApp().Contact->JoinDate.day = dd;
1538 wxGetApp().Contact->JoinDate.year = yyyy;
1539 }
1540 else
1541 {
1542 wxMessageBox(wxT("Improper date format. Please check the date\nspecified and try again.\n\nNOTE: Dates are in american format (MM/DD/YYYY)"),wxT("Notice..."),wxOK | wxICON_INFORMATION);
1543 return FALSE;
1544 }
1545
1546 tStr = pNameTxt->GetValue();
1547 wxStrcpy(wxGetApp().Contact->Name,(const wxChar*) tStr);
1548 wxStrcpy(wxGetApp().Contact->Addr1,pAddress1Txt->GetValue());
1549 wxStrcpy(wxGetApp().Contact->Addr2,pAddress2Txt->GetValue());
1550 wxStrcpy(wxGetApp().Contact->City,pCityTxt->GetValue());
1551 wxStrcpy(wxGetApp().Contact->State,pStateTxt->GetValue());
1552 wxStrcpy(wxGetApp().Contact->Country,pCountryTxt->GetValue());
1553 wxStrcpy(wxGetApp().Contact->PostalCode,pPostalCodeTxt->GetValue());
1554
1555 wxGetApp().Contact->Contributions = atoi(pContribTxt->GetValue());
1556 wxGetApp().Contact->LinesOfCode = atol(pLinesTxt->GetValue());
1557
1558 wxGetApp().Contact->NativeLanguage = (enum Language) pNativeLangChoice->GetSelection();
1559 wxGetApp().Contact->IsDeveloper = pDeveloperRadio->GetSelection() > 0;
1560
1561 return TRUE;
1562 } // CeditorDlg::GetData()
1563
1564
1565 /*
1566 * Retrieve data from the dialog, verify the validity of the data, and if it is valid,
1567 * try to insert/update the data to the table based on the current 'mode' the dialog
1568 * is set to.
1569 *
1570 * A return value of TRUE means the insert/update was completed successfully, a return
1571 * value of FALSE means that Save() failed. If returning FALSE, then this function
1572 * has displayed a detailed error message for the user.
1573 */
1574 bool CeditorDlg::Save()
1575 {
1576 bool failed = FALSE;
1577
1578 // Read the data in the widgets of the dialog to get the user's data
1579 if (!GetData())
1580 failed = TRUE;
1581
1582 // Perform any other required validations necessary before saving
1583 if (!failed)
1584 {
1585 wxBeginBusyCursor();
1586
1587 if (mode == mCreate)
1588 {
1589 RETCODE result = wxGetApp().Contact->Insert();
1590
1591 failed = (result != DB_SUCCESS);
1592 if (failed)
1593 {
1594 // Some errors may be expected, like a duplicate key, so handle those instances with
1595 // specific error messages.
1596 if (result == DB_ERR_INTEGRITY_CONSTRAINT_VIOL)
1597 {
1598 wxString tStr;
1599 tStr = wxT("A duplicate key value already exists in the table.\nUnable to save record\n\n");
1600 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1601 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1602 }
1603 else
1604 {
1605 // Some other unexpexted error occurred
1606 wxString tStr;
1607 tStr = wxT("Database insert failed\n\n");
1608 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1609 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1610 }
1611 }
1612 }
1613 else // mode == mEdit
1614 {
1615 wxGetApp().Contact->whereStr.Printf("NAME = '%s'",saveName.c_str());
1616 if (!wxGetApp().Contact->UpdateWhere(wxGetApp().Contact->whereStr))
1617 {
1618 wxString tStr;
1619 tStr = wxT("Database update failed\n\n");
1620 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1621 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1622 failed = TRUE;
1623 }
1624 }
1625
1626 if (!failed)
1627 {
1628 wxGetApp().Contact->GetDb()->CommitTrans();
1629 SetMode(mView); // Sets the dialog mode back to viewing after save is successful
1630 }
1631 else
1632 wxGetApp().Contact->GetDb()->RollbackTrans();
1633
1634 wxEndBusyCursor();
1635 }
1636
1637 return !failed;
1638 } // CeditorDlg::Save()
1639
1640
1641 /*
1642 * Where this program is only showing a single row at a time in the dialog,
1643 * a special where clause must be built to find just the single row which,
1644 * in sequence, would follow the currently displayed row.
1645 */
1646 bool CeditorDlg::GetNextRec()
1647 {
1648 wxString w;
1649
1650 if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
1651 wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
1652 {
1653 w = wxT("NAME = (SELECT MIN(NAME) FROM ");
1654 w += wxGetApp().Contact->GetTableName();
1655 w += wxT(" WHERE NAME > '");
1656 }
1657 else
1658 w = wxT("(NAME > '");
1659
1660 w += wxGetApp().Contact->Name;
1661 w += wxT("'");
1662
1663 // If a query where string is currently set, append that criteria
1664 if (!wxGetApp().Contact->qryWhereStr.IsEmpty())
1665 {
1666 w += wxT(" AND (");
1667 w += wxGetApp().Contact->qryWhereStr;
1668 w += wxT(")");
1669 }
1670
1671 w += wxT(")");
1672 return(GetRec(w));
1673
1674 } // CeditorDlg::GetNextRec()
1675
1676
1677 /*
1678 * Where this program is only showing a single row at a time in the dialog,
1679 * a special where clause must be built to find just the single row which,
1680 * in sequence, would precede the currently displayed row.
1681 */
1682 bool CeditorDlg::GetPrevRec()
1683 {
1684 wxString w;
1685
1686 if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
1687 wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
1688 {
1689 w = wxT("NAME = (SELECT MAX(NAME) FROM ");
1690 w += wxGetApp().Contact->GetTableName();
1691 w += wxT(" WHERE NAME < '");
1692 }
1693 else
1694 w = wxT("(NAME < '");
1695
1696 w += wxGetApp().Contact->Name;
1697 w += wxT("'");
1698
1699 // If a query where string is currently set, append that criteria
1700 if (!wxGetApp().Contact->qryWhereStr.IsEmpty())
1701 {
1702 w += wxT(" AND (");
1703 w += wxGetApp().Contact->qryWhereStr;
1704 w += wxT(")");
1705 }
1706
1707 w += wxT(")");
1708
1709 return(GetRec(w));
1710
1711 } // CeditorDlg::GetPrevRec()
1712
1713
1714 /*
1715 * This function is here to avoid duplicating this same code in both the
1716 * GetPrevRec() and GetNextRec() functions
1717 */
1718 bool CeditorDlg::GetRec(const wxString &whereStr)
1719 {
1720 wxGetApp().Contact->SetWhereClause(whereStr);
1721 wxGetApp().Contact->SetOrderByClause(wxT("NAME"));
1722
1723 if (!wxGetApp().Contact->Query())
1724 {
1725 wxString tStr;
1726 tStr = wxT("ODBC error during Query()\n\n");
1727 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1728 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1729
1730 return(FALSE);
1731 }
1732
1733 if (wxGetApp().Contact->GetNext())
1734 {
1735 PutData();
1736 return(TRUE);
1737 }
1738 else
1739 return(FALSE);
1740 } // CeditorDlg::GetRec()
1741
1742
1743
1744 /*
1745 * CparameterDlg constructor
1746 */
1747
1748 BEGIN_EVENT_TABLE(CparameterDlg, wxDialog)
1749 EVT_BUTTON(PARAMETER_DIALOG_SAVE, CparameterDlg::OnButton)
1750 EVT_BUTTON(PARAMETER_DIALOG_CANCEL, CparameterDlg::OnButton)
1751 EVT_CLOSE(CparameterDlg::OnCloseWindow)
1752 END_EVENT_TABLE()
1753
1754 CparameterDlg::CparameterDlg(wxWindow *parent) : wxDialog (parent, PARAMETER_DIALOG, wxT("ODBC parameter settings"), wxPoint(-1, -1), wxSize(400, 325))
1755 {
1756 // Since the ::OnCommand() function is overridden, this prevents the widget
1757 // detection in ::OnCommand() until all widgets have been initialized to prevent
1758 // uninitialized pointers from crashing the program
1759 widgetPtrsSet = FALSE;
1760
1761 pParamODBCSourceMsg = new wxStaticText(this, PARAMETER_DIALOG_SOURCE_MSG, wxT("ODBC data sources:"), wxPoint( 10, 10), wxSize( -1, -1), 0, wxT("ParamODBCSourceMsg"));
1762 pParamODBCSourceList = new wxListBox(this, PARAMETER_DIALOG_SOURCE_LISTBOX, wxPoint( 10, 29), wxSize(285, 150), 0, 0, wxLB_SINGLE|wxLB_ALWAYS_SB, wxDefaultValidator, wxT("ParamODBCSourceList"));
1763 pParamUserNameMsg = new wxStaticText(this, PARAMETER_DIALOG_NAME_MSG, wxT("Database user name:"), wxPoint( 10, 193), wxSize( -1, -1), 0, wxT("ParamUserNameMsg"));
1764 pParamUserNameTxt = new wxTextCtrl(this, PARAMETER_DIALOG_NAME_TEXT, wxT(""), wxPoint(10, 209), wxSize( 140, 25), 0, wxDefaultValidator, wxT("ParamUserNameTxt"));
1765 pParamPasswordMsg = new wxStaticText(this, PARAMETER_DIALOG_PASSWORD_MSG, wxT("Password:"), wxPoint(156, 193), wxSize( -1, -1), 0, wxT("ParamPasswordMsg"));
1766 pParamPasswordTxt = new wxTextCtrl(this, PARAMETER_DIALOG_PASSWORD_TEXT, wxT(""), wxPoint(156, 209), wxSize( 140, 25), 0, wxDefaultValidator, wxT("ParamPasswordTxt"));
1767 pParamDirPathMsg = new wxStaticText(this, PARAMETER_DIALOG_DIRPATH_MSG, wxT("Directory:"), wxPoint( 10, 243), wxSize( -1, -1), 0, wxT("ParamDirPathMsg"));
1768 pParamDirPathTxt = new wxTextCtrl(this, PARAMETER_DIALOG_DIRPATH_TEXT, wxT(""), wxPoint( 10, 259), wxSize(140, 25), 0, wxDefaultValidator, wxT("ParamDirPathTxt"));
1769 pParamSaveBtn = new wxButton(this, PARAMETER_DIALOG_SAVE, wxT("&Save"), wxPoint(310, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("ParamSaveBtn"));
1770 pParamCancelBtn = new wxButton(this, PARAMETER_DIALOG_CANCEL, wxT("C&ancel"), wxPoint(310, 66), wxSize( 70, 35), 0, wxDefaultValidator, wxT("ParamCancelBtn"));
1771
1772 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1773 // handle all widget processing
1774 widgetPtrsSet = TRUE;
1775
1776 saved = FALSE;
1777 savedParamSettings = wxGetApp().params;
1778
1779 Centre(wxBOTH);
1780 PutData();
1781 ShowModal();
1782 } // CparameterDlg constructor
1783
1784
1785 void CparameterDlg::OnCloseWindow(wxCloseEvent& event)
1786 {
1787 // Put any additional checking necessary to make certain it is alright
1788 // to close the program here that is not done elsewhere
1789 if (!saved)
1790 {
1791 bool Ok = (wxMessageBox(wxT("No changes have been saved.\n\nAre you sure you wish exit the parameter screen?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
1792
1793 if (!Ok)
1794 {
1795 event.Veto();
1796 return;
1797 }
1798
1799 wxGetApp().params = savedParamSettings;
1800 }
1801
1802 if (GetParent() != NULL)
1803 GetParent()->SetFocus();
1804
1805 while (wxIsBusy())
1806 wxEndBusyCursor();
1807
1808 Show(FALSE);
1809 SetReturnCode(0); // added so BoundsChecker would not report use of uninitialized variable
1810
1811 this->Destroy();
1812 } // CparameterDlg::OnCloseWindow()
1813
1814
1815 void CparameterDlg::OnButton( wxCommandEvent &event )
1816 {
1817 wxWindow *win = (wxWindow*) event.GetEventObject();
1818 OnCommand( *win, event );
1819 }
1820
1821
1822 void CparameterDlg::OnCommand(wxWindow& win, wxCommandEvent& event)
1823 {
1824 wxString widgetName;
1825
1826 widgetName = win.GetName();
1827
1828 if (!widgetPtrsSet)
1829 return;
1830
1831 if (widgetName == pParamSaveBtn->GetName())
1832 {
1833 if (Save())
1834 {
1835 wxString tStr;
1836 tStr = wxT("Database parameters have been saved.");
1837 if (GetParent() != NULL) // The parameter dialog was not called during startup due to a missing cfg file
1838 tStr += wxT("\nNew parameters will take effect the next time the program is started.");
1839 wxMessageBox(tStr,wxT("Notice..."),wxOK | wxICON_INFORMATION);
1840 saved = TRUE;
1841 Close();
1842 }
1843 return;
1844 }
1845
1846 if (widgetName == pParamCancelBtn->GetName())
1847 {
1848 Close();
1849 return;
1850 }
1851 } // CparameterDlg::OnCommand()
1852
1853
1854 bool CparameterDlg::PutData()
1855 {
1856 // Fill the data source list box
1857 FillDataSourceList();
1858
1859 // Fill in the fields from the params object
1860 if (wxGetApp().params.ODBCSource && wxStrlen(wxGetApp().params.ODBCSource))
1861 pParamODBCSourceList->SetStringSelection(wxGetApp().params.ODBCSource);
1862 pParamUserNameTxt->SetValue(wxGetApp().params.UserName);
1863 pParamPasswordTxt->SetValue(wxGetApp().params.Password);
1864 pParamDirPathTxt->SetValue(wxGetApp().params.DirPath);
1865 return TRUE;
1866 } // CparameterDlg::PutData()
1867
1868
1869 bool CparameterDlg::GetData()
1870 {
1871 wxString tStr;
1872 if (pParamODBCSourceList->GetStringSelection() != wxT(""))
1873 {
1874 tStr = pParamODBCSourceList->GetStringSelection();
1875 if (tStr.Length() > (sizeof(wxGetApp().params.ODBCSource)-1))
1876 {
1877 wxString errmsg;
1878 errmsg.Printf(wxT("ODBC Data source name is longer than the data structure to hold it.\n'Cparameter.ODBCSource' must have a larger character array\nto handle a data source with this long of a name\n\nThe data source currently selected is %d characters long."),tStr.Length());
1879 wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
1880 return FALSE;
1881 }
1882 wxStrcpy(wxGetApp().params.ODBCSource, tStr);
1883 }
1884 else
1885 return FALSE;
1886
1887 tStr = pParamUserNameTxt->GetValue();
1888 if (tStr.Length() > (sizeof(wxGetApp().params.UserName)-1))
1889 {
1890 wxString errmsg;
1891 errmsg.Printf(wxT("User name is longer than the data structure to hold it.\n'Cparameter.UserName' must have a larger character array\nto handle a data source with this long of a name\n\nThe user name currently specified is %d characters long."),tStr.Length());
1892 wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
1893 return FALSE;
1894 }
1895 wxStrcpy(wxGetApp().params.UserName, tStr);
1896
1897 tStr = pParamPasswordTxt->GetValue();
1898 if (tStr.Length() > (sizeof(wxGetApp().params.Password)-1))
1899 {
1900 wxString errmsg;
1901 errmsg.Printf(wxT("Password is longer than the data structure to hold it.\n'Cparameter.Password' must have a larger character array\nto handle a data source with this long of a name\n\nThe password currently specified is %d characters long."),tStr.Length());
1902 wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
1903 return FALSE;
1904 }
1905 wxStrcpy(wxGetApp().params.Password,tStr);
1906
1907 tStr = pParamDirPathTxt->GetValue();
1908 tStr.Replace(wxT("\\"),wxT("/"));
1909 if (tStr.Length() > (sizeof(wxGetApp().params.DirPath)-1))
1910 {
1911 wxString errmsg;
1912 errmsg.Printf(wxT("DirPath is longer than the data structure to hold it.\n'Cparameter.DirPath' must have a larger character array\nto handle a data source with this long of a name\n\nThe password currently specified is %d characters long."),tStr.Length());
1913 wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
1914 return FALSE;
1915 }
1916 wxStrcpy(wxGetApp().params.DirPath,tStr);
1917 return TRUE;
1918 } // CparameterDlg::GetData()
1919
1920
1921 bool CparameterDlg::Save()
1922 {
1923 // Copy the current params in case user cancels changing
1924 // the params, so that we can reset them.
1925 if (!GetData())
1926 {
1927 wxGetApp().params = savedParamSettings;
1928 return FALSE;
1929 }
1930
1931 wxGetApp().WriteParamFile(wxGetApp().params);
1932
1933 return TRUE;
1934 } // CparameterDlg::Save()
1935
1936
1937 void CparameterDlg::FillDataSourceList()
1938 {
1939 wxChar Dsn[SQL_MAX_DSN_LENGTH + 1];
1940 wxChar DsDesc[255];
1941 wxStringList strList;
1942
1943 while (wxDbGetDataSource(wxGetApp().DbConnectInf->GetHenv(), Dsn,
1944 SQL_MAX_DSN_LENGTH+1, DsDesc, 255))
1945 strList.Add(Dsn);
1946
1947 strList.Sort();
1948 strList.Add(wxT(""));
1949 wxChar **p = strList.ListToArray();
1950
1951 int i;
1952 for (i = 0; wxStrlen(p[i]); i++)
1953 pParamODBCSourceList->Append(p[i]);
1954
1955 wxDELETEA(p);
1956 } // CparameterDlg::FillDataSourceList()
1957
1958
1959 BEGIN_EVENT_TABLE(CqueryDlg, wxDialog)
1960 EVT_BUTTON(-1, CqueryDlg::OnButton)
1961 EVT_CLOSE(CqueryDlg::OnCloseWindow)
1962 END_EVENT_TABLE()
1963
1964
1965 // CqueryDlg() constructor
1966 CqueryDlg::CqueryDlg(wxWindow *parent, wxDb *pDb, wxChar *tblName[],
1967 const wxString &pWhereArg) :
1968 wxDialog (parent, QUERY_DIALOG, wxT("Query"), wxPoint(-1, -1), wxSize(480, 360))
1969 {
1970 wxBeginBusyCursor();
1971
1972 colInf = 0;
1973 dbTable = 0;
1974 masterTableName = tblName[0];
1975 widgetPtrsSet = FALSE;
1976 pDB = pDb;
1977
1978 // Initialize the WHERE clause from the string passed in
1979 pWhere = pWhereArg; // Save a pointer to the output buffer
1980 if (pWhere.Length() > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN) // Check the length of the buffer passed in
1981 {
1982 wxString s;
1983 s.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN+1);
1984 wxMessageBox(s,wxT("Error..."),wxOK | wxICON_EXCLAMATION);
1985 Close();
1986 return;
1987 }
1988
1989 pQueryCol1Msg = new wxStaticText(this, QUERY_DIALOG_COL_MSG, wxT("Column 1:"), wxPoint( 10, 10), wxSize( 69, 16), 0, wxT("QueryCol1Msg"));
1990 pQueryCol1Choice = new wxChoice(this, QUERY_DIALOG_COL_CHOICE, wxPoint( 10, 27), wxSize(250, 27), 0, 0, 0, wxDefaultValidator, wxT("QueryCol1Choice"));
1991 pQueryNotMsg = new wxStaticText(this, QUERY_DIALOG_NOT_MSG, wxT("NOT"), wxPoint(268, 10), wxSize( -1, -1), 0, wxT("QueryNotMsg"));
1992 pQueryNotCheck = new wxCheckBox(this, QUERY_DIALOG_NOT_CHECKBOX, wxT(""), wxPoint(275, 37), wxSize( 20, 20), 0, wxDefaultValidator, wxT("QueryNotCheck"));
1993
1994 wxString choice_strings[9];
1995 choice_strings[0] = wxT("=");
1996 choice_strings[1] = wxT("<");
1997 choice_strings[2] = wxT(">");
1998 choice_strings[3] = wxT("<=");
1999 choice_strings[4] = wxT(">=");
2000 choice_strings[5] = wxT("Begins");
2001 choice_strings[6] = wxT("Contains");
2002 choice_strings[7] = wxT("Like");
2003 choice_strings[8] = wxT("Between");
2004
2005 pQueryOperatorMsg = new wxStaticText(this, QUERY_DIALOG_OP_MSG, wxT("Operator:"), wxPoint(305, 10), wxSize( -1, -1), 0, wxT("QueryOperatorMsg"));
2006 pQueryOperatorChoice = new wxChoice(this, QUERY_DIALOG_OP_CHOICE, wxPoint(305, 27), wxSize( 80, 27), 9, choice_strings, 0, wxDefaultValidator, wxT("QueryOperatorChoice"));
2007 pQueryCol2Msg = new wxStaticText(this, QUERY_DIALOG_COL2_MSG, wxT("Column 2:"), wxPoint( 10, 65), wxSize( 69, 16), 0, wxT("QueryCol2Msg"));
2008 pQueryCol2Choice = new wxChoice(this, QUERY_DIALOG_COL2_CHOICE, wxPoint( 10, 82), wxSize(250, 27), 0, 0, 0, wxDefaultValidator, wxT("QueryCol2Choice"));
2009 pQuerySqlWhereMsg = new wxStaticText(this, QUERY_DIALOG_WHERE_MSG, wxT("SQL where clause:"), wxPoint( 10, 141), wxSize( -1, -1), 0, wxT("QuerySqlWhereMsg"));
2010 pQuerySqlWhereMtxt = new wxTextCtrl(this, QUERY_DIALOG_WHERE_TEXT, wxT(""), wxPoint( 10, 159), wxSize(377, 134), wxTE_MULTILINE, wxDefaultValidator, wxT("QuerySqlWhereMtxt"));
2011 pQueryAddBtn = new wxButton(this, QUERY_DIALOG_ADD, wxT("&Add"), wxPoint(406, 24), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryAddBtn"));
2012 pQueryAndBtn = new wxButton(this, QUERY_DIALOG_AND, wxT("A&nd"), wxPoint(406, 58), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryAndBtn"));
2013 pQueryOrBtn = new wxButton(this, QUERY_DIALOG_OR, wxT("&Or"), wxPoint(406, 92), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryOrBtn"));
2014 pQueryLParenBtn = new wxButton(this, QUERY_DIALOG_LPAREN, wxT("("), wxPoint(406, 126), wxSize( 26, 26), 0, wxDefaultValidator, wxT("QueryLParenBtn"));
2015 pQueryRParenBtn = new wxButton(this, QUERY_DIALOG_RPAREN, wxT(")"), wxPoint(436, 126), wxSize( 26, 26), 0, wxDefaultValidator, wxT("QueryRParenBtn"));
2016 pQueryDoneBtn = new wxButton(this, QUERY_DIALOG_DONE, wxT("&Done"), wxPoint(406, 185), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryDoneBtn"));
2017 pQueryClearBtn = new wxButton(this, QUERY_DIALOG_CLEAR, wxT("C&lear"), wxPoint(406, 218), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryClearBtn"));
2018 pQueryCountBtn = new wxButton(this, QUERY_DIALOG_COUNT, wxT("&Count"), wxPoint(406, 252), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryCountBtn"));
2019 pQueryValue1Msg = new wxStaticText(this, QUERY_DIALOG_VALUE1_MSG, wxT("Value:"), wxPoint(277, 66), wxSize( -1, -1), 0, wxT("QueryValue1Msg"));
2020 pQueryValue1Txt = new wxTextCtrl(this, QUERY_DIALOG_VALUE1_TEXT, wxT(""), wxPoint(277, 83), wxSize(108, 25), 0, wxDefaultValidator, wxT("QueryValue1Txt"));
2021 pQueryValue2Msg = new wxStaticText(this, QUERY_DIALOG_VALUE2_MSG, wxT("AND"), wxPoint(238, 126), wxSize( -1, -1), 0, wxT("QueryValue2Msg"));
2022 pQueryValue2Txt = new wxTextCtrl(this, QUERY_DIALOG_VALUE2_TEXT, wxT(""), wxPoint(277, 120), wxSize(108, 25), 0, wxDefaultValidator, wxT("QueryValue2Txt"));
2023 pQueryHintGrp = new wxStaticBox(this, QUERY_DIALOG_HINT_GROUP, wxT(""), wxPoint( 10, 291), wxSize(377, 40), 0, wxT("QueryHintGrp"));
2024 pQueryHintMsg = new wxStaticText(this, QUERY_DIALOG_HINT_MSG, wxT(""), wxPoint( 16, 306), wxSize( -1, -1), 0, wxT("QueryHintMsg"));
2025
2026 widgetPtrsSet = TRUE;
2027 // Initialize the dialog
2028 wxString qualName;
2029 pQueryCol2Choice->Append(wxT("VALUE -->"));
2030 colInf = pDB->GetColumns(tblName);
2031
2032 if (!colInf)
2033 {
2034 wxEndBusyCursor();
2035 wxString tStr;
2036 tStr = wxT("ODBC error during GetColumns()\n\n");
2037 tStr += GetExtendedDBErrorMsg(pDb,__FILE__,__LINE__);
2038 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
2039 return;
2040 }
2041
2042 int i;
2043 for (i = 0; colInf[i].colName && wxStrlen(colInf[i].colName); i++)
2044 {
2045 // If there is more than one table being queried, qualify
2046 // the column names with the table name prefix.
2047 if (tblName[1] && wxStrlen(tblName[1]))
2048 {
2049 qualName.Printf(wxT("%s.%s"), colInf[i].tableName, colInf[i].colName);
2050 pQueryCol1Choice->Append(qualName);
2051 pQueryCol2Choice->Append(qualName);
2052 }
2053 else // Single table query, append just the column names
2054 {
2055 pQueryCol1Choice->Append(colInf[i].colName);
2056 pQueryCol2Choice->Append(colInf[i].colName);
2057 }
2058 }
2059
2060 pQueryCol1Choice->SetSelection(0);
2061 pQueryCol2Choice->SetSelection(0);
2062 pQueryOperatorChoice->SetSelection(0);
2063
2064 pQueryValue2Msg->Show(FALSE);
2065 pQueryValue2Txt->Show(FALSE);
2066
2067 pQueryHintMsg->SetLabel(langQRY_EQ);
2068
2069 pQuerySqlWhereMtxt->SetValue(pWhere.c_str());
2070
2071 wxEndBusyCursor();
2072
2073 // Display the dialog window
2074 Centre(wxBOTH);
2075 ShowModal();
2076 } // CqueryDlg() constructor
2077
2078
2079 CqueryDlg::~CqueryDlg()
2080 {
2081 } // CqueryDlg::~CqueryDlg() destructor
2082
2083
2084 void CqueryDlg::OnButton(wxCommandEvent &event)
2085 {
2086 wxWindow *win = (wxWindow*) event.GetEventObject();
2087 OnCommand( *win, event );
2088 } // CqueryDlg::OnButton()
2089
2090
2091 void CqueryDlg::OnCommand(wxWindow& win, wxCommandEvent& event)
2092 {
2093 // Widget pointers won't be set when the dialog is constructed.
2094 // Control is passed through this function once for each widget on
2095 // a dialog as the dialog is constructed.
2096 if (!widgetPtrsSet)
2097 return;
2098
2099 wxString widgetName = win.GetName();
2100
2101 // Operator choice box
2102 if (widgetName == pQueryOperatorChoice->GetName())
2103 {
2104 // Set the help text
2105 switch((qryOp) pQueryOperatorChoice->GetSelection())
2106 {
2107 case qryOpEQ:
2108 pQueryHintMsg->SetLabel(langQRY_EQ);
2109 break;
2110 case qryOpLT:
2111 pQueryHintMsg->SetLabel(langQRY_LT);
2112 break;
2113 case qryOpGT:
2114 pQueryHintMsg->SetLabel(langQRY_GT);
2115 break;
2116 case qryOpLE:
2117 pQueryHintMsg->SetLabel(langQRY_LE);
2118 break;
2119 case qryOpGE:
2120 pQueryHintMsg->SetLabel(langQRY_GE);
2121 break;
2122 case qryOpBEGINS:
2123 pQueryHintMsg->SetLabel(langQRY_BEGINS);
2124 break;
2125 case qryOpCONTAINS:
2126 pQueryHintMsg->SetLabel(langQRY_CONTAINS);
2127 break;
2128 case qryOpLIKE:
2129 pQueryHintMsg->SetLabel(langQRY_LIKE);
2130 break;
2131 case qryOpBETWEEN:
2132 pQueryHintMsg->SetLabel(langQRY_BETWEEN);
2133 break;
2134 }
2135
2136 // Hide the value2 widget
2137 pQueryValue2Msg->Show(FALSE); // BETWEEN will show this widget
2138 pQueryValue2Txt->Show(FALSE); // BETWEEN will show this widget
2139
2140 // Disable the NOT operator for <, <=, >, >=
2141 switch((qryOp) pQueryOperatorChoice->GetSelection())
2142 {
2143 case qryOpLT:
2144 case qryOpGT:
2145 case qryOpLE:
2146 case qryOpGE:
2147 pQueryNotCheck->SetValue(0);
2148 pQueryNotCheck->Enable(FALSE);
2149 break;
2150 default:
2151 pQueryNotCheck->Enable(TRUE);
2152 break;
2153 }
2154
2155 // Manipulate the dialog to handle the selected operator
2156 switch((qryOp) pQueryOperatorChoice->GetSelection())
2157 {
2158 case qryOpEQ:
2159 case qryOpLT:
2160 case qryOpGT:
2161 case qryOpLE:
2162 case qryOpGE:
2163 pQueryCol2Choice->Enable(TRUE);
2164 if (pQueryCol2Choice->GetSelection()) // Column name is highlighted
2165 {
2166 pQueryValue1Msg->Show(FALSE);
2167 pQueryValue1Txt->Show(FALSE);
2168 }
2169 else // "Value" is highlighted
2170 {
2171 pQueryValue1Msg->Show(TRUE);
2172 pQueryValue1Txt->Show(TRUE);
2173 pQueryValue1Txt->SetFocus();
2174 }
2175 break;
2176 case qryOpBEGINS:
2177 case qryOpCONTAINS:
2178 case qryOpLIKE:
2179 pQueryCol2Choice->SetSelection(0);
2180 pQueryCol2Choice->Enable(FALSE);
2181 pQueryValue1Msg->Show(TRUE);
2182 pQueryValue1Txt->Show(TRUE);
2183 pQueryValue1Txt->SetFocus();
2184 break;
2185 case qryOpBETWEEN:
2186 pQueryCol2Choice->SetSelection(0);
2187 pQueryCol2Choice->Enable(FALSE);
2188 pQueryValue2Msg->Show(TRUE);
2189 pQueryValue2Txt->Show(TRUE);
2190 pQueryValue1Msg->Show(TRUE);
2191 pQueryValue1Txt->Show(TRUE);
2192 pQueryValue1Txt->SetFocus();
2193 break;
2194 }
2195
2196 return;
2197
2198 } // Operator choice box
2199
2200 // Column 2 choice
2201 if (widgetName == pQueryCol2Choice->GetName())
2202 {
2203 if (pQueryCol2Choice->GetSelection()) // Column name is highlighted
2204 {
2205 pQueryValue1Msg->Show(FALSE);
2206 pQueryValue1Txt->Show(FALSE);
2207 }
2208 else // "Value" is highlighted
2209 {
2210 pQueryValue1Msg->Show(TRUE);
2211 pQueryValue1Txt->Show(TRUE);
2212 pQueryValue1Txt->SetFocus();
2213 }
2214 return;
2215 } // Column 2 choice
2216
2217 // Add button
2218 if (widgetName == pQueryAddBtn->GetName())
2219 {
2220 ProcessAddBtn();
2221 return;
2222 } // Add button
2223
2224 // And button
2225 if (widgetName == pQueryAndBtn->GetName())
2226 {
2227 AppendToWhere(wxT(" AND\n"));
2228 return;
2229 } // And button
2230
2231 // Or button
2232 if (widgetName == pQueryOrBtn->GetName())
2233 {
2234 AppendToWhere(wxT(" OR\n"));
2235 return;
2236 } // Or button
2237
2238 // Left Paren button
2239 if (widgetName == pQueryLParenBtn->GetName())
2240 {
2241 AppendToWhere(wxT("("));
2242 return;
2243 } // Left Paren button
2244
2245 // Right paren button
2246 if (widgetName == pQueryRParenBtn->GetName())
2247 {
2248 AppendToWhere(wxT(")"));
2249 return;
2250 } // Right Paren button
2251
2252 // Done button
2253 if (widgetName == pQueryDoneBtn->GetName())
2254 {
2255 // Be sure the where clause will not overflow the output buffer
2256 if (wxStrlen(pQuerySqlWhereMtxt->GetValue()) > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN)
2257 {
2258 wxString s;
2259 s.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN+1);
2260 wxMessageBox(s,wxT("Error..."),wxOK | wxICON_EXCLAMATION);
2261 return;
2262 }
2263 // Validate the where clause for things such as matching parens
2264 if (!ValidateWhereClause())
2265 return;
2266 // Copy the where clause to the output buffer and exit
2267 pWhere = pQuerySqlWhereMtxt->GetValue();
2268 Close();
2269 return;
2270 } // Done button
2271
2272 // Clear button
2273 if (widgetName == pQueryClearBtn->GetName())
2274 {
2275 bool Ok = (wxMessageBox(wxT("Are you sure you wish to clear the Query?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
2276
2277 if (Ok)
2278 pQuerySqlWhereMtxt->SetValue(wxT(""));
2279 return;
2280 } // Clear button
2281
2282 // Count button
2283 if (widgetName == pQueryCountBtn->GetName())
2284 {
2285 wxBeginBusyCursor();
2286 ProcessCountBtn();
2287 wxEndBusyCursor();
2288 return;
2289 } // Count button
2290
2291 } // CqueryDlg::OnCommand
2292
2293
2294 void CqueryDlg::OnCloseWindow(wxCloseEvent& event)
2295 {
2296 // Clean up
2297 wxDELETEA(colInf);
2298
2299 wxDELETE(dbTable);
2300
2301 GetParent()->SetFocus();
2302 while (wxIsBusy())
2303 wxEndBusyCursor();
2304
2305 Show(FALSE);
2306 SetReturnCode(1); // added so BoundsChecker would not report use of uninitialized variable
2307
2308 this->Destroy();
2309 } // CqueryDlg::OnCloseWindow()
2310
2311
2312 void CqueryDlg::AppendToWhere(wxChar *s)
2313 {
2314 wxString whereStr = pQuerySqlWhereMtxt->GetValue();
2315 whereStr += s;
2316 pQuerySqlWhereMtxt->SetValue(whereStr);
2317 } // CqueryDlg::AppendToWhere()
2318
2319
2320 void CqueryDlg::ProcessAddBtn()
2321 {
2322 qryOp oper = (qryOp) pQueryOperatorChoice->GetSelection();
2323
2324 // Verify that eveything is filled in correctly
2325 if (pQueryCol2Choice->GetSelection() == 0) // "Value" is selected
2326 {
2327 // Verify that value 1 is filled in
2328 if (wxStrlen(pQueryValue1Txt->GetValue()) == 0)
2329 {
2330 wxBell();
2331 pQueryValue1Txt->SetFocus();
2332 return;
2333 }
2334 // For the BETWEEN operator, value 2 must be filled in as well
2335 if (oper == qryOpBETWEEN &&
2336 wxStrlen(pQueryValue2Txt->GetValue()) == 0)
2337 {
2338 wxBell();
2339 pQueryValue2Txt->SetFocus();
2340 return;
2341 }
2342 }
2343
2344 // Build the expression and append it to the where clause window
2345 wxString s = pQueryCol1Choice->GetStringSelection();
2346
2347 if (pQueryNotCheck->GetValue() && (oper != qryOpEQ))
2348 s += wxT(" NOT");
2349
2350 switch(oper)
2351 {
2352 case qryOpEQ:
2353 if (pQueryNotCheck->GetValue()) // NOT box is checked
2354 s += wxT(" <>");
2355 else
2356 s += wxT(" =");
2357 break;
2358 case qryOpLT:
2359 s += wxT(" <");
2360 break;
2361 case qryOpGT:
2362 s += wxT(" >");
2363 break;
2364 case qryOpLE:
2365 s += wxT(" <=");
2366 break;
2367 case qryOpGE:
2368 s += wxT(" >=");
2369 break;
2370 case qryOpBEGINS:
2371 case qryOpCONTAINS:
2372 case qryOpLIKE:
2373 s += wxT(" LIKE");
2374 break;
2375 case qryOpBETWEEN:
2376 s += wxT(" BETWEEN");
2377 break;
2378 }
2379
2380 s += wxT(" ");
2381
2382 int col1Idx = pQueryCol1Choice->GetSelection();
2383
2384 bool quote = FALSE;
2385 if (colInf[col1Idx].sqlDataType == SQL_VARCHAR ||
2386 oper == qryOpBEGINS ||
2387 oper == qryOpCONTAINS ||
2388 oper == qryOpLIKE)
2389 quote = TRUE;
2390
2391 if (pQueryCol2Choice->GetSelection()) // Column name
2392 s += pQueryCol2Choice->GetStringSelection();
2393 else // Column 2 is a "value"
2394 {
2395 if (quote)
2396 s += wxT("'");
2397 if (oper == qryOpCONTAINS)
2398 s += wxT("%");
2399 s += pQueryValue1Txt->GetValue();
2400 if (oper == qryOpCONTAINS || oper == qryOpBEGINS)
2401 s += wxT("%");
2402 if (quote)
2403 s += wxT("'");
2404 }
2405
2406 if (oper == qryOpBETWEEN)
2407 {
2408 s += wxT(" AND ");
2409 if (quote)
2410 s += wxT("'");
2411 s += pQueryValue2Txt->GetValue();
2412 if (quote)
2413 s += wxT("'");
2414 }
2415
2416 AppendToWhere((wxChar*) (const wxChar*) s);
2417
2418 } // CqueryDlg::ProcessAddBtn()
2419
2420
2421 void CqueryDlg::ProcessCountBtn()
2422 {
2423 if (!ValidateWhereClause())
2424 return;
2425
2426 if (!dbTable) // wxDbTable object needs to be created and opened
2427 {
2428 dbTable = new wxDbTable(pDB, masterTableName, 0, wxT(""),
2429 !wxDB_QUERY_ONLY,
2430 wxGetApp().DbConnectInf->GetDefaultDir());
2431 if (!dbTable)
2432 {
2433 wxMessageBox(wxT("Memory allocation failed creating a wxDbTable object."),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
2434 return;
2435 }
2436 if (!dbTable->Open())
2437 {
2438 wxString tStr;
2439 tStr = wxT("ODBC error during Open()\n\n");
2440 tStr += GetExtendedDBErrorMsg(dbTable->GetDb(),__FILE__,__LINE__);
2441 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
2442 return;
2443 }
2444 }
2445
2446 // Count() with WHERE clause
2447 wxString whereStr;
2448
2449 whereStr = pQuerySqlWhereMtxt->GetValue();
2450 dbTable->SetWhereClause(whereStr.c_str());
2451
2452 ULONG whereCnt = dbTable->Count();
2453
2454 // Count() of all records in the table
2455 dbTable->SetWhereClause(wxT(""));
2456 ULONG totalCnt = dbTable->Count();
2457
2458 if (whereCnt > 0 || totalCnt == 0)
2459 {
2460 wxString tStr;
2461 tStr.Printf(wxT("%lu of %lu records match the query criteria."),whereCnt,totalCnt);
2462 wxMessageBox(tStr,wxT("Notice..."),wxOK | wxICON_INFORMATION);
2463 }
2464 else
2465 {
2466 wxString tStr;
2467 tStr.Printf(wxT("%lu of %lu records match the query criteria.\n\nEither the criteria entered produced a result set\nwith no records, or there was a syntactical error\nin the clause you entered.\n\nPress the details button to see if any database errors were reported."),whereCnt,totalCnt);
2468 wxMessageBox(tStr,wxT("Notice..."),wxOK | wxICON_INFORMATION);
2469 }
2470
2471 // After a wxMessageBox, the focus does not necessarily return to the
2472 // window which was the focus when the message box popped up, so return
2473 // focus to the Query dialog for certain
2474 SetFocus();
2475
2476 } // CqueryDlg::ProcessCountBtn()
2477
2478
2479 bool CqueryDlg::ValidateWhereClause()
2480 {
2481 wxString where = pQuerySqlWhereMtxt->GetValue();
2482
2483 if (where.Freq(wxT('(')) != where.Freq(wxT(')')))
2484 {
2485 wxMessageBox(wxT("There are mismatched parenthesis in the constructed where clause"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
2486 return(FALSE);
2487 }
2488 // After a wxMessageBox, the focus does not necessarily return to the
2489 // window which was the focus when the message box popped up, so return
2490 // focus to the Query dialog for certain
2491 SetFocus();
2492
2493 return(TRUE);
2494
2495 } // CqueryDlg::ValidateWhereClause()
2496
2497
2498
2499 void DisplayDbDiagnostics(wxDb *pDb)
2500 {
2501 wxString s, t;
2502 bool comma = FALSE;
2503
2504 s = langDBINF_DB_NAME;
2505 s += pDb->dbInf.dbmsName;
2506 s += "\n";
2507
2508 s += langDBINF_DB_VER;
2509 s += pDb->dbInf.dbmsVer;
2510 s += "\n";
2511
2512 s += langDBINF_DRIVER_NAME;
2513 s += pDb->dbInf.driverName;
2514 s += "\n";
2515
2516 s += langDBINF_DRIVER_ODBC_VER;
2517 s += pDb->dbInf.odbcVer;
2518 s += "\n";
2519
2520 s += langDBINF_DRIVER_MGR_ODBC_VER;
2521 s += pDb->dbInf.drvMgrOdbcVer;
2522 s += "\n";
2523
2524 s += langDBINF_DRIVER_VER;
2525 s += pDb->dbInf.driverVer;
2526 s += "\n";
2527
2528 s += langDBINF_SERVER_NAME;
2529 s += pDb->dbInf.serverName;
2530 s += "\n";
2531
2532 s += langDBINF_FILENAME;
2533 s += pDb->dbInf.databaseName;
2534 s += "\n";
2535
2536 s += langDBINF_OUTER_JOINS;
2537 s += pDb->dbInf.outerJoins;
2538 s += "\n";
2539
2540 s += langDBINF_STORED_PROC;
2541 s += pDb->dbInf.procedureSupport;
2542 s += "\n";
2543
2544 if (pDb->dbInf.maxConnections)
2545 t.sprintf("%s%d\n", langDBINF_MAX_HDBC, pDb->dbInf.maxConnections);
2546 else
2547 t.sprintf("%s%s\n", langDBINF_MAX_HDBC, langDBINF_UNLIMITED);
2548 s += t;
2549
2550 if (pDb->dbInf.maxStmts)
2551 t.sprintf("%s%d\n", langDBINF_MAX_HSTMT, pDb->dbInf.maxStmts);
2552 else
2553 t.sprintf("%s%s\n", langDBINF_MAX_HSTMT, langDBINF_UNLIMITED);
2554 s += t;
2555
2556 s += langDBINF_API_LVL;
2557 switch(pDb->dbInf.apiConfLvl)
2558 {
2559 case SQL_OAC_NONE: s += langDBINF_NONE; break;
2560 case SQL_OAC_LEVEL1: s += langDBINF_LEVEL1; break;
2561 case SQL_OAC_LEVEL2: s += langDBINF_LEVEL2; break;
2562 }
2563 s += "\n";
2564
2565 s += langDBINF_CLI_LVL;
2566 switch(pDb->dbInf.cliConfLvl)
2567 {
2568 case SQL_OSCC_NOT_COMPLIANT: s += langDBINF_NOT_COMPLIANT; break;
2569 case SQL_OSCC_COMPLIANT: s += langDBINF_COMPLIANT; break;
2570 }
2571 s += "\n";
2572
2573 s += langDBINF_SQL_LVL;
2574 switch(pDb->dbInf.sqlConfLvl)
2575 {
2576 case SQL_OSC_MINIMUM: s += langDBINF_MIN_GRAMMAR; break;
2577 case SQL_OSC_CORE: s += langDBINF_CORE_GRAMMAR; break;
2578 case SQL_OSC_EXTENDED: s += langDBINF_EXT_GRAMMAR; break;
2579 }
2580 s += "\n";
2581
2582 s += langDBINF_COMMIT_BEHAVIOR;
2583 switch(pDb->dbInf.cursorCommitBehavior)
2584 {
2585 case SQL_CB_DELETE: s += langDBINF_DELETE_CURSORS; break;
2586 case SQL_CB_CLOSE: s += langDBINF_CLOSE_CURSORS; break;
2587 case SQL_CB_PRESERVE: s += langDBINF_PRESERVE_CURSORS; break;
2588 }
2589 s += "\n";
2590
2591 s += langDBINF_ROLLBACK_BEHAVIOR;
2592 switch(pDb->dbInf.cursorRollbackBehavior)
2593 {
2594 case SQL_CB_DELETE: s += langDBINF_DELETE_CURSORS; break;
2595 case SQL_CB_CLOSE: s += langDBINF_CLOSE_CURSORS; break;
2596 case SQL_CB_PRESERVE: s += langDBINF_PRESERVE_CURSORS; break;
2597 }
2598 s += "\n";
2599
2600 s += langDBINF_SUPP_NOT_NULL;
2601 switch(pDb->dbInf.supportNotNullClause)
2602 {
2603 case SQL_NNC_NULL: s += langNO; break;
2604 case SQL_NNC_NON_NULL: s += langYES; break;
2605 }
2606 s += "\n";
2607
2608 s += langDBINF_SUPP_IEF;
2609 s += pDb->dbInf.supportIEF;
2610 s += "\n";
2611
2612 // DEFAULT setting for "Transaction Isolation Level"
2613 s += langDBINF_TXN_ISOLATION;
2614 switch(pDb->dbInf.txnIsolation)
2615 {
2616 case SQL_TXN_READ_UNCOMMITTED: s += langDBINF_READ_UNCOMMITTED; break;
2617 case SQL_TXN_READ_COMMITTED: s += langDBINF_READ_COMMITTED; break;
2618 case SQL_TXN_REPEATABLE_READ: s += langDBINF_REPEATABLE_READ; break;
2619 case SQL_TXN_SERIALIZABLE: s += langDBINF_SERIALIZABLE; break;
2620 #ifdef ODBC_V20
2621 case SQL_TXN_VERSIONING: s += langDBINF_VERSIONING; break;
2622 #endif
2623 }
2624 s += "\n";
2625
2626 // CURRENT setting for "Transaction Isolation Level"
2627 long txnIsoLvl;
2628 s += langDBINF_TXN_ISOLATION_CURR;
2629 if (SQLGetConnectOption(pDb->GetHDBC(),SQL_TXN_ISOLATION,&txnIsoLvl) == SQL_SUCCESS)
2630 {
2631 switch(txnIsoLvl)
2632 {
2633 case SQL_TXN_READ_UNCOMMITTED: s += langDBINF_READ_UNCOMMITTED; break;
2634 case SQL_TXN_READ_COMMITTED: s += langDBINF_READ_COMMITTED; break;
2635 case SQL_TXN_REPEATABLE_READ: s += langDBINF_REPEATABLE_READ; break;
2636 case SQL_TXN_SERIALIZABLE: s += langDBINF_SERIALIZABLE; break;
2637 #ifdef ODBC_V20
2638 case SQL_TXN_VERSIONING: s += langDBINF_VERSIONING; break;
2639 #endif
2640 }
2641 }
2642 s += "\n";
2643
2644 comma = FALSE;
2645 s += langDBINF_TXN_ISOLATION_OPTS;
2646 if (pDb->dbInf.txnIsolationOptions & SQL_TXN_READ_UNCOMMITTED)
2647 {s += langDBINF_READ_UNCOMMITTED; comma++;}
2648 if (pDb->dbInf.txnIsolationOptions & SQL_TXN_READ_COMMITTED)
2649 {if (comma++) s += ", "; s += langDBINF_READ_COMMITTED;}
2650 if (pDb->dbInf.txnIsolationOptions & SQL_TXN_REPEATABLE_READ)
2651 {if (comma++) s += ", "; s += langDBINF_REPEATABLE_READ;}
2652 if (pDb->dbInf.txnIsolationOptions & SQL_TXN_SERIALIZABLE)
2653 {if (comma++) s += ", "; s += langDBINF_SERIALIZABLE;}
2654 #ifdef ODBC_V20
2655 if (pDb->dbInf.txnIsolationOptions & SQL_TXN_VERSIONING)
2656 {if (comma++) s += ", "; s += langDBINF_VERSIONING;}
2657 #endif
2658 s += "\n";
2659
2660 comma = FALSE;
2661 s += langDBINF_FETCH_DIRS;
2662 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_NEXT)
2663 {s += langDBINF_NEXT; comma++;}
2664 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_PRIOR)
2665 {if (comma++) s += ", "; s += langDBINF_PREV;}
2666 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_FIRST)
2667 {if (comma++) s += ", "; s += langDBINF_FIRST;}
2668 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_LAST)
2669 {if (comma++) s += ", "; s += langDBINF_LAST;}
2670 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_ABSOLUTE)
2671 {if (comma++) s += ", "; s += langDBINF_ABSOLUTE;}
2672 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_RELATIVE)
2673 {if (comma++) s += ", "; s += langDBINF_RELATIVE;}
2674 #ifdef ODBC_V20
2675 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_RESUME)
2676 {if (comma++) s += ", "; s += langDBINF_RESUME;}
2677 #endif
2678 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_BOOKMARK)
2679 {if (comma++) s += ", "; s += langDBINF_BOOKMARK;}
2680 s += "\n";
2681
2682 comma = FALSE;
2683 s += langDBINF_LOCK_TYPES;
2684 if (pDb->dbInf.lockTypes & SQL_LCK_NO_CHANGE)
2685 {s += langDBINF_NO_CHANGE; comma++;}
2686 if (pDb->dbInf.lockTypes & SQL_LCK_EXCLUSIVE)
2687 {if (comma++) s += ", "; s += langDBINF_EXCLUSIVE;}
2688 if (pDb->dbInf.lockTypes & SQL_LCK_UNLOCK)
2689 {if (comma++) s += ", "; s += langDBINF_UNLOCK;}
2690 s += "\n";
2691
2692 comma = FALSE;
2693 s += langDBINF_POS_OPERS;
2694 if (pDb->dbInf.posOperations & SQL_POS_POSITION)
2695 {s += langDBINF_POSITION; comma++;}
2696 if (pDb->dbInf.posOperations & SQL_POS_REFRESH)
2697 {if (comma++) s += ", "; s += langDBINF_REFRESH;}
2698 if (pDb->dbInf.posOperations & SQL_POS_UPDATE)
2699 {if (comma++) s += ", "; s += langDBINF_UPD;}
2700 if (pDb->dbInf.posOperations & SQL_POS_DELETE)
2701 {if (comma++) s += ", "; s += langDBINF_DEL;}
2702 if (pDb->dbInf.posOperations & SQL_POS_ADD)
2703 {if (comma++) s += ", "; s += langDBINF_ADD;}
2704 s += "\n";
2705
2706 comma = FALSE;
2707 s += langDBINF_POS_STMTS;
2708 if (pDb->dbInf.posStmts & SQL_PS_POSITIONED_DELETE)
2709 {s += langDBINF_POS_DEL; comma++;}
2710 if (pDb->dbInf.posStmts & SQL_PS_POSITIONED_UPDATE)
2711 {if (comma++) s += ", "; s += langDBINF_POS_UPD;}
2712 if (pDb->dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE)
2713 {if (comma++) s += ", "; s += langDBINF_SELECT_FOR_UPD;}
2714 s += "\n";
2715
2716 comma = FALSE;
2717 s += langDBINF_SCROLL_CONCURR;
2718 if (pDb->dbInf.scrollConcurrency & SQL_SCCO_READ_ONLY)
2719 {s += langDBINF_READ_ONLY; comma++;}
2720 if (pDb->dbInf.scrollConcurrency & SQL_SCCO_LOCK)
2721 {if (comma++) s += ", "; s += langDBINF_LOCK;}
2722 if (pDb->dbInf.scrollConcurrency & SQL_SCCO_OPT_ROWVER)
2723 {if (comma++) s += ", "; s += langDBINF_OPT_ROWVER;}
2724 if (pDb->dbInf.scrollConcurrency & SQL_SCCO_OPT_VALUES)
2725 {if (comma++) s += ", "; s += langDBINF_OPT_VALUES;}
2726 s += "\n";
2727
2728 comma = FALSE;
2729 s += langDBINF_SCROLL_OPTS;
2730 if (pDb->dbInf.scrollOptions & SQL_SO_FORWARD_ONLY)
2731 {s += langDBINF_FWD_ONLY; comma++;}
2732 if (pDb->dbInf.scrollOptions & SQL_SO_STATIC)
2733 {if (comma++) s += ", "; s += langDBINF_STATIC;}
2734 if (pDb->dbInf.scrollOptions & SQL_SO_KEYSET_DRIVEN)
2735 {if (comma++) s += ", "; s += langDBINF_KEYSET_DRIVEN;}
2736 if (pDb->dbInf.scrollOptions & SQL_SO_DYNAMIC)
2737 {if (comma++) s += ", "; s += langDBINF_DYNAMIC;}
2738 if (pDb->dbInf.scrollOptions & SQL_SO_MIXED)
2739 {if (comma++) s += ", "; s += langDBINF_MIXED;}
2740 s += "\n";
2741
2742 comma = FALSE;
2743 s += langDBINF_STATIC_SENS;
2744 if (pDb->dbInf.staticSensitivity & SQL_SS_ADDITIONS)
2745 {s += langDBINF_ADDITIONS; comma++;}
2746 if (pDb->dbInf.staticSensitivity & SQL_SS_DELETIONS)
2747 {if (comma++) s += ", "; s += langDBINF_DELETIONS;}
2748 if (pDb->dbInf.staticSensitivity & SQL_SS_UPDATES)
2749 {if (comma++) s += ", "; s += langDBINF_UPDATES;}
2750 s += "\n";
2751
2752
2753 s += langDBINF_TXN_CAPABLE;
2754 switch(pDb->dbInf.txnCapable)
2755 {
2756 case SQL_TC_NONE: s += langNO; break;
2757 case SQL_TC_DML: s += langDBINF_DML_ONLY; break;
2758 case SQL_TC_DDL_COMMIT: s += langDBINF_DDL_COMMIT; break;
2759 case SQL_TC_DDL_IGNORE: s += langDBINF_DDL_IGNORE; break;
2760 case SQL_TC_ALL: s += langDBINF_DDL_AND_DML; break;
2761 }
2762 s += "\n";
2763
2764 t.sprintf("%s%d\n", langDBINF_LOGIN_TIMEOUT, pDb->dbInf.loginTimeout);
2765 s += t;
2766
2767 // Oracle specific information
2768 if (pDb->Dbms() == dbmsORACLE)
2769 {
2770 s += "\n";
2771 s += langDBINF_ORACLE_BANNER;
2772 s += "\n";
2773
2774 // Oracle cache hit ratio
2775 SDWORD cb;
2776 ULONG dbBlockGets;
2777 pDb->ExecSql("SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'db block gets'");
2778 pDb->GetNext();
2779 if (pDb->GetData(1, SQL_C_ULONG, &dbBlockGets, 0, &cb))
2780 {
2781 t.sprintf("%s: %lu\n", langDBINF_DB_BLOCK_GETS, dbBlockGets);
2782 s += t;
2783 }
2784
2785 ULONG consistentGets;
2786 pDb->ExecSql("SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'consistent gets'");
2787 pDb->GetNext();
2788 if (pDb->GetData(1, SQL_C_ULONG, &consistentGets, 0, &cb))
2789 {
2790 t.sprintf("%s: %lu\n", langDBINF_CONSISTENT_GETS, consistentGets);
2791 s += t;
2792 }
2793
2794 ULONG physReads;
2795 pDb->ExecSql("SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'physical reads'");
2796 pDb->GetNext();
2797 if (pDb->GetData(1, SQL_C_ULONG, &physReads, 0, &cb))
2798 {
2799 t.sprintf("%s: %lu\n", langDBINF_PHYSICAL_READS, physReads);
2800 s += t;
2801 }
2802
2803 ULONG hitRatio = (ULONG)((1.00 - ((float)physReads / (float)(dbBlockGets + consistentGets))) * 100.00);
2804 t.sprintf("*** %s: %lu%%\n", langDBINF_CACHE_HIT_RATIO, hitRatio);
2805 s += t;
2806
2807 // Tablespace information
2808 s += "\n";
2809 s += langDBINF_TABLESPACE_IO;
2810 s += "\n";
2811 ULONG physWrites;
2812 char tablespaceName[257];
2813 pDb->ExecSql("SELECT NAME,PHYRDS,PHYWRTS FROM V$DATAFILE, V$FILESTAT WHERE V$DATAFILE.FILE# = V$FILESTAT.FILE#");
2814 while (pDb->GetNext())
2815 {
2816 pDb->GetData(1, SQL_C_CHAR, tablespaceName, 257, &cb);
2817 pDb->GetData(2, SQL_C_ULONG, &physReads, 0, &cb);
2818 pDb->GetData(3, SQL_C_ULONG, &physWrites, 0, &cb);
2819 t.sprintf("%s\n\t%s: %lu\t%s: %lu\n", tablespaceName,
2820 langDBINF_PHYSICAL_READS, physReads, langDBINF_PHYSICAL_WRITES, physWrites);
2821 s += t;
2822 }
2823
2824 s += "\n";
2825 }
2826
2827 wxLogMessage(s);
2828
2829 } // DisplayDbDiagnostics()
2830
2831
2832
2833
2834 /*
2835 TEST CODE FOR TESTING THE wxDbCreateDataSource() FUNCTION
2836
2837 int result = 0;
2838 result = wxDbCreateDataSource(wxT("Microsoft Access Driver (*.mdb)"),wxT("GLT-TEST2"),wxT("GLT-Descrip"),FALSE,wxT(""),this);
2839 if (!result)
2840 {
2841 // check for errors caused by ConfigDSN based functions
2842 DWORD retcode = 0;
2843 WORD cb;
2844 wxChar errMsg[500+1];
2845 errMsg[0] = wxT('\0');
2846
2847 SQLInstallerError(1,&retcode,errMsg,500,&cb);
2848
2849 wxMessageBox(wxT("FAILED creating data source"),wxT("FAILED"));
2850 }
2851 else
2852 wxMessageBox(wxT("SUCCEEDED creating data source"),wxT("SUCCESS"));
2853 */
2854
2855