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