]> git.saurik.com Git - wxWidgets.git/blob - src/common/dbgrid.cpp
added code for optimized handling of UTF-8 locales: some string operations are more...
[wxWidgets.git] / src / common / dbgrid.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/dbgrid.cpp
3 // Purpose: Displays a wxDbTable in a wxGrid.
4 // Author: Roger Gammans, Paul Gammans
5 // Modified by:
6 // Created:
7 // RCS-ID: $Id$
8 // Copyright: (c) 1999 The Computer Surgery (roger@computer-surgery.co.uk)
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11 // Branched From : dbgrid.cpp,v 1.18 2000/12/19 13:00:58
12 ///////////////////////////////////////////////////////////////////////////////
13
14 #include "wx/wxprec.h"
15
16 #ifdef __BORLANDC__
17 #pragma hdrstop
18 #endif
19
20 #if wxUSE_ODBC && wxUSE_GRID
21
22 #ifndef WX_PRECOMP
23 #include "wx/textctrl.h"
24 #include "wx/dc.h"
25 #include "wx/app.h"
26 #endif // WX_PRECOMP
27
28 #include "wx/generic/gridctrl.h"
29 #include "wx/dbgrid.h"
30
31 // DLL options compatibility check:
32 WX_CHECK_BUILD_OPTIONS("wxDbGrid")
33
34
35 wxDbGridCellAttrProvider::wxDbGridCellAttrProvider()
36 {
37 m_data=NULL;
38 m_ColInfo=NULL;
39 }
40
41 wxDbGridCellAttrProvider::wxDbGridCellAttrProvider(wxDbTable *tab, wxDbGridColInfoBase* ColInfo)
42 {
43 m_data=tab;
44 m_ColInfo=ColInfo;
45 }
46
47 wxDbGridCellAttrProvider::~wxDbGridCellAttrProvider()
48 {
49 }
50
51 wxGridCellAttr *wxDbGridCellAttrProvider::GetAttr(int row, int col,
52 wxGridCellAttr::wxAttrKind kind) const
53 {
54 wxGridCellAttr *attr = wxGridCellAttrProvider::GetAttr(row,col,kind);
55
56 if (m_data && m_ColInfo && (m_data->GetNumberOfColumns() > m_ColInfo[col].DbCol))
57 {
58 //FIXME: this test could.
59 // ??::InsertPending == m_data->get_ModifiedStatus()
60 // and if InsertPending use colDef[].InsertAllowed
61 if (!(m_data->GetColDefs()[(m_ColInfo[col].DbCol)].Updateable))
62 {
63 switch(kind)
64 {
65 case (wxGridCellAttr::Any):
66 if (!attr)
67 {
68 attr = new wxGridCellAttr;
69 // Store so we don't keep creating / deleting this...
70 wxDbGridCellAttrProvider * self = wxConstCast(this, wxDbGridCellAttrProvider) ;
71 attr->IncRef();
72 self->SetColAttr(attr, col);
73 attr->SetReadOnly();
74 }
75 else
76 {
77 //We now must check what we were returned. and do the right thing (tm)
78 wxGridCellAttr::wxAttrKind attrkind = attr->GetKind();
79 if ((attrkind == (wxGridCellAttr::Default)) || (attrkind == (wxGridCellAttr::Cell)) ||
80 (attrkind == (wxGridCellAttr::Col)))
81 {
82 wxGridCellAttr *attrtomerge = attr;
83 attr = new wxGridCellAttr;
84 attr->SetKind(wxGridCellAttr::Merged);
85 attr->MergeWith(attrtomerge);
86 attr->SetReadOnly();
87 attrtomerge->DecRef();
88 }
89 attr->SetReadOnly();
90 }
91 break;
92 case (wxGridCellAttr::Col):
93 //As we must have a Coll, and were setting Coll attributes
94 // we can based on wxdbTable's so just set RO if attr valid
95 if (!attr)
96 {
97 attr = new wxGridCellAttr;
98 wxDbGridCellAttrProvider * self = wxConstCast(this, wxDbGridCellAttrProvider) ;
99 attr->IncRef();
100 self->SetColAttr(attr, col);
101 }
102 attr->SetReadOnly();
103 break;
104 default:
105 //Dont add RO for...
106 // wxGridCellAttr::Cell - Not required, will inherit on merge from row.
107 // wxGridCellAttr::Row - If wxDbtable ever supports row locking could add
108 // support to make RO on a row basis also.
109 // wxGridCellAttr::Default - Don't edit this ! or all cell with a attr will become readonly
110 // wxGridCellAttr::Merged - This should never be asked for.
111 break;
112 }
113 }
114
115 }
116 return attr;
117 }
118
119 void wxDbGridCellAttrProvider::AssignDbTable(wxDbTable *tab)
120 {
121 m_data = tab;
122 }
123
124 wxDbGridTableBase::wxDbGridTableBase(wxDbTable *tab, wxDbGridColInfo* ColInfo,
125 int count, bool takeOwnership) :
126 m_keys(),
127 m_data(tab),
128 m_dbowner(takeOwnership),
129 m_rowmodified(false)
130 {
131
132 if (count == wxUSE_QUERY)
133 {
134 m_rowtotal = m_data ? m_data->Count() : 0;
135 }
136 else
137 {
138 m_rowtotal = count;
139 }
140 // m_keys.Size(m_rowtotal);
141 m_row = -1;
142 if (ColInfo)
143 {
144 m_nocols = ColInfo->Length();
145 m_ColInfo = new wxDbGridColInfoBase[m_nocols];
146 //Do Copy.
147 wxDbGridColInfo *ptr = ColInfo;
148 int i =0;
149 while (ptr && i < m_nocols)
150 {
151 m_ColInfo[i] = ptr->m_data;
152 ptr = ptr->m_next;
153 i++;
154 }
155 #ifdef __WXDEBUG__
156 if (ptr)
157 {
158 wxLogDebug(wxT("NoCols over length after traversing %i items"),i);
159 }
160 if (i < m_nocols)
161 {
162 wxLogDebug(wxT("NoCols under length after traversing %i items"),i);
163 }
164 #endif
165 }
166 }
167
168 wxDbGridTableBase::~wxDbGridTableBase()
169 {
170 wxDbGridCellAttrProvider *provider;
171
172 //Can't check for update here as
173
174 //FIXME: should i remove m_ColInfo and m_data from m_attrProvider if a wxDbGridAttrProvider
175 // if ((provider = dynamic_cast<wxDbGridCellAttrProvider *>(GetAttrProvider())))
176 // Using C casting for now until we can support dynamic_cast with wxWidgets
177 provider = (wxDbGridCellAttrProvider *)(GetAttrProvider());
178 if (provider)
179 {
180 provider->AssignDbTable(NULL);
181 }
182 delete [] m_ColInfo;
183
184 Writeback();
185 if (m_dbowner)
186 {
187 delete m_data;
188 }
189 }
190
191 bool wxDbGridTableBase::CanHaveAttributes()
192 {
193 if (!GetAttrProvider())
194 {
195 // use the default attr provider by default
196 SetAttrProvider(new wxDbGridCellAttrProvider(m_data, m_ColInfo));
197 }
198 return true;
199 }
200
201
202 bool wxDbGridTableBase::AssignDbTable(wxDbTable *tab, int count, bool takeOwnership)
203 {
204 wxDbGridCellAttrProvider *provider;
205
206 wxGridUpdateLocker locker(GetView());
207
208 //Remove Information from grid about old data
209 if (GetView())
210 {
211 wxGrid *grid = GetView();
212 grid->ClearSelection();
213 if (grid->IsCellEditControlEnabled())
214 {
215 grid->DisableCellEditControl();
216 }
217 wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_ROWS_DELETED,0,m_rowtotal);
218 grid->ProcessTableMessage(msg);
219 }
220
221 //reset our internals...
222 Writeback();
223 if (m_dbowner)
224 {
225 delete m_data;
226 }
227 m_keys.Empty();
228 m_data = tab;
229 //FIXME: Remove dynamic_cast before sumision to wxwin
230 // if ((provider = dynamic_cast<wxDbGridCellAttrProvider *> (GetAttrProvider())))
231 // Using C casting for now until we can support dynamic_cast with wxWidgets
232 provider = (wxDbGridCellAttrProvider *)(GetAttrProvider());
233 if (provider)
234 {
235 provider->AssignDbTable(m_data);
236 }
237
238 if (count == wxUSE_QUERY)
239 {
240 m_rowtotal = m_data ? m_data->Count() : 0;
241 }
242 else
243 {
244 m_rowtotal = count;
245 }
246 m_row = -1;
247
248 //Add Information to grid about new data
249 if (GetView())
250 {
251 wxGrid * grid = GetView();
252 wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rowtotal);
253 grid->ProcessTableMessage(msg);
254 }
255 m_dbowner = takeOwnership;
256 m_rowmodified = false;
257 return true;
258 }
259
260 wxString wxDbGridTableBase::GetTypeName(int WXUNUSED(row), int col)
261 {
262 if (GetNumberCols() > col)
263 {
264 if (m_ColInfo[col].wxtypename == wxGRID_VALUE_DBAUTO)
265 {
266 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
267 {
268 wxFAIL_MSG (_T("You can not use wxGRID_VALUE_DBAUTO for virtual columns"));
269 }
270 switch(m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype)
271 {
272 case SQL_C_CHAR:
273 #ifdef SQL_C_WCHAR
274 case SQL_C_WCHAR:
275 #endif
276 return wxGRID_VALUE_STRING;
277 case SQL_C_SHORT:
278 case SQL_C_SSHORT:
279 return wxGRID_VALUE_NUMBER;
280 case SQL_C_USHORT:
281 return wxGRID_VALUE_NUMBER;
282 case SQL_C_LONG:
283 case SQL_C_SLONG:
284 return wxGRID_VALUE_NUMBER;
285 case SQL_C_ULONG:
286 return wxGRID_VALUE_NUMBER;
287 case SQL_C_FLOAT:
288 return wxGRID_VALUE_FLOAT;
289 case SQL_C_DOUBLE:
290 return wxGRID_VALUE_FLOAT;
291 case SQL_C_DATE:
292 return wxGRID_VALUE_DATETIME;
293 case SQL_C_TIME:
294 return wxGRID_VALUE_DATETIME;
295 case SQL_C_TIMESTAMP:
296 return wxGRID_VALUE_DATETIME;
297 default:
298 return wxGRID_VALUE_STRING;
299 }
300 }
301 else
302 {
303 return m_ColInfo[col].wxtypename;
304 }
305 }
306 wxFAIL_MSG (_T("unknown column"));
307 return wxString();
308 }
309
310 bool wxDbGridTableBase::CanGetValueAs(int row, int col, const wxString& typeName)
311 {
312 wxLogDebug(wxT("CanGetValueAs() on %i,%i"),row,col);
313 //Is this needed? As it will be validated on GetValueAsXXXX
314 ValidateRow(row);
315
316 if (typeName == wxGRID_VALUE_STRING)
317 {
318 //FIXME ummm What about blob field etc.
319 return true;
320 }
321
322 if (m_data->IsColNull((UWORD)m_ColInfo[col].DbCol))
323 {
324 return false;
325 }
326
327 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
328 {
329 //If a virtual column then we can't find it's type. we have to
330 // return false to get using wxVariant.
331 return false;
332 }
333 int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
334
335 if (typeName == wxGRID_VALUE_DATETIME)
336 {
337 if ((sqltype == SQL_C_DATE) ||
338 (sqltype == SQL_C_TIME) ||
339 (sqltype == SQL_C_TIMESTAMP))
340 {
341 return true;
342 }
343 return false;
344 }
345 if (typeName == wxGRID_VALUE_NUMBER)
346 {
347 if ((sqltype == SQL_C_SSHORT) ||
348 (sqltype == SQL_C_USHORT) ||
349 (sqltype == SQL_C_SLONG) ||
350 (sqltype == SQL_C_ULONG))
351 {
352 return true;
353 }
354 return false;
355 }
356 if (typeName == wxGRID_VALUE_FLOAT)
357 {
358 if ((sqltype == SQL_C_SSHORT) ||
359 (sqltype == SQL_C_USHORT) ||
360 (sqltype == SQL_C_SLONG) ||
361 (sqltype == SQL_C_ULONG) ||
362 (sqltype == SQL_C_FLOAT) ||
363 (sqltype == SQL_C_DOUBLE))
364 {
365 return true;
366 }
367 return false;
368 }
369 return false;
370 }
371
372 bool wxDbGridTableBase::CanSetValueAs(int WXUNUSED(row), int col, const wxString& typeName)
373 {
374 if (typeName == wxGRID_VALUE_STRING)
375 {
376 //FIXME ummm What about blob field etc.
377 return true;
378 }
379
380 if (!(m_data->GetColDefs()[(m_ColInfo[col].DbCol)].Updateable))
381 {
382 return false;
383 }
384
385 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
386 {
387 //If a virtual column then we can't find it's type. we have to faulse to
388 //get using wxVairent.
389 return false;
390 }
391
392 int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
393 if (typeName == wxGRID_VALUE_DATETIME)
394 {
395 if ((sqltype == SQL_C_DATE) ||
396 (sqltype == SQL_C_TIME) ||
397 (sqltype == SQL_C_TIMESTAMP))
398 {
399 return true;
400 }
401 return false;
402 }
403 if (typeName == wxGRID_VALUE_NUMBER)
404 {
405 if ((sqltype == SQL_C_SSHORT) ||
406 (sqltype == SQL_C_USHORT) ||
407 (sqltype == SQL_C_SLONG) ||
408 (sqltype == SQL_C_ULONG))
409 {
410 return true;
411 }
412 return false;
413 }
414 if (typeName == wxGRID_VALUE_FLOAT)
415 {
416 if ((sqltype == SQL_C_SSHORT) ||
417 (sqltype == SQL_C_USHORT) ||
418 (sqltype == SQL_C_SLONG) ||
419 (sqltype == SQL_C_ULONG) ||
420 (sqltype == SQL_C_FLOAT) ||
421 (sqltype == SQL_C_DOUBLE))
422 {
423 return true;
424 }
425 return false;
426 }
427 return false;
428 }
429
430 long wxDbGridTableBase::GetValueAsLong(int row, int col)
431 {
432 ValidateRow(row);
433
434 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
435 {
436 wxFAIL_MSG (_T("You can not use GetValueAsLong for virtual columns"));
437 return 0;
438 }
439 int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
440 if ((sqltype == SQL_C_SSHORT) ||
441 (sqltype == SQL_C_USHORT) ||
442 (sqltype == SQL_C_SLONG) ||
443 (sqltype == SQL_C_ULONG))
444 {
445 wxVariant val = m_data->GetColumn(m_ColInfo[col].DbCol);
446 return val.GetLong();
447 }
448 wxFAIL_MSG (_T("unknown column, "));
449 return 0;
450 }
451
452 double wxDbGridTableBase::GetValueAsDouble(int row, int col)
453 {
454 wxLogDebug(wxT("GetValueAsDouble() on %i,%i"),row,col);
455 ValidateRow(row);
456
457 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
458 {
459 wxFAIL_MSG (_T("You can not use GetValueAsDouble for virtual columns"));
460 return 0.0;
461 }
462 int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
463 if ((sqltype == SQL_C_SSHORT) ||
464 (sqltype == SQL_C_USHORT) ||
465 (sqltype == SQL_C_SLONG) ||
466 (sqltype == SQL_C_ULONG) ||
467 (sqltype == SQL_C_FLOAT) ||
468 (sqltype == SQL_C_DOUBLE))
469 {
470 wxVariant val = m_data->GetColumn(m_ColInfo[col].DbCol);
471 return val.GetDouble();
472 }
473 wxFAIL_MSG (_T("unknown column"));
474 return 0.0;
475 }
476
477 bool wxDbGridTableBase::GetValueAsBool(int row, int col)
478 {
479 wxLogDebug(wxT("GetValueAsBool() on %i,%i"),row,col);
480 ValidateRow(row);
481
482 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
483 {
484 wxFAIL_MSG (_T("You can not use GetValueAsBool for virtual columns"));
485 return 0;
486 }
487 int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
488 if ((sqltype == SQL_C_SSHORT) ||
489 (sqltype == SQL_C_USHORT) ||
490 (sqltype == SQL_C_SLONG) ||
491 (sqltype == SQL_C_ULONG))
492 {
493 wxVariant val = m_data->GetColumn(m_ColInfo[col].DbCol);
494 return val.GetBool();
495 }
496 wxFAIL_MSG (_T("unknown column, "));
497 return 0;
498 }
499
500 void* wxDbGridTableBase::GetValueAsCustom(int row, int col, const wxString& typeName)
501 {
502 wxLogDebug(wxT("GetValueAsCustom() on %i,%i"),row,col);
503 ValidateRow(row);
504
505 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
506 {
507 wxFAIL_MSG (_T("You can not use GetValueAsCustom for virtual columns"));
508 return NULL;
509 }
510 if (m_data->IsColNull((UWORD)m_ColInfo[col].DbCol))
511 return NULL;
512
513 if (typeName == wxGRID_VALUE_DATETIME)
514 {
515 wxDbColDef *pColDefs = m_data->GetColDefs();
516 int sqltype = pColDefs[(m_ColInfo[col].DbCol)].SqlCtype;
517
518 if ((sqltype == SQL_C_DATE) ||
519 (sqltype == SQL_C_TIME) ||
520 (sqltype == SQL_C_TIMESTAMP))
521 {
522 wxVariant val = m_data->GetColumn(m_ColInfo[col].DbCol);
523 return new wxDateTime(val.GetDateTime());
524 }
525 }
526 wxFAIL_MSG (_T("unknown column data type "));
527 return NULL;
528 }
529
530
531 void wxDbGridTableBase::SetValueAsCustom(int row, int col, const wxString& typeName, void* value)
532 {
533 wxLogDebug(wxT("SetValueAsCustom() on %i,%i"),row,col);
534 ValidateRow(row);
535
536 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
537 {
538 wxFAIL_MSG (_T("You can not use SetValueAsCustom for virtual columns"));
539 return;
540 }
541
542 if (typeName == wxGRID_VALUE_DATETIME)
543 {
544 int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
545 if ((sqltype == SQL_C_DATE) ||
546 (sqltype == SQL_C_TIME) ||
547 (sqltype == SQL_C_TIMESTAMP))
548 {
549 //FIXME: you can't dynamic_cast from (void *)
550 //wxDateTime *date = wxDynamicCast(value, wxDateTime);
551 wxDateTime *date = (wxDateTime *)value;
552 if (!date)
553 {
554 wxFAIL_MSG (_T("Failed to convert data"));
555 return;
556 }
557 wxVariant val(date);
558 m_rowmodified = true;
559 m_data->SetColumn(m_ColInfo[col].DbCol,val);
560 }
561 }
562 wxFAIL_MSG (_T("unknown column data type"));
563 return ;
564 }
565
566
567 wxString wxDbGridTableBase::GetColLabelValue(int col)
568 {
569 if (GetNumberCols() > col)
570 {
571 return m_ColInfo[col].Title;
572 }
573 wxFAIL_MSG (_T("unknown column"));
574 return wxString();
575 }
576
577 bool wxDbGridTableBase::IsEmptyCell(int row, int col)
578 {
579 wxLogDebug(wxT("IsEmtpyCell on %i,%i"),row,col);
580
581 ValidateRow(row);
582 return m_data->IsColNull((UWORD)m_ColInfo[col].DbCol);
583 }
584
585
586 wxString wxDbGridTableBase::GetValue(int row, int col)
587 {
588 wxLogDebug(wxT("GetValue() on %i,%i"),row,col);
589
590 ValidateRow(row);
591 wxVariant val = m_data->GetColumn(m_ColInfo[col].DbCol);
592 wxLogDebug(wxT("\tReturning \"%s\"\n"),val.GetString().c_str());
593
594 return val.GetString();
595 }
596
597
598 void wxDbGridTableBase::SetValue(int row, int col,const wxString& value)
599 {
600 wxLogDebug(wxT("SetValue() on %i,%i"),row,col);
601
602 ValidateRow(row);
603 wxVariant val(value);
604
605 m_rowmodified = true;
606 m_data->SetColumn(m_ColInfo[col].DbCol,val);
607 }
608
609
610 void wxDbGridTableBase::SetValueAsLong(int row, int col, long value)
611 {
612 wxLogDebug(wxT("SetValueAsLong() on %i,%i"),row,col);
613
614 ValidateRow(row);
615 wxVariant val(value);
616
617 m_rowmodified = true;
618 m_data->SetColumn(m_ColInfo[col].DbCol,val);
619 }
620
621
622 void wxDbGridTableBase::SetValueAsDouble(int row, int col, double value)
623 {
624 wxLogDebug(wxT("SetValueAsDouble() on %i,%i"),row,col);
625
626 ValidateRow(row);
627 wxVariant val(value);
628
629 m_rowmodified = true;
630 m_data->SetColumn(m_ColInfo[col].DbCol,val);
631
632 }
633
634
635 void wxDbGridTableBase::SetValueAsBool(int row, int col, bool value)
636 {
637 wxLogDebug(wxT("SetValueAsBool() on %i,%i"),row,col);
638
639 ValidateRow(row);
640 wxVariant val(value);
641
642 m_rowmodified = true;
643 m_data->SetColumn(m_ColInfo[col].DbCol,val);
644 }
645
646
647 void wxDbGridTableBase::ValidateRow(int row)
648 {
649 wxLogDebug(wxT("ValidateRow(%i) currently on row (%i). Array count = %lu"),
650 row, m_row, (unsigned long)m_keys.GetCount());
651
652 if (row == m_row)
653 return;
654 Writeback();
655
656 //We add to row as Count is unsigned!
657 if ((unsigned)(row+1) > m_keys.GetCount())
658 {
659 wxLogDebug(wxT("\trow key unknown"));
660 // Extend Array, iterate through data filling with keys
661 m_data->SetRowMode(wxDbTable::WX_ROW_MODE_QUERY);
662 int trow;
663 for (trow = m_keys.GetCount(); trow <= row; trow++)
664 {
665 wxLogDebug(wxT("Fetching row %i.."), trow);
666 bool ret = m_data->GetNext();
667
668 wxLogDebug(wxT(" ...success=(%i)"),ret);
669 GenericKey k = m_data->GetKey();
670 m_keys.Add(k);
671 }
672 m_row = row;
673 }
674 else
675 {
676 wxLogDebug(wxT("\trow key known centering data"));
677 GenericKey k = m_keys.Item(row);
678 m_data->SetRowMode(wxDbTable::WX_ROW_MODE_INDIVIDUAL);
679 m_data->ClearMemberVars();
680 m_data->SetKey(k);
681 if (!m_data->QueryOnKeyFields())
682 {
683 wxDbLogExtendedErrorMsg(_T("ODBC error during Query()\n\n"), m_data->GetDb(),__TFILE__,__LINE__);
684 }
685
686 m_data->GetNext();
687
688 m_row = row;
689 }
690 m_rowmodified = false;
691 }
692
693 bool wxDbGridTableBase::Writeback() const
694 {
695 if (!m_rowmodified)
696 {
697 return true;
698 }
699
700 bool result=true;
701 wxLogDebug(wxT("\trow key unknown"));
702
703 // FIXME: this code requires dbtable support for record status
704 #if 0
705 switch (m_data->get_ModifiedStatus())
706 {
707 case wxDbTable::UpdatePending:
708 result = m_data->Update();
709 break;
710 case wxDbTable::InsertPending:
711 result = (m_data->Insert() == SQL_SUCCESS);
712 break;
713 default:
714 //Nothing
715 break;
716 }
717 #else
718 wxLogDebug(wxT("WARNING : Row writeback not implemented "));
719 #endif
720 return result;
721 }
722
723 #include "wx/arrimpl.cpp"
724
725 WX_DEFINE_EXPORTED_OBJARRAY(keyarray)
726
727 #endif // wxUSE_GRID && wxUSE_ODBC