Make versaplexd unit tests pass with new ReadArray<T> stuff.
[versaplex.git] / versaplexd / vxcli.cs
blob760e431c1b825ac354f46640b37f8091ff23b4f2
1 using System;
2 using System.Collections.Generic;
3 using System.Data;
4 using System.Data.Common;
5 using System.IO;
6 using System.Linq;
7 using Wv.Mono.Terminal;
8 using Wv;
9 using Wv.Extensions;
11 namespace Wv
13 public class VxDbException : DbException
15 public VxDbException(string msg) : base(msg)
20 [WvMoniker]
21 public class WvDbi_Versaplex : WvDbi
23 Bus bus;
25 struct ColInfo
27 public int size;
28 public string name;
29 public string type;
30 public short precision;
31 public short scale;
32 public byte nullable;
35 struct Stupid
37 public string s;
40 public static void wvmoniker_register()
42 WvMoniker<WvDbi>.register("vx",
43 (string m, object o) => new WvDbi_Versaplex());
46 public WvDbi_Versaplex()
48 if (Address.Session == null)
49 throw new Exception ("DBUS_SESSION_BUS_ADDRESS not set");
50 AddressEntry aent = AddressEntry.Parse(Address.Session);
51 DodgyTransport trans = new DodgyTransport();
52 trans.Open(aent);
53 bus = new Bus(trans);
56 public override WvSqlRows select(string sql, params object[] args)
58 Message call
59 = VxDbusUtils.CreateMethodCall(bus, "ExecRecordset", "s");
60 MessageWriter writer
61 = new MessageWriter(Connection.NativeEndianness);
63 writer.Write(typeof(string), sql);
64 call.Body = writer.ToArray();
66 log.print("Sending!\n");
68 Message reply = call.Connection.SendWithReplyAndBlock(call);
70 log.print("Answer came back!\n");
72 switch (reply.Header.MessageType)
74 case MessageType.MethodReturn:
75 case MessageType.Error:
77 object replysig;
78 if (!reply.Header.Fields.TryGetValue(FieldCode.Signature,
79 out replysig))
80 throw new Exception("D-Bus reply had no signature.");
82 if (replysig == null)
83 throw new Exception("D-Bus reply had null signature");
85 MessageReader reader = new MessageReader(reply);
87 // Some unexpected error
88 if (replysig.ToString() == "s")
89 throw new VxDbException(reader.ReadString());
91 if (replysig.ToString() != "a(issnny)vaay")
92 throw new
93 Exception("D-Bus reply had invalid signature: " +
94 replysig);
96 // decode the raw column info
97 ColInfo[] x = reader.ReadArray<ColInfo>();
98 WvColInfo[] colinfo
99 = (from c in x
100 select new WvColInfo(c.name, typeof(string),
101 (c.nullable & 1) != 0,
102 c.size, c.precision, c.scale))
103 .ToArray();
105 Signature sig = reader.ReadSignature();
106 log.print("Variant signature: '{0}'\n", sig);
108 WvSqlRow[] rows;
109 if (sig.ToString() == "a(s)")
111 Stupid[] a = reader.ReadArray<Stupid>();
112 rows = (from r in a
113 select new WvSqlRow(new object[] { r.s },
114 colinfo))
115 .ToArray();
117 else
118 rows = new WvSqlRow[0];
120 return new WvSqlRows_Versaplex(rows, colinfo);
122 default:
123 throw new Exception("D-Bus response was not a method "
124 + "return or error");
128 public override int execute(string sql, params object[] args)
130 using (select(sql, args))
131 return 0;
135 class WvSqlRows_Versaplex : WvSqlRows, IEnumerable<WvSqlRow>
137 WvSqlRow[] rows;
138 WvColInfo[] schema;
140 public WvSqlRows_Versaplex(WvSqlRow[] rows, WvColInfo[] schema)
142 this.rows = rows;
143 this.schema = schema;
146 public override IEnumerable<WvColInfo> columns
147 { get { return schema; } }
149 public override IEnumerator<WvSqlRow> GetEnumerator()
151 foreach (var row in rows)
152 yield return row;
157 public static class VxCli
159 public static int Main(string[] args)
161 WvLog.maxlevel = WvLog.L.Debug;
162 WvLog log = new WvLog("vxcli");
164 if (args.Length != 1)
166 Console.Error.WriteLine("Usage: vxcli <db-connection-string>");
167 return 1;
170 string moniker = args[0];
172 WvIni vxini = new WvIni("versaplexd.ini");
173 if (vxini.get("Connections", moniker) != null)
174 moniker = vxini.get("Connections", moniker);
176 WvIni bookmarks = new WvIni(
177 wv.PathCombine(wv.getenv("HOME"), ".wvdbi.ini"));
178 if (!moniker.Contains(":")
179 && bookmarks["Bookmarks"].ContainsKey(moniker))
181 moniker = bookmarks["Bookmarks"][moniker];
183 else
185 // not found in existing bookmarks, so see if we can parse and
186 // save instead.
187 WvUrl url = new WvUrl(moniker);
188 string path = url.path;
189 if (path.StartsWith("/"))
190 path = path.Substring(1);
191 if (path != "" && url.host != null)
193 log.print("Creating bookmark '{0}'\n", path);
194 bookmarks.set("Bookmarks", path, moniker);
195 try {
196 bookmarks.save();
197 } catch (IOException) {
198 // not a big deal if we can't save our bookmarks.
203 using (var dbi = WvDbi.create(moniker))
205 LineEditor le = new LineEditor("VxCli");
206 string inp;
208 while (true)
210 Console.WriteLine();
211 inp = le.Edit("vx> ", "");
212 if (inp == null) break;
213 if (inp == "") continue;
216 using (var result = dbi.select(inp))
218 var colnames =
219 from c in result.columns
220 select c.name.ToUpper();
221 Console.Write(wv.fmt("{0}\n\n",
222 colnames.Join(",")));
224 foreach (var row in result)
225 Console.Write(wv.fmt("{0}\n", row.Join(",")));
228 catch (DbException e)
230 Console.Write(wv.fmt("ERROR: {0}\n", e.Short()));
235 return 0;