Merge remote-tracking branch 'raof/aot-cpu-safety'
[mono.git] / mcs / class / System.Data / System.Data / CustomDataClassGenerator.cs
1 //
2 // Mono.Data.CustomDataClassGenerator
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // (C)2004 Novell Inc.
8 //
9 // API notes are the bottom of the source.
10 //
11 // This class is standalone testable (even under MS.NET) when compiled with
12 // -d:DATACLASS_GENERATOR_STANDALONE .
13 //
14
15 //
16 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
17 //
18 // Permission is hereby granted, free of charge, to any person obtaining
19 // a copy of this software and associated documentation files (the
20 // "Software"), to deal in the Software without restriction, including
21 // without limitation the rights to use, copy, modify, merge, publish,
22 // distribute, sublicense, and/or sell copies of the Software, and to
23 // permit persons to whom the Software is furnished to do so, subject to
24 // the following conditions:
25 // 
26 // The above copyright notice and this permission notice shall be
27 // included in all copies or substantial portions of the Software.
28 // 
29 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 //
37 using System;
38 using System.Xml;
39 using System.Data;
40 using System.Data.Common;
41 using System.Collections;
42 using System.CodeDom;
43 using System.Globalization;
44 using System.Text;
45 using System.CodeDom.Compiler;
46 using System.ComponentModel;
47 using System.Runtime.Serialization;
48 using System.Xml.Schema;
49 using System.Xml.Serialization;
50 using System.Reflection;
51
52 // only for Driver
53 using Microsoft.CSharp;
54 using System.IO;
55
56 namespace System.Data
57 {
58
59 #if DATACLASS_GENERATOR_STANDALONE
60         public class Driver
61         {
62                 public static void Main (string [] args)
63                 {
64                         try {
65                                 if (args.Length < 1) {
66                                         Console.WriteLine ("mono dsgentest.exe filename");
67                                         return;
68                                 }
69
70                                 DataSet ds = new DataSet ();
71                                 ds.ReadXml (args [0]);
72                                 ICodeGenerator gen = new CSharpCodeProvider ().CreateGenerator ();
73
74                                 CodeNamespace cns = new CodeNamespace ("MyNamespace");
75                                 TextWriter tw = new StreamWriter (Path.ChangeExtension (args [0], ".ms.cs"), false, Encoding.Default);
76                                 TypedDataSetGenerator.Generate (ds, cns, gen);
77                                 gen.GenerateCodeFromNamespace (cns, tw, null);
78                                 tw.Close ();
79
80                                 cns = new CodeNamespace ("MyNamespace");
81                                 tw = new StreamWriter (Path.ChangeExtension (args [0], ".mono.cs"), false, Encoding.Default);
82                                 CustomDataClassGenerator.CreateDataSetClasses (ds, cns, gen, null);
83                                 gen.GenerateCodeFromNamespace (cns, tw, null);
84                                 tw.Close ();
85                         } catch (Exception ex) {
86                                 Console.WriteLine (ex);
87                         }
88                 }
89         }
90 #endif
91
92 #if DATACLASS_GENERATOR_STANDALONE
93         public class CustomDataClassGenerator
94 #else
95         internal class CustomDataClassGenerator
96 #endif
97         {
98                 public static void CreateDataSetClasses (DataSet ds,
99                         CodeNamespace cns, ICodeGenerator gen,
100                         ClassGeneratorOptions options)
101                 {
102                         new Generator (ds, cns, gen, options).Run ();
103                 }
104
105 #if NET_2_0
106                 public static void CreateDataSetClasses (DataSet ds,
107                         CodeNamespace cns, CodeDomProvider codeProvider,
108                         ClassGeneratorOptions options)
109                 {
110                         new Generator (ds, cns, codeProvider, options).Run ();
111                 }
112
113                 public static void CreateDataSetClasses (DataSet ds, 
114                                                          CodeCompileUnit cunit, 
115                                                          CodeNamespace cns, 
116                                                          CodeDomProvider codeProvider, 
117                                                          ClassGeneratorOptions options)
118                 {
119                         new Generator (ds, cunit, cns, codeProvider, options).Run ();
120                 }
121 #endif
122                 public static string MakeSafeName (string name, ICodeGenerator codeGen)
123                 {
124                         if (name == null || codeGen == null)
125                                 throw new NullReferenceException ();
126
127                         name = codeGen.CreateValidIdentifier (name);
128
129                         return MakeSafeNameInternal (name);
130                 }
131                 
132 #if NET_2_0
133                 public static string MakeSafeName (string name, CodeDomProvider provider)
134                 {
135                         if (name == null || provider == null)
136                                 throw new NullReferenceException ();
137
138                         name = provider.CreateValidIdentifier (name);
139
140                         return MakeSafeNameInternal (name);
141                 }
142 #endif
143                 
144                 public static string MakeSafeNameInternal (string name)
145                 {
146                         if (name.Length == 0)
147                                 return "_";
148
149                         StringBuilder sb = null;
150                         if (!Char.IsLetter (name, 0) && name [0] != '_') {
151                                 sb = new StringBuilder ();
152                                 sb.Append ('_');
153                         }
154
155                         int start = 0;
156                         for (int i = 0; i < name.Length; i++) {
157                                 if (!Char.IsLetterOrDigit (name, i)) {
158                                         if (sb == null)
159                                                 sb = new StringBuilder ();
160                                         sb.Append (name, start, i - start);
161                                         sb.Append ('_');
162                                         start = i + 1;
163                                 }
164                         }
165
166                         if (sb != null) {
167                                 sb.Append (name, start, name.Length - start);
168                                 return sb.ToString ();
169                         }
170                         else
171                                 return name;
172                 }
173         }
174
175 #if DATACLASS_GENERATOR_STANDALONE
176         public delegate string CodeNamingMethod (string source, ICodeGenerator gen);
177 #else
178         internal delegate string CodeNamingMethod (string source, ICodeGenerator gen);
179 #endif
180
181 #if DATACLASS_GENERATOR_STANDALONE
182         public delegate string CodeDomNamingMethod (string source, CodeDomProvider provider);
183 #else
184         internal delegate string CodeDomNamingMethod (string source, CodeDomProvider provider);
185 #endif  
186         
187 #if DATACLASS_GENERATOR_STANDALONE
188         public class ClassICodeGeneratorOptions : ClassGeneratorOptions
189 #else
190         internal class ClassICodeGeneratorOptions : ClassGeneratorOptions
191 #endif
192         {
193                 ICodeGenerator gen;
194                 
195                 public CodeNamingMethod CreateDataSetName;
196                 public CodeNamingMethod CreateTableTypeName;
197                 public CodeNamingMethod CreateTableMemberName;
198                 public CodeNamingMethod CreateTableColumnName;
199                 public CodeNamingMethod CreateColumnName;
200                 public CodeNamingMethod CreateRowName;
201                 public CodeNamingMethod CreateRelationName;
202                 public CodeNamingMethod CreateTableDelegateName;
203                 public CodeNamingMethod CreateEventArgsName;
204                 public CodeNamingMethod CreateTableAdapterNSName;
205                 public CodeNamingMethod CreateTableAdapterName;
206
207                 public ClassICodeGeneratorOptions (ICodeGenerator codeGen)
208                 {
209                         this.gen = codeGen;
210                 }
211                 
212                 internal override string DataSetName (string source)
213                 {
214                         if (CreateDataSetName != null)
215                                 return CreateDataSetName (source, gen);
216                         else
217                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
218                 }
219
220                 internal override string TableTypeName (string source)
221                 {
222                         if (CreateTableTypeName != null)
223                                 return CreateTableTypeName (source, gen);
224                         else
225                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "DataTable";
226                 }
227
228                 internal override string TableMemberName (string source)
229                 {
230                         if (CreateTableMemberName != null)
231                                 return CreateTableMemberName (source, gen);
232                         else
233                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
234                 }
235
236                 internal override string TableColName (string source)
237                 {
238                         if (CreateTableColumnName != null)
239                                 return CreateTableColumnName (source, gen);
240                         else
241                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
242                 }
243
244                 internal override string TableDelegateName (string source)
245                 {
246                         if (CreateTableDelegateName != null)
247                                 return CreateTableDelegateName (source, gen);
248                         else
249                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "RowChangedEventHandler";
250                 }
251
252                 internal override string EventArgsName (string source)
253                 {
254                         if (CreateEventArgsName != null)
255                                 return CreateEventArgsName (source, gen);
256                         else
257                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "RowChangedEventArgs";
258                 }
259
260                 internal override string ColumnName (string source)
261                 {
262                         if (CreateColumnName != null)
263                                 return CreateColumnName (source, gen);
264                         else
265                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
266                 }
267
268                 internal override string RowName (string source)
269                 {
270                         if (CreateRowName != null)
271                                 return CreateRowName (source, gen);
272                         else
273                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "Row";
274                 }
275
276                 internal override string RelationName (string source)
277                 {
278                         if (CreateRelationName != null)
279                                 return CreateRelationName (source, gen);
280                         else
281                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "Relation";
282                 }
283
284                 internal override string TableAdapterNSName (string source)
285                 {
286                         if (CreateTableAdapterNSName != null)
287                                 return CreateTableAdapterNSName (source, gen);
288                         else
289                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "TableAdapters";
290                 }
291                 
292                 internal override string TableAdapterName (string source)
293                 {
294                         if (CreateTableAdapterName != null)
295                                 return CreateTableAdapterName (source, gen);
296                         else
297                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
298                 }
299         }
300         
301 #if NET_2_0
302 #if DATACLASS_GENERATOR_STANDALONE
303         public class ClassCodeDomProviderOptions : ClassGeneratorOptions
304 #else
305         internal class ClassCodeDomProviderOptions : ClassGeneratorOptions
306 #endif
307         {
308                 CodeDomProvider provider;
309                 
310                 public CodeDomNamingMethod CreateDataSetName;
311                 public CodeDomNamingMethod CreateTableTypeName;
312                 public CodeDomNamingMethod CreateTableMemberName;
313                 public CodeDomNamingMethod CreateTableColumnName;
314                 public CodeDomNamingMethod CreateColumnName;
315                 public CodeDomNamingMethod CreateRowName;
316                 public CodeDomNamingMethod CreateRelationName;
317                 public CodeDomNamingMethod CreateTableDelegateName;
318                 public CodeDomNamingMethod CreateEventArgsName;                 
319                 public CodeDomNamingMethod CreateTableAdapterNSName;
320                 public CodeDomNamingMethod CreateTableAdapterName;
321                 
322                 public ClassCodeDomProviderOptions (CodeDomProvider codeProvider)
323                 {
324                         this.provider = codeProvider;
325                 }
326                 
327                 internal override string DataSetName (string source)
328                 {
329                         if (CreateDataSetName != null)
330                                 return CreateDataSetName (source, provider);
331                         else
332                                 return CustomDataClassGenerator.MakeSafeName (source, provider);
333                 }
334
335                 internal override string TableTypeName (string source)
336                 {
337                         if (CreateTableTypeName != null)
338                                 return CreateTableTypeName (source, provider);
339                         else
340                                 return CustomDataClassGenerator.MakeSafeName (source, provider) + "DataTable";
341                 }
342
343                 internal override string TableMemberName (string source)
344                 {
345                         if (CreateTableMemberName != null)
346                                 return CreateTableMemberName (source, provider);
347                         else
348                                 return CustomDataClassGenerator.MakeSafeName (source, provider);
349                 }
350
351                 internal override string TableColName (string source)
352                 {
353                         if (CreateTableColumnName != null)
354                                 return CreateTableColumnName (source, provider);
355                         else
356                                 return CustomDataClassGenerator.MakeSafeName (source, provider);
357                 }
358
359                 internal override string TableDelegateName (string source)
360                 {
361                         if (CreateTableDelegateName != null)
362                                 return CreateTableDelegateName (source, provider);
363                         else
364                                 return CustomDataClassGenerator.MakeSafeName (source, provider) + "RowChangedEventHandler";
365                 }
366
367                 internal override string EventArgsName (string source)
368                 {
369                         if (CreateEventArgsName != null)
370                                 return CreateEventArgsName (source, provider);
371                         else
372                                 return CustomDataClassGenerator.MakeSafeName (source, provider) + "RowChangedEventArgs";
373                 }
374
375                 internal override string ColumnName (string source)
376                 {
377                         if (CreateColumnName != null)
378                                 return CreateColumnName (source, provider);
379                         else
380                                 return CustomDataClassGenerator.MakeSafeName (source, provider);
381                 }
382
383                 internal override string RowName (string source)
384                 {
385                         if (CreateRowName != null)
386                                 return CreateRowName (source, provider);
387                         else
388                                 return CustomDataClassGenerator.MakeSafeName (source, provider) + "Row";
389                 }
390
391                 internal override string RelationName (string source)
392                 {
393                         if (CreateRelationName != null)
394                                 return CreateRelationName (source, provider);
395                         else
396                                 return CustomDataClassGenerator.MakeSafeName (source, provider) + "Relation";
397                 }
398
399                 internal override string TableAdapterNSName (string source)
400                 {
401                         if (CreateTableAdapterNSName != null)
402                                 return CreateTableAdapterNSName (source, provider);
403                         else
404                                 return CustomDataClassGenerator.MakeSafeName (source, provider) + "TableAdapters";
405                 }
406
407                 internal override string TableAdapterName (string source)
408                 {
409                         if (CreateTableAdapterName != null)
410                                 return CreateTableAdapterName (source, provider);
411                         else
412                                 return CustomDataClassGenerator.MakeSafeName (source, provider);
413                 }               
414         }
415 #endif  // NET_2_0
416         
417 #if DATACLASS_GENERATOR_STANDALONE
418         public abstract class ClassGeneratorOptions
419 #else
420         internal abstract class ClassGeneratorOptions
421 #endif
422         {
423                 public bool MakeClassesInsideDataSet = true; // default = MS compatible
424                 
425                 internal abstract string DataSetName (string source);
426                 internal abstract string TableTypeName (string source);
427                 internal abstract string TableMemberName (string source);
428                 internal abstract string TableColName (string source);
429                 internal abstract string TableDelegateName (string source);
430                 internal abstract string EventArgsName (string source);
431                 internal abstract string ColumnName (string source);
432                 internal abstract string RowName (string source);
433                 internal abstract string RelationName (string source);
434                 internal abstract string TableAdapterNSName (string source);
435                 internal abstract string TableAdapterName (string source);
436         }
437
438         internal class Generator
439         {
440 //              static ClassGeneratorOptions DefaultOptions = new ClassGeneratorOptions ();
441
442                 DataSet ds;
443                 CodeNamespace cns;
444                 ClassGeneratorOptions opts;
445                 CodeCompileUnit cunit;
446
447                 CodeTypeDeclaration dsType;
448
449                 public Generator (DataSet ds, CodeNamespace cns, ICodeGenerator codeGen, ClassGeneratorOptions options)
450                 {
451                         this.ds = ds;
452                         this.cns = cns;
453                         this.opts = options;
454                         this.cunit = null;
455                         if (opts == null)
456                                 opts = new ClassICodeGeneratorOptions (codeGen);
457                 }
458 #if NET_2_0
459                 public Generator (DataSet ds, CodeNamespace cns, CodeDomProvider codeProvider, 
460                                   ClassGeneratorOptions options)
461                 {
462                         this.ds = ds;
463                         this.cns = cns;
464                         this.opts = options;
465                         this.cunit = null;
466                         if (opts == null)
467                                 opts = new ClassCodeDomProviderOptions (codeProvider);                  
468                 }
469
470                 public Generator (DataSet ds, CodeCompileUnit cunit, CodeNamespace cns, 
471                                   CodeDomProvider codeProvider, ClassGeneratorOptions options)
472                 {
473                         this.ds = ds;
474                         this.cns = cns;
475                         this.opts = options;
476                         this.cunit = cunit;
477                         if (opts == null)
478                                 opts = new ClassCodeDomProviderOptions (codeProvider);
479                 }
480 #endif
481                 public void Run ()
482                 {
483                         // using decls
484                         cns.Imports.Add (new CodeNamespaceImport ("System"));
485                         cns.Imports.Add (new CodeNamespaceImport ("System.Collections"));
486                         cns.Imports.Add (new CodeNamespaceImport ("System.ComponentModel"));
487                         cns.Imports.Add (new CodeNamespaceImport ("System.Data"));
488                         cns.Imports.Add (new CodeNamespaceImport ("System.Runtime.Serialization"));
489                         cns.Imports.Add (new CodeNamespaceImport ("System.Xml"));
490
491
492                         CodeTypeDeclaration dsType = GenerateDataSetType ();
493                         cns.Types.Add (dsType);
494
495                         foreach (DataTable dt in ds.Tables) {
496                                 // 1. table types ([foo]DataTable)
497                                 // 2. row types ([foo]Row)
498                                 // 3. delegates ([foo]RowChangedEventHandler)
499                                 // 4. eventargs ([foo]RowChangeEventArgs)
500
501                                 CodeTypeDeclaration dtType = GenerateDataTableType (dt);
502
503                                 CodeTypeDeclaration dtRow = GenerateDataRowType (dt);
504
505                                 CodeTypeDelegate dtDelegate = new CodeTypeDelegate (opts.TableDelegateName (dt.TableName));
506                                 dtDelegate.Parameters.Add (Param (typeof (object), "o"));
507                                 dtDelegate.Parameters.Add (Param (opts.EventArgsName (dt.TableName), "e"));
508
509                                 CodeTypeDeclaration dtEventType = GenerateEventType (dt);
510
511                                 // Add types to either DataSet or CodeNamespace
512                                 if (opts.MakeClassesInsideDataSet) {
513                                         dsType.Members.Add (dtType);
514                                         dsType.Members.Add (dtRow);
515                                         dsType.Members.Add (dtDelegate);
516                                         dsType.Members.Add (dtEventType);
517                                 }
518                                 else {
519                                         cns.Types.Add (dtType);
520                                         cns.Types.Add (dtRow);
521                                         cns.Types.Add (dtDelegate);
522                                         cns.Types.Add (dtEventType);
523                                 }
524                         }
525
526 #if NET_2_0
527                         if (cunit == null)
528                                 return;
529                         
530                         TableAdapterSchemaInfo adapterInfo = ds.TableAdapterSchemaData;
531                         if (adapterInfo != null) {
532                                 // #325464 debugging
533                                 //Console.WriteLine (opts.TableAdapterNSName(opts.DataSetName (ds.DataSetName)));
534                                 CodeNamespace cnsTA = new CodeNamespace (opts.TableAdapterNSName(opts.DataSetName (ds.DataSetName)));
535                                 CodeTypeDeclaration dtAdapter = GenerateTableAdapterType (adapterInfo);
536                                 cnsTA.Types.Add (dtAdapter);
537                                 cunit.Namespaces.Add (cnsTA);
538                         }
539 #endif
540                 }
541                 
542                 private CodeThisReferenceExpression This ()
543                 {
544                         return new CodeThisReferenceExpression ();
545                 }
546
547                 private CodeBaseReferenceExpression Base ()
548                 {
549                         return new CodeBaseReferenceExpression ();
550                 }
551
552                 private CodePrimitiveExpression Const (object value)
553                 {
554                         return new CodePrimitiveExpression (value);
555                 }
556
557                 private CodeTypeReference TypeRef (Type t)
558                 {
559                         return new CodeTypeReference (t);
560                 }
561
562                 private CodeTypeReference TypeRef (string name)
563                 {
564                         return new CodeTypeReference (name);
565                 }
566
567                 private CodeTypeReference TypeRefArray (Type t, int dimension)
568                 {
569                         return new CodeTypeReference (TypeRef (t), dimension);
570                 }
571
572                 private CodeTypeReference TypeRefArray (string name, int dimension)
573                 {
574                         return new CodeTypeReference (TypeRef (name), dimension);
575                 }
576                 
577                 private CodeParameterDeclarationExpression Param (string t, string name)
578                 {
579                         return new CodeParameterDeclarationExpression (t, name);
580                 }
581
582                 private CodeParameterDeclarationExpression Param (Type t, string name)
583                 {
584                         return new CodeParameterDeclarationExpression (t, name);
585                 }
586
587                 private CodeParameterDeclarationExpression Param (CodeTypeReference t, string name)
588                 {
589                         return new CodeParameterDeclarationExpression (t, name);
590                 }
591
592                 private CodeArgumentReferenceExpression ParamRef (string name)
593                 {
594                         return new CodeArgumentReferenceExpression (name);
595                 }
596
597                 private CodeCastExpression Cast (string t, CodeExpression exp)
598                 {
599                         return new CodeCastExpression (t, exp);
600                 }
601
602                 private CodeCastExpression Cast (Type t, CodeExpression exp)
603                 {
604                         return new CodeCastExpression (t, exp);
605                 }
606
607                 private CodeCastExpression Cast (CodeTypeReference t, CodeExpression exp)
608                 {
609                         return new CodeCastExpression (t, exp);
610                 }
611
612                 private CodeExpression New (Type t, params CodeExpression [] parameters)
613                 {
614                         return new CodeObjectCreateExpression (t, parameters);
615                 }
616
617                 private CodeExpression New (string t, params CodeExpression [] parameters)
618                 {
619                         return new CodeObjectCreateExpression (TypeRef (t), parameters);
620                 }
621
622                 private CodeExpression NewArray (Type t, params CodeExpression [] parameters)
623                 {
624                         return new CodeArrayCreateExpression (t, parameters);
625                 }
626
627                 private CodeExpression NewArray (Type t, int size )
628                 {
629                         return new CodeArrayCreateExpression (t, size);
630                 }
631
632                 private CodeVariableReferenceExpression Local (string name)
633                 {
634                         return new CodeVariableReferenceExpression (name);
635                 }
636
637                 private CodeFieldReferenceExpression FieldRef (string name)
638                 {
639                         return new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), name);
640                 }
641
642                 private CodeFieldReferenceExpression FieldRef (CodeExpression exp, string name)
643                 {
644                         return new CodeFieldReferenceExpression (exp, name);
645                 }
646
647                 private CodePropertyReferenceExpression PropRef (string name)
648                 {
649                         return new CodePropertyReferenceExpression (new CodeThisReferenceExpression (), name);
650                 }
651
652                 private CodePropertyReferenceExpression PropRef (CodeExpression target, string name)
653                 {
654                         return new CodePropertyReferenceExpression (target, name);
655                 }
656
657                 private CodeIndexerExpression IndexerRef (CodeExpression target, CodeExpression parameters)
658                 {
659                         return new CodeIndexerExpression (target, parameters);
660                 }
661
662                 private CodeIndexerExpression IndexerRef (CodeExpression param)
663                 {
664                         return new CodeIndexerExpression (new CodeThisReferenceExpression (), param);
665                 }
666
667                 private CodeEventReferenceExpression EventRef (string name)
668                 {
669                         return new CodeEventReferenceExpression (new CodeThisReferenceExpression (), name);
670                 }
671
672                 private CodeEventReferenceExpression EventRef (CodeExpression target, string name)
673                 {
674                         return new CodeEventReferenceExpression (target, name);
675                 }
676
677                 private CodeMethodInvokeExpression MethodInvoke (string name, params CodeExpression [] parameters)
678                 {
679                         return new CodeMethodInvokeExpression (new CodeThisReferenceExpression (), name, parameters);
680                 }
681
682                 private CodeMethodInvokeExpression MethodInvoke (CodeExpression target, string name, params CodeExpression [] parameters)
683                 {
684                         return new CodeMethodInvokeExpression (target, name, parameters);
685                 }
686
687                 private CodeBinaryOperatorExpression EqualsValue (CodeExpression exp1, CodeExpression exp2)
688                 {
689                         return new CodeBinaryOperatorExpression (exp1, CodeBinaryOperatorType.ValueEquality, exp2);
690                 }
691
692                 // note that this is "Identity" equality comparison
693                 private CodeBinaryOperatorExpression Equals (CodeExpression exp1, CodeExpression exp2)
694                 {
695                         return new CodeBinaryOperatorExpression (exp1, CodeBinaryOperatorType.IdentityEquality, exp2);
696                 }
697
698                 private CodeBinaryOperatorExpression Inequals (CodeExpression exp1, CodeExpression exp2)
699                 {
700                         return new CodeBinaryOperatorExpression (exp1, CodeBinaryOperatorType.IdentityInequality, exp2);
701                 }
702
703                 private CodeBinaryOperatorExpression GreaterThan (CodeExpression exp1, CodeExpression exp2)
704                 {
705                         return new CodeBinaryOperatorExpression (exp1, CodeBinaryOperatorType.GreaterThan, exp2);
706                 }
707
708                 private CodeBinaryOperatorExpression LessThan (CodeExpression exp1, CodeExpression exp2)
709                 {
710                         return new CodeBinaryOperatorExpression (exp1, CodeBinaryOperatorType.LessThan, exp2);
711                 }
712
713                 private CodeBinaryOperatorExpression Compute (CodeExpression exp1, CodeExpression exp2, CodeBinaryOperatorType ops)
714                 {
715                         if (ops >= CodeBinaryOperatorType.Add && ops < CodeBinaryOperatorType.Assign)
716                                 return new CodeBinaryOperatorExpression (exp1, ops, exp2);
717                         else
718                                 return null;
719                 }
720
721                 private CodeBinaryOperatorExpression BitOps (CodeExpression exp1, CodeExpression exp2, CodeBinaryOperatorType ops)
722                 {
723                         if (ops >= CodeBinaryOperatorType.BitwiseOr && ops <= CodeBinaryOperatorType.BitwiseAnd)
724                                 return new CodeBinaryOperatorExpression (exp1, ops, exp2);
725                         else
726                                 return null;
727                 }
728                 
729                 private CodeBinaryOperatorExpression BooleanOps (CodeExpression exp1, CodeExpression exp2, CodeBinaryOperatorType ops)
730                 {
731                         if (ops >= CodeBinaryOperatorType.BooleanOr && ops <= CodeBinaryOperatorType.BooleanAnd)
732                                 return new CodeBinaryOperatorExpression (exp1, ops, exp2);
733                         else
734                                 return null;
735                 }
736
737                 private CodeTypeReferenceExpression TypeRefExp (Type t)
738                 {
739                         return new CodeTypeReferenceExpression (t);
740                 }
741
742                 private CodeTypeOfExpression TypeOfRef (string name)
743                 {
744                         return new CodeTypeOfExpression (TypeRef (name));
745                 }
746
747                 private CodeExpressionStatement Eval (CodeExpression exp)
748                 {
749                         return new CodeExpressionStatement (exp);
750                 }
751
752                 private CodeAssignStatement Let (CodeExpression exp, CodeExpression value)
753                 {
754                         return new CodeAssignStatement (exp, value);
755                 }
756
757                 private CodeMethodReturnStatement Return (CodeExpression exp)
758                 {
759                         return new CodeMethodReturnStatement (exp);
760                 }
761
762                 private CodeVariableDeclarationStatement VarDecl (Type t,
763                         string name, CodeExpression init)
764                 {
765                         return new CodeVariableDeclarationStatement (t, name, init);
766                 }
767
768                 private CodeVariableDeclarationStatement VarDecl (string t,
769                         string name, CodeExpression init)
770                 {
771                         return new CodeVariableDeclarationStatement (t, name, init);
772                 }
773
774                 private CodeCommentStatement Comment (string comment)
775                 {
776                         return new CodeCommentStatement (comment);
777                 }
778
779                 private CodeThrowExceptionStatement Throw (CodeExpression exp)
780                 {
781                         return new CodeThrowExceptionStatement (exp);
782                 }
783
784 #region DataSet class
785
786                 private CodeTypeDeclaration GenerateDataSetType ()
787                 {
788                         // Type
789                         dsType = new CodeTypeDeclaration (opts.DataSetName (ds.DataSetName));
790                         dsType.BaseTypes.Add (TypeRef (typeof (DataSet)));
791                         dsType.BaseTypes.Add (TypeRef (typeof (IXmlSerializable)));
792
793                         // .ctor()
794                         dsType.Members.Add (CreateDataSetDefaultCtor ());
795                         // runtime serialization .ctor()
796                         dsType.Members.Add (CreateDataSetSerializationCtor ());
797
798                         // Clone()
799                         dsType.Members.Add (CreateDataSetCloneMethod (dsType));
800
801 // FIXME: I keep these methods out of the generated source right now.
802 // It should be added after runtime serialization was implemented.
803 /*
804                         // ShouldSerializeTables()
805                         dsType.Members.Add (CreateDataSetShouldSerializeTables ());
806
807                         // ShouldSerializeRelations()
808                         dsType.Members.Add (CreateDataSetShouldSerializeRelations ());
809
810                         // ReadXmlSerializable()
811                         dsType.Members.Add (CreateDataSetReadXmlSerializable ());
812 */
813
814                         // GetSchemaSerializable()
815                         dsType.Members.Add (CreateDataSetGetSchemaSerializable ());
816
817                         dsType.Members.Add (CreateDataSetGetSchema ());
818                         dsType.Members.Add (CreateDataSetInitializeClass ());
819                         dsType.Members.Add (CreateDataSetInitializeFields ());
820                         dsType.Members.Add (CreateDataSetSchemaChanged ());
821
822                         // table class and members
823                         foreach (DataTable table in ds.Tables)
824                                 CreateDataSetTableMembers (dsType, table);
825                         // relation class and members
826                         foreach (DataRelation rel in ds.Relations)
827                                 CreateDataSetRelationMembers (dsType, rel);
828
829                         return dsType;
830                 }
831
832                 // Code:
833                 // public Foo ()
834                 // {
835                 //   InitializeClass();
836                 //   CollectionChangeEventHandler handler = new CollectionChangeEventHandler (SchemaChanged);
837                 //   Tables.CollectionChanged += handler;
838                 //   Relations.CollectionChanged += handler;
839                 // }
840                 private CodeConstructor CreateDataSetDefaultCtor ()
841                 {
842                         CodeConstructor ctor = new CodeConstructor ();
843                         ctor.Attributes = MemberAttributes.Public;
844                         // Code: InitializeClass().
845                         ctor.Statements.Add (Eval (MethodInvoke ("InitializeClass")));
846
847                         // Code: CollectionChangedEventHandler handler = new CollectionChangeEventHandler (SchemeChanged);
848                         CodeVariableDeclarationStatement stmt2 = 
849                                 VarDecl (
850                                         typeof (CollectionChangeEventHandler), 
851                                         "handler", 
852                                         New (
853                                                 typeof (CollectionChangeEventHandler), 
854                                                 new CodeDelegateCreateExpression (
855                                                         new CodeTypeReference (typeof (CollectionChangeEventHandler)),
856                                                         new CodeThisReferenceExpression (), 
857                                                         "SchemaChanged")));
858
859                         ctor.Statements.Add (stmt2);
860
861                         // Code: Tables.CollectionChanged += handler;
862                         ctor.Statements.Add (
863                                 new CodeAttachEventStatement (
864                                         EventRef (
865                                                 PropRef ("Tables"), 
866                                                 "CollectionChanged"),
867                                         Local ("handler")));
868
869                         // Code: Relations.CollectionChanged += handler;
870                         ctor.Statements.Add (
871                                 new CodeAttachEventStatement (
872                                         EventRef (
873                                                 PropRef ("Relations"), 
874                                                 "CollectionChanged"), 
875                                         Local ("handler")));
876
877                         return ctor;
878                 }
879
880                 // TODO: implement
881
882                 // Code:
883                 // protected Foo (SerializationInfo info, StreamingContext ctx)
884                 // {
885                 //   throw new NotImplementedException ();
886                 // }
887                 private CodeConstructor CreateDataSetSerializationCtor ()
888                 {
889                         CodeConstructor ctor = new CodeConstructor ();
890                         ctor.Attributes = MemberAttributes.Family;
891                         ctor.Parameters.Add (Param (typeof (SerializationInfo), "info"));
892                         ctor.Parameters.Add (Param (typeof (StreamingContext), "ctx"));
893
894                         // Code: 
895                         //  // TODO: implement
896                         //  throw new NotImplementedException ();
897                         ctor.Statements.Add (Comment ("TODO: implement"));
898                         ctor.Statements.Add (Throw (New (typeof (NotImplementedException))));
899
900                         return ctor;
901                 }
902
903                 // Code:
904                 //  public override DataSet Clone()
905                 //  {
906                 //    [foo] set = ([foo]) base.Clone ();
907                 //    set.InitializeFields ();
908                 //    return set;
909                 //  }
910                 private CodeMemberMethod CreateDataSetCloneMethod (CodeTypeDeclaration dsType)
911                 {
912                         CodeMemberMethod m = new CodeMemberMethod ();
913                         m.ReturnType = TypeRef (typeof (DataSet));
914                         m.Attributes = MemberAttributes.Public | MemberAttributes.Override;
915                         m.Name = "Clone";
916                         // Code: [foo] set = ([foo]) base.Clone ();
917                         CodeVariableReferenceExpression set = Local ("set");
918                         m.Statements.Add (VarDecl (
919                                         dsType.Name,
920                                         "set", 
921                                         Cast (
922                                                 dsType.Name,
923                                                 MethodInvoke (Base (), "Clone"))));
924                         m.Statements.Add (Eval (MethodInvoke (set, "InitializeFields")));
925                         m.Statements.Add (Return (set));
926                         return m;
927                 }
928
929                 // Code:
930                 // protected override bool ShouldSerializeTables ()
931                 // {
932                 //   return true; // it should be false
933                 // }
934                 /*
935                 private CodeMemberMethod CreateDataSetShouldSerializeTables ()
936                 {
937                         CodeMemberMethod m = new CodeMemberMethod ();
938                         m.Name = "ShouldSerializeTables";
939                         m.ReturnType = TypeRef (typeof (bool));
940                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
941                         // FIXME: set "false" after serialization .ctor() implementation
942                         m.Statements.Add (Return (Const (true)));
943                         return m;
944                 }
945                 */
946                 // Code:
947                 // protected override bool ShouldSerializeRelations ()
948                 // {
949                 //   return true; // it should be false
950                 // }
951                 
952                 /*
953                 private CodeMemberMethod CreateDataSetShouldSerializeRelations ()
954                 {
955                         CodeMemberMethod m = new CodeMemberMethod ();
956                         m.Name = "ShouldSerializeRelations";
957                         m.ReturnType = TypeRef (typeof (bool));
958                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
959                         // FIXME: set "false" after serialization .ctor() implementation
960                         m.Statements.Add (Return (Const (true)));
961                         return m;
962                 }
963                 */
964
965                 // Code:
966                 // protected override void ReadXmlSerializable()
967                 // {
968                 //   // TODO: implement
969                 //   throw new NotImplementedException ();
970                 // }
971                 /*
972                 private CodeMemberMethod CreateDataSetReadXmlSerializable ()
973                 {
974                         CodeMemberMethod method = new CodeMemberMethod ();
975                         method.Name = "ReadXmlSerializable";
976                         method.Attributes = MemberAttributes.Family | MemberAttributes.Override;
977                         method.Parameters.Add (Param (TypeRef (typeof (XmlReader)), "reader"));
978                         // TODO: implemnet
979                         method.Statements.Add (Comment ("TODO: implement"));
980                         // Hey, how can I specify the constructor to invoke chained ctor with an empty parameter list!?
981                         method.Statements.Add (Throw (New (typeof (NotImplementedException))));
982                         return method;
983                 }
984                 */
985
986                 private CodeMemberMethod CreateDataSetGetSchema ()
987                 {
988                         CodeMemberMethod m = new CodeMemberMethod ();
989                         m.PrivateImplementationType = TypeRef (typeof (IXmlSerializable));
990                         m.Name = "GetSchema";
991                         m.ReturnType = TypeRef (typeof (XmlSchema));
992                         m.Statements.Add (Return (MethodInvoke ("GetSchemaSerializable")));
993
994                         return m;
995                 }
996
997                 private CodeMemberMethod CreateDataSetGetSchemaSerializable ()
998                 {
999                         CodeMemberMethod m = new CodeMemberMethod ();
1000                         m.Attributes = MemberAttributes.Family | 
1001                                 MemberAttributes.Override;
1002                         m.Name = "GetSchemaSerializable";
1003                         m.ReturnType = TypeRef (typeof (XmlSchema));
1004
1005                         m.Statements.Add (VarDecl (typeof (StringWriter), "sw",
1006                                 New (typeof (StringWriter))));
1007                         m.Statements.Add (Eval (MethodInvoke ("WriteXmlSchema", Local ("sw"))));
1008                         m.Statements.Add (Return (MethodInvoke (
1009                                 TypeRefExp (typeof (XmlSchema)),
1010                                 "Read",
1011                                 New (typeof (XmlTextReader),
1012                                         New (typeof (StringReader),
1013                                                 MethodInvoke (Local ("sw"),
1014                                                         "ToString"))),
1015                                 Const (null))));
1016
1017                         return m;
1018                 }
1019
1020                 private CodeMemberMethod CreateDataSetInitializeClass ()
1021                 {
1022                         CodeMemberMethod m = new CodeMemberMethod ();
1023                         m.Name = "InitializeClass";
1024                         m.Attributes = MemberAttributes.Assembly;
1025
1026                         // dataset properties
1027                         m.Statements.Add (Let (PropRef ("DataSetName"), Const (ds.DataSetName)));
1028                         m.Statements.Add (Let (PropRef ("Prefix"), Const (ds.Prefix)));
1029                         m.Statements.Add (Let (PropRef ("Namespace"), Const (ds.Namespace)));
1030                         m.Statements.Add (Let (PropRef ("Locale"), New (typeof (CultureInfo), Const (ds.Locale.Name))));
1031                         m.Statements.Add (Let (PropRef ("CaseSensitive"), Const (ds.CaseSensitive)));
1032                         m.Statements.Add (Let (PropRef ("EnforceConstraints"), Const (ds.EnforceConstraints)));
1033
1034                         // table
1035                         foreach (DataTable dt in ds.Tables) {
1036                                 string tableFieldName = "__table" + opts.TableMemberName (dt.TableName);
1037                                 string tableTypeName = opts.TableTypeName (dt.TableName);
1038                                 m.Statements.Add (Let (FieldRef (tableFieldName), New (tableTypeName)));
1039                                 m.Statements.Add (Eval (MethodInvoke (PropRef ("Tables"), "Add", FieldRef (tableFieldName))));
1040                         }
1041
1042                         bool fkcExists = false;
1043                         bool ucExists = false;
1044                         // First the UniqueConstraints
1045                         foreach (DataTable dt in ds.Tables) {
1046                                 string tname = "__table" + opts.TableMemberName (dt.TableName);
1047                                 foreach (Constraint c in dt.Constraints) {
1048                                         UniqueConstraint uc = c as UniqueConstraint;
1049                                         if (uc != null) {
1050                                                 if (!ucExists) {
1051                                                         m.Statements.Add (VarDecl (typeof (UniqueConstraint), "uc", null));
1052                                                         ucExists = true;
1053                                                 }
1054                                                 CreateUniqueKeyStatements (m, uc, tname);
1055                                         }
1056                                 }
1057                         }
1058                         // Then the ForeignKeyConstraints
1059                         foreach (DataTable dt in ds.Tables) {
1060                                 string tname = "__table" + opts.TableMemberName (dt.TableName);
1061                                 foreach (Constraint c in dt.Constraints) {
1062                                         ForeignKeyConstraint fkc = c as ForeignKeyConstraint;
1063                                         if (fkc != null) {
1064                                                 if (!fkcExists) {
1065                                                         m.Statements.Add (VarDecl (typeof (ForeignKeyConstraint), "fkc", null));
1066                                                         fkcExists = true;
1067                                                 }
1068                                                 string rtname = "__table" + opts.TableMemberName (fkc.RelatedTable.TableName);
1069                                                 CreateForeignKeyStatements (m, fkc, tname, rtname);
1070                                         }
1071                                 }
1072                         }
1073                         // What if other cases? dunno. Just ignore ;-)
1074                         foreach (DataRelation rel in ds.Relations) {
1075                                 string relName = opts.RelationName (rel.RelationName);
1076                                 ArrayList pcols = new ArrayList ();
1077                                 foreach (DataColumn pcol in rel.ParentColumns)
1078                                         pcols.Add (IndexerRef (PropRef (FieldRef ("__table" + opts.TableMemberName (rel.ParentTable.TableName)), "Columns"), Const (pcol.ColumnName)));
1079
1080                                 ArrayList ccols = new ArrayList ();
1081                                 foreach (DataColumn ccol in rel.ChildColumns)
1082                                         ccols.Add (IndexerRef (PropRef (FieldRef ("__table" + opts.TableMemberName (rel.ChildTable.TableName)), "Columns"), Const (ccol.ColumnName)));
1083
1084                                 // relation field
1085                                 string fieldName = "__relation" + relName;
1086                                 m.Statements.Add (Let (FieldRef (fieldName), New (typeof (DataRelation),
1087                                         Const (rel.RelationName),
1088                                         NewArray (typeof (DataColumn), pcols.ToArray (typeof (CodeExpression)) as CodeExpression []),
1089                                         NewArray (typeof (DataColumn), ccols.ToArray (typeof (CodeExpression)) as CodeExpression []),
1090                                         Const (false)
1091                                         )));
1092                                 m.Statements.Add (Let (PropRef (FieldRef (fieldName), "Nested"), Const (rel.Nested)));
1093                                 m.Statements.Add (MethodInvoke (PropRef ("Relations"), "Add", FieldRef (fieldName)));
1094                         }
1095
1096                         return m;
1097                 }
1098
1099                 private void CreateUniqueKeyStatements (CodeMemberMethod m, UniqueConstraint uc, string tableField)
1100                 {
1101                         ArrayList al = new ArrayList ();
1102                         foreach (DataColumn col in uc.Columns)
1103                                 al.Add (IndexerRef (PropRef (FieldRef (tableField), "Columns"), Const (col.ColumnName)));
1104
1105                         m.Statements.Add (Let (Local ("uc"), New (
1106                                 typeof (UniqueConstraint),
1107                                 Const (uc.ConstraintName),
1108                                 NewArray (
1109                                         typeof (DataColumn),
1110                                         al.ToArray (typeof (CodeExpression)) as CodeExpression []),
1111                                 Const (uc.IsPrimaryKey))));
1112                         m.Statements.Add (MethodInvoke (PropRef (FieldRef (tableField), "Constraints"), "Add", Local ("uc")));
1113                 }
1114
1115                 private void CreateForeignKeyStatements (CodeMemberMethod m,ForeignKeyConstraint fkc, string tableField, string rtableField)
1116                 {
1117                         ArrayList pcols = new ArrayList ();
1118                         foreach (DataColumn col in fkc.RelatedColumns)
1119                                 pcols.Add (IndexerRef (PropRef (FieldRef (rtableField), "Columns"), Const (col.ColumnName)));
1120
1121                         ArrayList ccols = new ArrayList ();
1122                         foreach (DataColumn col in fkc.Columns)
1123                                 ccols.Add (IndexerRef (PropRef (FieldRef (tableField), "Columns"), Const (col.ColumnName)));
1124
1125                         m.Statements.Add (Let (Local ("fkc"), New (
1126                                 typeof (ForeignKeyConstraint),
1127                                 Const (fkc.ConstraintName),
1128                                 NewArray (
1129                                         typeof (DataColumn),
1130                                         pcols.ToArray (typeof (CodeExpression)) as CodeExpression []),
1131                                 NewArray (
1132                                         typeof (DataColumn),
1133                                         ccols.ToArray (typeof (CodeExpression)) as CodeExpression []))));
1134
1135                         m.Statements.Add (Let (
1136                                 PropRef (Local ("fkc"), "AcceptRejectRule"),
1137                                 FieldRef (TypeRefExp (typeof (AcceptRejectRule)), Enum.GetName (typeof (AcceptRejectRule), fkc.AcceptRejectRule))));
1138                         m.Statements.Add (Let (
1139                                 PropRef (Local ("fkc"), "DeleteRule"),
1140                                 FieldRef (TypeRefExp (typeof (Rule)), Enum.GetName (typeof (Rule), fkc.DeleteRule))));
1141                         m.Statements.Add (Let (
1142                                 PropRef (Local ("fkc"), "UpdateRule"),
1143                                 FieldRef (TypeRefExp (typeof (Rule)), Enum.GetName (typeof (Rule), fkc.UpdateRule))));
1144
1145                         m.Statements.Add (MethodInvoke (PropRef (FieldRef (tableField), "Constraints"), "Add", Local ("fkc")));
1146                 }
1147
1148                 private CodeMemberMethod CreateDataSetInitializeFields ()
1149                 {
1150                         CodeMemberMethod m = new CodeMemberMethod ();
1151                         m.Attributes = MemberAttributes.Assembly;
1152                         m.Name = "InitializeFields";
1153
1154                         foreach (DataTable dt in ds.Tables)
1155                                 m.Statements.Add (Eval (MethodInvoke (FieldRef ("__table" + opts.TableMemberName (dt.TableName)), "InitializeFields")));
1156
1157                         foreach (DataRelation rel in ds.Relations)
1158                                 m.Statements.Add (Let (FieldRef ("__relation" + opts.RelationName (rel.RelationName)), IndexerRef (PropRef ("Relations"), Const (rel.RelationName))));
1159
1160                         return m;
1161                 }
1162
1163                 private CodeMemberMethod CreateDataSetSchemaChanged ()
1164                 {
1165                         CodeMemberMethod m = new CodeMemberMethod ();
1166                         m.Name = "SchemaChanged";
1167                         m.Parameters.Add (Param (typeof (object), "sender"));
1168                         m.Parameters.Add (Param (typeof (CollectionChangeEventArgs), "e"));
1169
1170                         m.Statements.Add (
1171                                 new CodeConditionStatement (
1172                                         EqualsValue (
1173                                                 PropRef (ParamRef ("e"), "Action"),
1174                                                 FieldRef (TypeRefExp (typeof (CollectionChangeAction)), "Remove")),
1175                                         new CodeStatement [] { Eval (MethodInvoke ("InitializeFields")) },
1176                                         new CodeStatement [] {}));
1177                         return m;
1178                 }
1179
1180                 private void CreateDataSetTableMembers (CodeTypeDeclaration dsType, DataTable table)
1181                 {
1182                         string tableTypeName = opts.TableTypeName (table.TableName);
1183                         string tableVarName = opts.TableMemberName (table.TableName);
1184
1185                         CodeMemberField privTable = new CodeMemberField ();
1186                         privTable.Type = TypeRef (tableTypeName);
1187                         privTable.Name = "__table" + tableVarName;
1188                         dsType.Members.Add (privTable);
1189
1190                         CodeMemberProperty pubTable = new CodeMemberProperty ();
1191                         pubTable.Type = TypeRef (tableTypeName);
1192                         pubTable.Attributes = MemberAttributes.Public;
1193                         pubTable.Name = tableVarName == table.TableName ? "_"+tableVarName : tableVarName;
1194                         pubTable.HasSet = false;
1195                         // Code: return __table[foo];
1196                         pubTable.GetStatements.Add (Return (FieldRef ("__table" + tableVarName)));
1197
1198                         dsType.Members.Add (pubTable);
1199
1200                 }
1201
1202                 private void CreateDataSetRelationMembers (CodeTypeDeclaration dsType, DataRelation relation)
1203                 {
1204                         string relName = opts.RelationName (relation.RelationName);
1205                         string fieldName = "__relation" + relName;
1206
1207                         CodeMemberField field = new CodeMemberField ();
1208                         field.Type = TypeRef (typeof (DataRelation));
1209                         field.Name = fieldName;
1210                         dsType.Members.Add (field);
1211
1212                         // This is not supported in MS.NET
1213                         CodeMemberProperty prop = new CodeMemberProperty ();
1214                         prop.Type = TypeRef (typeof (DataRelation));
1215                         prop.Attributes = MemberAttributes.Public;
1216                         prop.Name = relName;
1217                         prop.HasSet = false;
1218                         // Code: return __relation[foo_bar];
1219                         prop.GetStatements.Add (Return (FieldRef (fieldName)));
1220                         dsType.Members.Add (prop);
1221                 }
1222
1223 #endregion
1224
1225
1226
1227 #region DataTable class
1228
1229                 private CodeTypeDeclaration GenerateDataTableType (DataTable dt)
1230                 {
1231                         CodeTypeDeclaration t = new CodeTypeDeclaration ();
1232                         t.Name = opts.TableTypeName (dt.TableName);
1233                         t.BaseTypes.Add (TypeRef (typeof (DataTable)));
1234                         t.BaseTypes.Add (TypeRef (typeof (IEnumerable)));
1235
1236                         t.Members.Add (CreateTableCtor1 (dt));
1237                         t.Members.Add (CreateTableCtor2 (dt));
1238
1239                         t.Members.Add (CreateTableCount (dt));
1240                         t.Members.Add (CreateTableIndexer (dt));
1241
1242                         t.Members.Add (CreateTableInitializeClass (dt));
1243                         t.Members.Add (CreateTableInitializeFields (dt));
1244
1245                         t.Members.Add (CreateTableGetEnumerator (dt));
1246                         t.Members.Add (CreateTableClone (dt));
1247                         t.Members.Add (CreateTableCreateInstance (dt));
1248
1249                         t.Members.Add (CreateTableAddRow1 (dt));
1250                         t.Members.Add (CreateTableAddRow2 (dt));
1251                         t.Members.Add (CreateTableNewRow (dt));
1252                         t.Members.Add (CreateTableNewRowFromBuilder (dt));
1253                         t.Members.Add (CreateTableRemoveRow (dt));
1254                         t.Members.Add (CreateTableGetRowType (dt));
1255
1256                         t.Members.Add (CreateTableEventStarter (dt, "Changing"));
1257                         t.Members.Add (CreateTableEventStarter (dt, "Changed"));
1258                         t.Members.Add (CreateTableEventStarter (dt, "Deleting"));
1259                         t.Members.Add (CreateTableEventStarter (dt, "Deleted"));
1260
1261                         // events
1262                         t.Members.Add (CreateTableEvent (dt, "RowChanging"));
1263                         t.Members.Add (CreateTableEvent (dt, "RowChanged"));
1264                         t.Members.Add (CreateTableEvent (dt, "RowDeleting"));
1265                         t.Members.Add (CreateTableEvent (dt, "RowDeleted"));
1266
1267                         // column members
1268                         foreach (DataColumn col in dt.Columns) {
1269                                 t.Members.Add (CreateTableColumnField (dt, col));
1270                                 t.Members.Add (CreateTableColumnProperty (dt, col));
1271                         }
1272
1273                         return t;
1274                 }
1275
1276                 // Code:
1277                 //  internal [foo]DataTable () : base ("[foo]")
1278                 //  {
1279                 //    InitializeClass ();
1280                 //  }
1281                 private CodeConstructor CreateTableCtor1 (DataTable dt)
1282                 {
1283                         CodeConstructor c = new CodeConstructor ();
1284                         c.Attributes = MemberAttributes.Assembly;
1285                         c.BaseConstructorArgs.Add (Const (dt.TableName));
1286                         c.Statements.Add (Eval (MethodInvoke ("InitializeClass")));
1287                         c.Statements.Add (Eval (MethodInvoke ("InitializeFields")));
1288                         return c;
1289                 }
1290
1291                 // Code:
1292                 //  internal [foo]DataTable (DataTable table) : base (table.TableName)
1293                 //  {
1294                 //    // TODO: implement
1295                 //    throw new NotImplementedException ();
1296                 //  }
1297                 private CodeConstructor CreateTableCtor2 (DataTable dt)
1298                 {
1299                         CodeConstructor c = new CodeConstructor ();
1300                         c.Attributes = MemberAttributes.Assembly;
1301                         c.Parameters.Add (Param (typeof (DataTable), GetRowTableFieldName (dt)));
1302                         c.BaseConstructorArgs.Add (PropRef (ParamRef (GetRowTableFieldName (dt)), "TableName"));
1303                         // TODO: implement
1304                         c.Statements.Add (Comment ("TODO: implement"));
1305                         c.Statements.Add (Throw (New (typeof (NotImplementedException))));
1306                         return c;
1307                 }
1308
1309                 private CodeMemberMethod CreateTableInitializeClass (DataTable dt)
1310                 {
1311                         CodeMemberMethod m = new CodeMemberMethod ();
1312                         m.Name = "InitializeClass";
1313                         foreach (DataColumn col in dt.Columns) {
1314                                 m.Statements.Add (Eval (MethodInvoke (
1315                                         PropRef ("Columns"),
1316                                         "Add",
1317                                         New (typeof (DataColumn),
1318                                                 Const (col.ColumnName),
1319                                                 new CodeTypeOfExpression (col.DataType)
1320                                                 ))));
1321                         }
1322                         return m;
1323                 }
1324
1325                 private CodeMemberMethod CreateTableInitializeFields (DataTable dt)
1326                 {
1327                         CodeMemberMethod m = new CodeMemberMethod ();
1328                         m.Name = "InitializeFields";
1329                         m.Attributes = MemberAttributes.Assembly;
1330
1331                         string colRef;
1332                         foreach (DataColumn col in dt.Columns) {
1333                                 colRef = String.Format("__column{0}", opts.TableColName (col.ColumnName));
1334
1335                                 m.Statements.Add (Let (FieldRef (colRef), IndexerRef (PropRef ("Columns"), Const (col.ColumnName))));
1336                                 if (!col.AllowDBNull)
1337                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AllowDBNull"), Const (col.AllowDBNull)));
1338                                 if (col.DefaultValue != null && col.DefaultValue.GetType() != typeof(System.DBNull))
1339                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "DefaultValue"), Const (col.DefaultValue)));
1340                                 if (col.AutoIncrement)
1341                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AutoIncrement"), Const (col.AutoIncrement)));
1342                                 if (col.AutoIncrementSeed != 0)
1343                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AutoIncrementSeed"), Const (col.AutoIncrementSeed)));
1344                                 if (col.AutoIncrementStep != 1)
1345                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AutoIncrementStep"), Const (col.AutoIncrementStep)));
1346                                 if (col.ReadOnly)
1347                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "ReadOnly"), Const (col.ReadOnly)));
1348                         }
1349                         return m;
1350                 }
1351
1352                 private CodeMemberMethod CreateTableClone (DataTable dt)
1353                 {
1354                         CodeMemberMethod m = new CodeMemberMethod ();
1355                         m.Name = "Clone";
1356                         m.Attributes = MemberAttributes.Public | MemberAttributes.Override;
1357                         m.ReturnType = TypeRef (typeof (DataTable));
1358                         string typeName = opts.TableTypeName (dt.TableName);
1359                         m.Statements.Add (
1360                                 VarDecl (typeName, "t", Cast (typeName, MethodInvoke (Base (), "Clone"))));
1361                         m.Statements.Add (Eval (MethodInvoke (Local ("t"), "InitializeFields")));
1362                         m.Statements.Add (Return (Local ("t")));
1363                         return m;
1364                 }
1365
1366                 private CodeMemberMethod CreateTableGetEnumerator (DataTable dt)
1367                 {
1368                         CodeMemberMethod m = new CodeMemberMethod ();
1369                         m.Name = "GetEnumerator";
1370                         m.Attributes = MemberAttributes.Public;
1371                         m.ReturnType = TypeRef (typeof (IEnumerator));
1372                         m.Statements.Add (Return (MethodInvoke (PropRef ("Rows"), "GetEnumerator")));
1373                         m.ImplementationTypes.Add (TypeRef (typeof (IEnumerable)));
1374                         return m;
1375                 }
1376
1377                 private CodeMemberMethod CreateTableCreateInstance (DataTable dt)
1378                 {
1379                         CodeMemberMethod m = new CodeMemberMethod ();
1380                         m.Name = "CreateInstance";
1381                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1382                         m.ReturnType = TypeRef (typeof (DataTable));
1383                         m.Statements.Add (Return (New (opts.TableTypeName (dt.TableName))));
1384                         return m;
1385                 }
1386
1387                 private CodeMemberField CreateTableColumnField (DataTable dt, DataColumn col)
1388                 {
1389                         CodeMemberField f = new CodeMemberField ();
1390                         f.Name = "__column" + opts.ColumnName (col.ColumnName);
1391                         f.Type = TypeRef (typeof (DataColumn));
1392                         return f;
1393                 }
1394
1395                 private CodeMemberProperty CreateTableColumnProperty (DataTable dt, DataColumn col)
1396                 {
1397                         string name = opts.ColumnName (col.ColumnName);
1398                         CodeMemberProperty p = new CodeMemberProperty ();
1399                         p.Name = name + "Column";
1400                         p.Attributes = MemberAttributes.Assembly;
1401                         p.Type = TypeRef (typeof (DataColumn));
1402                         p.HasSet = false;
1403                         p.GetStatements.Add (Return (FieldRef ("__column" + name)));
1404                         return p;
1405                 }
1406
1407                 private CodeMemberProperty CreateTableCount (DataTable dt)
1408                 {
1409                         CodeMemberProperty p = new CodeMemberProperty ();
1410                         p.Name = "Count";
1411                         p.Attributes = MemberAttributes.Public;
1412                         p.Type = TypeRef (typeof (int));
1413                         p.HasSet = false;
1414                         p.GetStatements.Add (Return (PropRef (PropRef ("Rows"), "Count")));
1415                         return p;
1416                 }
1417
1418                 private CodeMemberProperty CreateTableIndexer (DataTable dt)
1419                 {
1420                         string rowName = opts.RowName (dt.TableName);
1421                         CodeMemberProperty ix = new CodeMemberProperty ();
1422                         ix.Name = "Item"; // indexer
1423                         ix.Attributes = MemberAttributes.Public;
1424                         ix.Type = TypeRef (rowName);
1425                         ix.Parameters.Add (Param (typeof (int), "i"));
1426                         ix.HasSet = false;
1427                         ix.GetStatements.Add (Return (Cast (rowName, IndexerRef (PropRef ("Rows"), ParamRef ("i")))));
1428                         return ix;
1429                 }
1430
1431                 private CodeMemberMethod CreateTableAddRow1 (DataTable dt)
1432                 {
1433                         CodeMemberMethod m = new CodeMemberMethod ();
1434                         string rowType = opts.RowName (dt.TableName);
1435                         m.Name = "Add" + rowType;
1436                         m.Attributes = MemberAttributes.Public;
1437                         m.Parameters.Add (Param (TypeRef (rowType), "row"));
1438                         m.Statements.Add (Eval (MethodInvoke (PropRef ("Rows"), "Add", ParamRef ("row"))));
1439                         return m;
1440                 }
1441
1442                 private CodeMemberMethod CreateTableAddRow2 (DataTable dt)
1443                 {
1444                         CodeMemberMethod m = new CodeMemberMethod ();
1445                         string rowType = opts.RowName (dt.TableName);
1446                         m.Name = "Add" + rowType;
1447                         m.ReturnType = TypeRef (rowType);
1448                         m.Attributes = MemberAttributes.Public;
1449
1450                         m.Statements.Add (VarDecl (rowType, "row", MethodInvoke ("New" + rowType)));
1451
1452                         foreach (DataColumn col in dt.Columns) {
1453                                 if (col.ColumnMapping == MappingType.Hidden) {
1454                                         foreach (DataRelation r in dt.DataSet.Relations) {
1455                                                 if (r.ChildTable == dt) {
1456                                                         // parameter
1457                                                         string paramType = opts.RowName (r.ParentTable.TableName);
1458                                                         string paramName = paramType;
1459                                                         m.Parameters.Add (Param (paramType, paramName));
1460                                                         // CODE: SetParentRow (fooRow, DataSet.Relations ["foo_bar"]);
1461                                                         m.Statements.Add (Eval (MethodInvoke (Local ("row"), "SetParentRow", ParamRef (paramName), IndexerRef (PropRef (PropRef ("DataSet"), "Relations"), Const (r.RelationName)))));
1462                                                         break;
1463                                                 }
1464                                         }
1465                                 }
1466                                 else {
1467                                         // parameter
1468                                         string paramName = opts.ColumnName (col.ColumnName);
1469                                         m.Parameters.Add (Param (col.DataType, paramName));
1470                                         // row ["foo"] = foo;
1471                                         m.Statements.Add (Let (IndexerRef (Local ("row"), Const (paramName)), ParamRef (paramName)));
1472                                 }
1473                         }
1474
1475                         // Rows.Add (row);
1476                         m.Statements.Add (MethodInvoke (PropRef ("Rows"), "Add", Local ("row")));
1477                         m.Statements.Add (Return (Local ("row")));
1478
1479                         return m;
1480                 }
1481
1482                 private CodeMemberMethod CreateTableNewRow (DataTable dt)
1483                 {
1484                         CodeMemberMethod m = new CodeMemberMethod ();
1485                         string rowType = opts.RowName (dt.TableName);
1486                         m.Name = "New" + rowType;
1487                         m.ReturnType = TypeRef (rowType);
1488                         m.Attributes = MemberAttributes.Public;
1489                         m.Statements.Add (Return (Cast (rowType, MethodInvoke ("NewRow"))));
1490                         return m;
1491                 }
1492
1493                 private CodeMemberMethod CreateTableNewRowFromBuilder (DataTable dt)
1494                 {
1495                         CodeMemberMethod m = new CodeMemberMethod ();
1496                         m.Name = "NewRowFromBuilder";
1497                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1498                         m.ReturnType = TypeRef (typeof (DataRow));
1499                         m.Parameters.Add (Param (typeof (DataRowBuilder), "builder"));
1500                         m.Statements.Add (Return (New (opts.RowName (dt.TableName), ParamRef ("builder"))));
1501                         return m;
1502                 }
1503
1504                 private CodeMemberMethod CreateTableRemoveRow (DataTable dt)
1505                 {
1506                         CodeMemberMethod m = new CodeMemberMethod ();
1507                         string rowType = opts.RowName (dt.TableName);
1508                         m.Name = "Remove" + rowType;
1509                         m.Attributes = MemberAttributes.Public;
1510                         m.Parameters.Add (Param (TypeRef (rowType), "row"));
1511                         m.Statements.Add (Eval (MethodInvoke (PropRef ("Rows"), "Remove", ParamRef ("row"))));
1512                         return m;
1513                 }
1514
1515                 private CodeMemberMethod CreateTableGetRowType (DataTable dt)
1516                 {
1517                         CodeMemberMethod m = new CodeMemberMethod ();
1518                         m.Name = "GetRowType";
1519                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1520                         m.ReturnType = TypeRef (typeof (Type));
1521                         m.Statements.Add (Return (new CodeTypeOfExpression (opts.RowName (dt.TableName))));
1522                         return m;
1523                 }
1524
1525                 private CodeMemberMethod CreateTableEventStarter (DataTable dt, string type)
1526                 {
1527                         CodeMemberMethod m = new CodeMemberMethod ();
1528                         m.Name = "OnRow" + type;
1529                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1530                         m.Parameters.Add (Param (typeof (DataRowChangeEventArgs), "e"));
1531
1532                         m.Statements.Add (Eval (MethodInvoke (
1533                                         Base (),
1534                                         m.Name,
1535                                         ParamRef ("e"))));
1536                         string eventName = opts.TableMemberName (dt.TableName) + "Row" + type;
1537                         CodeStatement trueStmt = Eval (
1538                                 new CodeDelegateInvokeExpression(
1539                                         new CodeEventReferenceExpression (This (), eventName),
1540                                         This (), 
1541                                         New (
1542                                                 opts.EventArgsName (dt.TableName),
1543                                                 Cast (opts.RowName (dt.TableName), PropRef (ParamRef ("e"), "Row")),
1544                                                 PropRef (ParamRef ("e"), "Action"))));
1545
1546                         m.Statements.Add (
1547                                 new CodeConditionStatement (
1548                                         Inequals (EventRef (eventName), Const (null)),
1549                                         new CodeStatement [] {trueStmt},
1550                                         new CodeStatement [] {}));
1551
1552                         return m;
1553                 }
1554
1555                 private CodeMemberEvent CreateTableEvent (DataTable dt, string nameSuffix)
1556                 {
1557                         CodeMemberEvent cme = new CodeMemberEvent ();
1558                         cme.Attributes = MemberAttributes.Public;
1559                         cme.Name = opts.TableMemberName (dt.TableName) + nameSuffix;
1560                         cme.Type = TypeRef (opts.TableDelegateName (dt.TableName));
1561                         return cme;
1562                 }
1563
1564 #endregion
1565
1566
1567
1568 #region Row class
1569
1570                 public CodeTypeDeclaration GenerateDataRowType (DataTable dt)
1571                 {
1572                         CodeTypeDeclaration t = new CodeTypeDeclaration ();
1573                         t.Name = opts.RowName (dt.TableName);
1574                         t.BaseTypes.Add (TypeRef (typeof (DataRow)));
1575
1576                         t.Members.Add (CreateRowCtor (dt));
1577
1578                         t.Members.Add (CreateRowTableField (dt));
1579
1580                         foreach (DataColumn col in dt.Columns) {
1581                                 if (col.ColumnMapping != MappingType.Hidden) {
1582                                         t.Members.Add (CreateRowColumnProperty (dt, col));
1583                                         t.Members.Add (CreateRowColumnIsNull (dt, col));
1584                                         t.Members.Add (CreateRowColumnSetNull (dt, col));
1585                                 }
1586                         }
1587
1588                         foreach (DataRelation rel in dt.ParentRelations)
1589                                 t.Members.Add (CreateRowParentRowProperty (dt, rel));
1590                         foreach (DataRelation rel in dt.ChildRelations)
1591                                 t.Members.Add (CreateRowGetChildRows (dt, rel));
1592
1593                         return t;
1594                 }
1595
1596                 private CodeConstructor CreateRowCtor (DataTable dt)
1597                 {
1598                         CodeConstructor c = new CodeConstructor ();
1599                         c.Attributes = MemberAttributes.Assembly;
1600                         c.Parameters.Add (Param (typeof (DataRowBuilder), "builder"));
1601                         c.BaseConstructorArgs.Add (ParamRef ("builder"));
1602                         c.Statements.Add (Let (FieldRef (GetRowTableFieldName (dt)), Cast (
1603                                 opts.TableTypeName (dt.TableName),
1604                                 PropRef ("Table"))));
1605                         return c;
1606                 }
1607                 
1608                 private string GetRowTableFieldName (DataTable dt)
1609                 {
1610                         return "table" + dt.TableName;
1611                 }
1612                 private CodeMemberField CreateRowTableField (DataTable dt)
1613                 {
1614                         CodeMemberField f = new CodeMemberField ();
1615                         f.Name = GetRowTableFieldName (dt);
1616                         f.Type = TypeRef (opts.TableTypeName (dt.TableName));
1617                         return f;
1618                 }
1619
1620                 private CodeMemberProperty CreateRowColumnProperty (DataTable dt, DataColumn col)
1621                 {
1622                         CodeMemberProperty p = new CodeMemberProperty ();
1623                         p.Name = opts.ColumnName (col.ColumnName);
1624                         p.Type = TypeRef (col.DataType);
1625                         p.Attributes = MemberAttributes.Public;
1626
1627                         // This part should be better than MS code output.
1628                         // Code:
1629                         //  object ret = this [col];
1630                         //  if (ret == DBNull.Value)
1631                         //    throw new StrongTypingException ()
1632                         //  else
1633                         //    return (type) ret;
1634                         p.GetStatements.Add (VarDecl (typeof (object), "ret",
1635                                 IndexerRef (PropRef 
1636                                         (PropRef (GetRowTableFieldName (dt)), 
1637                                         opts.TableColName (col.ColumnName) + "Column"))));
1638                         p.GetStatements.Add (new CodeConditionStatement (
1639                                 Equals (
1640                                         Local ("ret"),
1641                                         PropRef (TypeRefExp (typeof (DBNull)), "Value")),
1642                                 new CodeStatement [] {
1643                                         Throw (New (typeof (StrongTypingException), Const ("Cannot get strong typed value since it is DB null."), Const (null))) },
1644                                 new CodeStatement [] {
1645                                         Return (Cast (col.DataType, Local ("ret"))) }));
1646
1647                         p.SetStatements.Add (Let (IndexerRef (PropRef (PropRef (GetRowTableFieldName (dt)), opts.TableColName (col.ColumnName) + "Column")), new CodePropertySetValueReferenceExpression ()));
1648
1649                         return p;
1650                 }
1651
1652                 private CodeMemberMethod CreateRowColumnIsNull (DataTable dt, DataColumn col)
1653                 {
1654                         CodeMemberMethod m = new CodeMemberMethod ();
1655                         m.Name = "Is" + opts.ColumnName (col.ColumnName) + "Null";
1656                         m.Attributes = MemberAttributes.Public;
1657                         m.ReturnType = TypeRef (typeof (bool));
1658                         m.Statements.Add (Return (MethodInvoke (
1659                                 "IsNull",
1660                                 // table[foo].[bar]Column
1661                                 PropRef (
1662                                         PropRef (GetRowTableFieldName (dt)), 
1663                                         opts.TableColName (col.ColumnName) + "Column"))));
1664                         return m;
1665                 }
1666
1667                 private CodeMemberMethod CreateRowColumnSetNull (DataTable dt, DataColumn col)
1668                 {
1669                         CodeMemberMethod m = new CodeMemberMethod ();
1670                         m.Name = "Set" + opts.ColumnName (col.ColumnName) + "Null";
1671                         m.Attributes = MemberAttributes.Public;
1672                         m.Statements.Add (Let (IndexerRef (
1673                                 PropRef (
1674                                         PropRef (GetRowTableFieldName (dt)), 
1675                                         opts.TableColName (col.ColumnName) + "Column")),
1676                                 PropRef (TypeRefExp (typeof (DBNull)), "Value")));
1677
1678                         return m;
1679                 }
1680
1681                 private CodeMemberProperty CreateRowParentRowProperty (DataTable dt, DataRelation rel)
1682                 {
1683                         CodeMemberProperty p = new CodeMemberProperty ();
1684                         p.Name = opts.TableMemberName (rel.ParentTable.TableName) + "Row" +
1685                                 (rel.ParentTable.TableName == rel.ChildTable.TableName ? "Parent" : String.Empty);
1686                         p.Attributes = MemberAttributes.Public;
1687                         p.Type = TypeRef (opts.RowName (rel.ParentTable.TableName));
1688                         p.GetStatements.Add (Return (Cast (p.Type, MethodInvoke (
1689                                 "GetParentRow",
1690                                 IndexerRef (
1691                                         PropRef (
1692                                                 PropRef (
1693                                                         PropRef ("Table"),
1694                                                         "DataSet"),
1695                                                 "Relations"),
1696                                         Const (rel.RelationName))))));
1697                         p.SetStatements.Add (Eval (MethodInvoke (
1698                                 "SetParentRow",
1699                                 new CodePropertySetValueReferenceExpression (),
1700                                 IndexerRef (
1701                                         PropRef (
1702                                                 PropRef (
1703                                                         PropRef ("Table"),
1704                                                         "DataSet"),
1705                                                 "Relations"),
1706                                         Const (rel.RelationName)))));
1707
1708                         return p;
1709                 }
1710
1711                 private CodeMemberMethod CreateRowGetChildRows (DataTable dt, DataRelation rel)
1712                 {
1713                         CodeMemberMethod m = new CodeMemberMethod ();
1714                         m.Name = "Get" + opts.TableMemberName (rel.ChildTable.TableName) + "Rows";
1715                         m.Attributes = MemberAttributes.Public;
1716                         m.ReturnType = new CodeTypeReference (opts.RowName (rel.ChildTable.TableName), 1);
1717                         m.Statements.Add (Return (Cast (m.ReturnType, MethodInvoke (
1718                                 "GetChildRows",
1719                                 IndexerRef (
1720                                         PropRef (
1721                                                 PropRef (
1722                                                         PropRef ("Table"),
1723                                                         "DataSet"),
1724                                                 "Relations"),
1725                                         Const (rel.RelationName))))));
1726                         return m;
1727                 }
1728
1729 #endregion
1730
1731
1732 #region Event class
1733
1734                 // Code:
1735                 //  public class [foo]ChangeEventArgs : EventArgs
1736                 //  {
1737                 //    private [foo]Row eventRow;
1738                 //    private DataRowAction eventAction;
1739                 //    (.ctor())
1740                 //    (Row)
1741                 //    (Action)
1742                 //  }
1743                 private CodeTypeDeclaration GenerateEventType (DataTable dt)
1744                 {
1745                         CodeTypeDeclaration t = new CodeTypeDeclaration ();
1746                         t.Name = opts.EventArgsName (dt.TableName);
1747                         t.BaseTypes.Add (TypeRef (typeof (EventArgs)));
1748                         t.Attributes = MemberAttributes.Public;
1749
1750                         t.Members.Add (
1751                                 new CodeMemberField (
1752                                         TypeRef (opts.RowName (dt.TableName)),
1753                                         "eventRow"));
1754                         t.Members.Add (
1755                                 new CodeMemberField (
1756                                         TypeRef (typeof (DataRowAction)), "eventAction"));
1757                         t.Members.Add (CreateEventCtor (dt));
1758
1759                         t.Members.Add (CreateEventRow (dt));
1760
1761                         t.Members.Add (CreateEventAction (dt));
1762
1763                         return t;
1764                 }
1765
1766                 // Code:
1767                 //  public [foo]RowChangeEventArgs ([foo]Row r, DataRowAction a)
1768                 //  {
1769                 //    eventRow = r;
1770                 //    eventAction = a;
1771                 //  }
1772                 private CodeConstructor CreateEventCtor (DataTable dt)
1773                 {
1774                         CodeConstructor c = new CodeConstructor ();
1775                         c.Attributes = MemberAttributes.Public;
1776                         c.Parameters.Add (Param (TypeRef (opts.RowName (dt.TableName)), "r"));
1777                         c.Parameters.Add (Param (TypeRef (typeof (DataRowAction)), "a"));
1778                         c.Statements.Add (Let (FieldRef ("eventRow"), ParamRef ("r")));
1779                         c.Statements.Add (Let (FieldRef ("eventAction"), ParamRef ("a")));
1780
1781                         return c;
1782                 }
1783
1784                 // Code:
1785                 //  public [foo]Row Row {
1786                 //   get { return eventRow; }
1787                 // }
1788                 private CodeMemberProperty CreateEventRow (DataTable dt)
1789                 {
1790                         CodeMemberProperty p = new CodeMemberProperty ();
1791                         p.Name = "Row";
1792                         p.Attributes = MemberAttributes.Public | MemberAttributes.Final;
1793                         p.Type = TypeRef (opts.RowName (dt.TableName));
1794                         p.HasSet = false;
1795                         p.GetStatements.Add (Return (FieldRef ("eventRow")));
1796                         return p;
1797                 }
1798
1799                 // Code:
1800                 //  public DataRowAction Action {
1801                 //   get { return eventAction; }
1802                 // }
1803                 private CodeMemberProperty CreateEventAction (DataTable dt)
1804                 {
1805                         CodeMemberProperty p = new CodeMemberProperty ();
1806                         p.Name = "Action";
1807                         p.Attributes = MemberAttributes.Public | MemberAttributes.Final;
1808                         p.Type = TypeRef (typeof (DataRowAction));
1809                         p.HasSet = false;
1810                         p.GetStatements.Add (Return (FieldRef ("eventAction")));
1811                         return p;
1812                 }
1813
1814 #endregion
1815
1816 #if NET_2_0
1817 #region Table Adapter class
1818                 
1819                 private CodeTypeDeclaration GenerateTableAdapterType (TableAdapterSchemaInfo taInfo)
1820                 {
1821                         CodeTypeDeclaration t = new CodeTypeDeclaration ();
1822                         t.Name = opts.TableAdapterName (taInfo.Name);
1823                         t.BaseTypes.Add (TypeRef (taInfo.BaseClass));
1824                 
1825                         t.Members.Add (CreateTableAdapterDefaultCtor ());
1826
1827                         // table adapter fields/properties
1828                         CreateDBAdapterFieldAndProperty (t, taInfo.Adapter);
1829                         CreateDBConnectionFieldAndProperty (t, taInfo.Connection);
1830                         
1831                         DbCommand cmd = null;
1832                         if (taInfo.Commands.Count > 0)
1833                                 cmd = ((DbCommandInfo)taInfo.Commands[0]).Command;
1834                         else
1835                                 cmd = taInfo.Provider.CreateCommand ();
1836                         CreateDBCommandCollectionFieldAndProperty (t, cmd);
1837                         CreateAdapterClearBeforeFillFieldAndProperty (t);
1838
1839                         CreateAdapterInitializeMethod (t, taInfo);
1840                         CreateConnectionInitializeMethod (t, taInfo);
1841                         CreateCommandCollectionInitializeMethod (t, taInfo);
1842
1843                         CreateDbSourceMethods (t, taInfo);
1844                         if (taInfo.ShortCommands)
1845                                 CreateShortCommandMethods (t, taInfo);
1846                         
1847                         return t;
1848                 }
1849                 
1850                 private CodeConstructor CreateTableAdapterDefaultCtor ()
1851                 {
1852                         CodeConstructor ctor = new CodeConstructor ();
1853                         ctor.Attributes = MemberAttributes.Public;
1854                         ctor.Statements.Add (Let (PropRef ("ClearBeforeFill"), Const (true)));
1855                         
1856                         return ctor;
1857                 }       
1858
1859                 private void CreateDBAdapterFieldAndProperty (CodeTypeDeclaration t, DbDataAdapter adapter)
1860                 {
1861                         CodeExpression expr;
1862                         CodeStatement setStmt;
1863                         CodeStatement stmt;
1864                         CodeMemberField f = new CodeMemberField ();
1865                         f.Name = "_adapter";
1866                         f.Type = TypeRef (adapter.GetType ());
1867                         t.Members.Add (f);
1868                         
1869                         CodeMemberProperty p = new CodeMemberProperty ();
1870                         p.Name = "Adapter";
1871                         p.Attributes = MemberAttributes.Private;
1872                         p.Type = f.Type;
1873                         p.HasSet = false;
1874
1875                         expr = FieldRef ("_adapter");
1876                         setStmt = Eval (MethodInvoke ("InitAdapter"));
1877                         stmt = new CodeConditionStatement (Equals (expr, Const (null)),
1878                                                            new CodeStatement [] {setStmt},
1879                                                            new CodeStatement [] {});
1880                         p.GetStatements.Add (stmt);
1881                         p.GetStatements.Add (Return (expr));
1882                         t.Members.Add (p);
1883                 }
1884                 
1885                 private void CreateDBConnectionFieldAndProperty (CodeTypeDeclaration t, DbConnection conn)
1886                 {
1887                         CodeExpression expr;
1888                         CodeStatement setStmt;
1889                         CodeStatement stmt;
1890                         CodeMemberField f = new CodeMemberField ();
1891                         f.Name = "_connection";
1892                         f.Type = TypeRef (conn.GetType ());
1893                         t.Members.Add (f);
1894
1895                         CodeMemberProperty p = new CodeMemberProperty ();
1896                         p.Name = "Connection";
1897                         p.Attributes = MemberAttributes.Assembly;
1898                         p.Type = f.Type;
1899
1900                         expr = FieldRef ("_connection");
1901                         setStmt = Eval (MethodInvoke ("InitConnection"));
1902                         stmt = new CodeConditionStatement (Equals (expr, Const (null)),
1903                                                            new CodeStatement [] {setStmt},
1904                                                            new CodeStatement [] {});
1905                         p.GetStatements.Add (stmt);
1906                         p.GetStatements.Add (Return (expr));
1907                         p.SetStatements.Add (Let (expr, new CodePropertySetValueReferenceExpression()));
1908
1909                         // update connection in Insert/Delete/Update commands of adapter
1910                                                 
1911                         // insert command
1912                         string cmdStr = "InsertCommand";
1913                         string connStr = "Connection";
1914                         setStmt = null;
1915                         stmt = null;
1916                         expr = null;
1917
1918                         expr = PropRef (PropRef ("Adapter"), cmdStr);
1919                         setStmt = Let (PropRef (expr, connStr), new CodePropertySetValueReferenceExpression());
1920                         stmt = new CodeConditionStatement (Inequals (expr, Const (null)),
1921                                                            new CodeStatement [] {setStmt},
1922                                                            new CodeStatement [] {});                    
1923                         p.SetStatements.Add (stmt);
1924
1925                         // delete command
1926                         setStmt = null;
1927                         stmt = null;
1928                         expr = null;
1929                         
1930                         cmdStr = "DeleteCommand";
1931                         expr = PropRef (PropRef ("Adapter"), cmdStr);
1932                         setStmt = Let (PropRef (expr, connStr), new CodePropertySetValueReferenceExpression());
1933                         stmt = new CodeConditionStatement (Inequals (expr, Const (null)),
1934                                                            new CodeStatement [] {setStmt}, new CodeStatement [] {});
1935                         p.SetStatements.Add (stmt);
1936
1937                         // update command
1938                         setStmt = null;
1939                         stmt = null;
1940
1941                         cmdStr = "UpdateCommand";
1942                         expr = PropRef (PropRef ("Adapter"), cmdStr);                   
1943                         setStmt = Let (PropRef (expr, connStr), new CodePropertySetValueReferenceExpression());
1944                         stmt = new CodeConditionStatement (Inequals (expr, Const (null)),
1945                                                            new CodeStatement [] {setStmt}, new CodeStatement [] {});
1946                         p.SetStatements.Add (stmt);
1947
1948                         // iterate through command collection and update it
1949                         setStmt = null;
1950                         expr = null;
1951                         stmt = null;
1952                         setStmt = VarDecl (typeof (int), "i", Const (0));
1953                         expr = LessThan (Local ("i"), PropRef (PropRef ("CommandCollection"), "Length"));
1954                         stmt = Let (Local ("i"), Compute (Local ("i"), Const (1), CodeBinaryOperatorType.Add));
1955                         
1956                         // statements to execute in the loop
1957                         CodeExpression expr1 = IndexerRef (PropRef ("CommandCollection"), Local ("i"));
1958                         CodeStatement setStmt1 = Let (PropRef (expr1, "Connection"), new CodePropertySetValueReferenceExpression());
1959                         CodeStatement stmt1 = new CodeConditionStatement (Inequals (expr1, Const (null)),
1960                                                            new CodeStatement [] {setStmt1}, new CodeStatement [] {});
1961                         CodeIterationStatement forLoop = new CodeIterationStatement (setStmt, expr, stmt,
1962                                                                                      new CodeStatement[] {stmt1});
1963                         p.SetStatements.Add (forLoop);                                          
1964                         t.Members.Add (p);
1965                 }
1966
1967                 private void CreateDBCommandCollectionFieldAndProperty (CodeTypeDeclaration t, DbCommand cmd)
1968                 {
1969                         CodeExpression expr;
1970                         CodeStatement setStmt;
1971                         CodeStatement stmt;
1972                         CodeMemberField f = new CodeMemberField ();
1973                         f.Name = "_commandCollection";
1974                         f.Type = TypeRefArray (cmd.GetType (), 1);
1975                         t.Members.Add (f);
1976                         
1977                         CodeMemberProperty p = new CodeMemberProperty ();
1978                         p.Name = "CommandCollection";
1979                         p.Attributes = MemberAttributes.Family;
1980                         p.Type = f.Type;
1981                         p.HasSet = false;
1982
1983                         expr = FieldRef ("_commandCollection");
1984                         setStmt = Eval (MethodInvoke ("InitCommandCollection"));
1985                         stmt = new CodeConditionStatement (Equals (expr, Const (null)),
1986                                                            new CodeStatement [] {setStmt},
1987                                                            new CodeStatement [] {});
1988                         p.GetStatements.Add (stmt);
1989                         p.GetStatements.Add (Return (expr));
1990                         t.Members.Add (p);
1991                 }
1992
1993                 private void CreateAdapterClearBeforeFillFieldAndProperty (CodeTypeDeclaration t)
1994                 {
1995                         CodeMemberField f = new CodeMemberField ();
1996                         f.Name = "_clearBeforeFill";
1997                         f.Type = TypeRef (typeof (bool));
1998                         t.Members.Add (f);
1999                         
2000                         CodeMemberProperty p = new CodeMemberProperty ();
2001                         p.Name = "ClearBeforeFill";
2002                         p.Attributes = MemberAttributes.Public;
2003                         p.Type = f.Type;
2004                         p.SetStatements.Add (Let (FieldRef ("_clearBeforeFill"), 
2005                                                   new CodePropertySetValueReferenceExpression()));
2006                         p.GetStatements.Add (Return (FieldRef ("_clearBeforeFill")));
2007                         t.Members.Add (p);
2008                 }
2009
2010                 private void CreateAdapterInitializeMethod (CodeTypeDeclaration t, TableAdapterSchemaInfo taInfo)
2011                 {
2012                         CodeMemberMethod m = new CodeMemberMethod ();
2013                         m.Name = "InitAdapter";
2014                         m.Attributes = MemberAttributes.Private;
2015                         
2016                         // code statements
2017                         CodeExpression expr;
2018                         CodeStatement stmt;
2019                         
2020                         // initialize adapter
2021                         expr = FieldRef ("_adapter");
2022                         stmt = Let (expr, New (taInfo.Adapter.GetType ()));
2023                         m.Statements.Add (stmt);
2024                         
2025                         // populate tableMapping
2026                         stmt = VarDecl (typeof (DataTableMapping), "tableMapping", null);
2027                         m.Statements.Add (stmt);
2028                         foreach (DataTableMapping tblMap in taInfo.Adapter.TableMappings) {
2029                                 expr = Local ("tableMapping");
2030                                 stmt = Let (expr, New (tblMap.GetType ()));
2031                                 m.Statements.Add (stmt);
2032                                 
2033                                 stmt = Let (PropRef (expr, "SourceTable"), Const (tblMap.SourceTable));
2034                                 m.Statements.Add (stmt);
2035                                 
2036                                 stmt = Let (PropRef (expr, "DataSetTable"), Const (tblMap.DataSetTable));
2037                                 m.Statements.Add (stmt);
2038                                 
2039                                 foreach (DataColumnMapping colMap in tblMap.ColumnMappings) { 
2040                                         stmt = Eval (MethodInvoke (PropRef (expr, "ColumnMappings"), "Add", 
2041                                                                    new CodeExpression [] {Const (colMap.SourceColumn), Const (colMap.DataSetColumn)}));
2042                                         m.Statements.Add (stmt);
2043                                 }
2044                                 expr = PropRef (FieldRef ("_adapter"), "TableMappings");
2045                                 stmt = Eval (MethodInvoke (expr, "Add", Local ("tableMapping")));
2046                                 m.Statements.Add (stmt);
2047                         }
2048                         // Generate code for adapter's deletecommand
2049                         expr = PropRef (FieldRef ("_adapter"), "DeleteCommand");
2050                         DbCommand cmd = taInfo.Adapter.DeleteCommand;
2051                         AddDbCommandStatements (m, expr, cmd);
2052
2053                         // Generate code for adapter's insertcommand
2054                         expr = PropRef (FieldRef ("_adapter"), "InsertCommand");
2055                         cmd = taInfo.Adapter.InsertCommand;
2056                         AddDbCommandStatements (m, expr, cmd);
2057
2058                         // Generate code for adapter's updatecommand
2059                         expr = PropRef (FieldRef ("_adapter"), "UpdateCommand");
2060                         cmd = taInfo.Adapter.UpdateCommand;
2061                         AddDbCommandStatements (m, expr, cmd);
2062
2063                         t.Members.Add (m);
2064                 }
2065                 
2066                 private void AddDbCommandStatements (CodeMemberMethod m, 
2067                                                      CodeExpression expr, 
2068                                                      DbCommand cmd)
2069                 {
2070                         if (cmd == null)
2071                                 return;
2072                         
2073                         CodeExpression expr1;
2074                         CodeStatement stmt = Let (expr, New (cmd.GetType ()));
2075                         m.Statements.Add (stmt);
2076                         
2077                         stmt = Let (PropRef (expr,"Connection"), PropRef ("Connection"));
2078                         m.Statements.Add (stmt);
2079                         stmt = Let (PropRef (expr, "CommandText"), Const (cmd.CommandText));
2080                         m.Statements.Add (stmt);
2081                         expr1 = PropRef (Local(typeof (CommandType).FullName), cmd.CommandType.ToString ());
2082                         stmt = Let (PropRef (expr, "CommandType"), expr1);
2083                         m.Statements.Add (stmt);
2084                         
2085                         expr1 = PropRef (expr, "Parameters");
2086                         foreach (DbParameter param in cmd.Parameters) {
2087                                 AddDbParameterStatements (m, expr1, param);
2088                         }
2089                 }
2090                 
2091                 private void AddDbParameterStatements (CodeMemberMethod m, 
2092                                                        CodeExpression expr, 
2093                                                        DbParameter param)
2094                 {
2095                         object dbType = param.FrameworkDbType;
2096                         string srcColumn = null;
2097                         
2098                         if (param.SourceColumn != String.Empty)
2099                                 srcColumn = param.SourceColumn;
2100                         
2101                         CodeExpression[] args = new CodeExpression[] {
2102                                 Const (param.ParameterName),
2103                                 PropRef (Local(dbType.GetType().FullName), dbType.ToString ()), 
2104                                 Const (param.Size),
2105                                 PropRef(Local(typeof (ParameterDirection).FullName), param.Direction.ToString ()),
2106                                 Const (param.IsNullable),
2107                                 Const (((IDbDataParameter)param).Precision),
2108                                 Const (((IDbDataParameter)param).Scale),
2109                                 Const (srcColumn),
2110                                 PropRef (Local (typeof (DataRowVersion).FullName), param.SourceVersion.ToString ()),
2111                                 /* Const (param.SourceColumnNullMapping), */ // TODO: Investigate with other providers
2112                                 Const (param.Value)
2113                         };
2114                         m.Statements.Add (Eval (MethodInvoke (expr, "Add", New (param.GetType (), args))));
2115                 }
2116                 private void CreateConnectionInitializeMethod (CodeTypeDeclaration t, 
2117                                                                TableAdapterSchemaInfo taInfo)
2118                 {
2119                         CodeMemberMethod m = new CodeMemberMethod ();
2120                         m.Name = "InitConnection";
2121                         m.Attributes = MemberAttributes.Private;
2122                         
2123                         // code statements
2124                         CodeExpression expr, expr1;
2125                         CodeStatement stmt;
2126                         
2127                         // initialize connection
2128                         expr = FieldRef ("_connection");
2129                         stmt = Let (expr, New (taInfo.Connection.GetType ()));
2130                         m.Statements.Add (stmt);
2131                         
2132                         // assign connection string
2133                         expr = PropRef (FieldRef ("_connection"), "ConnectionString");
2134                         expr1 = IndexerRef (PropRef (Local (typeof (System.Configuration.ConfigurationManager).ToString()), "ConnectionStrings"), 
2135                                             Const (taInfo.ConnectionString));
2136                         stmt = Let (expr, PropRef (expr1, "ConnectionString"));
2137                         m.Statements.Add (stmt);
2138                         
2139                         t.Members.Add (m);
2140                 }
2141                 
2142                 private void CreateCommandCollectionInitializeMethod (CodeTypeDeclaration t, 
2143                                                                       TableAdapterSchemaInfo taInfo)
2144                 {
2145                         //string tmp = null;
2146                         Type type;
2147                         CodeMemberMethod m = new CodeMemberMethod ();
2148                         m.Name = "InitCommandCollection";
2149                         m.Attributes = MemberAttributes.Private;
2150                         
2151                         // code statements
2152                         CodeExpression expr, expr1;
2153                         CodeStatement stmt;
2154                         
2155                         type = ((DbCommandInfo)taInfo.Commands[0]).Command.GetType();
2156                         
2157                         // initialize connection
2158                         expr = FieldRef ("_commandCollection");
2159                         stmt = Let (expr, NewArray (type, taInfo.Commands.Count));
2160                         m.Statements.Add (stmt);
2161                         
2162                         // loop through the collection and generate the code
2163                         for (int idx = 0; idx < taInfo.Commands.Count; idx++) {
2164                                 DbCommand cmd = ((DbCommandInfo)taInfo.Commands[idx]).Command;
2165                                 // Allocate
2166                                 expr1 = IndexerRef (expr, Const (idx));
2167                                 stmt = Let (expr1, New (type));
2168                                 m.Statements.Add (stmt);
2169                                 
2170                                 // Initialize cmd members
2171                                 stmt = Let (PropRef (expr1, "Connection"), PropRef ("Connection"));
2172                                 m.Statements.Add (stmt);
2173                                 stmt = Let (PropRef (expr1, "CommandText"), Const (cmd.CommandText));
2174                                 m.Statements.Add (stmt);
2175                                 stmt = Let (PropRef (expr1, "CommandType"), 
2176                                             PropRef (Local(typeof (CommandType).FullName), cmd.CommandType.ToString ()));
2177                                 m.Statements.Add (stmt);
2178                                 expr1 = PropRef (expr1, "Parameters");
2179                                 foreach (DbParameter param in cmd.Parameters) {
2180                                         AddDbParameterStatements (m, expr1, param);
2181                                 }
2182                         }               
2183                         t.Members.Add (m);
2184                 }
2185                 
2186                 private void CreateDbSourceMethods (CodeTypeDeclaration t, 
2187                                                     TableAdapterSchemaInfo taInfo)
2188                 {
2189                         string tmp = null;
2190                         CodeMemberMethod m = null;
2191                         CodeExpression expr, expr1, expr2;
2192                         CodeStatement stmt;
2193                         string tmpScalarVal = null;
2194                         
2195                         expr = PropRef (PropRef ("Adapter"), "SelectCommand");
2196                         // loop through the collection and generate the code
2197                         for (int idx = 0; idx < taInfo.Commands.Count; idx++) {
2198                                 DbCommandInfo cmdInfo = (DbCommandInfo)taInfo.Commands[idx];
2199                                 
2200                                 foreach (DbSourceMethodInfo mInfo in cmdInfo.Methods) {
2201                                         //Console.WriteLine ("Generating code for {0} method", mInfo.Name);
2202                                         
2203                                         // TODO: Add support for Fill methods
2204                                         if (mInfo.MethodType == GenerateMethodsType.Fill)
2205                                                 continue;
2206                                         
2207                                         m = new CodeMemberMethod ();
2208                                         m.Name = mInfo.Name;
2209                                         
2210                                         stmt = Let (expr, IndexerRef (PropRef ("CommandCollection"), Const (idx)));
2211                                         m.Statements.Add (stmt);
2212                                         
2213                                         switch ((MemberAttributes) Enum.Parse (typeof (MemberAttributes), mInfo.Modifier)) {
2214                                                 case MemberAttributes.Public:
2215                                                         m.Attributes = MemberAttributes.Public;
2216                                                         break;
2217
2218                                                 case MemberAttributes.Private:
2219                                                         m.Attributes = MemberAttributes.Private;
2220                                                         break;
2221                                                 
2222                                                 case MemberAttributes.Assembly:
2223                                                         m.Attributes = MemberAttributes.Assembly;
2224                                                         break;
2225                                                 
2226                                                 case MemberAttributes.Family:
2227                                                         m.Attributes = MemberAttributes.Family;
2228                                                         break;
2229                                         }
2230                                         //Console.WriteLine ("QueryType: {0}", mInfo.QueryType);
2231                                         QueryType qType = (QueryType) Enum.Parse (typeof (QueryType), mInfo.QueryType);
2232                                         switch (qType) {
2233                                                 case QueryType.Scalar:
2234                                                 case QueryType.NoData:
2235                                                         // executes non query and returns status
2236                                                         m.ReturnType = TypeRef (typeof (int));
2237                                                         AddGeneratedMethodParametersAndStatements (m, expr, cmdInfo.Command);
2238                                                 
2239                                                         // store connection state
2240                                                         tmp = typeof (System.Data.ConnectionState).FullName;
2241                                                         expr1 = PropRef (Local ("command"), "Connection");
2242                                                         expr2 = PropRef (PropRef (Local ("System"), "Data"), "ConnectionState");
2243                                                         stmt = VarDecl (tmp, "previousConnectionState", PropRef (expr1, "State"));
2244                                                         m.Statements.Add (stmt);
2245                                                         
2246                                                         // Open connection, if its not already
2247                                                         CodeExpression expr3 = BitOps (PropRef (expr1, "State"), PropRef (expr2, "Open"),
2248                                                                                    CodeBinaryOperatorType.BitwiseAnd);
2249                                                         stmt = new CodeConditionStatement (Inequals (expr3, PropRef (expr2, "Open")), 
2250                                                                                                           new CodeStatement[] {Eval (MethodInvoke (expr1, "Open", 
2251                                                                                                                                                                         new CodeExpression[] {}))},
2252                                                                                                           new CodeStatement[] {});
2253                                                         m.Statements.Add (stmt);
2254                                                 
2255                                                         // declare return variable and execute query
2256                                                         CodeTryCatchFinallyStatement try1 = new CodeTryCatchFinallyStatement ();
2257                                                 
2258                                                         if (qType == QueryType.NoData) {
2259                                                                 m.Statements.Add (VarDecl (typeof (int), "returnValue", null));
2260                                                                 expr3 = MethodInvoke (Local ("command"), "ExecuteNonQuery", new CodeExpression[] {});
2261                                                         } else {
2262                                                                 tmpScalarVal = mInfo.ScalarCallRetval.Substring (0, mInfo.ScalarCallRetval.IndexOf (','));
2263                                                                 m.Statements.Add (VarDecl (TypeRef (tmpScalarVal).BaseType, "returnValue", null));
2264                                                                 expr3 = MethodInvoke (Local ("command"), "ExecuteScalar", new CodeExpression[] {});
2265                                                         }
2266                                                 
2267                                                         // Execute query
2268                                                         try1.TryStatements.Add (Let (Local ("returnValue"), expr3));
2269                                                         
2270                                                         // fill finally block
2271                                                         stmt = new CodeConditionStatement (Equals (Local ("previousConnectionState"), PropRef (expr2, "Closed")), 
2272                                                                                                                                 new CodeStatement[] {Eval (MethodInvoke (expr1, "Close", 
2273                                                                                                                                                                         new CodeExpression[] {}))},
2274                                                                                                                                 new CodeStatement[] {});
2275                                                         try1.FinallyStatements.Add (stmt);
2276                                                         m.Statements.Add (try1);
2277                                                 
2278                                                         // return the value
2279                                                         if (qType == QueryType.NoData) {
2280                                                                 m.Statements.Add (Return (Local ("returnValue")));
2281                                                         } else {
2282                                                                 expr2 = Equals (Local ("returnValue"), Const (null));
2283                                                                 expr3 = Equals (MethodInvoke (Local ("returnValue"), "GetType", new CodeExpression[] {}), 
2284                                                                                 TypeOfRef ("System.DBNull"));
2285                                                                 stmt = new CodeConditionStatement (BooleanOps (expr2, expr3, CodeBinaryOperatorType.BooleanOr), 
2286                                                                                                         new CodeStatement[] {Return (Const (null))},
2287                                                                                                                                         new CodeStatement[] {Return (Cast (tmpScalarVal, Local ("returnValue")))});
2288                                                                 m.Statements.Add (stmt);
2289                                                         }
2290                                                 
2291                                                         break;
2292
2293                                                 case QueryType.Rowset:
2294                                                         // returns DataTable
2295                                                         // TODO: Handle multiple DataTables
2296                                                         tmp = opts.DataSetName (ds.DataSetName) + "." + opts.TableTypeName (ds.Tables[0].TableName);
2297                                                         m.ReturnType = TypeRef (tmp);
2298
2299                                                         AddGeneratedMethodParametersAndStatements (m, expr, cmdInfo.Command);
2300                                                         stmt = VarDecl (tmp, "dataTable", New (tmp));
2301                                                         m.Statements.Add (stmt);
2302
2303                                                         // fill datatable
2304                                                         expr = PropRef ("Adapter");
2305                                                         stmt = Eval (MethodInvoke (expr, "Fill", Local ("dataTable")));
2306                                                         m.Statements.Add (stmt);
2307
2308                                                         // return statement
2309                                                         m.Statements.Add (Return (Local ("dataTable")));
2310                                                         break;
2311                                         }
2312                                         t.Members.Add (m);
2313                                 }                       
2314                         }
2315                 }
2316                 
2317                 private void AddGeneratedMethodParametersAndStatements (CodeMemberMethod m, 
2318                                                                         CodeExpression expr,
2319                                                                         DbCommand cmd)
2320                 {
2321                         CodeStatement stmt;
2322                         CodeExpression expr1;
2323                         int idx = 0;
2324                         string tmp;
2325
2326                         foreach (DbParameter param in cmd.Parameters) {
2327                                 if (param.Direction != ParameterDirection.ReturnValue) {
2328                                         if (param.ParameterName[0] == '@')
2329                                                 tmp = param.ParameterName.Substring (1);
2330                                         else
2331                                                 tmp = param.ParameterName;
2332                                         if (param.SystemType != null)
2333                                                 m.Parameters.Add (Param (TypeRef(param.SystemType), tmp));
2334                                         expr1 = IndexerRef (PropRef (expr, "Parameters"), Const (idx));
2335                                         stmt = Let (expr1, ParamRef (tmp));
2336                                         m.Statements.Add (stmt);
2337                                 }
2338                                 idx++;
2339                         }
2340                 }
2341                 
2342                 private void CreateShortCommandMethods (CodeTypeDeclaration t, TableAdapterSchemaInfo taInfo)
2343                 {
2344                         
2345                 }
2346                 
2347 #endregion
2348 #endif  //NET_2_0
2349
2350         }
2351         
2352 }
2353
2354
2355 /* =========================================================
2356
2357
2358 MonoDataSetGenerator API notes
2359
2360
2361 ** generator API:
2362         CreateDataSetClasses (
2363                 DataSet ds,
2364                 CodeNamespace cns,
2365                 ICodeGenerator gen,
2366                 GeneratorOptions options)
2367
2368 ** classes:
2369
2370 *** Code naming method delegate
2371
2372         public delegate string CodeNamingMethod (string sourceName);
2373
2374         It is used in CodeGeneratorOptions (describled immediately below).
2375
2376
2377
2378 *** Generator Options
2379
2380         public bool MakeClassesInsideDataSet
2381                 indicates whether classes and delegates other than DataSet
2382                 itself are "contained" in the DataSet class or not.
2383
2384         public CodeNamingMethod CreateDataSetName;
2385         public CodeNamingMethod CreateTableTypeName;
2386         public CodeNamingMethod CreateTableMemberName;
2387         public CodeNamingMethod CreateColumnName;
2388         public CodeNamingMethod CreateRowName;
2389         public CodeNamingMethod CreateRelationName;
2390         public CodeNamingMethod CreateTableDelegateName;
2391         public CodeNamingMethod CreateEventArgsName;
2392                 Custom methods each of that returns type or member name.
2393
2394                 By default, they are set as to useTypedDataSetGenerator.
2395                 CreateIdName() with modifications listed as below:
2396
2397                 DataSetName: as is
2398                 TableTypeName: "DataTable" suffix
2399                 TableMemberName: as is
2400                 ColumnName: as is
2401                 RowName: "Row" suffix
2402                 RelationName: (TBD; maybe had better have another delegate type)
2403                 DelegateName: "RowChangedEventHandler" suffix
2404                 EventArgsName: "RowChangedEventArgs" suffix
2405
2406 ** Auto Generated classes
2407
2408 1. Custom DataSet class 
2409
2410         class name = dataset name, encoded by options.CreateDataSetName().
2411
2412 *** .ctor
2413
2414         public default .ctor()
2415                 "initialize" class.
2416                 set custom delegate on Tables.CollectionChanged
2417                 set custom delegate on Relations.CollectionChanged
2418
2419         runtime serialization .ctor()
2420                 TBD
2421
2422 *** public members
2423
2424         data tables: [foo]DataTable foo { return this.table[foo]; }
2425
2426         Clone()
2427                 init variables on new dataset.
2428
2429 *** protected members
2430
2431         ShouldSerializeTables()
2432                 returns false, while default DataSet returns true.
2433         ShouldSerializeRelations()
2434                 returns false, while default DataSet returns true.
2435
2436         ReadXmlSerializable() ... similar to runtime serialization
2437                 TBD
2438
2439         GetSchemaSerializable()
2440                 Write its schema to temporary MemoryStream
2441                 Read XML schema from the stream
2442
2443 *** internal members
2444
2445         "init variables"
2446                 set member fields (tables, relations)
2447                 call members' "init variables"
2448
2449         "init class"
2450                 set DataSetName, Prefix, Namespace, Locale, CaseSensitive, EnforceConstraints
2451                 for each table
2452                         allocate table[foo] 
2453                         Tables.Add() 
2454                         create FKC: new FKC([rel], new DataColumn [] {table[foo].[keyColumnName]Column}, new DataColumn [] {table[child].[childColName]Column}
2455                 fill Rule properties.
2456                 allocate relation[rel] and fill Nested, then Relations.Add()
2457
2458 *** private members
2459
2460         data tables: [foo]DataTable table[foo];
2461
2462         data relations: DataRelation relation[rel];
2463
2464         ShouldSerialize[foo]
2465
2466
2467
2468 2. Custom DataTable classes for each DataTable
2469
2470         This class is created under the dataset.
2471
2472 *** internal members
2473
2474         .ctor() : base("[foo]")
2475                 initialize class
2476
2477         .ctor(DataTable)
2478                 wtf?
2479
2480         DataColumn [bar]Column { return column[bar]; }
2481
2482         "init variables"()
2483                 fill each column fields
2484
2485 *** public members
2486
2487         int Count { rowcount }
2488
2489         this [int index] { row [i]; }
2490
2491         event [foo]RowChangedEventHandler [foo]RowChanged
2492         event [foo]RowChangedEventHandler [foo]RowChanging
2493         event [foo]RowChangedEventHandler [foo]RowDeleted
2494         event [foo]RowChangedEventHandler [foo]RowDeleting
2495
2496         void Add[foo]Row ([foo]Row row) { Rows.Add (row); }
2497
2498         [foo]Row Add[foo]Row ([columnType] [columnName])
2499                 create new [foo]row.
2500                 set members
2501                 Rows.Add ()
2502                 // where
2503                 //      non-relation-children are just created as column type
2504                 //      relation-children are typeof fooRow[]
2505
2506         GetEnumerator() { Rows.GetEnumerator (); }
2507
2508         override DataTable Clone()
2509                 "init variables"
2510
2511         [foo]Row New[foo]Row()
2512
2513         void Remove[foo]Row([foo]Row)
2514
2515         //for each ChildRelations
2516         [bar]Row [] Get[foo_bar]Rows ()
2517
2518 *** protected members
2519
2520         override DataTable CreateInstance() { return new }
2521
2522         override DataRow NewRowFromBuilder(DataRowBuilder)
2523
2524         override Type GetRowType()
2525
2526         override void OnRowChanged(DataRowChangedEventArgs)
2527                 base.()
2528                 check this event [foo]RowChanged.
2529
2530         override void OnRowChanging(DataRowChangedEventArgs)
2531         override void OnRowDeleted(DataRowChangedEventArgs)
2532         override void OnRowDeleting(DataRowChangedEventArgs)
2533         ... as well
2534
2535 *** private members
2536
2537         "initialize class"
2538                 for each columns {
2539                         column[bar] = new DataColumn (...);
2540                         Columns.Add()
2541                 }
2542
2543         DataColumn [bar]Column
2544
2545 3. Custom DataRow classses
2546
2547 *** public members
2548
2549         for simple members:
2550
2551                 [bar_type] [bar] {
2552                         get { try { } catch { throw StrongTypingException(); }
2553                         set { this [[foo]Table.[bar]Column] = value; }
2554
2555                 bool Is[bar]Null ()
2556                         IsNull ([foo]Table.[bar]Column);
2557
2558                 void Set[bar]Null ()
2559
2560         if the table is parent of some relations
2561
2562                 public [child]Row [] Get[child]Rows()
2563
2564 *** internal members
2565
2566         .ctor(DataRowBuilder) : base.()
2567                 table[foo] = Table;
2568
2569 *** private members
2570
2571         [foo]DataTable table[foo]
2572
2573
2574 4. Custom DataRowChangeEvent classes
2575
2576 *** private members
2577
2578         [foo]Row eventRow
2579         DataRowAction eventAction
2580
2581 *** public members
2582
2583         .ctor([foo]Row row, DataRowAction action)
2584
2585         [foo]Row Row
2586
2587         DataRowAction Action
2588
2589
2590
2591 5. public Table RowChangedEventHandler delegates
2592
2593         [foo]RowChangedEventHandler(object, [foo]RowChangedEvent e)
2594
2595
2596 ======================================================== */