Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / System.Data / System.Data.Odbc / OdbcCommandBuilder.cs
1 //
2 // System.Data.Odbc.OdbcCommandBuilder
3 //
4 // Author:
5 //   Umadevi S (sumadevi@novell.com)
6 //   Sureshkumar T (tsureshkumar@novell.com)
7 //
8 // Copyright (C) Novell Inc, 2004
9 //
10
11 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System.Text;
35 using System.Data;
36 using System.Data.Common;
37 using System.ComponentModel;
38
39 namespace System.Data.Odbc
40 {
41         /// <summary>
42         /// Provides a means of automatically generating single-table commands used to reconcile changes made to a DataSet with the associated database. This class cannot be inherited.
43         /// </summary>
44
45 #if NET_2_0
46         public sealed class OdbcCommandBuilder : DbCommandBuilder
47 #else // 1_1
48         public sealed class OdbcCommandBuilder : Component
49 #endif // NET_2_0
50         {
51                 #region Fields
52
53                 private OdbcDataAdapter _adapter;
54 #if ONLY_1_1
55                 private string                  _quotePrefix;
56                 private string                  _quoteSuffix;
57 #endif
58
59                 private DataTable               _schema;
60                 private string                  _tableName;
61                 private OdbcCommand             _insertCommand;
62                 private OdbcCommand             _updateCommand;
63                 private OdbcCommand             _deleteCommand;
64
65                 bool _disposed;
66
67                 private OdbcRowUpdatingEventHandler rowUpdatingHandler;
68                 
69                 #endregion // Fields
70
71                 #region Constructors
72                 
73                 public OdbcCommandBuilder ()
74                 {
75                 }
76
77                 public OdbcCommandBuilder (OdbcDataAdapter adapter)
78                         : this ()
79                 {
80                         DataAdapter = adapter;
81                 }
82
83                 #endregion // Constructors
84
85                 #region Properties
86
87                 [OdbcDescriptionAttribute ("The DataAdapter for which to automatically generate OdbcCommands")]
88                 [DefaultValue (null)]
89                 public
90 #if NET_2_0
91                 new
92 #endif // NET_2_0
93                 OdbcDataAdapter DataAdapter {
94                         get {
95                                 return _adapter;
96                         }
97                         set {
98                                 if (_adapter == value)
99                                         return;
100
101                                 if (rowUpdatingHandler != null)
102                                         rowUpdatingHandler = new OdbcRowUpdatingEventHandler (OnRowUpdating);
103                                 
104                                 if (_adapter != null)
105                                         _adapter.RowUpdating -= rowUpdatingHandler;
106                                 _adapter = value;
107                                 if (_adapter != null)
108                                         _adapter.RowUpdating += rowUpdatingHandler;
109                         }
110                 }
111
112                 private OdbcCommand SelectCommand {
113                         get {
114                                 if (DataAdapter == null)
115                                         return null;
116                                 return DataAdapter.SelectCommand;
117                         }
118                 }
119
120                 private DataTable Schema {
121                         get {
122                                 if (_schema == null)
123                                         RefreshSchema ();
124                                 return _schema;
125                         }
126                 }
127                 
128                 private string TableName {
129                         get {
130                                 if (_tableName != string.Empty)
131                                         return _tableName;
132
133                                 DataRow [] schemaRows = Schema.Select ("BaseTableName is not null and BaseTableName <> ''");
134                                 if (schemaRows.Length > 1) {
135                                         string tableName = (string) schemaRows [0] ["BaseTableName"];
136                                         foreach (DataRow schemaRow in schemaRows) {
137                                                 if ( (string) schemaRow ["BaseTableName"] != tableName)
138                                                         throw new InvalidOperationException ("Dynamic SQL generation is not supported against multiple base tables.");
139                                         }
140                                 }
141                                 if (schemaRows.Length == 0)
142                                         throw new InvalidOperationException ("Cannot determine the base table name. Cannot proceed");
143                                 _tableName = schemaRows [0] ["BaseTableName"].ToString ();
144                                 return _tableName;
145                         }
146                 }
147
148 #if ONLY_1_1
149                 [BrowsableAttribute (false)]
150                 [OdbcDescriptionAttribute ("The prefix string wrapped around sql objects")]
151                 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
152                 public string QuotePrefix {
153                         get {
154                                 if (_quotePrefix == null)
155                                         return string.Empty;
156                                 return _quotePrefix;
157                         }
158                         set {
159                                 if (IsCommandGenerated)
160                                         throw new InvalidOperationException (
161                                                 "QuotePrefix cannot be set after " +
162                                                 "an Insert, Update or Delete command " +
163                                                 "has been generated.");
164                                 _quotePrefix = value;
165                         }
166                 }
167
168                 [BrowsableAttribute (false)]
169                 [OdbcDescriptionAttribute ("The suffix string wrapped around sql objects")]
170                 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
171                 public string QuoteSuffix {
172                         get {
173                                 if (_quoteSuffix == null)
174                                         return string.Empty;
175                                 return _quoteSuffix;
176                         }
177                         set {
178                                 if (IsCommandGenerated)
179                                         throw new InvalidOperationException (
180                                                 "QuoteSuffix cannot be set after " +
181                                                 "an Insert, Update or Delete command " +
182                                                 "has been generated.");
183                                 _quoteSuffix = value;
184                         }
185                 }
186 #endif
187
188                 #endregion // Properties
189
190                 #region Methods
191
192                 [MonoTODO]
193                 public static void DeriveParameters (OdbcCommand command)
194                 {
195                         throw new NotImplementedException ();
196                 }
197
198 #if ONLY_1_1
199                 protected override
200 #else
201                 new
202 #endif
203                 void Dispose (bool disposing)
204                 {
205                         if (_disposed)
206                                 return;
207                         
208                         if (disposing) {
209                                 // dispose managed resource
210                                 if (_insertCommand != null)
211                                         _insertCommand.Dispose ();
212                                 if (_updateCommand != null)
213                                         _updateCommand.Dispose ();
214                                 if (_deleteCommand != null)
215                                         _deleteCommand.Dispose ();
216                                 if (_schema != null)
217                                         _schema.Dispose ();
218
219                                 _insertCommand = null;
220                                 _updateCommand = null;
221                                 _deleteCommand = null;
222                                 _schema = null;
223                         }
224                         _disposed = true;
225                 }
226
227                 private bool IsUpdatable (DataRow schemaRow)
228                 {
229                         if ( (! schemaRow.IsNull ("IsAutoIncrement") && (bool) schemaRow ["IsAutoIncrement"])
230                              || (! schemaRow.IsNull ("IsRowVersion") && (bool) schemaRow ["IsRowVersion"])
231                              || (! schemaRow.IsNull ("IsReadOnly") && (bool) schemaRow ["IsReadOnly"])
232                              || (schemaRow.IsNull ("BaseTableName") || ((string) schemaRow ["BaseTableName"]).Length == 0)
233                              )
234                                 return false;
235                         return true;
236                 }
237                 
238                 private string GetColumnName (DataRow schemaRow)
239                 {
240                         string columnName = schemaRow.IsNull ("BaseColumnName") ? String.Empty : (string) schemaRow ["BaseColumnName"];
241                         if (columnName == String.Empty)
242                                 columnName = schemaRow.IsNull ("ColumnName") ? String.Empty : (string) schemaRow ["ColumnName"];
243                         return columnName;
244                 }
245                 
246                 private OdbcParameter AddParameter (OdbcCommand cmd, string paramName, OdbcType odbcType,
247                                                     int length, string sourceColumnName, DataRowVersion rowVersion)
248                 {
249                         OdbcParameter param;
250                         if (length >= 0 && sourceColumnName != String.Empty)
251                                 param = cmd.Parameters.Add (paramName, odbcType, length, sourceColumnName);
252                         else
253                                 param = cmd.Parameters.Add (paramName, odbcType);
254                         param.SourceVersion = rowVersion;
255                         return param;
256                 }
257
258                 /*
259                  * creates where clause for optimistic concurrency
260                  */
261                 private string CreateOptWhereClause (OdbcCommand command, int paramCount)
262                 {
263                         string [] whereClause = new string [Schema.Rows.Count];
264
265                         int partCount = 0;
266
267                         foreach (DataRow schemaRow in Schema.Rows) {
268                                 // exclude non updatable columns
269                                 if (! IsUpdatable (schemaRow))
270                                         continue;
271
272                                 string columnName = GetColumnName (schemaRow);
273                                 if (columnName == String.Empty)
274                                         throw new InvalidOperationException ("Cannot form delete command. Column name is missing!");
275
276                                 bool    allowNull  = schemaRow.IsNull ("AllowDBNull") || (bool) schemaRow ["AllowDBNull"];
277                                 OdbcType sqlDbType = schemaRow.IsNull ("ProviderType") ? OdbcType.VarChar : (OdbcType) schemaRow ["ProviderType"];
278                                 int     length     = schemaRow.IsNull ("ColumnSize") ? -1 : (int) schemaRow ["ColumnSize"];
279
280                                 if (allowNull) {
281                                         whereClause [partCount++] = String.Format ("((? = 1 AND {0} IS NULL) OR ({0} = ?))",
282                                                 GetQuotedString (columnName));
283                                         OdbcParameter nullParam = AddParameter (
284                                                 command,
285                                                 GetParameterName (++paramCount),
286                                                 OdbcType.Int,
287                                                 length,
288 #if NET_2_0
289                                                 columnName,
290 #else
291                                                 string.Empty,
292 #endif
293                                                 DataRowVersion.Original);
294                                         nullParam.Value = 1;
295                                         AddParameter (command, GetParameterName (++paramCount),
296                                                 sqlDbType, length, columnName,
297                                                 DataRowVersion.Original);
298                                 } else {
299                                         whereClause [partCount++] = String.Format ("({0} = ?)",
300                                                 GetQuotedString (columnName));
301                                         AddParameter (command, GetParameterName (++paramCount),
302                                                 sqlDbType, length, columnName,
303                                                 DataRowVersion.Original);
304                                 }
305                         }
306
307                         return String.Join (" AND ", whereClause, 0, partCount);
308                 }
309
310                 private void CreateNewCommand (ref OdbcCommand command)
311                 {
312                         OdbcCommand sourceCommand = SelectCommand;
313                         if (command == null) {
314                                 command = new OdbcCommand ();
315                                 command.Connection = sourceCommand.Connection;
316                                 command.CommandTimeout = sourceCommand.CommandTimeout;
317                                 command.Transaction = sourceCommand.Transaction;
318                         }
319                         command.CommandType = CommandType.Text;
320                         command.UpdatedRowSource = UpdateRowSource.None;
321                         command.Parameters.Clear ();
322                 }
323                 
324                 private OdbcCommand CreateInsertCommand (bool option)
325                 {
326                         CreateNewCommand (ref _insertCommand);
327
328                         string query = String.Format ("INSERT INTO {0}", GetQuotedString (TableName));
329                         string [] columns = new string [Schema.Rows.Count];
330                         string [] values  = new string [Schema.Rows.Count];
331
332                         int count = 0;
333
334                         foreach (DataRow schemaRow in Schema.Rows) {
335                                 // exclude non updatable columns
336                                 if (! IsUpdatable (schemaRow))
337                                         continue;
338
339                                 string columnName = GetColumnName (schemaRow);
340                                 if (columnName == String.Empty)
341                                         throw new InvalidOperationException ("Cannot form insert command. Column name is missing!");
342
343                                 // create column string & value string
344                                 columns [count] = GetQuotedString (columnName);
345                                 values [count++] = "?";
346
347                                 // create parameter and add
348                                 OdbcType sqlDbType = schemaRow.IsNull ("ProviderType") ? OdbcType.VarChar : (OdbcType) schemaRow ["ProviderType"];
349                                 int length = schemaRow.IsNull ("ColumnSize") ? -1 : (int) schemaRow ["ColumnSize"];
350
351                                 AddParameter (_insertCommand, GetParameterName (count),
352                                         sqlDbType, length, columnName, DataRowVersion.Current);
353                         }
354
355                         query = String.Format (
356 #if NET_2_0
357                                 "{0} ({1}) VALUES ({2})", 
358 #else
359                                 "{0}( {1} ) VALUES ( {2} )", 
360 #endif
361                                 query, 
362 #if NET_2_0
363                                 String.Join (", ", columns, 0, count),
364                                 String.Join (", ", values, 0, count));
365 #else
366                                 String.Join (" , ", columns, 0, count),
367                                 String.Join (" , ", values, 0, count));
368 #endif
369                         _insertCommand.CommandText = query;
370                         return _insertCommand;
371                 }
372
373                 public
374 #if NET_2_0
375                 new
376 #endif // NET_2_0
377                 OdbcCommand GetInsertCommand ()
378                 {
379                         // FIXME: check validity of adapter
380                         if (_insertCommand != null)
381                                 return _insertCommand;
382
383                         if (_schema == null)
384                                 RefreshSchema ();
385
386                         return CreateInsertCommand (false);
387                 }
388
389 #if NET_2_0
390                 public new OdbcCommand GetInsertCommand (bool useColumnsForParameterNames)
391                 {
392                         // FIXME: check validity of adapter
393                         if (_insertCommand != null)
394                                 return _insertCommand;
395
396                         if (_schema == null)
397                                 RefreshSchema ();
398
399                         return CreateInsertCommand (useColumnsForParameterNames);
400                 }
401 #endif // NET_2_0
402
403                 private OdbcCommand CreateUpdateCommand (bool option)
404                 {
405                         CreateNewCommand (ref _updateCommand);
406
407                         string query = String.Format ("UPDATE {0} SET", GetQuotedString (TableName));
408                         string [] setClause = new string [Schema.Rows.Count];
409
410                         int count = 0;
411
412                         foreach (DataRow schemaRow in Schema.Rows) {
413                                 // exclude non updatable columns
414                                 if (! IsUpdatable (schemaRow))
415                                         continue;
416
417                                 string columnName = GetColumnName (schemaRow);
418                                 if (columnName == String.Empty)
419                                         throw new InvalidOperationException ("Cannot form update command. Column name is missing!");
420
421                                 OdbcType sqlDbType = schemaRow.IsNull ("ProviderType") ? OdbcType.VarChar : (OdbcType) schemaRow ["ProviderType"];
422                                 int length = schemaRow.IsNull ("ColumnSize") ? -1 : (int) schemaRow ["ColumnSize"];
423
424                                 // create column = value string
425                                 setClause [count++] = String.Format ("{0} = ?", GetQuotedString (columnName));
426                                 AddParameter (_updateCommand, GetParameterName (count),
427                                         sqlDbType, length, columnName, DataRowVersion.Current);
428                         }
429
430                         // create where clause. odbc uses positional parameters. so where class
431                         // is created seperate from the above loop.
432                         string whereClause = CreateOptWhereClause (_updateCommand, count);
433                         
434                         query = String.Format (
435 #if NET_2_0
436                                 "{0} {1} WHERE ({2})",
437 #else
438                                 "{0} {1} WHERE ( {2} )",
439 #endif
440                                 query,
441 #if NET_2_0
442                                 String.Join (", ", setClause, 0, count),
443 #else
444                                 String.Join (" , ", setClause, 0, count),
445 #endif
446                                 whereClause);
447                         _updateCommand.CommandText = query;
448                         return _updateCommand;
449                 }
450                 
451                 public
452 #if NET_2_0
453                 new
454 #endif // NET_2_0
455                 OdbcCommand GetUpdateCommand ()
456                 {
457                         // FIXME: check validity of adapter
458                         if (_updateCommand != null)
459                                 return _updateCommand;
460
461                         if (_schema == null)
462                                 RefreshSchema ();
463
464                         return CreateUpdateCommand (false);
465                 }
466
467 #if NET_2_0
468                 public new OdbcCommand GetUpdateCommand (bool useColumnsForParameterNames)
469                 {
470                         // FIXME: check validity of adapter
471                         if (_updateCommand != null)
472                                 return _updateCommand;
473
474                         if (_schema == null)
475                                 RefreshSchema ();
476
477                         return CreateUpdateCommand (useColumnsForParameterNames);
478                 }
479 #endif // NET_2_0
480
481                 private OdbcCommand CreateDeleteCommand (bool option)
482                 {
483                         CreateNewCommand (ref _deleteCommand);
484
485                         string query = String.Format (
486 #if NET_2_0
487                                 "DELETE FROM {0}",
488 #else
489                                 "DELETE FROM  {0}",
490 #endif
491                                 GetQuotedString (TableName));
492                         string whereClause = CreateOptWhereClause (_deleteCommand, 0);
493                         
494                         query = String.Format (
495 #if NET_2_0
496                                 "{0} WHERE ({1})",
497 #else
498                                 "{0} WHERE ( {1} )",
499 #endif
500                                 query,
501                                 whereClause);
502                         _deleteCommand.CommandText = query;
503                         return _deleteCommand;
504                 }
505
506                 public
507 #if NET_2_0
508                 new
509 #endif // NET_2_0
510                 OdbcCommand GetDeleteCommand ()
511                 {
512                         // FIXME: check validity of adapter
513                         if (_deleteCommand != null)
514                                 return _deleteCommand;
515
516                         if (_schema == null)
517                                 RefreshSchema ();
518                         
519                         return CreateDeleteCommand (false);
520                 }
521
522 #if NET_2_0
523                 public new OdbcCommand GetDeleteCommand (bool useColumnsForParameterNames)
524                 {
525                         // FIXME: check validity of adapter
526                         if (_deleteCommand != null)
527                                 return _deleteCommand;
528
529                         if (_schema == null)
530                                 RefreshSchema ();
531
532                         return CreateDeleteCommand (useColumnsForParameterNames);
533                 }
534 #endif // NET_2_0
535
536 #if ONLY_1_1
537                 public
538 #else
539                 new
540 #endif // NET_2_0
541                 void RefreshSchema ()
542                 {
543                         // creates metadata
544                         if (SelectCommand == null)
545                                 throw new InvalidOperationException ("SelectCommand should be valid");
546                         if (SelectCommand.Connection == null)
547                                 throw new InvalidOperationException ("SelectCommand's Connection should be valid");
548                         
549                         CommandBehavior behavior = CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo;
550                         if (SelectCommand.Connection.State != ConnectionState.Open) {
551                                 SelectCommand.Connection.Open ();
552                                 behavior |= CommandBehavior.CloseConnection;
553                         }
554                         
555                         OdbcDataReader reader = SelectCommand.ExecuteReader (behavior);
556                         _schema = reader.GetSchemaTable ();
557                         reader.Close ();
558                         
559                         // force creation of commands
560                         _insertCommand  = null;
561                         _updateCommand  = null;
562                         _deleteCommand  = null;
563                         _tableName      = String.Empty;
564                 }
565
566 #if NET_2_0
567                 protected override
568 #endif
569                 string GetParameterName (int parameterOrdinal)
570                 {
571 #if NET_2_0
572                         return String.Format ("p{0}", parameterOrdinal);
573 #else
574                         return String.Format ("@p{0}", parameterOrdinal);
575 #endif
576                 }
577
578
579 #if NET_2_0
580                 protected override void ApplyParameterInfo (DbParameter parameter,
581                                                             DataRow datarow,
582                                                             StatementType statementType,
583                                                             bool whereClause)
584                 {
585                         OdbcParameter odbcParam = (OdbcParameter) parameter;
586                         odbcParam.Size = int.Parse (datarow ["ColumnSize"].ToString ());
587                         if (datarow ["NumericPrecision"] != DBNull.Value)
588                                 odbcParam.Precision = byte.Parse (datarow ["NumericPrecision"].ToString ());
589                         if (datarow ["NumericScale"] != DBNull.Value)
590                                 odbcParam.Scale = byte.Parse (datarow ["NumericScale"].ToString ());
591                         odbcParam.DbType = (DbType) datarow ["ProviderType"];
592                 }
593
594                 protected override string GetParameterName (string parameterName)
595                 {
596                         return String.Format("@{0}", parameterName);
597                 }
598
599                 protected override string GetParameterPlaceholder (int parameterOrdinal)
600                 {
601                         return GetParameterName (parameterOrdinal);
602                 }
603
604                 // FIXME: According to MSDN - "if this method is called again with
605                 // the same DbDataAdapter, the DbCommandBuilder is unregistered for 
606                 // that DbDataAdapter's RowUpdating event" - this behaviour is yet
607                 // to be verified
608                 protected override void SetRowUpdatingHandler (DbDataAdapter adapter)
609                 {
610                         if (!(adapter is OdbcDataAdapter))
611                                 throw new InvalidOperationException ("Adapter needs to be a SqlDataAdapter");
612                         if (rowUpdatingHandler == null)
613                                 rowUpdatingHandler = new OdbcRowUpdatingEventHandler (OnRowUpdating);
614
615                         ((OdbcDataAdapter) adapter).RowUpdating += rowUpdatingHandler;
616                 }
617
618                 public override string QuoteIdentifier (string unquotedIdentifier)
619                 {
620                         return QuoteIdentifier (unquotedIdentifier, null);
621                 }
622
623                 public string QuoteIdentifier (string unquotedIdentifier, OdbcConnection connection)
624                 {
625                         if (unquotedIdentifier == null)
626                                 throw new ArgumentNullException ("unquotedIdentifier");
627
628                         string prefix = QuotePrefix;
629                         string suffix = QuoteSuffix;
630
631                         if (QuotePrefix.Length == 0) {
632                                 if (connection == null)
633                                         throw new InvalidOperationException (
634                                                 "An open connection is required if "
635                                                 + "QuotePrefix is not set.");
636                                 prefix = suffix = GetQuoteCharacter (connection);
637                         }
638
639                         if (prefix.Length > 0 && prefix != " ") {
640                                 string escaped;
641                                 if (suffix.Length > 0)
642                                         escaped = unquotedIdentifier.Replace (
643                                                 suffix, suffix + suffix);
644                                 else
645                                         escaped = unquotedIdentifier;
646                                 return string.Concat (prefix, escaped, suffix);
647                         }
648                         return unquotedIdentifier;
649                 }
650
651                 public string UnquoteIdentifier (string quotedIdentifier, OdbcConnection connection)
652                 {
653                         return UnquoteIdentifier (quotedIdentifier);
654                 }
655
656                 public override string UnquoteIdentifier (string quotedIdentifier)
657                 {
658                         if (quotedIdentifier == null || quotedIdentifier.Length == 0)
659                                 return quotedIdentifier;
660                         
661                         StringBuilder sb = new StringBuilder (quotedIdentifier.Length);
662                         sb.Append (quotedIdentifier);
663                         if (quotedIdentifier.StartsWith (QuotePrefix))
664                                 sb.Remove (0,QuotePrefix.Length);
665                         if (quotedIdentifier.EndsWith (QuoteSuffix))
666                                 sb.Remove (sb.Length - QuoteSuffix.Length, QuoteSuffix.Length );
667                         return sb.ToString ();
668                 }
669 #endif
670
671                 private void OnRowUpdating (object sender, OdbcRowUpdatingEventArgs args)
672                 {
673                         if (args.Command != null)
674                                 return;
675                         try {
676                                 switch (args.StatementType) {
677                                 case StatementType.Insert:
678                                         args.Command = GetInsertCommand ();
679                                         break;
680                                 case StatementType.Update:
681                                         args.Command = GetUpdateCommand ();
682                                         break;
683                                 case StatementType.Delete:
684                                         args.Command = GetDeleteCommand ();
685                                         break;
686                                 }
687                         } catch (Exception e) {
688                                 args.Errors = e;
689                                 args.Status = UpdateStatus.ErrorsOccurred;
690                         }
691                 }
692
693                 string GetQuotedString (string unquotedIdentifier)
694                 {
695                         string prefix = QuotePrefix;
696                         string suffix = QuoteSuffix;
697
698                         if (prefix.Length == 0 && suffix.Length == 0)
699                                 return unquotedIdentifier;
700
701                         return String.Format ("{0}{1}{2}", prefix,
702                                 unquotedIdentifier, suffix);
703                 }
704
705                 bool IsCommandGenerated {
706                         get {
707                                 return (_insertCommand != null || _updateCommand != null || _deleteCommand != null);
708                         }
709                 }
710
711 #if NET_2_0
712                 string GetQuoteCharacter (OdbcConnection conn)
713                 {
714                         return conn.GetInfo (OdbcInfo.IdentifierQuoteChar);
715                 }
716 #endif
717
718                 #endregion // Methods
719         }
720 }