using System; using System.Collections; namespace System.Data { /// /// Summary description for Index. /// internal class Index { // fields private DataTable _table; private DataColumn[] _columns; private bool _unique; private Node _root; private string _indexName; internal Index (string name, DataTable table, DataColumn[] columns, bool unique) { _indexName = name; _table = table; _columns = columns; _unique = unique; } internal void SetUnique (bool unique) { _unique = unique; } internal Node Root { get { return _root; } set { _root = value; } } internal string Name { get { return _indexName; } set { } } internal bool IsUnique { get { return _unique; } } internal DataColumn[] Columns { get { return _columns; // todo: this gives back also primary key field! } } internal bool IsEquivalent (Index index) { if (_unique == index._unique && _columns.Length == index._columns.Length) { for (int j = 0; j < _columns.Length; j++) { if (_columns[j] != index._columns[j]) { return false; } } return true; } return false; } internal void Insert (Node i, DataRowVersion version) { DataRow data = i.Row; Node n = _root, x = n; bool way = true; int compare = -1; bool needBalance = true; while (true) { if (n == null) { if (x == null) { _root = i; return; } Set(x, way, i); break; } DataRow nData = n.Row; if (data == nData) { //Set(x, way, i); needBalance = false; break; } compare = CompareRow(data, version, nData); if (compare == 0) { throw new ConstraintException("Unique key violation"); } way = compare < 0; x = n; n = Child(x, way); } if(needBalance) { Balance(x, way); } } private void Balance(Node x, bool way) { while (true) { int sign = way ? 1 : -1; switch (x.GetBalance() * sign) { case 1 : x.SetBalance(0); return; case 0 : x.SetBalance(-sign); break; case -1 : Node l = Child(x, way); if (l.GetBalance() == -sign) { Replace(x, l); Set(x, way, Child(l, !way)); Set(l, !way, x); x.SetBalance(0); l.SetBalance(0); } else { Node r = Child(l, !way); Replace(x, r); Set(l, !way, Child(r, way)); Set(r, way, l); Set(x, way, Child(r, !way)); Set(r, !way, x); int rb = r.GetBalance(); x.SetBalance((rb == -sign) ? sign : 0); l.SetBalance((rb == sign) ? -sign : 0); r.SetBalance(0); } return; } if (x.Equals(_root)) { return; } way = x.From(); x = x.Parent; } } internal void Delete (DataRow row) { Node x = Search(row,DataRowVersion.Current); Delete (x); } internal void Delete(Node x) { if (x == null) { return; } Node n; if (x.Left == null) { n = x.Right; } else if (x.Right == null) { n = x.Left; } else { Node d = x; x = x.Left; // todo: this can be improved while (x.Right != null) { x = x.Right; } // x will be replaced with n later n = x.Left; // swap d and x int b = x.GetBalance(); x.SetBalance(d.GetBalance()); d.SetBalance(b); // set x.parent Node xp = x.Parent; Node dp = d.Parent; if (d == _root) { _root = x; } x.Parent = dp; if (dp != null) { if (dp.Right.Equals(d)) { dp.Right = x; } else { dp.Left = x; } } // for in-memory tables we could use: d.rData=x.rData; // but not for cached tables // relink d.parent, x.left, x.right if (xp == d) { d.Parent = x; if (d.Left.Equals(x)) { x.Left = d; x.Right = d.Right; } else { x.Right = d; x.Left = d.Left; } } else { d.Parent = xp; xp.Right = d; x.Right = d.Right; x.Left = d.Left; } x.Right.Parent = x; x.Left.Parent = x; // set d.left, d.right d.Left = n; if (n != null) { n.Parent = d; } d.Right = null; x = d; } bool way = x.From(); Replace(x, n); n = x.Parent; x.Delete(); while (n != null) { x = n; int sign = way ? 1 : -1; switch (x.GetBalance() * sign) { case -1 : x.SetBalance(0); break; case 0 : x.SetBalance(sign); return; case 1 : Node r = Child(x, !way); int b = r.GetBalance(); if (b * sign >= 0) { Replace(x, r); Set(x, !way, Child(r, way)); Set(r, way, x); if (b == 0) { x.SetBalance(sign); r.SetBalance(-sign); return; } x.SetBalance(0); r.SetBalance(0); x = r; } else { Node l = Child(r, way); Replace(x, l); b = l.GetBalance(); Set(r, way, Child(l, !way)); Set(l, !way, r); Set(x, !way, Child(l, way)); Set(l, way, x); x.SetBalance((b == sign) ? -sign : 0); r.SetBalance((b == -sign) ? sign : 0); l.SetBalance(0); x = l; } break; } way = x.From(); n = x.Parent; } } internal Node[] FindAllSimple(Object[] indexcoldata) { ArrayList nodes = new ArrayList(); Node n = FindSimple (indexcoldata, true); if (n == null) return new Node[0]; while (n != null && ComparePartialRowNonUnique(indexcoldata, n.Row) == 0) { nodes.Add (n); n = Next (n); } return (Node[])nodes.ToArray (typeof (Node)); } internal Node FindSimple(Object[] indexcoldata, bool first) { Node x = _root, n; Node result = null; if (indexcoldata[0] == null) { return null; } while (x != null) { int i = this.ComparePartialRowNonUnique(indexcoldata, x.Row); if (i == 0) { if (first == false) { result = x; break; } else if (result == x) { break; } result = x; n = x.Left; } else if (i > 0) { n = x.Right; } else { n = x.Left; } if (n == null) { break; } x = n; } return result; } internal Node Find(DataRow data, DataRowVersion version) { Node x = _root, n; while (x != null) { int i = CompareRow(data, version, x.Row); if (i == 0) { return x; } else if (i > 0) { n = x.Right; } else { n = x.Left; } if (n == null) { return null; } x = n; } return null; } // internal Node FindFirst(Object value, int compare) // { // Node x = _root; // int iTest = 1; // // // if (compare == Expression.BIGGER) { // // iTest = 0; // // } // // while (x != null) { // bool t = CompareValue(value, x.GetData()[0]) >= iTest; // // if (t) { // Node r = x.Right; // // if (r == null) // { // break; // } // // x = r; // } // else { // Node l = x.Left; // // if (l == null) { // break; // } // // x = l; // } // } // // while (x != null && CompareValue(value, x.GetData()[0]) >= iTest) { // x = Next(x); // } // // return x; // } // internal Node First() // { // // Node x = _root, // l = x; // // while (l != null) { // // x = l; // l = x.Left; // } // // return x; // } internal Node Next(Node x) { if (x == null) { return null; } Node r = x.Right; if (r != null) { x = r; Node l = x.Left; while (l != null) { x = l; l = x.Left; } return x; } Node ch = x; x = x.Parent; while (x != null && ch.Equals(x.Right)) { ch = x; x = x.Parent; } return x; } private Node Child(Node x, bool w) { return w ? x.Left : x.Right; } private void Replace(Node x, Node n) { if (x.Equals(_root)) { _root = n; if (n != null) { n.Parent = null; } } else { Set(x.Parent, x.From(), n); } } private void Set(Node x, bool w, Node n) { if (w) { x.Left = n; } else { x.Right = n; } if (n != null) { n.Parent = x; } } private Node Search(DataRow r,DataRowVersion version) { Node x = _root; while (x != null) { int c = CompareRow(r, version, x.Row); if (c == 0) { return x; } else if (c < 0) { x = x.Left; } else { x = x.Right; } } return null; } internal int ComparePartialRowNonUnique(object[] a, DataRow b) { int i = DataColumn.CompareValues(a[0], b[_columns[0].Ordinal, DataRowVersion.Current], _columns[0].DataType, !_columns[0].Table.CaseSensitive); if (i != 0) { return i; } int fieldcount = _columns.Length; for (int j = 1; j < a.Length && j < fieldcount; j++) { Object o = a[j]; if (o == null) { continue; } i = DataColumn.CompareValues(o, b[_columns[j].Ordinal, DataRowVersion.Current], _columns[j].DataType, !_columns[j].Table.CaseSensitive); if (i != 0) { return i; } } return 0; } // private int CompareRowNonUnique(DataRow a, DataRow b) // { // if (a == b) // return 0; // // int i = DataColumn.CompareValues(a[0], GetNodeValue(b,0), _columns[0].DataType, !_columns[0].Table.CaseSensitive); // // if (i != 0) { // return i; // } // // int fieldcount = _columns.Length; // // for (int j = 1; j < fieldcount; j++) { // i = DataColumn.CompareValues(a[_columns[j].Ordinal], b[_columns[j].Ordinal], _columns[j].DataType, !_columns[j].Table.CaseSensitive); // // if (i != 0) { // return i; // } // } // // return 0; // } private int CompareRow(DataRow a, DataRowVersion version, DataRow b) { // if (a == b) // return 0; int i = 0; for (int j = 0; j < _columns.Length; j++) { i = DataColumn.CompareValues(a[_columns[j].Ordinal, version], b[_columns[j].Ordinal, DataRowVersion.Current], _columns[j].DataType, !_columns[j].Table.CaseSensitive); if (i != 0) { return i; } } return 0; } // private int CompareValue(Object a, Object b) // { // if (a == DBNull.Value) { // if (b == DBNull.Value) // return 0; // return -1; // } // // if (b == DBNull.Value) // return 1; // // return System.Data.Common.DBComparerFactory.GetComparer(b.GetType(), false).Compare(a, b); // } // /// // /// When we are inspectiong node (row) value in the index // /// we are alway referencing its Current value // /// // private object GetNodeValue(DataRow row,DataColumn column) // { // return row[column,DataRowVersion.Current]; // } // // /// // /// When we are inspectiong node (row) value in the index // /// we are alway referencing its Current value // /// // private object GetNodeValue(DataRow row,index idx) // { // return row[idx,DataRowVersion.Current]; // } // internal String GetString() // { // System.Text.StringBuilder sb = new System.Text.StringBuilder(); // for(int i =0; i < this._columns.Length; i++) { // sb.Append("[ " + _columns[i].ColumnName + " ] "); // } // sb.Append("\n"); // if(this.Root != null) { // this.Root.CollectString(sb,0); // } // return sb.ToString(); // } } }