This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[mono.git] / mcs / class / System.Data / Mono.Data.SqlExpressions / ColumnReference.cs
1 //
2 // ColumnReference.cs
3 //
4 // Author:
5 //   Juraj Skripsky (juraj@hotfeet.ch)
6 //
7 // (C) 2004 HotFeet GmbH (http://www.hotfeet.ch)
8 //
9
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.Collections;
35 using System.Data;
36
37 namespace Mono.Data.SqlExpressions {
38         internal enum ReferencedTable {
39                 Self,
40                 Parent,
41                 Child
42         }
43         
44         internal class ColumnReference : IExpression {
45                 ReferencedTable refTable;
46                 string relationName, columnName;
47
48                 public ColumnReference (string columnName) : this (ReferencedTable.Self, null, columnName) {}
49
50                 public ColumnReference (ReferencedTable refTable, string relationName, string columnName)
51                 {
52                         this.refTable = refTable;
53                         this.relationName = relationName;
54                         this.columnName = columnName;
55                 }
56
57                 public ReferencedTable ReferencedTable {
58                         get { return refTable; }
59                 }
60
61                 protected DataRelation GetRelation (DataRow row)
62                 {
63                         DataRelationCollection relations;
64                         if (relationName != null) {
65                                 relations = row.Table.DataSet.Relations;
66                                 return relations[relations.IndexOf(relationName)];
67                         }
68
69                         if (refTable == ReferencedTable.Parent)
70                                 relations = row.Table.ParentRelations;
71                         else
72                                 relations = row.Table.ChildRelations;
73                                 
74                         if (relations.Count > 1)
75                                 throw new EvaluateException (String.Format (
76                                         "The table [{0}] is involved in more than one relation." +
77                                         "You must explicitly mention a relation name.",
78                                         row.Table.TableName));
79                         else
80                                 return relations[0];
81                 }
82
83                 public DataRow GetReferencedRow (DataRow row)
84                 {
85                         switch (refTable) {
86                         case ReferencedTable.Self:
87                         default:
88                                 return row;
89
90                         case ReferencedTable.Parent:
91                                 return row.GetParentRow (GetRelation (row));
92
93                         case ReferencedTable.Child:
94                                 return row.GetChildRows (GetRelation (row)) [0];
95                         }
96                 }
97                 
98                 public DataRow[] GetReferencedRows (DataRow row)
99                 {
100                         switch (refTable) {
101                         case ReferencedTable.Self:
102                         default:
103                                 DataRow[] rows = new DataRow [row.Table.Rows.Count];
104                                 row.Table.Rows.CopyTo (rows, 0);
105                                 return rows;
106                                 
107                         case ReferencedTable.Parent:
108                                 return row.GetParentRows (GetRelation (row));
109
110                         case ReferencedTable.Child:
111                                 return row.GetChildRows (GetRelation (row));
112                         }
113                 }
114                 
115                 public object[] GetValues (DataRow[] rows)
116                 {
117                         object[] values = new object [rows.Length];
118                         for (int i = 0; i < rows.Length; i++)
119                                 values [i] = Unify (rows [i][columnName]);
120                                 
121                         return values;
122                 }
123
124                 private object Unify (object val) {
125                         if (Numeric.IsNumeric (val))
126                                 return Numeric.Unify ((IConvertible)val);
127                                 
128                         if (val == null || val == DBNull.Value)
129                                 return null;
130                                 
131                         if (val is bool || val is string || val is DateTime)
132                                 return val;
133                         
134                         if (val is Enum)
135                                 return (int)val;
136                         
137                         throw new EvaluateException (String.Format ("Cannot handle data type found in column '{0}'.", columnName));                     
138                 }
139
140                 public object Eval (DataRow row)
141                 {
142                         DataRow referencedRow = GetReferencedRow (row);
143                         if (referencedRow == null)
144                                 return null;
145                                 
146                         object val;
147                         try {
148                                 referencedRow._inExpressionEvaluation = true;
149                                 val = referencedRow [columnName];
150                                 referencedRow._inExpressionEvaluation = false;
151                         } catch (IndexOutOfRangeException) {
152                                 throw new EvaluateException (String.Format ("Cannot find column [{0}].", columnName));
153                         }
154                         return Unify (val);
155                 }
156         }
157 }