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 :; }
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 :; }
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(); }