DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
TableInfo.cs
Go to the documentation of this file.
1 //
2 // Copyright 2010-2015 Deveel
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 using System;
18 using System.Collections;
19 using System.Collections.Generic;
20 using System.Collections.ObjectModel;
21 using System.IO;
22 using System.Linq;
23 using System.Text;
24 
28 using Deveel.Data.Types;
29 
30 namespace Deveel.Data.Sql.Tables {
40  [Serializable]
41  public sealed class TableInfo : IObjectInfo, IEnumerable<ColumnInfo>, ISerializable {
42  private readonly IList<ColumnInfo> columns;
43  private readonly Dictionary<ObjectName, int> columnsCache;
44 
54  public TableInfo(ObjectName tableName)
55  : this(tableName, -1, false, new List<ColumnInfo>(), false) {
56  }
57 
58  private TableInfo(ObjectName tableName, int id, bool perm, IList<ColumnInfo> columns, bool isReadOnly) {
59  if (tableName == null)
60  throw new ArgumentNullException("tableName");
61 
62  TableName = tableName;
63  Id = id;
64  IsPermanent = perm;
65  this.columns = columns;
66  IsReadOnly = isReadOnly;
67 
68  columnsCache = new Dictionary<ObjectName, int>();
69  }
70 
71  private TableInfo(ObjectData data) {
72  TableName = data.GetValue<ObjectName>("TableName");
73  Id = data.GetInt32("TableId");
74  IsPermanent = data.GetBoolean("Permanent");
75  IsReadOnly = data.GetBoolean("ReaDOnly");
76 
77  columns = new List<ColumnInfo>();
78  var columnInfo = data.GetValue<ColumnInfo[]>("Columns");
79  if (columnInfo != null) {
80  foreach (var info in columnInfo) {
81  info.TableInfo = this;
82  columns.Add(info);
83  }
84  }
85 
86  columnsCache = new Dictionary<ObjectName, int>();
87  }
88 
90  get { return DbObjectType.Table; }
91  }
92 
97  public ObjectName TableName { get; private set; }
98 
100  get { return TableName; }
101  }
102 
107  public int Id { get; private set; }
108 
113  public bool IsPermanent { get; private set; }
114 
120  public string Name {
121  get { return TableName.Name; }
122  }
123 
129  public ObjectName SchemaName {
130  get { return TableName.Parent; }
131  }
132 
136  public string CatalogName {
137  get { return SchemaName != null && SchemaName.Parent != null ? SchemaName.Parent.Name : null; }
138  }
139 
147  //public bool IgnoreCase { get; set; }
148 
153  public bool IsReadOnly { get; private set; }
154 
159  public int ColumnCount {
160  get { return columns.Count; }
161  }
162 
176  public ColumnInfo this[int offset] {
177  get {
178  if (offset < 0 || offset >= columns.Count)
179  throw new ArgumentOutOfRangeException("offset");
180 
181  return columns[offset];
182  }
183  }
184 
185  private void AssertNotReadOnly() {
186  if (IsReadOnly)
187  throw new InvalidOperationException();
188  }
189 
190  public void Establish(int id) {
191  Id = id;
192  IsPermanent = true;
193  }
194 
196  data.SetValue("TableName", TableName);
197  data.SetValue("TableId", Id);
198  data.SetValue("ReadOnly", IsReadOnly);
199  data.SetValue("Permanent", IsPermanent);
200  data.SetValue("Columns", columns.ToArray());
201  }
202 
203  internal void AddColumnSafe(ColumnInfo column) {
204  if (column == null)
205  throw new ArgumentNullException("column");
206 
207  AssertNotReadOnly();
208 
209  columnsCache.Clear();
210  column.TableInfo = this;
211  columns.Add(column);
212  }
213 
230  public void AddColumn(ColumnInfo column) {
231  if (column == null)
232  throw new ArgumentNullException("column");
233 
234  AssertNotReadOnly();
235 
236  if (column.TableInfo != null &&
237  column.TableInfo != this)
238  throw new ArgumentException(String.Format("The column {0} belongs to another table already ({1})", column.ColumnName,
239  column.TableInfo.Name));
240 
241  if (columns.Any(x => x.ColumnName == column.ColumnName))
242  throw new ArgumentException(String.Format("Column {0} is already defined in table {1}", column.ColumnName, TableName));
243 
244  columnsCache.Clear();
245  column.TableInfo = this;
246  columns.Add(column);
247  }
248 
259  public ColumnInfo AddColumn(string columnName, SqlType columnType) {
260  return AddColumn(columnName, columnType, false);
261  }
262 
279  public ColumnInfo AddColumn(string columnName, SqlType columnType, bool notNull) {
280  if (String.IsNullOrEmpty(columnName))
281  throw new ArgumentNullException("columnName");
282 
283  if (columnType == null)
284  throw new ArgumentNullException("columnType");
285 
286  var column = new ColumnInfo(columnName, columnType);
287  column.IsNotNull = notNull;
288  AddColumn(column);
289  return column;
290  }
291 
293  public IEnumerator<ColumnInfo> GetEnumerator() {
294  return columns.GetEnumerator();
295  }
296 
297  IEnumerator IEnumerable.GetEnumerator() {
298  return GetEnumerator();
299  }
300 
310  public int IndexOfColumn(string columnName) {
311  return IndexOfColumn(new ObjectName(TableName, columnName));
312  }
313 
314  public int IndexOfColumn(ObjectName columnName) {
315  int index;
316  if (!columnsCache.TryGetValue(columnName, out index)) {
317  bool found = false;
318  for (int i = 0; i < columns.Count; i++) {
319  var column = columns[i];
320  if (column.ColumnName.Equals(columnName.Name, StringComparison.Ordinal)) {
321  index = i;
322  columnsCache[columnName] = index;
323  found = true;
324  }
325  }
326 
327  if (!found)
328  index = -1;
329  }
330 
331  return index;
332  }
333 
343  return new TableInfo(TableName, Id, IsPermanent, new ReadOnlyCollection<ColumnInfo>(columns), true);
344  }
345 
346  public TableInfo Alias(ObjectName alias) {
347  return new TableInfo(alias, Id, IsPermanent, new ReadOnlyCollection<ColumnInfo>(columns), true);
348  }
349 
350  internal SqlExpression ResolveColumns(bool ignoreCase, SqlExpression expression) {
351  var visitor = new ColumnsResolver(this, ignoreCase);
352  return visitor.Visit(expression);
353  }
354 
356  private readonly TableInfo tableInfo;
357  private readonly bool ignoreCase;
358 
359  public ColumnsResolver(TableInfo tableInfo, bool ignoreCase) {
360  this.tableInfo = tableInfo;
361  this.ignoreCase = ignoreCase;
362  }
363 
365  var exp = reference;
366 
367  var colName = exp.ReferenceName.Name;
368  var comparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
369 
370  foreach (var columnInfo in tableInfo) {
371  if (String.Equals(colName, columnInfo.ColumnName, comparison)) {
372  exp = SqlExpression.Reference(new ObjectName(tableInfo.TableName, columnInfo.ColumnName));
373  }
374  }
375 
376  return exp;
377  }
378  }
379 
380  public IEnumerable<int> IndexOfColumns(IEnumerable<string> columnNames) {
381  if (columnNames == null)
382  return new int[0];
383 
384  return columnNames.Select(IndexOfColumn).ToArray();
385  }
386 
387  public static void Serialize(TableInfo tableInfo, Stream stream) {
388  var writer = new BinaryWriter(stream, Encoding.Unicode);
389  Serialize(tableInfo, writer);
390  }
391 
392  public static void Serialize(TableInfo tableInfo, BinaryWriter writer) {
393  writer.Write(3); // Version
394 
395  var catName = tableInfo.CatalogName;
396  if (catName == null)
397  catName = String.Empty;
398 
399  writer.Write(catName);
400  writer.Write(tableInfo.SchemaName.Name);
401  writer.Write(tableInfo.Name);
402 
403  var colCount = tableInfo.columns.Count;
404  writer.Write(colCount);
405  for (int i = 0; i < colCount; i++) {
406  var column = tableInfo.columns[i];
407  ColumnInfo.Serialize(column, writer);
408  }
409  }
410 
411  public static TableInfo Deserialize(Stream stream, ITypeResolver typeResolver) {
412  var reader = new BinaryReader(stream, Encoding.Unicode);
413  return Deserialize(reader, typeResolver);
414  }
415 
416  public static TableInfo Deserialize(BinaryReader reader, ITypeResolver typeResolver) {
417  var version = reader.ReadInt32();
418  if (version != 3)
419  throw new FormatException("Invalid version of the table info.");
420 
421  var catName = reader.ReadString();
422  var schemName = reader.ReadString();
423  var tableName = reader.ReadString();
424 
425  var objSchemaName = !String.IsNullOrEmpty(catName)
426  ? new ObjectName(new ObjectName(catName), schemName)
427  : new ObjectName(schemName);
428 
429  var objTableName = new ObjectName(objSchemaName, tableName);
430 
431  var tableInfo = new TableInfo(objTableName);
432 
433  var colCount = reader.ReadInt32();
434  for (int i = 0; i < colCount; i++) {
435  var columnInfo = ColumnInfo.Deserialize(reader, typeResolver);
436 
437  if (columnInfo != null)
438  tableInfo.AddColumn(columnInfo);
439  }
440 
441  return tableInfo;
442  }
443  }
444 }
Defines the metadata properties of a column within a table of a database.
Definition: ColumnInfo.cs:36
ColumnInfo AddColumn(string columnName, SqlType columnType)
Adds a new column to the table having the given name and type.
Definition: TableInfo.cs:259
static TableInfo Deserialize(Stream stream, ITypeResolver typeResolver)
Definition: TableInfo.cs:411
string Name
Gets the name part of the table name.
Definition: TableInfo.cs:120
ObjectName ReferenceName
Gets the name of the object referenced by the expression.
void GetData(SerializeData data)
readonly Dictionary< ObjectName, int > columnsCache
Definition: TableInfo.cs:43
An expression that references an object within a context.
A long string in the system.
TableInfo(ObjectName tableName)
Constructs the object with the given table name.
Definition: TableInfo.cs:54
void AddColumnSafe(ColumnInfo column)
Definition: TableInfo.cs:203
string CatalogName
Gets the name of the catalog containing the table, if defined.
Definition: TableInfo.cs:136
int IndexOfColumn(ObjectName columnName)
Definition: TableInfo.cs:314
ColumnsResolver(TableInfo tableInfo, bool ignoreCase)
Definition: TableInfo.cs:359
TableInfo(ObjectData data)
Definition: TableInfo.cs:71
void SetValue(string key, Type type, object value)
Describes the name of an object within a database.
Definition: ObjectName.cs:44
TableInfo TableInfo
Gets the table where the column is attached to.
Definition: ColumnInfo.cs:74
TableInfo Alias(ObjectName alias)
Definition: TableInfo.cs:346
void AddColumn(ColumnInfo column)
Adds a new column to the table at the last position of the columns list in the table metadata...
Definition: TableInfo.cs:230
static void Serialize(TableInfo tableInfo, BinaryWriter writer)
Definition: TableInfo.cs:392
TableInfo AsReadOnly()
Creates a new instance of TableInfo as an immutable copy of this table metadata.
Definition: TableInfo.cs:342
static ColumnInfo Deserialize(Stream stream, ITypeResolver typeResolver)
Definition: ColumnInfo.cs:198
static TableInfo Deserialize(BinaryReader reader, ITypeResolver typeResolver)
Definition: TableInfo.cs:416
static void Serialize(ColumnInfo columnInfo, BinaryWriter writer)
Definition: ColumnInfo.cs:173
Defines the properties of a specific SQL Type and handles the values compatible.
Definition: SqlType.cs:33
string ColumnName
Gets the name of the column.
Definition: ColumnInfo.cs:79
TableInfo(ObjectName tableName, int id, bool perm, IList< ColumnInfo > columns, bool isReadOnly)
Definition: TableInfo.cs:58
int IndexOfColumn(string columnName)
Gets the offset of the column with the given name.
Definition: TableInfo.cs:310
ColumnInfo AddColumn(string columnName, SqlType columnType, bool notNull)
Adds a new column to the table having the given name and type.
Definition: TableInfo.cs:279
ObjectName Parent
Gets the parent reference of the current one, if any or null if none.
Definition: ObjectName.cs:99
string Name
Gets the name of the object being referenced.
Definition: ObjectName.cs:108
static SqlReferenceExpression Reference(ObjectName objectName)
ObjectName SchemaName
Gets the schema name part of the table name.
Definition: TableInfo.cs:129
override SqlExpression VisitReference(SqlReferenceExpression reference)
Definition: TableInfo.cs:364
readonly IList< ColumnInfo > columns
Definition: TableInfo.cs:42
Defines the base class for instances that represent SQL expression tree nodes.
DbObjectType
The kind of objects that can be handled by a database system and its managers
Definition: DbObjectType.cs:27
IEnumerator< ColumnInfo > GetEnumerator()
Definition: TableInfo.cs:293
Defines the metadata properties of a table existing within a database.
Definition: TableInfo.cs:41
IEnumerable< int > IndexOfColumns(IEnumerable< string > columnNames)
Definition: TableInfo.cs:380
SqlExpression ResolveColumns(bool ignoreCase, SqlExpression expression)
Definition: TableInfo.cs:350
static void Serialize(TableInfo tableInfo, Stream stream)
Definition: TableInfo.cs:387