// String and Binary handling. These are represented as a long, which is an offset into a file.
 
  public long EncodeString( string s ) 
  { 
    if ( s == "" ) return 0;
    // See if it is in SysStringIndex
    try
    {
      var start = new StringStart( s );
      foreach( IndexFileRecord ixr in SysStringIndex.From( start.Compare, false ) )
      {
        if ( (string)(ixr.Col[0]._O) == s ) return ixr.Col[0].L;
        break;
      }
    }
    catch ( System.Exception x )
    {
      SysStringIndex.Dump();
      throw x;
    }

    // Save to file.
    long sid = SysString.Length;
    SysString.Position = sid;
    SysStringWriter.Write( s );

    // Insert into the index
    IndexFileRecord r = new IndexFileRecord( 1 );
    r.Col[ 0 ].L = sid + 1;
    r.Col[ 0 ]._O = s;
    SysStringIndex.Insert( ref r );

    return sid + 1; // + 1 because zero indicates the encoding has not yet been done.
  }
        int Compare(ref IndexFileRecord r) // This make not be quite optimal for Less and Greater.
        {
            int cf = 0;

            if (Op <= Token.LessEqual) // Op == Token.Less || Op == Token.LessEqual
            {
                switch (Type)
                {
                case DataType.Binary:
                    cf = Util.Compare((byte[])V._O, (byte[])r.Col[0]._O);
                    if (cf == 0)
                    {
                        cf = +1;  // Should be -1 if Op == Less ?
                    }
                    break;

                case DataType.String:
                    cf = string.Compare((string)V._O, (string)r.Col[0]._O);
                    if (cf == 0)
                    {
                        cf = +1;  // Should be -1 if Op == Less ?
                    }
                    break;

                case DataType.Bigint:
                    cf = V.L < r.Col[0].L ? -1 : +1; // Should be <= if Op == Less ?
                    break;

                default: throw new System.Exception("Type error");
                }
            }
            else // ( Op == Token.Greater || Op == Token.GreaterEqual || Op == Token.Equal )
            {
                switch (Type)
                {
                case DataType.Binary:
                    cf = Util.Compare((byte[])V._O, (byte[])r.Col[0]._O);
                    if (cf == 0)
                    {
                        cf = -1;
                    }
                    break;

                case DataType.String:
                    cf = string.Compare((string)V._O, (string)r.Col[0]._O);
                    if (cf == 0)
                    {
                        cf = -1;
                    }
                    break;

                case DataType.Bigint:
                    cf = V.L <= r.Col[0].L ? -1 : +1;
                    break;

                default: throw new System.Exception("Type error");
                }
            }
            return(cf);
        }
 public IndexFileRecord Copy()
 {
   IndexFileRecord result = new IndexFileRecord( Col.Length );
   result.Child = Child;
   for ( int i=0; i<Col.Length; i += 1 ) result.Col[i] = Col[i];
   return result;
 }
        protected virtual void SetRecord(int x, ref IndexFileRecord r)
        {
            int off = NodeOverhead + NodeBase + x * NodeSize;

            for (int i = 0; i < ColStore; i += 1)
            {
                long     v = r.Col[i].L;
                DataType t = Inf.Types[i];
                if (t == DataType.String && v == 0)
                {
                    r.Col[i].L = Database.EncodeString((string)r.Col[i]._O);
                }
                else if (t == DataType.Binary && v == 0)
                {
                    r.Col[i].L = Database.EncodeBinary((byte[])r.Col[i]._O);
                }
                int size = DTI.Size(t);

                ulong p = (ulong)r.Col[i].L;
                if (t == DataType.Float)
                {
                    p = Conv.PackFloat(p);
                }

                Set(off, p, size);
                off += size;
            }
        }
예제 #5
0
        void Divide(IndexPage L, IndexPage R, ref IndexFileRecord div)
        {
            var r     = new IndexFileRecord();
            int count = Count / 2;

            foreach (int x in Nodes(Root))
            {
                GetRecord(x, ref r);;
                if (count > 0)
                {
                    L.Insert(ref r, true);
                }
                else
                {
                    if (count == 0)
                    {
                        div = r;
                        if (IsLeafPage())
                        {
                            R.Insert(ref div, true);
                        }
                    }
                    else
                    {
                        R.Insert(ref r, true);
                    }
                }
                count -= 1;
            }
        }
