Esempio n. 1
0
        static void Main(string[] args)
        {
            SDatabase  stbase  = new SDatabase();
            AsDatabase astbase = new AsDatabase();

            string choice; link1:

            Console.WriteLine("For new student type - 1");
            Console.WriteLine("For new aspirant- 2 ");
            Console.WriteLine("For information about Students-3");
            Console.WriteLine("For information about Aspirants-4");
            Console.WriteLine("For compare Students-5");
            Console.WriteLine("For compare Aspirants-6");
            Console.WriteLine("Type -end- to exit");
            choice = Console.ReadLine();

            switch (choice)
            {
            case "1":
                CreateStudent(); goto link1;
                break;

            case "2":
                CreateAspirant(); goto link1;
                break;

            case "3":
                CreateStudent(); goto link1;
                break;

            case "4":
                CreateAspirant(); goto link1;
                break;

            case "5":
                CreateStudent(); goto link1;
                break;

            case "6":
                CreateAspirant(); goto link1;
                break;

            case "end":

                break;

            default:
                Console.WriteLine("Choose from menu"); goto link1;
                break;
            }


            Console.ReadKey();
Esempio n. 2
0
            static string CreateStudent()
            {
                String    surname     = null;
                int       yearofstudy = 0;
                int       number      = 0;
                SDatabase stbase      = new SDatabase();
                int       n           = 0;//counter student
                string    choice      = "1";

                while (choice == "1")
                {
                    Console.WriteLine("type surname");
                    surname = Console.ReadLine();
                    Console.WriteLine("type study year");
                    yearofstudy = Convert.ToInt32(Console.ReadLine());
                    if (yearofstudy > 4)
                    {
                        Console.WriteLine("Study year for bachelors cant be more than 4"); yearofstudy = 4;
                    }
                    Console.WriteLine("type student number");
                    number    = Convert.ToInt32(Console.ReadLine());
                    stbase[n] = new StudentPerson(surname, yearofstudy, number);
                    n         = n + 1;
                    Console.WriteLine("For new student type - 1 \t  For new aspirant- 2 \t For Students information -3 \t For Aspirant information -4 \t For compare Students-5 \t For compare Aspirants-6 \t Type -end- to exit");
                    choice = Console.ReadLine();
                }
                while (choice == "3")
                {
                    Console.WriteLine("Enter index");
                    int m = Convert.ToInt32(Console.ReadLine());
                    stbase[m].Display();
                    Console.WriteLine("Object to string = " + stbase[m].ToString());
                    Console.WriteLine("Gethashcode = " + stbase[m].GetHashCode());
                    Console.WriteLine("GetType = " + stbase[m].GetType());
                    Console.WriteLine("For new student type - 1 \t Type - end - to exit \t For new aspirant- 2 \t For information -3 \t For Students information -4 \t For compare Students-5 \t For compare Aspirants-6 \t Type -end- to exit ");
                    choice = Console.ReadLine();
                }
                while (choice == "5")
                {
                    int a; int b; bool result;
                    Console.WriteLine("Type the 1st student index");
                    a = Convert.ToInt32(Console.ReadLine());
                    Console.WriteLine("Type the 2nd student index");
                    b = Convert.ToInt32(Console.ReadLine());
                    bool studentequal = stbase[a].Equals(stbase[b]);
                    Console.WriteLine("Onject equal" + studentequal);
                    Console.WriteLine("For new student type - 1 \t Type - end - to exit \t For new aspirant- 2 \t For information -3 \t For Students information -4 \t For compare Students-5 \t For compare Aspirants-6 \t Type -end- to exit ");
                    choice = Console.ReadLine();
                }
                return(choice);
            }
        public void Server()
        {
            // client.Blocking = false;
            // process the connection string
            asy = new ServerStream(client);
            var rdr = asy.rdr;
            var wtr = asy.wtr;
            int p   = -1;

            try
            {
                var fn = rdr.GetString();
                db = SDatabase.Open(path, fn);
                wtr.Write(Types.Done);
                wtr.PutLong(0);
                wtr.PutLong(0);
                asy.Flush();
            }
            catch (IOException)
            {
                asy.Close();
                return;
            }
            catch (Exception e)
            {
                try
                {
                    asy.StartException();
                    wtr.Write(Types.Exception);
                    wtr.PutString(e.Message);
                    asy.Flush();
                }
                catch (Exception) { }
                goto _return;
            }
            // start a Strong protocol service
            for (; ;)
            {
                p = -1;
                try
                {
                    p = rdr.ReadByte();
                } catch (Exception)
                {
                    p = -1;
                }
                if (p < 0)
                {
                    goto _return;
                }
                try
                {
                    //           Console.WriteLine("[" + cid + "] Start " + ((Types)p).ToString());
                    switch ((Types)p)
                    {
                    case Types.SNames:
                    {
                        var tr = db.Transact(rdr);
                        var us = db.uids;
                        for (var b = us.PositionAt(SysTable._SysUid); b != null && b.Value.Item1 < 0; b = b.Next())
                        {
                            us -= b.Value.Item1;
                        }
                        var n = rdr.GetInt();
                        for (var i = 0; i < n; i++)
                        {
                            var u = rdr.GetLong();
                            var s = rdr.GetString();
                            if (u < rdr.lastAlias)
                            {
                                rdr.lastAlias = u;
                            }
                            us += (u, s);
                        }
                        db = new STransaction(tr, new SRole(tr.role, us));
                        break;
                    }

                    case Types.DescribedGet:
                    case Types.Get:
                    {
                        var    tr = db.Transact(rdr);
                        SQuery?qy = null;
                        try
                        {
                            qy = rdr._Get() as SQuery;
                            tr = (STransaction)rdr.db;
                        } catch (Exception e)
                        {
                            rdr.buf.len = 0;
                            throw e;
                        }
                        if (qy == null)
                        {
                            throw new StrongException("Bad query");
                        }
                        qy = (SQuery)qy.Prepare(tr, qy.Names(tr, SDict <long, long> .Empty));
                        RowSet rs = qy.RowSet(tr, qy, Context.Empty);
                        var    sb = new StringBuilder("[");
                        var    cm = "";
                        for (var b = rs?.First(); b != null; b = b.Next())
                        {
                            if (((RowBookmark)b)._ob is SRow sr && sr.isValue)
                            {
                                sb.Append(cm); cm = ",";
                                sr.Append(rs._tr, sb);
                            }
                        }
                        sb.Append(']');
                        var ts = db.curpos;
                        (db, ts) = rs._tr.MaybeAutoCommit(cid);
                        wtr.Write(Types.Done);
                        wtr.PutLong(ts);
                        wtr.PutLong(db.curpos);
                        if ((Types)p == Types.DescribedGet)
                        {
                            var dp = rs._qry.Display;
                            wtr.PutInt(dp.Length ?? 0);
                            for (var b = dp.First(); b != null; b = b.Next())
                            {
                                wtr.PutString(b.Value.Item2.Item2);
                            }
                        }
                        wtr.PutString(sb.ToString());
                        asy.Flush();
                        break;
                    }

                    case Types.SCreateTable:
                    {
                        var tr = db.Transact(rdr);
                        var tn = db.role[rdr.GetLong()];        // table name
                        if (db.role.globalNames.Contains(tn))
                        {
                            throw new StrongException("Duplicate table name " + tn);
                        }
                        tr     = (STransaction)tr.Install(new STable(tr), tn, tr.curpos);
                        rdr.db = tr;
                        var n = rdr.GetInt();
                        for (var i = 0; i < n; i++)
                        {
                            CreateColumn(rdr);
                        }
                        n = rdr.GetInt();
                        for (var i = 0; i < n; i++)
                        {
                            rdr.ReadByte();
                            CreateIndex(rdr);
                        }
                        var ts = db.curpos;
                        (db, ts) = rdr.db.MaybeAutoCommit(cid);
                        wtr.Write(Types.Done);
                        wtr.PutLong(ts);
                        wtr.PutLong(db.curpos);
                        asy.Flush();
                        break;
                    }

                    case Types.SCreateColumn:
                    {
                        var tr = db.Transact(rdr);
                        rdr.db = tr;
                        CreateColumn(rdr);
                        var ts = db.curpos;
                        (db, ts) = rdr.db.MaybeAutoCommit(cid);
                        wtr.Write(Types.Done);
                        wtr.PutLong(ts);
                        wtr.PutLong(db.curpos);
                        asy.Flush();
                        break;
                    }

                    case Types.SInsert:
                    {
                        var tr = db.Transact(rdr);
                        var tn = tr.role[rdr.GetLong()];
                        if (!db.role.globalNames.Contains(tn))
                        {
                            throw new StrongException("Table " + tn + " not found");
                        }
                        var tb = (STable)db.objects[db.role.globalNames[tn]];
                        rdr.context = tb;
                        var n = rdr.GetInt();
                        var c = SList <long> .Empty;
                        for (var i = 0; i < n; i++)
                        {
                            c += (rdr.GetLong(), i);
                        }
                        var ins = new SInsert(tb.uid, c, rdr);
                        tr = ins.Prepare(tr, tb.Names(tr, SDict <long, long> .Empty)).Obey(tr, Context.Empty);
                        var ts = db.curpos;
                        (db, ts) = tr.MaybeAutoCommit(cid);
                        wtr.Write(Types.Done);
                        wtr.PutLong(ts);
                        wtr.PutLong(db.curpos);
                        asy.Flush();
                        break;
                    }

                    case Types.Insert:
                    {
                        var tr = db.Transact(rdr);
                        var tn = tr.role[rdr.GetLong()];
                        if (!db.role.globalNames.Contains(tn))
                        {
                            throw new StrongException("Table " + tn + " not found");
                        }
                        var tb = (STable)db.objects[db.role.globalNames[tn]];
                        rdr.context = tb;
                        var       n  = rdr.GetInt();  // # named cols
                        var       cs = SList <SColumn> .Empty;
                        Exception?ex = null;
                        for (var i = 0; i < n; i++)
                        {
                            var cn = db.role[rdr.GetLong()];
                            var ss = db.role.subs[tb.uid];
                            if (ss.defs.Contains(cn))
                            {
                                cs += ((SColumn)db.objects[ss.obs[ss.defs[cn]].Item1], i);
                            }
                            else
                            {
                                ex = new StrongException("Column " + cn + " not found");
                            }
                        }
                        var nc = rdr.GetInt();         // #cols
                        if ((n == 0 && nc != tb.cpos.Length) || (n != 0 && n != nc))
                        {
                            ex = new StrongException("Wrong number of columns");
                        }
                        var nr = rdr.GetInt();         // #records
                        for (var i = 0; i < nr; i++)
                        {
                            var f = SDict <long, Serialisable> .Empty;
                            if (n == 0)
                            {
                                for (var b = tb.cpos.First(); b != null; b = b.Next())
                                {
                                    if (b.Value.Item2 is SColumn sc)
                                    {
                                        f += (sc.uid, rdr._Get());
                                    }
                                }
                            }
                            else
                            {
                                for (var b = cs; b.Length != 0; b = b.next)
                                {
                                    f += (b.element.uid, rdr._Get());
                                }
                            }
                            tr = (STransaction)tr.Install(new SRecord(tr, tb.uid, f), tr.curpos);
                        }
                        if (ex != null)
                        {
                            throw ex;
                        }
                        var ts = db.curpos;
                        (db, ts) = tr.MaybeAutoCommit(cid);
                        wtr.Write(Types.Done);
                        wtr.PutLong(ts);
                        wtr.PutLong(db.curpos);
                        asy.Flush();
                        break;
                    }

                    case Types.SAlter:
                    {
                        var tr = db.Transact(asy.rdr);
                        rdr.db = tr;
                        var at = SAlter.Get(rdr);
                        tr = (STransaction)rdr.db;
                        tr = at.Prepare(tr, SDict <long, long> .Empty)
                             .Obey(tr, Context.Empty);
                        var ts = db.curpos;
                        (db, ts) = tr.MaybeAutoCommit(cid);
                        wtr.Write(Types.Done);
                        wtr.PutLong(ts);
                        wtr.PutLong(db.curpos);
                        asy.Flush();
                        break;
                    }

                    case Types.SDrop:
                    {
                        var tr = db.Transact(asy.rdr);
                        var dr = SDrop.Get(rdr).Prepare(tr, SDict <long, long> .Empty);
                        tr = dr.Obey(tr, Context.Empty);
                        var ts = db.curpos;
                        (db, ts) = tr.MaybeAutoCommit(cid);
                        wtr.Write(Types.Done);
                        wtr.PutLong(ts);
                        wtr.PutLong(db.curpos);
                        asy.Flush();
                        break;
                    }

                    case Types.SIndex:
                    {
                        var tr = db.Transact(asy.rdr);
                        rdr.db = tr;
                        CreateIndex(rdr);
                        var ts = db.curpos;
                        (db, ts) = rdr.db.MaybeAutoCommit(cid);
                        wtr.Write(Types.Done);
                        wtr.PutLong(ts);
                        wtr.PutLong(db.curpos);
                        asy.Flush();
                        break;
                    }

                    case Types.SDropIndex:
                    {
                        var tr = db.Transact(rdr);
                        rdr.db = tr;
                        var dr = new SDropIndex(rdr);
                        tr = (STransaction)rdr.db;
                        tr = dr.Prepare(tr, SDict <long, long> .Empty)
                             .Obey(tr, Context.Empty);
                        var ts = db.curpos;
                        (db, ts) = tr.MaybeAutoCommit(cid);
                        wtr.Write(Types.Done);
                        wtr.PutLong(ts);
                        wtr.PutLong(db.curpos);
                        asy.Flush();
                        break;
                    }

                    case Types.Read:
                    {
                        var id = rdr.GetLong();
                        var sb = new StringBuilder();
                        db.Get(id).Append(db, sb);
                        wtr.PutString(sb.ToString());
                        asy.Flush();
                        break;
                    }

                    case Types.SUpdateSearch:
                    {
                        var tr = db.Transact(rdr);
                        var u  = SUpdateSearch.Get(rdr);
                        tr = u.Prepare(tr, u.qry.Names(tr, SDict <long, long> .Empty)).Obey(tr, Context.Empty);
                        var ts = db.curpos;
                        (db, ts) = tr.MaybeAutoCommit(cid);
                        wtr.Write(Types.Done);
                        wtr.PutLong(ts);
                        wtr.PutLong(db.curpos);
                        asy.Flush();
                        break;
                    }

                    case Types.SUpdate:
                    {
                        var tr = db.Transact(rdr);
                        var id = rdr.GetLong();
                        var rc = db.Get(id);
                        var tb = (STable)tr.objects[rc.table];
                        var n  = rdr.GetInt();        // # cols updated
                        var f  = SDict <long, Serialisable> .Empty;
                        for (var i = 0; i < n; i++)
                        {
                            var cn = rdr.GetLong();
                            f += (cn, rdr._Get());
                        }
                        tr = (STransaction)tr.Install(new SUpdate(tr, rc, f), tr.curpos);
                        var ts = db.curpos;
                        (db, ts) = rdr.db.MaybeAutoCommit(cid);
                        wtr.Write(Types.Done);
                        wtr.PutLong(ts);
                        wtr.PutLong(db.curpos);
                        asy.Flush();
                        break;
                    }

                    case Types.SDeleteSearch:
                    {
                        var tr = db.Transact(rdr);
                        var dr = SDeleteSearch.Get(rdr);
                        tr = dr.Prepare(tr, dr.qry.Names(tr, SDict <long, long> .Empty)).Obey(tr, Context.Empty);
                        var ts = db.curpos;
                        (db, ts) = tr.MaybeAutoCommit(cid);
                        wtr.Write(Types.Done);
                        wtr.PutLong(ts);
                        wtr.PutLong(db.curpos);
                        asy.Flush();
                        break;
                    }

                    case Types.SDelete:
                    {
                        var tr = db.Transact(rdr);
                        var id = rdr.GetLong();
                        var rc = db.Get(id) as SRecord ??
                                 throw new StrongException("Record " + id + " not found");
                        tr = (STransaction)tr.Install(new SDelete(tr, rc), tr.curpos);
                        var ts = db.curpos;
                        (db, ts) = tr.MaybeAutoCommit(cid);
                        wtr.Write(Types.Done);
                        wtr.PutLong(ts);
                        wtr.PutLong(db.curpos);
                        asy.Flush();
                        break;
                    }

                    case Types.SBegin:
                        db = db.Transact(rdr, false);
                        wtr.Write(Types.Done);
                        wtr.PutLong(db.curpos);
                        wtr.PutLong(db.curpos);
                        asy.Flush();
                        break;

                    case Types.SRollback:
                        db = db.Rollback();
                        wtr.Write(Types.Done);
                        wtr.PutLong(db.curpos);
                        wtr.PutLong(db.curpos);
                        asy.Flush();
                        break;

                    case Types.SCommit:
                    {
                        var tr = db as STransaction ??
                                 throw new StrongException("No transaction to commit");
                        var ts = db.curpos;
                        (db, ts) = tr.Commit(cid);
                        wtr.Write(Types.Done);
                        wtr.PutLong(ts);
                        wtr.PutLong(db.curpos);
                        asy.Flush();
                        break;
                    }

                    default:
                        throw new StrongException("Protocol error");
                    }
                    //           Console.WriteLine("[" + cid + "] End " + ((Types)p).ToString());
                }
                catch (SocketException)
                {
                    return;
                }
                catch (StrongException e)
                {
                    try
                    {
                        db = db.Rollback();
                        //             db.result = null;
                        asy.StartException();
                        //             Console.WriteLine(""+cid+" Reporting Exception: " + e.Message);
                        wtr.Write(Types.Exception);
                        wtr.PutString(e.Message);
                        asy.Flush();
                    }
                    catch (Exception) { }
                }
                catch (Exception e)
                {
                    try
                    {
                        db = db.Rollback();
                        //             db.result = null;
                        asy.StartException();
                        //             Console.WriteLine(""+cid+" Reporting Exception: " + e.Message);
                        wtr.Write(Types.Exception);
                        wtr.PutString(e.Message);
                        asy.Flush();
                    }
                    catch (Exception) { }
                }
            }
            _return :;
        }
        public void Server()
        {
            // client.Blocking = false;
            // process the connection string
            asy = new ServerStream(client);
            var rdr = asy.rbuf;
            int p   = -1;

            try
            {
                var fn = rdr.GetString();
                db = SDatabase.Open(path, fn);
                asy.Write(Types.Done);
                asy.Flush();
            }
            catch (IOException)
            {
                asy.Close();
                return;
            }
            catch (Exception e)
            {
                try
                {
                    asy.StartException();
                    asy.Write(Types.Exception);
                    asy.PutString(e.Message);
                    asy.Flush();
                }
                catch (Exception) { }
                goto _return;
            }
            // start a Strong protocol service
            for (; ;)
            {
                p = -1;
                try
                {
                    p = rdr.ReadByte();
                } catch (Exception)
                {
                    p = -1;
                }
                if (p < 0)
                {
                    goto _return;
                }
                try
                {
                    switch ((Types)p)
                    {
                    case Types.DescribedGet:
                    case Types.Get:
                    {
                        var    tr = db.Transact();
                        SQuery?qy = null;
                        try
                        {
                            qy = rdr._Get(tr) as SQuery;
                        } catch (Exception e)
                        {
                            rdr.buf.len = 0;
                            throw e;
                        }
                        if (qy == null)
                        {
                            throw new Exception("Bad query");
                        }
                        RowSet rs = qy.RowSet(tr, qy, SDict <long, SFunction> .Empty, Context.Empty);
                        var    sb = new StringBuilder("[");
                        var    cm = "";
                        for (var b = rs?.First(); b != null; b = b.Next())
                        {
                            sb.Append(cm); cm = ",";
                            ((RowBookmark)b)._ob.Append(db, sb);
                        }
                        sb.Append(']');
                        db = db.MaybeAutoCommit(rs._tr);
                        asy.Write(Types.Done);
                        if ((Types)p == Types.DescribedGet)
                        {
                            asy.PutInt(rs._qry.Display.Length ?? 0);
                            for (var b = rs._qry.Display.First(); b != null; b = b.Next())
                            {
                                asy.PutString(b.Value.Item2);
                            }
                        }
                        asy.PutString(sb.ToString());
                        asy.Flush();
                        break;
                    }

                    case Types.SCreateTable:
                    {
                        var tr = db.Transact();
                        var tn = rdr.GetString();        // table name
                        if (tr.names.Contains(tn))
                        {
                            throw new Exception("Duplicate table name " + tn);
                        }
                        var tb = new STable(tr, tn);
                        tr = (STransaction)tr.Install(tb, tr.curpos);
                        var n = rdr.GetInt();         // #cols
                        for (var i = 0; i < n; i++)
                        {
                            var cn = rdr.GetString();         // column name
                            var dt = (Types)rdr.ReadByte();   // dataType
                            tr = (STransaction)tr.Install(new SColumn(tr, cn, dt, tb.uid), tr.curpos);
                        }
                        db = db.MaybeAutoCommit(tr);
                        asy.Write(Types.Done);
                        asy.Flush();
                        break;
                    }

                    case Types.SInsert:
                    {
                        var tr = db.Transact();
                        tr = SInsertStatement.Get(db, rdr).Obey(tr);
                        db = db.MaybeAutoCommit(tr);
                        asy.Write(Types.Done);
                        asy.Flush();
                        break;
                    }

                    case Types.Insert:
                    {
                        var       tr = db.Transact();
                        var       tb = (STable)tr.names.Lookup(rdr.GetString()); // table name
                        var       n  = rdr.GetInt();                             // # named cols
                        var       cs = SList <long> .Empty;
                        Exception?ex = null;
                        for (var i = 0; i < n; i++)
                        {
                            var cn = rdr.GetString();
                            if (tb.names.Lookup(cn) is SColumn sc)
                            {
                                cs += (sc.uid, i);
                            }
                            else
                            {
                                ex = new Exception("Column " + cn + " not found");
                            }
                        }
                        var nc = rdr.GetInt();         // #cols
                        if ((n == 0 && nc != tb.cpos.Length) || (n != 0 && n != nc))
                        {
                            throw new Exception("Wrong number of columns");
                        }
                        var nr = rdr.GetInt();         // #records
                        for (var i = 0; i < nr; i++)
                        {
                            var f = SDict <long, Serialisable> .Empty;
                            if (n == 0)
                            {
                                for (var b = tb.cpos.First(); b != null; b = b.Next())
                                {
                                    if (b.Value.Item2 is SColumn sc)
                                    {
                                        f += (sc.uid, rdr._Get(tr));         // serialisable values
                                    }
                                }
                            }
                            else
                            {
                                for (var b = cs; b.Length != 0; b = b.next)
                                {
                                    f += (b.element, rdr._Get(tr));         // serialisable values
                                }
                            }
                            tr = (STransaction)tr.Install(new SRecord(tr, tb.uid, f), tr.curpos);
                        }
                        if (ex != null)
                        {
                            throw ex;
                        }
                        db = db.MaybeAutoCommit(tr);
                        asy.Write(Types.Done);
                        asy.Flush();
                        break;
                    }

                    case Types.SAlter:
                    {
                        var tr = db.Transact();
                        var tn = rdr.GetString();         // table name
                        var tb = (STable)tr.names.Lookup(tn) ??
                                 throw new Exception("Table " + tn + " not found");
                        var cn = rdr.GetString();         // column name or ""
                        var nm = rdr.GetString();         // new name
                        if (cn.Length == 0)
                        {
                            tr = (STransaction)tr.Install(new SAlter(tr, nm, Types.STable, tb.uid, 0), tr.curpos);
                        }
                        else
                        {
                            tr = (STransaction)tr.Install(new SAlter(tr, nm, Types.SColumn, tb.uid,
                                                                     (tb.names.Lookup(cn) is SColumn sc) ? sc.uid :
                                                                     throw new Exception("Column " + cn + " not found")), tr.curpos);
                        }
                        db = db.MaybeAutoCommit(tr);
                        asy.Write(Types.Done);
                        asy.Flush();
                        break;
                    }

                    case Types.SDrop:
                    {
                        var tr = db.Transact();
                        var nm = rdr.GetString();         // object name
                        var pt = tr.names.Lookup(nm) ??
                                 throw new Exception("Object " + nm + " not found");
                        var cn = rdr.GetString();
                        tr = (STransaction)tr.Install(
                            (cn.Length == 0) ?
                            new SDrop(tr, pt.uid, -1) :
                            new SDrop(tr,
                                      (((STable)pt).names.Lookup(cn) is SColumn sc) ? sc.uid :
                                      throw new Exception("Column " + cn + " not found"),
                                      pt.uid), tr.curpos);
                        db = db.MaybeAutoCommit(tr);
                        asy.Write(Types.Done);
                        asy.Flush();
                        break;
                    }

                    case Types.SCreateIndex:
                    {
                        var tr = db.Transact();
                        var tn = rdr.GetString();         // table name
                        var tb = (STable)tr.names.Lookup(tn) ??
                                 throw new Exception("Table " + tn + " not found");
                        var xt = rdr.ReadByte();
                        var rn = rdr.GetString();
                        var ru = (rn.Length == 0)?-1: (tr.names.Lookup(rn)?.uid ??
                                                       throw new Exception("Table " + tn + " not found"));
                        var nc = rdr.GetInt();
                        var cs = SList <long> .Empty;
                        for (var i = 0; i < nc; i++)
                        {
                            var cn = rdr.GetString();
                            var se = (tb.names.Lookup(cn) is SColumn sc)? sc.uid :
                                     throw new Exception("Column " + cn + " not found");
                            cs += (se, i);
                        }
                        tr = (STransaction)tr.Install(new SIndex(tr, tb.uid, xt < 2, ru, cs), tr.curpos);
                        db = db.MaybeAutoCommit(tr);
                        asy.Write(Types.Done);
                        asy.Flush();
                        break;
                    }

                    case Types.Read:
                    {
                        var id = rdr.GetLong();
                        var sb = new StringBuilder();
                        db.Get(id).Append(db, sb);
                        asy.PutString(sb.ToString());
                        asy.Flush();
                        break;
                    }

                    case Types.SUpdateSearch:
                    {
                        var tr = db.Transact();
                        tr = SUpdateSearch.Get(db, rdr).Obey(tr, Context.Empty);
                        db = db.MaybeAutoCommit(tr);
                        asy.Write(Types.Done);
                        asy.Flush();
                        break;
                    }

                    case Types.SUpdate:
                    {
                        var tr = db.Transact();
                        var id = rdr.GetLong();
                        var rc = db.Get(id);
                        var tb = (STable)tr.objects[rc.table];
                        var n  = rdr.GetInt();        // # cols updated
                        var f  = SDict <string, Serialisable> .Empty;
                        for (var i = 0; i < n; i++)
                        {
                            var cn = rdr.GetString();
                            f += (cn, rdr._Get(db));
                        }
                        tr = (STransaction)tr.Install(new SUpdate(tr, rc, f), tr.curpos);
                        db = db.MaybeAutoCommit(tr);
                        asy.Write(Types.Done);
                        asy.Flush();
                        break;
                    }

                    case Types.SDeleteSearch:
                    {
                        var tr = db.Transact();
                        tr = SDeleteSearch.Get(db, rdr).Obey(tr, Context.Empty);
                        db = db.MaybeAutoCommit(tr);
                        asy.Write(Types.Done);
                        asy.Flush();
                        break;
                    }

                    case Types.SDelete:
                    {
                        var tr = db.Transact();
                        var id = rdr.GetLong();
                        var rc = db.Get(id) as SRecord ??
                                 throw new Exception("Record " + id + " not found");
                        tr = (STransaction)tr.Install(new SDelete(tr, rc.table, rc.uid), tr.curpos);
                        db = db.MaybeAutoCommit(tr);
                        asy.Write(Types.Done);
                        asy.Flush();
                        break;
                    }

                    case Types.SBegin:
                        db = new STransaction(db, false);
                        asy.WriteByte((byte)Types.Done);
                        asy.Flush();
                        break;

                    case Types.SRollback:
                        db = db.Rollback();
                        asy.WriteByte((byte)Types.Done);
                        asy.Flush();
                        break;

                    case Types.SCommit:
                    {
                        var tr = db as STransaction ??
                                 throw new Exception("No transaction to commit");
                        db = tr.Commit();
                        asy.WriteByte((byte)Types.Done);
                        asy.Flush();
                        break;
                    }

                    default:
                        throw new Exception("Protocol error");
                    }
                }
                catch (SocketException)
                {
                    return;
                }
                catch (Exception e)
                {
                    try
                    {
                        db = db.Rollback();
                        //             db.result = null;
                        asy.StartException();
                        asy.Write(Types.Exception);
                        asy.PutString(e.Message);
                        asy.Flush();
                    }
                    catch (Exception) { }
                }
            }
            _return :;
        }
        static void Main(string[] args)
        {
            // Tests for SList (unordered list)
            var sl = SList <string> .New("Red", "Blue", "Green");

            sl = sl.InsertAt("Yellow", 0);
            var s2 = sl;

            sl = sl.RemoveAt(3);
            sl = sl.UpdateAt("Pink", 1);
            sl = sl.InsertAt("Orange", 2);
            Check <string>(sl.ToArray(), "Yellow", "Pink", "Orange", "Blue");
            Check <string>(s2.ToArray(), "Yellow", "Red", "Blue", "Green");
            Console.WriteLine("SList done");
            // Tests for SArray
            var sa = new SArray <string>("Red", "Blue", "Green");

            sa = sa.InsertAt(0, "Yellow");
            sa = sa.RemoveAt(3);
            var sb = sa;

            sa = sa.InsertAt(2, "Orange", "Violet");
            Check(sa.ToArray(), "Yellow", "Red", "Orange", "Violet", "Blue");
            Check(sb.ToArray(), "Yellow", "Red", "Blue");
            Console.WriteLine("SArray done");
            // Tests for SSearchTree<string>
            var ss = SSearchTree <string> .New("InfraRed", "Red", "Orange", "Yellow", "Green", "Blue", "Violet");

            Check(ss.ToArray(), "Blue", "Green", "InfraRed", "Orange", "Red", "Violet", "Yellow");
            var si = SSearchTree <int> .New(56, 22, 24, 31, 23);

            Check(si.ToArray(), 22, 23, 24, 31, 56);
            Console.WriteLine("SSearchTree done");
            // Tests for SDict
            var sd = SDict <string, string> .Empty;

            sd = sd.Add("Y", "Yellow");
            sd = sd.Add("G", "Green");
            sd = sd.Add("B", "Blue");
            sd = sd.Remove("G");
            var sr = new string[sd.Count];
            var j  = 0;

            for (var b = sd.First(); b != null; b = b.Next())
            {
                sr[j++] = b.Value.key + ": " + b.Value.val;
            }
            Check(sr, "B: Blue", "Y: Yellow");
            Console.WriteLine("SDict done");
            // Tests for SMTree
            var ti = SList <TreeInfo> .Empty;

            ti = ti.InsertAt(new TreeInfo("0", 'D', 'D'), 0); // onDuplicate must be Disallow on all except last entry
            ti = ti.InsertAt(new TreeInfo("1", 'A', 'A'), 1);
            var sm   = new SMTree(ti);
            var test = new string[] { "BALTIM", "ANNU", "A", "ANNO", "BALTIC", "BRAIL" };

            for (var i = 0; i < test.Length; i++)
            {
                sm = Add(sm, test[i], i);
            }
            var sorted = new string[test.Length];

            j = 0;
            for (var b = sm.First(); b != null; b = b.Next())
            {
                sorted[j++] = test[((MTreeBookmark)b).value()];
            }
            // we are only sorting on the first two letters!
            // Check() we should offer some alternatives here
            Check(sorted, "A", "ANNU", "ANNO", "BALTIM", "BALTIC", "BRAIL");
            Console.WriteLine("SMTree done");
            File.Delete("strong");
            File.Create("strong").Close();
            var d  = SDatabase.Open("strong");
            var tr = new STransaction(d);

            tr = new STransaction(tr, new SString("This is Strong"));
            tr = new STransaction(tr, new STable(tr, "tbl"));
            var c = tr.Commit();

            d.Close();
            d = SDatabase.Open("strong");
            Console.WriteLine(d.objects.First().Value.val.ToString());
            Console.ReadKey();
        }