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