예제 #6
0
        protected int FindSplit(DCompare compare)
        {
            int             x      = Root;
            int             result = 0;
            IndexFileRecord r      = new IndexFileRecord();

            while (x != 0)
            {
                GetRecord(x, ref r);
                int c = compare(ref r);
                if (c < 0)
                {
                    x = GetLeft(x);
                }
                else if (c > 0)
                {
                    result = x;
                    x      = GetRight(x);
                }
                else // c == 0
                {
                    result = x;
                    break;
                }
            }
            return(result);
        }
예제 #7
0
        int Compare(int x, ref IndexFileRecord r)
        {
            IndexFileRecord y = new IndexFileRecord();

            GetRecord(x, ref y);
            return(Compare(ref r, ref y));
        }
예제 #8
0
        int Compare(int x, DCompare seek)
        {
            IndexFileRecord r = new IndexFileRecord();

            GetRecord(x, ref r);
            return(seek(ref r));
        }
예제 #9
0
        // Higher level operations ( indexes are updated as required ).

        public long Insert(Value [] row, int idCol)
        {
            long id;

            if (idCol < 0) // Id is not in INSERT list, allocate a new id.
            {
                id = ++RowCount;
            }
            else
            {
                id = row[idCol].L;
                if (RowCount < id)
                {
                    RowCount = id;
                }
            }
            Save(id, row, idCol >= 0);

            // Update indexes.
            foreach (G.KeyValuePair <long, IndexFile> p in IxDict)
            {
                IndexFile       ixf = p.Value;
                IndexFileRecord ixr = ixf.ExtractKey(row, id);
                ixf.Insert(ref ixr);
            }
            return(id);
        }
예제 #10
0
        // Methods to Insert, Remove records, enumerate Node Ids.

        void Insert(ref IndexFileRecord r, bool append) // Insert IndexFileRecord into the tree ( set append true if Records are pre-sorted )
        {
            bool h;

            Root  = Insert(Root, ref r, out h, append);
            Saved = false;
        }
예제 #11
0
        void Remove(ref IndexFileRecord r)
        {
            bool h;

            Root  = Remove(Root, ref r, out h);
            Saved = false;
        }
예제 #12
0
        protected int FindSplit(ref IndexFileRecord r)
        // Returns node id of the greatest IndexFileRecord less than or equal to v, or zero if no such node exists.
        {
            int x      = Root;
            int result = 0;

            while (x != 0)
            {
                int c = Compare(x, ref r);
                if (c < 0)
                {
                    x = GetLeft(x);
                }
                else if (c > 0)
                {
                    result = x;
                    x      = GetRight(x);
                }
                else // c == 0
                {
                    result = x;
                    break;
                }
            }
            return(result);
        }
예제 #13
0
 public IndexFileRecord ExtractKey( Value[] x, long id )
 {
   int n = Inf.BaseIx.Length;
   IndexFileRecord result = new IndexFileRecord( n + 1 );
   for ( int i = 0; i < n; i += 1 ) result.Col[ i ] = x[ Inf.BaseIx[ i ] ];
   result.Col[ n ].L = id;
   return result;
 }
예제 #14
0
        public override void LeafOp(IndexFile ixf, ref IndexFileRecord r, bool insert)
        {
            int       x       = FindSplit(ref r);
            long      childId = x == 0 ? FirstPage : GetChild(x);
            IndexPage cp      = ixf.GetPage(childId);

            cp.ParentId = PageId;
            cp.LeafOp(ixf, ref r, insert);
        }
예제 #15
0
        public virtual G.IEnumerable <IndexFileRecord> From(IndexFile ixf, DCompare seek, bool desc)
        {
            IndexFileRecord v = new IndexFileRecord();

            foreach (int x in From(seek, desc))
            {
                GetRecord(x, ref v);
                yield return(v);
            }
        }
예제 #16
0
 public void Delete(long id, Value[] dr)
 {
     Save(id, null, false);
     // Update indexes.
     foreach (G.KeyValuePair <long, IndexFile> p in IxDict)
     {
         IndexFile       ixf = p.Value;
         IndexFileRecord ixd = ixf.ExtractKey(dr, id);
         ixf.Delete(ref ixd);
     }
 }
예제 #17
0
 public virtual void LeafOp(IndexFile ixf, ref IndexFileRecord r, bool insert)
 {
     if (insert)
     {
         Insert(ixf, ref r);
     }
     else
     {
         Remove(ref r);
     }
 }
