[boehm] Put *_freelists into thread_local_freelists (as in BDWGC v7)
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / SqlDataSourceView.cs
1 //
2 // System.Web.UI.WebControls.SqlDataSourceView
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //      Sanjay Gupta (gsanjay@novell.com)
7 //
8 // (C) 2003 Ben Maurer
9 // (C) Novell, Inc. (http://www.novell.com)
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System.Collections;
34 using System.Collections.Specialized;
35 using System.Text;
36 using System.Data;
37 using System.ComponentModel;
38 using System.Data.Common;
39
40 namespace System.Web.UI.WebControls {
41         public class SqlDataSourceView : DataSourceView, IStateManager {
42
43                 HttpContext context;
44                 DbProviderFactory factory;
45                 DbConnection connection;
46
47                 public SqlDataSourceView (SqlDataSource owner, string name, HttpContext context)
48                         : base (owner, name)
49                 {
50                         this.owner = owner;
51                         this.name = name;
52                         this.context = context;
53                 }
54
55                 void InitConnection ()
56                 {
57                         if (factory == null) factory = owner.GetDbProviderFactoryInternal ();
58                         if (connection == null) {
59                                 connection = factory.CreateConnection ();
60                                 connection.ConnectionString = owner.ConnectionString;
61                         }
62                 }
63
64                 public int Delete (IDictionary keys, IDictionary oldValues)
65                 {
66                         return ExecuteDelete (keys, oldValues);
67                 }
68                 
69                 protected override int ExecuteDelete (IDictionary keys, IDictionary oldValues)
70                 {
71                         if (!CanDelete)
72                                 throw new NotSupportedException("Delete operation is not supported");
73                         if (oldValues == null && ConflictDetection == ConflictOptions.CompareAllValues)
74                                 throw new InvalidOperationException ("oldValues parameters should be specified when ConflictOptions is set to CompareAllValues");
75
76                         InitConnection ();
77
78                         DbCommand command = factory.CreateCommand ();
79                         command.CommandText = DeleteCommand;
80                         command.Connection = connection;
81                         if (DeleteCommandType == SqlDataSourceCommandType.Text)
82                                 command.CommandType = CommandType.Text;
83                         else
84                                 command.CommandType = CommandType.StoredProcedure;
85
86                         IDictionary oldDataValues;
87                         if (ConflictDetection == ConflictOptions.CompareAllValues) {
88                                 oldDataValues = new Hashtable ();
89                                 if (keys != null) {
90                                         foreach (DictionaryEntry de in keys)
91                                                 oldDataValues [de.Key] = de.Value;
92                                 }
93                                 if (oldValues != null) {
94                                         foreach (DictionaryEntry de in oldValues)
95                                                 oldDataValues [de.Key] = de.Value;
96                                 }
97                         }
98                         else
99                                 oldDataValues = keys;
100                         
101                         InitializeParameters (command, DeleteParameters, null, oldDataValues, true);
102
103                         SqlDataSourceCommandEventArgs args = new SqlDataSourceCommandEventArgs (command);
104                         OnDeleting (args);
105                         if (args.Cancel)
106                                 return -1; 
107
108                         bool closed = connection.State == ConnectionState.Closed;
109
110                         if (closed)
111                                 connection.Open();
112                         Exception exception = null; 
113                         int result = -1;;
114                         try {
115                                 result = command.ExecuteNonQuery();
116                         } catch (Exception e) {
117                                 exception = e;
118                         }
119
120                         if (closed)
121                                 connection.Close ();
122
123                         OnDataSourceViewChanged (EventArgs.Empty);
124
125                         SqlDataSourceStatusEventArgs deletedArgs =
126                                 new SqlDataSourceStatusEventArgs (command, result, exception);
127                         OnDeleted (deletedArgs);
128
129                         if (exception != null && !deletedArgs.ExceptionHandled)
130                                 throw exception;
131
132                         return result;
133                 }
134                 
135                 public int Insert (IDictionary values)
136                 {
137                         return ExecuteInsert (values);
138                 }
139
140                 protected override int ExecuteInsert (IDictionary values)
141                 {
142                         if (!CanInsert)
143                                 throw new NotSupportedException ("Insert operation is not supported");
144
145                         InitConnection ();
146
147                         DbCommand command = factory.CreateCommand ();
148                         command.CommandText = InsertCommand;
149                         command.Connection = connection;
150                         if (InsertCommandType == SqlDataSourceCommandType.Text)
151                                 command.CommandType = CommandType.Text;
152                         else
153                                 command.CommandType = CommandType.StoredProcedure;
154
155                         InitializeParameters (command, InsertParameters, values, null, false);
156
157                         SqlDataSourceCommandEventArgs args = new SqlDataSourceCommandEventArgs (command);
158                         OnInserting (args);
159                         if (args.Cancel)
160                                 return -1;
161
162                         bool closed = connection.State == ConnectionState.Closed;
163                         if (closed)
164                                 connection.Open ();
165                         Exception exception = null;
166                         int result = -1;
167                         try {
168                                 result = command.ExecuteNonQuery ();
169                         }
170                         catch (Exception e) {
171                                 exception = e;
172                         }
173
174                         if (closed)
175                                 connection.Close ();
176
177                         OnDataSourceViewChanged (EventArgs.Empty);
178
179                         OnInserted (new SqlDataSourceStatusEventArgs (command, result, exception));
180
181                         if (exception != null)
182                                 throw exception;
183                         return result;
184                 }
185                                 
186                 public IEnumerable Select (DataSourceSelectArguments arguments)
187                 {
188                         return ExecuteSelect (arguments);
189                 }
190
191                 protected internal override IEnumerable ExecuteSelect (DataSourceSelectArguments arguments)
192                 {
193                         if (SortParameterName.Length > 0 && SelectCommandType == SqlDataSourceCommandType.Text)
194                                 throw new NotSupportedException ("The SortParameterName property is only supported with stored procedure commands in SqlDataSource");
195
196                         if (arguments.SortExpression.Length > 0 && owner.DataSourceMode == SqlDataSourceMode.DataReader)
197                                 throw new NotSupportedException ("SqlDataSource cannot sort. Set DataSourceMode to DataSet to enable sorting.");
198
199                         if (arguments.StartRowIndex > 0 || arguments.MaximumRows > 0)
200                                 throw new NotSupportedException ("SqlDataSource does not have paging enabled. Set the DataSourceMode to DataSet to enable paging.");
201
202                         if (FilterExpression.Length > 0 && owner.DataSourceMode == SqlDataSourceMode.DataReader)
203                                 throw new NotSupportedException ("SqlDataSource only supports filtering when the data source's DataSourceMode is set to DataSet.");
204
205                         InitConnection ();
206
207                         DbCommand command = factory.CreateCommand ();
208                         command.CommandText = SelectCommand;
209                         command.Connection = connection;
210                         if (SelectCommandType == SqlDataSourceCommandType.Text)
211                                 command.CommandType = CommandType.Text;
212                         else {
213                                 command.CommandType = CommandType.StoredProcedure;
214                                 if (SortParameterName.Length > 0 && arguments.SortExpression.Length > 0)
215                                         command.Parameters.Add (CreateDbParameter (SortParameterName, arguments.SortExpression));
216                         }
217
218                         if (SelectParameters.Count > 0)
219                                 InitializeParameters (command, SelectParameters, null, null, false);
220
221                         Exception exception = null;
222                         if (owner.DataSourceMode == SqlDataSourceMode.DataSet) {
223                                 DataView dataView = null;
224
225                                 if (owner.EnableCaching)
226                                         dataView = (DataView) owner.Cache.GetCachedObject (SelectCommand, SelectParameters);
227
228                                 if (dataView == null) {
229                                         SqlDataSourceSelectingEventArgs selectingArgs = new SqlDataSourceSelectingEventArgs (command, arguments);
230                                         OnSelecting (selectingArgs);
231                                         if (selectingArgs.Cancel || !PrepareNullParameters (command, CancelSelectOnNullParameter)) {
232                                                 return null;
233                                         }
234                                         try {
235                                                 DbDataAdapter adapter = factory.CreateDataAdapter ();
236                                                 DataSet dataset = new DataSet ();
237
238                                                 adapter.SelectCommand = command;
239                                                 adapter.Fill (dataset, name);
240
241                                                 dataView = dataset.Tables [0].DefaultView;
242                                                 if (dataView == null)
243                                                         throw new InvalidOperationException ();
244                                         }
245                                         catch (Exception e) {
246                                                 exception = e;
247                                         }
248                                         int rowsAffected = (dataView == null) ? 0 : dataView.Count;
249                                         SqlDataSourceStatusEventArgs selectedArgs = new SqlDataSourceStatusEventArgs (command, rowsAffected, exception);
250                                         OnSelected (selectedArgs);
251
252                                         if (exception != null && !selectedArgs.ExceptionHandled)
253                                                 throw exception;
254
255                                         if (owner.EnableCaching)
256                                                 owner.Cache.SetCachedObject (SelectCommand, selectParameters, dataView);
257                                 }
258
259                                 if (SortParameterName.Length == 0 || SelectCommandType == SqlDataSourceCommandType.Text)
260                                         dataView.Sort = arguments.SortExpression;
261
262                                 if (FilterExpression.Length > 0) {
263                                         IOrderedDictionary fparams = FilterParameters.GetValues (context, owner);
264                                         SqlDataSourceFilteringEventArgs fargs = new SqlDataSourceFilteringEventArgs (fparams);
265                                         OnFiltering (fargs);
266                                         if (!fargs.Cancel) {
267                                                 object [] formatValues = new object [fparams.Count];
268                                                 for (int n = 0; n < formatValues.Length; n++) {
269                                                         formatValues [n] = fparams [n];
270                                                         if (formatValues [n] == null) return dataView;
271                                                 }
272                                                 dataView.RowFilter = string.Format (FilterExpression, formatValues);
273                                         }
274                                 }
275
276                                 return dataView;
277                         }
278                         else {
279                                 SqlDataSourceSelectingEventArgs selectingArgs = new SqlDataSourceSelectingEventArgs (command, arguments);
280                                 OnSelecting (selectingArgs);
281                                 if (selectingArgs.Cancel || !PrepareNullParameters (command, CancelSelectOnNullParameter)) {
282                                         return null;
283                                 }
284
285                                 DbDataReader reader = null;
286                                 bool closed = connection.State == ConnectionState.Closed;
287
288                                 if (closed)
289                                         connection.Open ();
290                                 try {
291                                         reader = command.ExecuteReader (closed ? CommandBehavior.CloseConnection : CommandBehavior.Default);
292                                 }
293                                 catch (Exception e) {
294                                         exception = e;
295                                 }
296                                 SqlDataSourceStatusEventArgs selectedArgs =
297                                         new SqlDataSourceStatusEventArgs (command, reader.RecordsAffected, exception);
298                                 OnSelected (selectedArgs);
299                                 if (exception != null && !selectedArgs.ExceptionHandled)
300                                         throw exception;
301
302                                 return reader;
303                         }
304                 }
305
306                 static bool PrepareNullParameters (DbCommand command, bool cancelIfHas)
307                 {
308                         for (int i = 0; i < command.Parameters.Count; i++) {
309                                 DbParameter param = command.Parameters [i];
310                                 if (param.Value == null && ((param.Direction & ParameterDirection.Input) != 0)) {
311                                         if (cancelIfHas)
312                                                 return false;
313                                         else
314                                                 param.Value = DBNull.Value;
315                                 }
316                         }
317                         return true;
318                 }
319
320                 public int Update (IDictionary keys, IDictionary values, IDictionary oldValues)
321                 {
322                         return ExecuteUpdate (keys, values, oldValues);
323                 }
324
325                 protected override int ExecuteUpdate (IDictionary keys, IDictionary values, IDictionary oldValues)
326                 {
327                         if (!CanUpdate)
328                                 throw new NotSupportedException ("Update operation is not supported");
329                         if (oldValues == null && ConflictDetection == ConflictOptions.CompareAllValues)
330                                 throw new InvalidOperationException ("oldValues parameters should be specified when ConflictOptions is set to CompareAllValues");
331
332                         InitConnection ();
333
334                         DbCommand command = factory.CreateCommand ();
335                         command.CommandText = UpdateCommand;
336                         command.Connection = connection;
337                         if (UpdateCommandType == SqlDataSourceCommandType.Text)
338                                 command.CommandType = CommandType.Text;
339                         else
340                                 command.CommandType = CommandType.StoredProcedure;
341
342                         IDictionary oldDataValues;
343                         if (ConflictDetection == ConflictOptions.CompareAllValues) {
344                                 oldDataValues = new OrderedDictionary ();
345                                 if (keys != null) {
346                                         foreach (DictionaryEntry de in keys)
347                                                 oldDataValues [de.Key] = de.Value;
348                                 }
349                                 if (oldValues != null) {
350                                         foreach (DictionaryEntry de in oldValues)
351                                                 oldDataValues [de.Key] = de.Value;
352                                 }
353                         }
354                         else {
355                                 oldDataValues = keys;
356                         }
357
358                         IDictionary dataValues = values;
359
360                         InitializeParameters (command, UpdateParameters, dataValues, oldDataValues, ConflictDetection == ConflictOptions.OverwriteChanges);
361
362                         SqlDataSourceCommandEventArgs args = new SqlDataSourceCommandEventArgs (command);
363                         OnUpdating (args);
364                         if (args.Cancel)
365                                 return -1;
366
367                         bool closed = connection.State == ConnectionState.Closed;
368                         if (closed)
369                                 connection.Open ();
370                         Exception exception = null;
371                         int result = -1;
372                         try {
373                                 result = command.ExecuteNonQuery ();
374                         }
375                         catch (Exception e) {
376                                 exception = e;
377                         }
378
379                         if (closed)
380                                 connection.Close ();
381
382                         OnDataSourceViewChanged (EventArgs.Empty);
383
384                         SqlDataSourceStatusEventArgs updatedArgs =
385                                 new SqlDataSourceStatusEventArgs (command, result, exception);
386                         OnUpdated (updatedArgs);
387
388                         if (exception != null && !updatedArgs.ExceptionHandled)
389                                 throw exception;
390
391                         return result;
392                 }
393
394                 string FormatOldParameter (string name)
395                 {
396                         string f = OldValuesParameterFormatString;
397                         if (f.Length > 0)
398                                 return String.Format (f, name);
399                         else
400                                 return name;
401                 }
402
403                 object FindValueByName (string parameterName, IDictionary values, bool format)
404                 {
405                         if (values == null)
406                                 return null;
407
408                         foreach (DictionaryEntry de in values) {
409                                 string valueName = format == true ? FormatOldParameter (de.Key.ToString ()) : de.Key.ToString ();
410                                 if (String.Compare(parameterName, valueName, StringComparison.InvariantCultureIgnoreCase) == 0)
411                                         return values [de.Key];
412                         }
413                         return null;
414                 }
415
416                 void InitializeParameters (DbCommand command, ParameterCollection parameters, IDictionary values, IDictionary oldValues, bool parametersMayMatchOldValues)
417                 {
418                         IOrderedDictionary parameterValues = parameters.GetValues (context, owner);
419
420                         foreach (string parameterName in parameterValues.Keys) {
421                                 Parameter p = parameters [parameterName];
422                                 object value = FindValueByName (parameterName, values, false);
423                                 string valueName = parameterName;
424                                 if (value == null)
425                                         value = FindValueByName (parameterName, oldValues, true);
426
427                                 if (value == null && parametersMayMatchOldValues) {
428                                         value = FindValueByName (parameterName, oldValues, false);
429                                         valueName = FormatOldParameter (parameterName);
430                                 }
431
432                                 if (value != null) {
433                                         object dbValue = p.ConvertValue (value);
434                                         DbParameter newParameter = CreateDbParameter (valueName, dbValue, p.Direction, p.Size);
435                                         if (!command.Parameters.Contains (newParameter.ParameterName)) {
436                                                 command.Parameters.Add (newParameter);
437                                         }
438                                 }
439                                 else {
440                                         command.Parameters.Add (CreateDbParameter (p.Name, parameterValues [parameterName], p.Direction, p.Size));
441                                 }
442                         }
443
444                         if (values != null) {
445                                 foreach (DictionaryEntry de in values)
446                                         if (!command.Parameters.Contains (ParameterPrefix + (string) de.Key))
447                                                 command.Parameters.Add (CreateDbParameter ((string) de.Key, de.Value));
448                         }
449
450                         if (oldValues != null) {
451                                 foreach (DictionaryEntry de in oldValues)
452                                         if (!command.Parameters.Contains (ParameterPrefix + FormatOldParameter ((string) de.Key)))
453                                                 command.Parameters.Add (CreateDbParameter (FormatOldParameter ((string) de.Key), de.Value));
454                         }
455                 }
456
457                 DbParameter CreateDbParameter (string name, object value)
458                 {
459                         return CreateDbParameter (name, value, ParameterDirection.Input, -1);
460                 }
461                 
462                 DbParameter CreateDbParameter (string name, object value, ParameterDirection dir, int size)
463                 {
464                         DbParameter dbp = factory.CreateParameter ();
465                         dbp.ParameterName = ParameterPrefix + name;
466                         dbp.Value = value;
467                         dbp.Direction = dir;
468                         if (size != -1)
469                                 dbp.Size = size;
470
471                         return dbp;
472                 }
473
474                 void IStateManager.LoadViewState (object savedState)
475                 {
476                         LoadViewState (savedState);
477                 }
478                 
479                 object IStateManager.SaveViewState ()
480                 {
481                         return SaveViewState ();
482                 }
483                 
484                 void IStateManager.TrackViewState ()
485                 {
486                         TrackViewState ();
487                 }
488
489                 NotSupportedException CreateNotSupportedException (string capabilityName)
490                 {
491                         return new NotSupportedException ("Data source does not have the '" + capabilityName + "' capability enabled.");
492                 }
493                 
494                 protected internal override void RaiseUnsupportedCapabilityError (DataSourceCapabilities capability)
495                 {
496                         if ((capability & DataSourceCapabilities.Sort) != 0 && !CanSort)
497                                 throw CreateNotSupportedException ("Sort");
498
499                         if ((capability & DataSourceCapabilities.Page) != 0 && !CanPage)
500                                 throw CreateNotSupportedException ("Page");
501
502                         if ((capability & DataSourceCapabilities.RetrieveTotalRowCount) != 0 && !CanRetrieveTotalRowCount)
503                                 throw CreateNotSupportedException ("RetrieveTotalRowCount");
504                 }
505                 
506                 protected virtual void LoadViewState (object savedState)
507                 {
508                         object [] vs = savedState as object [];
509                         if (vs == null)
510                                 return;
511                         
512                         if (vs [0] != null) ((IStateManager) deleteParameters).LoadViewState (vs [0]);
513                         if (vs [1] != null) ((IStateManager) filterParameters).LoadViewState (vs [1]);
514                         if (vs [2] != null) ((IStateManager) insertParameters).LoadViewState (vs [2]);
515                         if (vs [3] != null) ((IStateManager) selectParameters).LoadViewState (vs [3]);
516                         if (vs [4] != null) ((IStateManager) updateParameters).LoadViewState (vs [4]);
517                 }
518
519                 protected virtual object SaveViewState ()
520                 {
521                         object [] vs = new object [5];
522                         
523                         if (deleteParameters != null) vs [0] = ((IStateManager) deleteParameters).SaveViewState ();
524                         if (filterParameters != null) vs [1] = ((IStateManager) filterParameters).SaveViewState ();
525                         if (insertParameters != null) vs [2] = ((IStateManager) insertParameters).SaveViewState ();
526                         if (selectParameters != null) vs [3] = ((IStateManager) selectParameters).SaveViewState ();
527                         if (updateParameters != null) vs [4] = ((IStateManager) updateParameters).SaveViewState ();
528                                 
529                         foreach (object o in vs)
530                                 if (o != null) return vs;
531                         return null;
532                 }
533                 
534                 protected virtual void TrackViewState ()
535                 {
536                         tracking = true;
537                         
538                         if (filterParameters != null) ((IStateManager) filterParameters).TrackViewState ();
539                         if (selectParameters != null) ((IStateManager) selectParameters).TrackViewState ();
540                 }
541                 
542                 bool IStateManager.IsTrackingViewState {
543                         get { return IsTrackingViewState; }
544                 }
545
546                 // LAME SPEC: MSDN says value should be saved in ViewState but tests show otherwise.
547                 bool cancelSelectOnNullParameter = true;
548                 public bool CancelSelectOnNullParameter {
549                         get { return cancelSelectOnNullParameter; }
550                         set {
551                                 if (CancelSelectOnNullParameter == value)
552                                         return;
553                                 cancelSelectOnNullParameter = value;
554                                 OnDataSourceViewChanged (EventArgs.Empty);
555                         }
556                 }
557
558                 public override bool CanDelete {
559                         get { return DeleteCommand != null && DeleteCommand != ""; }
560                 }
561
562                 public override bool CanInsert {
563                         get { return InsertCommand != null && InsertCommand != ""; }
564                 }
565                 
566                 public override bool CanPage {
567                         /* according to MS, this is false in all cases */
568                         get { return false; }
569                 }
570
571                 public override bool CanRetrieveTotalRowCount {
572                         /* according to MS, this is false in all cases */
573                         get { return false; }
574                 }
575
576                 public override bool CanSort {
577                         get {
578                                 /* we can sort if we're a DataSet, regardless of sort parameter name.
579                                    we can sort if we're a DataReader, if the sort parameter name is not null/"".
580                                 */
581                                 return (owner.DataSourceMode == SqlDataSourceMode.DataSet
582                                         || (SortParameterName != null && SortParameterName != ""));
583                         }
584                 }
585                 
586                 public override bool CanUpdate {
587                         get { return UpdateCommand != null && UpdateCommand != ""; }
588                 }
589
590                 // LAME SPEC: MSDN says value should be saved in ViewState but tests show otherwise.
591                 ConflictOptions conflictDetection = ConflictOptions.OverwriteChanges;
592                 public ConflictOptions ConflictDetection {
593                         get { return conflictDetection; }
594                         set {
595                                 if (ConflictDetection == value)
596                                         return;
597                                 conflictDetection = value;
598                                 OnDataSourceViewChanged (EventArgs.Empty);
599                         }
600                 }
601
602                 // LAME SPEC: MSDN says value should be saved in ViewState but tests show otherwise.
603                 string deleteCommand = String.Empty;
604                 public string DeleteCommand {
605                         get { return deleteCommand; }
606                         set { deleteCommand = value; }
607                 }
608
609                 // LAME SPEC: MSDN says value should be saved in ViewState but tests show otherwise.
610                 SqlDataSourceCommandType deleteCommandType = SqlDataSourceCommandType.Text;
611                 public SqlDataSourceCommandType DeleteCommandType {
612                         get { return deleteCommandType; }
613                         set { deleteCommandType = value; }
614                 }
615
616                 [DefaultValueAttribute (null)]
617                 [PersistenceModeAttribute (PersistenceMode.InnerProperty)]
618                 [EditorAttribute ("System.Web.UI.Design.WebControls.ParameterCollectionEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
619                 public ParameterCollection DeleteParameters {
620                         get { return GetParameterCollection (ref deleteParameters, false, false); }
621                 }
622
623                 // LAME SPEC: MSDN says value should be saved in ViewState but tests show otherwise.
624                 string filterExpression;
625                 public string FilterExpression {
626                         get { return filterExpression ?? string.Empty; }
627                         set {
628                                 if (FilterExpression == value)
629                                         return;
630                                 filterExpression = value;
631                                 OnDataSourceViewChanged (EventArgs.Empty);
632                         }
633                 }
634
635                 [EditorAttribute ("System.Web.UI.Design.WebControls.ParameterCollectionEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
636                 [PersistenceModeAttribute (PersistenceMode.InnerProperty)]
637                 [DefaultValueAttribute (null)]
638                 public ParameterCollection FilterParameters {
639                         get { return GetParameterCollection (ref filterParameters, true, true); }
640                 }
641
642                 // LAME SPEC: MSDN says value should be saved in ViewState but tests show otherwise.
643                 string insertCommand = String.Empty;
644                 public string InsertCommand {
645                         get { return insertCommand; }
646                         set { insertCommand = value; }
647                 }
648
649                 // LAME SPEC: MSDN says value should be saved in ViewState but tests show otherwise.
650                 SqlDataSourceCommandType insertCommandType = SqlDataSourceCommandType.Text;
651                 public SqlDataSourceCommandType InsertCommandType {
652                         get { return insertCommandType; }
653                         set { insertCommandType = value; }
654                 }
655
656                 [EditorAttribute ("System.Web.UI.Design.WebControls.ParameterCollectionEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
657                 [PersistenceModeAttribute (PersistenceMode.InnerProperty)]
658                 [DefaultValueAttribute (null)]
659                 public ParameterCollection InsertParameters {
660                         get { return GetParameterCollection (ref insertParameters, false, false); }
661                 }
662
663                 protected bool IsTrackingViewState {
664                         get { return tracking; }
665                 }
666
667                 // LAME SPEC: MSDN says value should be saved in ViewState but tests show otherwise.
668                 string oldValuesParameterFormatString = "{0}";
669                 [DefaultValue ("{0}")]
670                 public string OldValuesParameterFormatString {
671                         get { return oldValuesParameterFormatString; }
672                         set {
673                                 if (OldValuesParameterFormatString == value)
674                                         return;
675                                 oldValuesParameterFormatString = value;
676                                 OnDataSourceViewChanged (EventArgs.Empty);
677                         }
678                 }
679
680                 // LAME SPEC: MSDN says value should be saved in ViewState but tests show otherwise.
681                 string selectCommand;
682                 public string SelectCommand {
683                         get { return selectCommand != null ? selectCommand : string.Empty; }
684                         set {
685                                 if (SelectCommand == value)
686                                         return;
687                                 selectCommand = value;
688                                 OnDataSourceViewChanged (EventArgs.Empty);
689                         }
690                 }
691
692                 // LAME SPEC: MSDN says value should be saved in ViewState but tests show otherwise.
693                 SqlDataSourceCommandType selectCommandType = SqlDataSourceCommandType.Text;
694                 public SqlDataSourceCommandType SelectCommandType {
695                         get { return selectCommandType; }
696                         set { selectCommandType = value; }
697                 }
698                 
699                 public ParameterCollection SelectParameters {
700                         get { return GetParameterCollection (ref selectParameters, true, true); }
701                 }
702
703                 // LAME SPEC: MSDN says value should be saved in ViewState but tests show otherwise.
704                 string sortParameterName = String.Empty;
705                 public string SortParameterName {
706                         get { return sortParameterName; }
707                         set {
708                                 if (SortParameterName == value)
709                                         return;
710                                 sortParameterName = value;
711                                 OnDataSourceViewChanged (EventArgs.Empty);
712                         }
713                 }
714
715                 // LAME SPEC: MSDN says value should be saved in ViewState but tests show otherwise.
716                 string updateCommand = String.Empty;
717                 public string UpdateCommand {
718                         get { return updateCommand; }
719                         set { updateCommand = value; }
720                 }
721
722                 // LAME SPEC: MSDN says value should be saved in ViewState but tests show otherwise.
723                 SqlDataSourceCommandType updateCommandType = SqlDataSourceCommandType.Text;
724                 public SqlDataSourceCommandType UpdateCommandType {
725                         get { return updateCommandType; }
726                         set { updateCommandType = value; }
727                 }
728
729                 [EditorAttribute ("System.Web.UI.Design.WebControls.ParameterCollectionEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
730                 [PersistenceModeAttribute (PersistenceMode.InnerProperty)]
731                 [DefaultValueAttribute (null)]
732                 public ParameterCollection UpdateParameters {
733                         get { return GetParameterCollection (ref updateParameters, false, false); }
734                 }
735                 
736                 void ParametersChanged (object source, EventArgs args)
737                 {
738                         OnDataSourceViewChanged (EventArgs.Empty);
739                 }
740                 
741                 ParameterCollection GetParameterCollection (ref ParameterCollection output, bool propagateTrackViewState, bool subscribeChanged)
742                 {
743                         if (output != null)
744                                 return output;
745                         
746                         output = new ParameterCollection ();
747                         if(subscribeChanged)
748                                 output.ParametersChanged += new EventHandler (ParametersChanged);
749                         
750                         if (IsTrackingViewState && propagateTrackViewState)
751                                 ((IStateManager) output).TrackViewState ();
752                         
753                         return output;
754                 }
755                 
756                 protected virtual string ParameterPrefix {
757                         get {
758                                 switch (owner.ProviderName) {
759                                         case "":
760                                         case "System.Data.SqlClient": return "@";
761                                         case "System.Data.OracleClient": return ":";
762                                 }
763                                 return "";
764                         }
765                 }
766
767                 ParameterCollection deleteParameters;
768                 ParameterCollection filterParameters;
769                 ParameterCollection insertParameters;
770                 ParameterCollection selectParameters;
771                 ParameterCollection updateParameters;
772
773                 bool tracking;
774         
775                 string name;
776                 SqlDataSource owner;
777
778                 #region OnDelete
779                 static readonly object EventDeleted = new object ();
780                 protected virtual void OnDeleted (SqlDataSourceStatusEventArgs e)
781                 {
782                         if (!HasEvents ()) return;
783                         SqlDataSourceStatusEventHandler h = Events [EventDeleted] as SqlDataSourceStatusEventHandler;
784                         if (h != null)
785                                 h (this, e);
786                 }
787                 
788                 public event SqlDataSourceStatusEventHandler Deleted {
789                         add { Events.AddHandler (EventDeleted, value); }
790                         remove { Events.RemoveHandler (EventDeleted, value); }
791                 }
792                 
793                 static readonly object EventDeleting = new object ();
794                 protected virtual void OnDeleting (SqlDataSourceCommandEventArgs e)
795                 {
796                         if (!HasEvents ()) return;
797                         SqlDataSourceCommandEventHandler h = Events [EventDeleting] as SqlDataSourceCommandEventHandler;
798                         if (h != null)
799                                 h (this, e);
800                 }
801                 public event SqlDataSourceCommandEventHandler Deleting {
802                         add { Events.AddHandler (EventDeleting, value); }
803                         remove { Events.RemoveHandler (EventDeleting, value); }
804                 }
805                 #endregion
806
807                 #region OnFiltering
808                 static readonly object EventFiltering = new object ();
809                 protected virtual void OnFiltering (SqlDataSourceFilteringEventArgs e)
810                 {
811                         if (!HasEvents ()) return;
812                         SqlDataSourceFilteringEventHandler h = Events [EventFiltering] as SqlDataSourceFilteringEventHandler;
813                         if (h != null)
814                                 h (this, e);
815                 }
816                 public event SqlDataSourceFilteringEventHandler Filtering {
817                         add { Events.AddHandler (EventFiltering, value); }
818                         remove { Events.RemoveHandler (EventFiltering, value); }
819                 }
820                 #endregion
821                 
822                 #region OnInsert
823                 static readonly object EventInserted = new object ();
824                 protected virtual void OnInserted (SqlDataSourceStatusEventArgs e)
825                 {
826                         if (!HasEvents ()) return;
827                         SqlDataSourceStatusEventHandler h = Events [EventInserted] as SqlDataSourceStatusEventHandler;
828                         if (h != null)
829                                 h (this, e);
830                 }
831                 
832                 public event SqlDataSourceStatusEventHandler Inserted {
833                         add { Events.AddHandler (EventInserted, value); }
834                         remove { Events.RemoveHandler (EventInserted, value); }
835                 }
836                 
837                 static readonly object EventInserting = new object ();
838                 protected virtual void OnInserting (SqlDataSourceCommandEventArgs e)
839                 {
840                         if (!HasEvents ()) return;
841                         SqlDataSourceCommandEventHandler h = Events [EventInserting] as SqlDataSourceCommandEventHandler;
842                         if (h != null)
843                                 h (this, e);
844                 }
845                 public event SqlDataSourceCommandEventHandler Inserting {
846                         add { Events.AddHandler (EventInserting, value); }
847                         remove { Events.RemoveHandler (EventInserting, value); }
848                 }
849                 #endregion
850                 
851                 #region OnSelect
852                 static readonly object EventSelected = new object ();
853                 protected virtual void OnSelected (SqlDataSourceStatusEventArgs e)
854                 {
855                         if (!HasEvents ()) return;
856                         SqlDataSourceStatusEventHandler h = Events [EventSelected] as SqlDataSourceStatusEventHandler;
857                         if (h != null)
858                                 h (this, e);
859                 }
860                 
861                 public event SqlDataSourceStatusEventHandler Selected {
862                         add { Events.AddHandler (EventSelected, value); }
863                         remove { Events.RemoveHandler (EventSelected, value); }
864                 }
865                 
866                 static readonly object EventSelecting = new object ();
867                 protected virtual void OnSelecting (SqlDataSourceSelectingEventArgs e)
868                 {
869                         if (!HasEvents ()) return;
870                         SqlDataSourceSelectingEventHandler h = Events [EventSelecting] as SqlDataSourceSelectingEventHandler;
871                         if (h != null)
872                                 h (this, e);
873                 }
874                 public event SqlDataSourceSelectingEventHandler Selecting {
875                         add { Events.AddHandler (EventSelecting, value); }
876                         remove { Events.RemoveHandler (EventSelecting, value); }
877                 }
878                 #endregion
879                 
880                 #region OnUpdate
881                 static readonly object EventUpdated = new object ();
882                 protected virtual void OnUpdated (SqlDataSourceStatusEventArgs e)
883                 {
884                         if (owner.EnableCaching)
885                                 owner.Cache.Expire ();
886
887                         if (!HasEvents ()) return;
888                         SqlDataSourceStatusEventHandler h = Events [EventUpdated] as SqlDataSourceStatusEventHandler;
889                         if (h != null)
890                                 h (this, e);
891                 }
892                 
893                 public event SqlDataSourceStatusEventHandler Updated {
894                         add { Events.AddHandler (EventUpdated, value); }
895                         remove { Events.RemoveHandler (EventUpdated, value); }
896                 }
897                 
898                 static readonly object EventUpdating = new object ();
899                 protected virtual void OnUpdating (SqlDataSourceCommandEventArgs e)
900                 {
901                         if (!HasEvents ()) return;
902                         SqlDataSourceCommandEventHandler h = Events [EventUpdating] as SqlDataSourceCommandEventHandler;
903                         if (h != null)
904                                 h (this, e);
905                 }
906                 public event SqlDataSourceCommandEventHandler Updating {
907                         add { Events.AddHandler (EventUpdating, value); }
908                         remove { Events.RemoveHandler (EventUpdating, value); }
909                 }
910                 #endregion
911                                 
912         }
913         
914 }
915
916