DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
Row.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.Generic;
19 using System.Linq;
20 
22 using Deveel.Data.Sql.Objects;
23 using Deveel.Data.Types;
24 
25 namespace Deveel.Data.Sql.Tables {
44  public sealed class Row : IDbObject {
46  private Dictionary<int, DataObject> values;
47 
61  public Row(ITable table, RowId rowId) {
62  if (table == null)
63  throw new ArgumentNullException("table");
64 
65  if (!rowId.IsNull &&
66  table.TableInfo.Id >= 0 &&
67  table.TableInfo.Id != rowId.TableId)
68  throw new ArgumentException(String.Format("The table ID {0} does not match the identifier specified by the row ID ({1})",
69  table.TableInfo.Id,
70  rowId.TableId));
71 
72  Table = table;
73  RowId = rowId;
74  }
75 
76  public Row(ITable table, int rowNumber)
77  : this(table, new RowId(table.TableInfo.Id, rowNumber)) {
78  }
79 
85  public Row(ITable table)
86  : this(table, RowId.Null) {
87  }
88 
92  public ITable Table { get; private set; }
93 
101  public RowId RowId { get; private set; }
102 
104  get { return new ObjectName(Table.FullName, RowId.RowNumber.ToString());}
105  }
106 
108  get { return DbObjectType.Row; }
109  }
110 
122  public DataObject this[int columnOffset] {
123  get { return GetValue(columnOffset); }
124  set { SetValue(columnOffset, value); }
125  }
126 
137  public DataObject this[string columnName] {
138  get { return GetValue(columnName); }
139  set { SetValue(columnName, value); }
140  }
141 
142  private IVariableResolver VariableResolver {
143  get {
144  if (variableResolver == null) {
145  variableResolver = new RowVariableResolver(this);
146  } else {
147  variableResolver.NextAssignment();
148  }
149  return variableResolver;
150  }
151  }
152 
156  public int ColumnCount {
157  get { return Table.TableInfo.ColumnCount; }
158  }
159 
164  public bool Exists {
165  get { return Table.Any(x => x.RowId.Equals(RowId)); }
166  }
167 
168  private bool? canBeCached;
169 
170  public bool CanBeCached {
171  get {
172  if (canBeCached == null) {
173  canBeCached = values.All(value => value.Value.IsCacheable);
174  }
175 
176  return canBeCached.Value;
177  }
178  }
179 
180 
203  public DataObject GetValue(int columnOffset) {
204  if (columnOffset < 0 || columnOffset >= Table.TableInfo.ColumnCount)
205  throw new ArgumentOutOfRangeException("columnOffset");
206 
207  if (values == null) {
208  if (RowId.IsNull)
209  throw new InvalidOperationException("Row was not established to any table.");
210 
211  var colCount = Table.TableInfo.ColumnCount;
212  values = new Dictionary<int, DataObject>(colCount);
213 
214  for (int i = 0; i < colCount; i++) {
215  values[i] = Table.GetValue(RowId.RowNumber, i);
216  }
217  }
218 
219  DataObject value;
220  if (!values.TryGetValue(columnOffset, out value)) {
221  var columnType = Table.TableInfo[columnOffset].ColumnType;
222  return DataObject.Null(columnType);
223  }
224 
225  return value;
226  }
227 
247  public void SetValue(int columnOffset, DataObject value) {
248  var colCount = Table.TableInfo.ColumnCount;
249 
250  if (columnOffset < 0 || columnOffset >= Table.TableInfo.ColumnCount)
251  throw new ArgumentOutOfRangeException("columnOffset");
252 
253  if (values == null)
254  values = new Dictionary<int, DataObject>(colCount);
255 
256  var column = Table.TableInfo[columnOffset];
257  var columnType = column.ColumnType;
258 
259  if (!value.Type.IsComparable(columnType)) {
260  throw new ArgumentException(
261  String.Format("The specified value of type '{0}' is not comparable to '{1}' defined by '{2}'.",
262  value.Type, columnType, column.FullColumnName));
263  }
264 
265  values[columnOffset] = value;
266  }
267 
285  public DataObject GetValue(string columnName) {
286  if (String.IsNullOrEmpty(columnName))
287  throw new ArgumentNullException("columnName");
288 
289  var offset = Table.TableInfo.IndexOfColumn(columnName);
290  if (offset < 0)
291  throw new ArgumentException(String.Format("Could not find column '{0}' in the table '{1}'.", columnName, Table.FullName));
292 
293  return GetValue(offset);
294  }
295 
296  public void SetValue(string columnName, DataObject value) {
297  if (String.IsNullOrEmpty(columnName))
298  throw new ArgumentNullException("columnName");
299 
300  var offset = Table.TableInfo.IndexOfColumn(columnName);
301  if (offset < 0)
302  throw new ArgumentException(String.Format("Could not find column '{0}' in the table '{1}'.", columnName, Table.FullName));
303 
304  SetValue(offset, value);
305  }
306 
307  public void SetValue(int columnIndex, string value) {
308  SetValue(columnIndex, DataObject.String(value));
309  }
310 
311  public void SetValue(int columnIndex, int value) {
312  SetValue(columnIndex, DataObject.Integer(value));
313  }
314 
315  public void SetValue(int columnIndex, long value) {
316  SetValue(columnIndex, DataObject.BigInt(value));
317  }
318 
319  public void SetValue(int columnIndex, short value) {
320  SetValue(columnIndex, DataObject.SmallInt(value));
321  }
322 
323  public void SetValue(int columnIndex, float value) {
324  SetValue(columnIndex, new SqlNumber(value));
325  }
326 
327  public void SetValue(int columnIndex, double value) {
328  SetValue(columnIndex, DataObject.Number(new SqlNumber(value)));
329  }
330 
331  public void SetValue(int columnIndex, SqlNumber value) {
332  SetValue(columnIndex, DataObject.Number(value));
333  }
334 
335  public void SetValue(int columnIndex, bool value) {
336  SetValue(columnIndex, DataObject.Boolean(value));
337  }
338 
339  public void SetValue(int columnIndex, byte[] bytes) {
340  SetValue(columnIndex, DataObject.Binary(bytes));
341  }
342 
343  public void SetValue(int columnIndex, SqlBinary binary) {
344  SetValue(columnIndex, DataObject.Binary(binary));
345  }
346 
352  public void SetNull(int columnOffset) {
353  if (columnOffset < 0 || columnOffset >= Table.TableInfo.ColumnCount)
354  throw new ArgumentOutOfRangeException("columnOffset");
355 
356  var columnType = Table.TableInfo[columnOffset].ColumnType;
357  SetValue(columnOffset, new DataObject(columnType, null));
358  }
359 
374  public void SetDefault(int columnOffset, IQuery context) {
375  if (columnOffset < 0 || columnOffset >= Table.TableInfo.ColumnCount)
376  throw new ArgumentOutOfRangeException("columnOffset");
377 
378  var column = Table.TableInfo[columnOffset];
379  if (!column.HasDefaultExpression)
380  throw new InvalidOperationException(String.Format("Column '{0}' in table '{1}' has no DEFAULT set.", column.ColumnName, Table.FullName));
381 
382  var value = Evaluate(column.DefaultExpression, context);
383  SetValue(columnOffset, value);
384  }
385 
393  public void SetDefault(IQuery context) {
394  for (int i = 0; i < Table.TableInfo.ColumnCount; ++i) {
395  if (!values.ContainsKey(i)) {
396  SetDefault(i, context);
397  }
398  }
399  }
400 
401  private DataObject Evaluate(SqlExpression expression, IQuery queryContext) {
402  var ignoreCase = queryContext.IgnoreIdentifiersCase();
403  // Resolve any variables to the table_def for this expression.
404  expression = Table.TableInfo.ResolveColumns(ignoreCase, expression);
405  // Get the variable resolver and evaluate over this data.
406  IVariableResolver vresolver = VariableResolver;
407  var reduced = expression.Evaluate(queryContext, vresolver, null);
408  if (reduced.ExpressionType != SqlExpressionType.Constant)
409  throw new InvalidOperationException("The DEFAULT expression of the column cannot be reduced to a constant");
410 
411  return ((SqlConstantExpression) reduced).Value;
412  }
413 
428  public void SetNumber(int number) {
429  RowId = new RowId(Table.TableInfo.Id, number);
430  }
431 
432  #region RowVariableResolver
433 
435  private readonly Row row;
436  private int assignmentCount;
437 
438  public RowVariableResolver(Row row) {
439  this.row = row;
440  }
441 
442  internal void NextAssignment() {
443  ++assignmentCount;
444  }
445 
446  public int SetId {
447  get { return assignmentCount; }
448  }
449 
450  public DataObject Resolve(ObjectName columnName) {
451  string colName = columnName.Name;
452 
453  int colIndex = row.Table.TableInfo.IndexOfColumn(colName);
454  if (colIndex == -1)
455  throw new InvalidOperationException(String.Format("Column '{0}' could not be found in table '{1}'", colName, row.Table.FullName));
456 
457  DataObject value;
458  if (!row.values.TryGetValue(colIndex, out value))
459  throw new InvalidOperationException("Column " + colName + " hasn't been set yet.");
460 
461  return value;
462  }
463 
464  public SqlType ReturnType(ObjectName columnName) {
465  string colName = columnName.Name;
466 
467  int colIndex = row.Table.TableInfo.IndexOfColumn(colName);
468  if (colIndex == -1)
469  throw new InvalidOperationException("Can't find column: " + colName);
470 
471  return row.Table.TableInfo[colIndex].ColumnType;
472  }
473  }
474 
475  #endregion
476 
484  public void SetRowNumber(int rowNumber) {
485  RowId = new RowId(Table.TableInfo.Id, rowNumber);
486  }
487 
494  public void SetFromTable() {
495  for (int i = 0; i < Table.TableInfo.ColumnCount; i++) {
496  SetValue(i, Table.GetValue(RowId.RowNumber, i));
497  }
498  }
499 
500  public void EvaluateAssignment(SqlAssignExpression assignExpression, IQuery context) {
501  var colRef = (SqlReferenceExpression) assignExpression.ReferenceExpression;
502  var valueExp = assignExpression.ValueExpression;
503  var value = valueExp.EvaluateToConstant(context, VariableResolver);
504 
505  // Check the column name is within this row.
506  var columnName = colRef.ReferenceName;
507  int column = Table.FindColumn(columnName);
508 
509  if (column == -1)
510  throw new ObjectNotFoundException(columnName,
511  String.Format("Table '{0}' has none column named '{1}': cannot assign.", Table.TableInfo.TableName, columnName));
512 
513  SetValue(column, value);
514  }
515  }
516 }
abstract DataObject GetValue(long rowNumber, int columnOffset)
Gets a single cell within the table that is located at the given column offset and row...
RowVariableResolver variableResolver
Definition: Row.cs:45
void SetFromTable()
Gathers the original values from the table for the row number corresponding and populates this row wi...
Definition: Row.cs:494
bool IsNull
Gets a boolean value indicating if the object equivales to a NULL.
Definition: RowId.cs:64
static DataObject Integer(int value)
Definition: DataObject.cs:576
Defines the contract to access the data contained into a table of a database.
Definition: ITable.cs:40
static DataObject Binary(SqlBinary binary)
Definition: DataObject.cs:638
SqlType Type
Gets the SqlType that defines the object properties
Definition: DataObject.cs:78
void SetValue(int columnIndex, byte[] bytes)
Definition: Row.cs:339
void SetValue(int columnIndex, SqlBinary binary)
Definition: Row.cs:343
Row(ITable table)
Constructs a new row on the given table that is not established into that table.
Definition: Row.cs:85
An expression that references an object within a context.
A long string in the system.
void SetValue(int columnIndex, bool value)
Definition: Row.cs:335
Row(ITable table, RowId rowId)
Constructs a new row object for the table given, identified by the given RowId.
Definition: Row.cs:61
DataObject GetValue(string columnName)
Gets a value for a cell of the row that corresponds to the column of the table with the given name...
Definition: Row.cs:285
DataObject GetValue(int columnOffset)
Gets or the value of a cell of the row at the given offset.
Definition: Row.cs:203
Implements a BINARY object that handles a limited number of bytes, not exceding MaxLength.
Definition: SqlBinary.cs:27
static DataObject Number(SqlNumber value)
Definition: DataObject.cs:552
int Id
Gets a unique identifier of the table in a database system.
Definition: TableInfo.cs:107
virtual bool IsComparable(SqlType type)
Verifies if a given SqlType is comparable to this data-type.
Definition: SqlType.cs:137
Represents a database object, such as a table, a trigger, a type or a column.
Definition: IDbObject.cs:24
int FindColumn(ObjectName columnName)
Definition: Table.cs:143
void SetNull(int columnOffset)
Sets the value of a cell of the row at the given offset to NULL.
Definition: Row.cs:352
static DataObject Null(SqlType type)
Definition: DataObject.cs:630
ObjectName FullName
Gets the fully qualified name of the object used to resolve it uniquely within the database...
Definition: IDbObject.cs:30
void SetValue(string columnName, DataObject value)
Definition: Row.cs:296
void SetDefault(IQuery context)
Sets the DEFAULT value of all cells in the row as configured in the columns definition corresponding ...
Definition: Row.cs:393
Describes the name of an object within a database.
Definition: ObjectName.cs:44
Row(ITable table, int rowNumber)
Definition: Row.cs:76
A single row in a table of a database.
Definition: Row.cs:44
static DataObject String(string s)
Definition: DataObject.cs:592
void SetValue(int columnIndex, string value)
Definition: Row.cs:307
static DataObject Boolean(SqlBoolean value)
Definition: DataObject.cs:544
void EvaluateAssignment(SqlAssignExpression assignExpression, IQuery context)
Definition: Row.cs:500
DataObject Evaluate(SqlExpression expression, IQuery queryContext)
Definition: Row.cs:401
SqlExpressionType
All the possible type of SqlExpression supported
int RowNumber
Gets the number of the column within the table referenced.
Definition: RowId.cs:58
void SetValue(int columnIndex, SqlNumber value)
Definition: Row.cs:331
ObjectName TableName
Gets the fully qualified name of the table that is ensured to be unique within the system...
Definition: TableInfo.cs:97
void SetDefault(int columnOffset, IQuery context)
Sets the value of a cell of the row at the given offset to the DEFAULT set at the column definition...
Definition: Row.cs:374
void SetValue(int columnIndex, long value)
Definition: Row.cs:315
void SetNumber(int number)
Sets the row number part of the identificator
Definition: Row.cs:428
virtual SqlExpression Evaluate(EvaluateContext context)
When overridden by a derived class, this method evaluates the expression within the provided context...
void SetValue(int columnIndex, int value)
Definition: Row.cs:311
SqlType ReturnType(ObjectName columnName)
Returns the SqlType of object the given variable is.
Definition: Row.cs:464
Represents a dynamic object that encapsulates a defined SqlType and a compatible constant ISqlObject ...
Definition: DataObject.cs:35
DbObjectType ObjectType
Gets the type of database object that the implementation is for
Definition: IDbObject.cs:35
Defines the properties of a specific SQL Type and handles the values compatible.
Definition: SqlType.cs:33
TableInfo TableInfo
Gets the metadata information of the table, used to resolve the column sources.
Definition: ITable.cs:47
void SetValue(int columnIndex, short value)
Definition: Row.cs:319
int IndexOfColumn(string columnName)
Gets the offset of the column with the given name.
Definition: TableInfo.cs:310
An interface to resolve a variable name to a constant object.
Defines the value of a ROWID object, that is a unique reference within a database system to a single ...
Definition: RowId.cs:24
An expression that holds a constant value.
void SetValue(int columnOffset, DataObject value)
Sets the value of a cell of the row at the given offset.
Definition: Row.cs:247
void SetValue(int columnIndex, float value)
Definition: Row.cs:323
static DataObject BigInt(long value)
Definition: DataObject.cs:580
string Name
Gets the name of the object being referenced.
Definition: ObjectName.cs:108
static DataObject SmallInt(short value)
Definition: DataObject.cs:572
int ColumnCount
Gets a count of the columns defined by this object.
Definition: TableInfo.cs:159
DataObject Resolve(ObjectName columnName)
Returns the value of a given variable.
Definition: Row.cs:450
void SetValue(int columnIndex, double value)
Definition: Row.cs:327
void SetRowNumber(int rowNumber)
Sets the number component of the ID of this column.
Definition: Row.cs:484
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
Defines the metadata properties of a table existing within a database.
Definition: TableInfo.cs:41
int TableId
Gets the unique identifier of the table the row is contained.
Definition: RowId.cs:53
Dictionary< int, DataObject > values
Definition: Row.cs:46
SqlExpression ResolveColumns(bool ignoreCase, SqlExpression expression)
Definition: TableInfo.cs:350
abstract TableInfo TableInfo
Definition: Table.cs:51