Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data / System / Data / Filter / NameNode.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="NameNode.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 // <owner current="false" primary="false">Microsoft</owner>
8 //------------------------------------------------------------------------------
9
10 namespace System.Data {
11     using System;
12     using System.ComponentModel;
13     using System.Collections.Generic;
14     using System.Diagnostics;
15     using System.Globalization;
16
17     internal sealed class NameNode : ExpressionNode {
18         internal char open = '\0';
19         internal char close = '\0';
20         internal string name;
21         internal bool found;
22         internal bool type = false;
23         internal DataColumn column;
24
25         internal NameNode(DataTable table, char[] text, int start, int pos) : base(table) {
26             this.name = ParseName(text, start, pos);
27         }
28
29         internal NameNode(DataTable table, string name) : base(table) {
30             this.name = name;
31         }
32
33         internal override bool IsSqlColumn{
34             get{
35                 return column.IsSqlType;
36             }
37         }
38
39         internal override void Bind(DataTable table, List<DataColumn> list) {
40             BindTable(table);
41             if (table == null)
42                 throw ExprException.UnboundName(name);
43
44             try {
45                 this.column = table.Columns[name];
46             }
47             catch (Exception e) {
48                 found = false;
49                 // 
50                 if (!Common.ADP.IsCatchableExceptionType(e)) {
51                     throw;
52                 }
53                 throw ExprException.UnboundName(name);
54             }
55
56             if (column == null)
57                 throw ExprException.UnboundName(name);
58
59             name = column.ColumnName;
60             found = true;
61
62             // add column to the dependency list, do not add duplicate columns
63             Debug.Assert(column != null, "Failed to bind column " + name);
64
65             int i;
66             for (i = 0; i < list.Count; i++) {
67                 // walk the list, check if the current column already on the list
68                 DataColumn dataColumn = list[i];
69                 if (column == dataColumn) {
70                     break;
71                 }
72             }
73             if (i >= list.Count) {
74                 list.Add(column);
75             }
76         }
77
78         internal override object Eval() {
79             // can not eval column without ROW value;
80             throw ExprException.EvalNoContext();
81         }
82
83         internal override object Eval(DataRow row, DataRowVersion version) {
84             if (!found) {
85                 throw ExprException.UnboundName(name);
86             }
87
88             if (row == null) {
89                 if(IsTableConstant()) // this column is TableConstant Aggregate Function
90                     return column.DataExpression.Evaluate();
91                 else {
92                     throw ExprException.UnboundName(name);
93                 }
94             }
95
96             return column[row.GetRecordFromVersion(version)];
97         }
98
99         internal override object Eval(int[] records) {
100             throw ExprException.ComputeNotAggregate(this.ToString());
101         }
102
103         internal override bool IsConstant() {
104             return false;
105         }
106
107         internal override bool IsTableConstant() {
108             if (column != null && column.Computed) {
109                 return this.column.DataExpression.IsTableAggregate();
110             }
111             return false;
112         }
113
114         internal override bool HasLocalAggregate() {
115             if (column != null && column.Computed) {
116                 return this.column.DataExpression.HasLocalAggregate();
117             }
118             return false;
119         }
120
121         internal override bool HasRemoteAggregate() {
122             if (column != null && column.Computed) {
123                 return this.column.DataExpression.HasRemoteAggregate();
124             }
125             return false;
126         }
127
128         internal override bool DependsOn(DataColumn column) {
129             if (this.column == column)
130                 return true;
131
132             if (this.column.Computed) {
133                 return this.column.DataExpression.DependsOn(column);
134             }
135
136             return false;
137         }
138
139         internal override ExpressionNode Optimize() {
140             return this;
141         }
142
143         /// <devdoc>
144         ///     Parses given name and checks it validity
145         /// </devdoc>
146         internal static string ParseName(char[] text, int start, int pos) {
147             char esc = '\0';
148             string charsToEscape = "";
149             int saveStart = start;
150             int savePos = pos;
151
152             if (text[start] == '`') {
153                 Debug.Assert(text[checked((int)pos-1)] == '`', "Invalid identifyer bracketing, pos = " + pos.ToString(CultureInfo.InvariantCulture) + ", end = " + text[checked((int)pos-1)].ToString(CultureInfo.InvariantCulture));
154                 start = checked((int)start+1);
155                 pos = checked((int)pos-1);
156                 esc = '\\';
157                 charsToEscape = "`";
158             }
159             else if (text[start] == '[') {
160                 Debug.Assert(text[checked((int)pos-1)] == ']', "Invalid identifyer bracketing of name " + new string(text, start, pos-start) + " pos = " + pos.ToString(CultureInfo.InvariantCulture) + ", end = " + text[checked((int)pos-1)].ToString(CultureInfo.InvariantCulture));
161                 start = checked((int)start+1);
162                 pos = checked((int)pos-1);
163                 esc = '\\';
164                 charsToEscape = "]\\";
165             }
166
167             if (esc != '\0') {
168                 // scan the name in search for the ESC
169                 int posEcho = start;
170
171                 for (int i = start; i < pos; i++) {
172                     if (text[i] == esc) {
173                         if (i+1 < pos && charsToEscape.IndexOf(text[i+1]) >= 0) {
174                             i++;
175                         }
176                     }
177                     text[posEcho] = text[i];
178                     posEcho++;
179                 }
180                 pos = posEcho;
181             }
182
183             if (pos == start)
184                 throw ExprException.InvalidName(new string(text, saveStart, savePos - saveStart));
185
186             return new string(text, start, pos - start);
187         }
188     }
189 }