예제 #18
0
 public override void Dump(IndexFile ixf) // For debugging only
 {
     System.Console.WriteLine("Dump Parent Page, PageId=" + PageId + " First Page=" + FirstPage + " Count=" + Count + " NodeSize=" + NodeSize);
     ixf.GetPage(FirstPage).Dump(ixf);
     foreach (int x in Nodes(Root))
     {
         IndexFileRecord v = new IndexFileRecord();
         System.Console.WriteLine("Parent Node=" + x);
         GetRecord(x, ref v);
         System.Console.WriteLine("Parent Key=" + v.ToString(Inf));
         ixf.GetPage(GetChild(x)).Dump(ixf);
     }
     System.Console.WriteLine("End Dump Parent Page, PageId=" + PageId + " First Page=" + FirstPage + " Count=" + Count);
 }
예제 #19
0
        public virtual void Dump(IndexFile ixf) // For debugging.
        {
            System.Console.WriteLine("Page Dump PageId=" + PageId + " NodeSize=" + NodeSize + " MaxNode=" + MaxNode + " Count=" + Count + " Root=" + Root);
            CheckPage();
            IndexFileRecord r = new IndexFileRecord();

            foreach (int x in Nodes(Root))
            {
                GetRecord(x, ref r);
                System.Console.WriteLine("Record=" + r.ToString(ixf.Inf) + " Node=" + x + " Left=" + GetLeft(x) + " Right=" + GetRight(x)
                                         + " Balance=" + GetBalance(x));
            }
            System.Console.WriteLine("End Page Dump PageId=" + PageId + " NodeSize=" + NodeSize + " MaxNode=" + MaxNode + " Count=" + Count + " Root=" + Root);
        }
예제 #20
0
        // Record comparison - determines the order in which the Records are stored.

        public int Compare(ref IndexFileRecord r, ref IndexFileRecord y)
        {
            int cf = 0;

            for (int i = 0; i < Inf.KeyCount; i += 1)
            {
                cf = Util.Compare(r.Col[i], y.Col[i], Inf.Types[i]);
                if (cf != 0)
                {
                    break;
                }
            }
            return(cf);
        }
예제 #21
0
        int Compare(ref IndexFileRecord r) // This make not be quite optimal for Less and Greater.
        {
            int cf = Util.Compare(V, r.Col[0], Type);

            if (cf == 0)
            {
                if (Op <= Token.LessEqual) // Op == Token.Less || Op == Token.LessEqual
                {
                    cf = +1;               // Should be -1 if Op == Less ?
                }
                else // ( Op == Token.Greater || Op == Token.GreaterEqual || Op == Token.Equal )
                {
                    cf = -1;
                }
            }
            return(cf);
        }
예제 #22
0
        public bool Saved = false; // Indicates whether tree has been saved to disk.

        void Insert(IndexFile ixf, ref IndexFileRecord r)
        {
            if (Free == 0 && NodeAlloc == MaxNode) // Page is full, have to split it.
            {
                PageParent pp;
                if (this == ixf.Root)
                {
                    pp = new PageParent(Inf, null, Database);
                    ixf.AllocPageId(this);
                    pp.FirstPage   = PageId;
                    ixf.Root       = pp;
                    ixf.PageMap[0] = pp;
                }
                else
                {
                    pp = (PageParent)ixf.PageMap[ParentId];
                }

                IndexPage left = Clone();
                left.PageId         = PageId;
                left.FirstPage      = FirstPage;
                ixf.PageMap[PageId] = left;

                IndexPage right = Clone();
                ixf.AllocPageId(right);

                var div = new IndexFileRecord(); // IndexFileRecord that divides page into left/right, will be inserted into parent page.
                Divide(left, right, ref div);
                right.FirstPage = div.Child;
                div.Child       = right.PageId;
                pp.Insert(ixf, ref div);

                // Insert into either left or right depending on comparison with sv.
                (Compare(ref r, ref div) < 0 ? left : right).Insert(ref r, false);

                // Console.WriteLine( "Insert Split, NodeAlloc=" + NodeAlloc + " MaxNode=" + MaxNode + "ixf.PageAlloc=" + ixf.PageAlloc );
                // Console.WriteLine( "Split div=" + div.ToString(ixf.Inf) );
                // ixf.Dump();
            }
            else
            {
                Insert(ref r, false);
            }
        }
        protected virtual void GetRecord(int x, ref IndexFileRecord r)
        {
            if (r.Col == null)
            {
                r.Col = new Value[ColStore];
            }
            int off = NodeOverhead + NodeBase + x * NodeSize;

            for (int i = 0; i < ColStore; i += 1)
            {
                DataType t    = Inf.Types[i];
                int      size = DTI.Size(t);
                ulong    u    = Get(off, size);
                off += size;

                if (t == DataType.Float)
                {
                    u = Conv.UnpackFloat((uint)u);
                }
                else if (t == DataType.Int)
                {
                    u = (ulong)(long)(int)(uint)u;
                }
                else if (t == DataType.Smallint)
                {
                    u = (ulong)(long)(short)(ushort)u;
                }
                else if (t == DataType.Tinyint)
                {
                    u = (ulong)(long)(sbyte)(byte)u;
                }

                r.Col[i].L = (long)u;
                if (t == DataType.String)
                {
                    r.Col[i]._O = Database.DecodeString((long)u);
                }
                else if (t == DataType.Binary)
                {
                    r.Col[i]._O = Database.DecodeBinary((long)u);
                }
            }
        }
