public static long ParseAlias(TextReader textreader)
        {
            return(SystemsDatabase.Instance.ExecuteWithDatabase(func: db =>
            {
                var cn = db.Connection;
                System.Diagnostics.Debug.WriteLine("Update aliases");

                long updates = 0;

                using (DbTransaction txn = cn.BeginTransaction())
                {
                    DbCommand selectCmd = null;
                    DbCommand deletesystemcmd = null;
                    DbCommand insertCmd = null;
                    try
                    {
                        selectCmd = cn.CreateSelect("Aliases", "edsmid", "edsmid = @edsmid", inparas: new string[] { "edsmid:int64" }, limit: "1", tx: txn);   // 1 return matching ID
                        deletesystemcmd = cn.CreateDelete("Systems", "edsmid=@edsmid", paras: new string[] { "edsmid:int64" }, tx: txn);
                        insertCmd = cn.CreateReplace("Aliases", paras: new string[] { "edsmid:int64", "edsmid_mergedto:int64", "name:string" }, tx: txn);

                        var parser = new BaseUtils.StringParserQuickTextReader(textreader, 32768);
                        var enumerator = JToken.ParseToken(parser, JToken.ParseOptions.None).GetEnumerator();

                        try
                        {       // protect against json exceptions
                            while (true)
                            {
                                if (!enumerator.MoveNext())
                                {
                                    break;
                                }

                                JToken t = enumerator.Current;

                                if (t.IsObject)
                                {
                                    enumerator.Load();          // load all objects associated with the entry
                                    JObject jo = t as JObject;

                                    long edsmid = jo["id"].Long();
                                    string name = jo["system"].Str("Default");
                                    string action = jo["action"].Str("NOP");
                                    long mergedto = 0;

                                    if (jo["mergedTo"] != null)
                                    {
                                        mergedto = jo["mergedTo"].Long();
                                    }

                                    if (action.Contains("delete system", System.StringComparison.InvariantCultureIgnoreCase))
                                    {
                                        deletesystemcmd.Parameters[0].Value = edsmid;
                                        deletesystemcmd.ExecuteNonQuery();
                                    }

                                    if (mergedto > 0)
                                    {
                                        selectCmd.Parameters[0].Value = edsmid;
                                        long foundedsmid = selectCmd.ExecuteScalar <long>(-1);

                                        if (foundedsmid == -1)
                                        {
                                            insertCmd.Parameters[0].Value = edsmid;
                                            insertCmd.Parameters[1].Value = mergedto;
                                            insertCmd.Parameters[2].Value = name;
                                            insertCmd.ExecuteNonQuery();
                                            //System.Diagnostics.Debug.WriteLine("Alias " + edsmid + " -> " + mergedto + " " + name);
                                            updates++;
                                        }
                                    }
                                }
                            }
                        }
                        catch (System.Exception ex)
                        {
                            System.Diagnostics.Debug.WriteLine("JSON format error in aliases " + ex);
                        }

                        txn.Commit();
                    }
                    finally
                    {
                        selectCmd.Dispose();
                        deletesystemcmd.Dispose();
                        insertCmd.Dispose();
                    }
                }

                return updates;
            }));
        }
        // set tempostfix to use another set of tables

        public static long ParseEDSMJSON(TextReader textreader,
                                         bool[] grididallowed,      // null = all, else grid bool value
                                         ref DateTime maxdate,      // updated with latest date
                                         Func <bool> cancelRequested,
                                         Action <string> reportProgress,
                                         string tablepostfix,            // set to add on text to table names to redirect to another table
                                         bool tablesareempty    = false, // set to presume table is empty, so we don't have to do look up queries
                                         string debugoutputfile = null
                                         )
        {
            var cache = new SectorCache();

            long updates = 0;

            int          nextsectorid = GetNextSectorID();
            StreamWriter sw           = null;

            try
            {
#if DEBUG
                try
                {
                    if (debugoutputfile != null)
                    {
                        sw = new StreamWriter(debugoutputfile);
                    }
                }
                catch
                {
                }
#endif
                var parser     = new BaseUtils.StringParserQuickTextReader(textreader, 32768);
                var enumerator = JToken.ParseToken(parser, JToken.ParseOptions.None).GetEnumerator();       // Parser may throw note

                while (true)
                {
                    if (cancelRequested())
                    {
                        updates = -1;
                        break;
                    }

                    int recordstostore = ProcessBlock(cache, enumerator, grididallowed, tablesareempty, tablepostfix, ref maxdate, ref nextsectorid, out bool jr_eof);

                    System.Diagnostics.Debug.WriteLine("Process " + BaseUtils.AppTicks.TickCountLap("L1") + "   " + updates);

                    if (recordstostore > 0)
                    {
                        updates += StoreNewEntries(cache, tablepostfix, sw);

                        reportProgress?.Invoke("EDSM Star database updated " + updates);
                    }

                    if (jr_eof)
                    {
                        break;
                    }

                    System.Threading.Thread.Sleep(20);      // just sleepy for a bit to let others use the db
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("Exception during EDSM parse " + ex);
            }
            finally
            {
                if (sw != null)
                {
                    sw.Close();
                }
            }

            System.Diagnostics.Debug.WriteLine("Process " + BaseUtils.AppTicks.TickCountLap("L1") + "   " + updates);
            reportProgress?.Invoke("EDSM Star database updated " + updates);

            PutNextSectorID(nextsectorid);    // and store back

            return(updates);
        }