**** Merged from MCS ****
[mono-project.git] / mcs / class / System.Data / System.Data / Index.cs
blob5e173a84106f49da088faf199566587f7b172a18
2 //
3 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the
7 // "Software"), to deal in the Software without restriction, including
8 // without limitation the rights to use, copy, modify, merge, publish,
9 // distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so, subject to
11 // the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 using System;
25 using System.Collections;
27 namespace System.Data
29 /// <summary>
30 /// Summary description for Index.
31 /// </summary>
32 internal class Index
35 // fields
36 private DataTable _table;
37 private DataColumn[] _columns;
38 private bool _unique;
39 private Node _root;
40 private string _indexName;
44 internal Index (string name, DataTable table, DataColumn[] columns,
45 bool unique)
48 _indexName = name;
49 _table = table;
50 _columns = columns;
51 _unique = unique;
54 internal void SetUnique (bool unique)
56 _unique = unique;
59 internal Node Root
61 get
63 return _root;
66 set
68 _root = value;
72 internal string Name
74 get
76 return _indexName;
79 set
85 internal bool IsUnique
87 get
89 return _unique;
93 internal DataColumn[] Columns
95 get
97 return _columns; // todo: this gives back also primary key field!
101 internal bool IsEquivalent (Index index)
104 if (_unique == index._unique
105 && _columns.Length == index._columns.Length) {
106 for (int j = 0; j < _columns.Length; j++) {
107 if (_columns[j] != index._columns[j]) {
108 return false;
112 return true;
115 return false;
118 internal void Insert (Node i, DataRowVersion version)
120 DataRow data = i.Row;
121 Node n = _root,
122 x = n;
123 bool way = true;
124 int compare = -1;
125 bool needBalance = true;
127 while (true) {
128 if (n == null) {
129 if (x == null) {
130 _root = i;
132 return;
135 Set(x, way, i);
137 break;
140 DataRow nData = n.Row;
142 if (data == nData) {
143 //Set(x, way, i);
144 needBalance = false;
145 break;
148 compare = CompareRow(data, version, nData);
150 if (compare == 0) {
151 throw new ConstraintException("Unique key violation");
154 way = compare < 0;
155 x = n;
156 n = Child(x, way);
159 if(needBalance) {
160 Balance(x, way);
164 private void Balance(Node x, bool way)
167 while (true) {
169 int sign = way ? 1
170 : -1;
172 switch (x.GetBalance() * sign) {
174 case 1 :
175 x.SetBalance(0);
177 return;
179 case 0 :
180 x.SetBalance(-sign);
181 break;
183 case -1 :
184 Node l = Child(x, way);
186 if (l.GetBalance() == -sign) {
187 Replace(x, l);
188 Set(x, way, Child(l, !way));
189 Set(l, !way, x);
190 x.SetBalance(0);
191 l.SetBalance(0);
193 else {
194 Node r = Child(l, !way);
196 Replace(x, r);
197 Set(l, !way, Child(r, way));
198 Set(r, way, l);
199 Set(x, way, Child(r, !way));
200 Set(r, !way, x);
202 int rb = r.GetBalance();
204 x.SetBalance((rb == -sign) ? sign
205 : 0);
206 l.SetBalance((rb == sign) ? -sign
207 : 0);
208 r.SetBalance(0);
211 return;
214 if (x.Equals(_root)) {
215 return;
218 way = x.From();
219 x = x.Parent;
223 internal void Delete (DataRow row)
225 Node x = Search(row,DataRowVersion.Current);
226 Delete (x);
229 internal void Delete(Node x)
231 if (x == null) {
232 return;
235 Node n;
237 if (x.Left == null) {
238 n = x.Right;
240 else if (x.Right == null) {
241 n = x.Left;
243 else {
244 Node d = x;
246 x = x.Left;
248 // todo: this can be improved
249 while (x.Right != null) {
250 x = x.Right;
253 // x will be replaced with n later
254 n = x.Left;
256 // swap d and x
257 int b = x.GetBalance();
259 x.SetBalance(d.GetBalance());
260 d.SetBalance(b);
262 // set x.parent
263 Node xp = x.Parent;
264 Node dp = d.Parent;
266 if (d == _root) {
267 _root = x;
270 x.Parent = dp;
272 if (dp != null) {
273 if (dp.Right.Equals(d)) {
274 dp.Right = x;
276 else {
277 dp.Left = x;
281 // for in-memory tables we could use: d.rData=x.rData;
282 // but not for cached tables
283 // relink d.parent, x.left, x.right
284 if (xp == d) {
285 d.Parent = x;
287 if (d.Left.Equals(x)) {
288 x.Left = d;
289 x.Right = d.Right;
291 else {
292 x.Right = d;
293 x.Left = d.Left;
296 else {
297 d.Parent = xp;
298 xp.Right = d;
299 x.Right = d.Right;
300 x.Left = d.Left;
303 x.Right.Parent = x;
304 x.Left.Parent = x;
306 // set d.left, d.right
307 d.Left = n;
309 if (n != null) {
310 n.Parent = d;
313 d.Right = null;
315 x = d;
318 bool way = x.From();
320 Replace(x, n);
322 n = x.Parent;
323 x.Delete();
325 while (n != null) {
326 x = n;
328 int sign = way ? 1
329 : -1;
331 switch (x.GetBalance() * sign) {
333 case -1 :
334 x.SetBalance(0);
335 break;
337 case 0 :
338 x.SetBalance(sign);
340 return;
342 case 1 :
343 Node r = Child(x, !way);
344 int b = r.GetBalance();
346 if (b * sign >= 0) {
347 Replace(x, r);
348 Set(x, !way, Child(r, way));
349 Set(r, way, x);
351 if (b == 0) {
352 x.SetBalance(sign);
353 r.SetBalance(-sign);
355 return;
358 x.SetBalance(0);
359 r.SetBalance(0);
361 x = r;
363 else {
364 Node l = Child(r, way);
366 Replace(x, l);
368 b = l.GetBalance();
370 Set(r, way, Child(l, !way));
371 Set(l, !way, r);
372 Set(x, !way, Child(l, way));
373 Set(l, way, x);
374 x.SetBalance((b == sign) ? -sign
375 : 0);
376 r.SetBalance((b == -sign) ? sign
377 : 0);
378 l.SetBalance(0);
380 x = l;
382 break;
385 way = x.From();
386 n = x.Parent;
390 internal Node[] FindAllSimple(DataColumn[] relatedColumns, int index)
392 if (_columns.Length == 0) {
393 return new Node[0];
396 int tmpRecord = _columns[0].Table.RecordCache.NewRecord();
398 try {
399 for (int i = 0; i < relatedColumns.Length && i < _columns.Length; i++) {
400 // according to MSDN: the DataType value for both columns must be identical.
401 _columns[i].DataContainer.CopyValue(relatedColumns[i].DataContainer, index, tmpRecord);
404 return FindAllSimple(tmpRecord, relatedColumns.Length);
406 finally {
407 _columns[0].Table.RecordCache.DisposeRecord(tmpRecord);
411 internal Node[] FindAllSimple(int index, int length)
413 ArrayList nodes = new ArrayList();
414 Node n = FindSimple (index, length, true);
415 if (n == null)
416 return new Node[0];
417 while (n != null && ComparePartialRowNonUnique(index, n.Row.IndexFromVersion(DataRowVersion.Current), length) == 0) {
418 nodes.Add (n);
419 n = Next (n);
422 return (Node[])nodes.ToArray (typeof (Node));
425 internal Node FindSimple(int index, int length, bool first)
427 Node x = _root, n;
428 Node result = null;
430 if (_columns.Length > 0 && _columns[0].DataContainer.IsNull(index)) {
431 return null;
434 while (x != null) {
436 int i = this.ComparePartialRowNonUnique(index, x.Row.IndexFromVersion(DataRowVersion.Current), length);
438 if (i == 0) {
439 if (first == false) {
440 result = x;
441 break;
443 else if (result == x) {
444 break;
446 result = x;
447 n = x.Left;
449 else if (i > 0) {
450 n = x.Right;
452 else {
453 n = x.Left;
456 if (n == null)
458 break;
461 x = n;
464 return result;
467 internal Node Find(DataRow data, DataRowVersion version)
470 Node x = _root, n;
472 while (x != null) {
473 int i = CompareRow(data, version, x.Row);
475 if (i == 0) {
476 return x;
478 else if (i > 0) {
479 n = x.Right;
481 else {
482 n = x.Left;
485 if (n == null) {
486 return null;
489 x = n;
492 return null;
495 // internal Node FindFirst(Object value, int compare)
496 // {
497 // Node x = _root;
498 // int iTest = 1;
500 // // if (compare == Expression.BIGGER) {
501 // // iTest = 0;
502 // // }
504 // while (x != null) {
505 // bool t = CompareValue(value, x.GetData()[0]) >= iTest;
507 // if (t) {
508 // Node r = x.Right;
510 // if (r == null)
511 // {
512 // break;
513 // }
515 // x = r;
516 // }
517 // else {
518 // Node l = x.Left;
520 // if (l == null) {
521 // break;
522 // }
524 // x = l;
525 // }
526 // }
528 // while (x != null && CompareValue(value, x.GetData()[0]) >= iTest) {
529 // x = Next(x);
530 // }
532 // return x;
533 // }
535 // internal Node First()
536 // {
538 // Node x = _root,
539 // l = x;
541 // while (l != null) {
543 // x = l;
544 // l = x.Left;
545 // }
547 // return x;
548 // }
550 internal Node Next(Node x)
553 if (x == null) {
554 return null;
557 Node r = x.Right;
559 if (r != null) {
560 x = r;
562 Node l = x.Left;
564 while (l != null) {
565 x = l;
566 l = x.Left;
569 return x;
572 Node ch = x;
574 x = x.Parent;
576 while (x != null && ch.Equals(x.Right)) {
578 ch = x;
579 x = x.Parent;
582 return x;
585 private Node Child(Node x, bool w)
587 return w ? x.Left
588 : x.Right;
591 private void Replace(Node x, Node n)
594 if (x.Equals(_root)) {
595 _root = n;
597 if (n != null) {
598 n.Parent = null;
601 else {
602 Set(x.Parent, x.From(), n);
606 private void Set(Node x, bool w, Node n)
608 if (w) {
609 x.Left = n;
611 else {
612 x.Right = n;
615 if (n != null) {
616 n.Parent = x;
620 private Node Search(DataRow r,DataRowVersion version)
623 Node x = _root;
625 while (x != null) {
626 int c = CompareRow(r, version, x.Row);
628 if (c == 0) {
629 return x;
631 else if (c < 0) {
632 x = x.Left;
634 else {
635 x = x.Right;
639 return null;
642 internal int ComparePartialRowNonUnique(int index1, int index2, int length)
644 int i = _columns[0].CompareValues(index1, index2);
646 if (i != 0) {
647 return i;
650 int fieldcount = _columns.Length;
652 for (int j = 1; j < length && j < fieldcount; j++) {
653 DataColumn column = _columns[j];
655 if (column.DataContainer.IsNull(index1)) {
656 continue;
659 i = column.CompareValues(index1, index2);
661 if (i != 0) {
662 return i;
666 return 0;
669 // private int CompareRowNonUnique(DataRow a, DataRow b)
670 // {
671 // if (a == b)
672 // return 0;
674 // int i = DataColumn.CompareValues(a[0], GetNodeValue(b,0), _columns[0].DataType, !_columns[0].Table.CaseSensitive);
676 // if (i != 0) {
677 // return i;
678 // }
680 // int fieldcount = _columns.Length;
682 // for (int j = 1; j < fieldcount; j++) {
683 // i = DataColumn.CompareValues(a[_columns[j].Ordinal], b[_columns[j].Ordinal], _columns[j].DataType, !_columns[j].Table.CaseSensitive);
685 // if (i != 0) {
686 // return i;
687 // }
688 // }
690 // return 0;
691 // }
693 private int CompareRow(DataRow a, DataRowVersion version, DataRow b)
695 // if (a == b)
696 // return 0;
698 int index1 = a.IndexFromVersion(version);
699 int index2 = b.IndexFromVersion(DataRowVersion.Current);
700 for (int j = 0; j < _columns.Length; j++) {
701 int i = _columns[j].DataContainer.CompareValues(index1, index2);
703 if (i != 0) {
704 return i;
708 return 0;
711 // private int CompareValue(Object a, Object b)
712 // {
713 // if (a == DBNull.Value) {
714 // if (b == DBNull.Value)
715 // return 0;
716 // return -1;
717 // }
719 // if (b == DBNull.Value)
720 // return 1;
722 // return System.Data.Common.DBComparerFactory.GetComparer(b.GetType(), false).Compare(a, b);
723 // }
725 // /// <summary>
726 // /// When we are inspectiong node (row) value in the index
727 // /// we are alway referencing its Current value
728 // /// </summary>
729 // private object GetNodeValue(DataRow row,DataColumn column)
730 // {
731 // return row[column,DataRowVersion.Current];
732 // }
734 // /// <summary>
735 // /// When we are inspectiong node (row) value in the index
736 // /// we are alway referencing its Current value
737 // /// </summary>
738 // private object GetNodeValue(DataRow row,index idx)
739 // {
740 // return row[idx,DataRowVersion.Current];
741 // }
743 // internal String GetString()
744 // {
745 // System.Text.StringBuilder sb = new System.Text.StringBuilder();
746 // for(int i =0; i < this._columns.Length; i++) {
747 // sb.Append("[ " + _columns[i].ColumnName + " ] ");
748 // }
749 // sb.Append("\n");
750 // if(this.Root != null) {
751 // this.Root.CollectString(sb,0);
752 // }
753 // return sb.ToString();
754 // }