예제 #24
0
        public void Update(long id, Value[] dr, Value [] nr)
        {
            Save(id, nr, false);

            // Update indexes.
            foreach (G.KeyValuePair <long, IndexFile> p in IxDict)
            {
                IndexFile ixf = p.Value;

                IndexFileRecord ixd = ixf.ExtractKey(dr, id);
                IndexFileRecord ixn = ixf.ExtractKey(nr, id);

                // Check if new and old keys are the same to save work.
                if (ixf.Root.Compare(ref ixd, ref ixn) != 0)
                {
                    ixf.Delete(ref ixd);
                    ixf.Insert(ref ixn);
                }
            }
        }
예제 #25
0
        protected virtual void GetRecord(int x, ref IndexFileRecord r)
        {
            if (r.Col == null)
            {
                r.Col = new Value[ColStore];
            }
            int off = NodeOverhead + NodeBase + x * NodeSize;

            for (int i = 0; i < ColStore; i += 1)
            {
                DataType t    = Inf.Types[i];
                int      size = DTI.Size(t);
                long     v    = Util.Get(Data, off, size, t);
                off       += size;
                r.Col[i].L = v;
                if (t <= DataType.String)
                {
                    r.Col[i]._O = Database.Decode(v, t);
                }
            }
        }
예제 #26
0
        // Functions related to Indexing.

        public void InitIndex(long indexId) // Called during CREATE INDEX to index existing rows.
        {
            IndexFile       ixf = IxDict[indexId];
            var             rc  = new RowCursor(this);
            int             n   = ixf.Inf.BaseIx.Length;
            IndexFileRecord ixr = new IndexFileRecord(n + 1);

            for (long id = 1; id <= RowCount; id += 1)
            {
                if (rc.Get(id))
                {
                    // Create the IndexFileRecord to be inserted.
                    for (int i = 0; i < n; i += 1)
                    {
                        ixr.Col[i] = rc.V[ixf.Inf.BaseIx[i]];
                    }
                    ixr.Col[n].L = id; // Append the id of the row.
                    ixf.Insert(ref ixr);
                }
            }
            Dirty = true;
        }
  public long EncodeBinary( byte [] data ) 
  { 
    if ( data.Length == 0 ) return 0;
    // See if it is in SysBinaryIndex
    var start = new BinaryStart( data );
    foreach( IndexFileRecord ixr in SysBinaryIndex.From( start.Compare, false ) )
    {
      if ( Util.Compare( (byte[])(ixr.Col[0]._O), data ) == 0 ) return ixr.Col[0].L;
      break;
    }

    // Save to file.
    long sid = SysBinary.Length;
    SysBinary.Position = sid;
    SysBinaryWriter.WriteBytes( data );

    // Insert into the index
    IndexFileRecord r = new IndexFileRecord( 1 );
    r.Col[ 0 ].L = sid + 1;
    r.Col[ 0 ]._O = data;
    SysBinaryIndex.Insert( ref r );
    return sid + 1; // + 1 because zero means the encoding has not yet been done.
  }
예제 #28
0
        protected virtual void SetRecord(int x, ref IndexFileRecord r)
        {
            int off = NodeOverhead + NodeBase + x * NodeSize;

            for (int i = 0; i < ColStore; i += 1)
            {
                DataType t = Inf.Types[i];
                if (t <= DataType.String && r.Col[i].L == 0)
                {
                    r.Col[i].L = Database.Encode(r.Col[i]._O, t);
                }
                int size = DTI.Size(t);

                long p = r.Col[i].L;
                if (t == DataType.Float)
                {
                    p = Conv.PackFloat(p);
                }

                Set(off, (ulong)p, size);
                off += size;
            }
        }
예제 #29
0
        public int Compare(ref IndexFileRecord r)
        {
            int cf = Util.Compare(K, (byte[])r.Col[0]._O);

            return(cf == 0 ? -1 : cf);
        }
예제 #30
0
        public int Compare(ref IndexFileRecord r)
        {
            int cf = string.Compare(K, (string)r.Col[0]._O);

            return(cf == 0 ? -1 : cf);
        }