예제 #1
0
        // Invoke a defined function with required argument in scope
        // If folded, applies an offset to get the right accumulator
        public TypedValue Invoke(CodeValue funcarg, PointerValue accblkarg, NumberValue accbasarg, TypedValue[] valargs)
        {
            Logger.WriteLine(3, "Invoke {0} accbase={1} ({2})", funcarg, accbasarg, String.Join(",", valargs.Select(a => a.ToString()).ToArray()));

            // wrap raw value with evaluator
            var expr = funcarg.Value as ExpressionEval;

            Logger.Assert(expr != null, "invoke eval");
            var        args = DataRow.CreateNonTuple(expr.Lookup, valargs);
            TypedValue ret;

            if (expr.HasFold)
            {
                var accblk  = accblkarg.Value as AccumulatorBlock;
                var accbase = (int)accbasarg.Value;
                ret = expr.EvalHasFold(args, accblk, accbase);
            }
            else
            {
                ret = expr.EvalOpen(args);
            }

            // If the return value is an unresolved sql table then resolve it now
            // before exiting the lookup scope (which it may need)
            if (ret is RelationValue && !(ret.AsTable() is DataTableLocal))
            {
                ret = RelationValue.Create(DataTableLocal.Convert(ret.AsTable(), args, expr.Evaluator));
            }
            Logger.WriteLine(3, "[Inv {0}]", ret);
            return(ret);
        }
예제 #2
0
        // Antijoin via hash index and project onto given header
        DataTableLocal GeneralisedAntijoin(DataTableLocal other, DataHeading newheading, DataHeading joinhdng)
        {
            Logger.WriteLine(4, "GenAntijoin L={0} R={1} new={2} j={3}", this.Heading, other.Heading, newheading, joinhdng);

            // Build a dictionary on other
            var odict = new Dictionary <DataRow, int>();

            BuildIndex(other, joinhdng, odict);

            // Build each new row based on join heading and if it's not in the odict
            // add row based on newheading to the new table
            var cmpndx   = joinhdng.MakeIndex(Heading);
            var movndx   = newheading.MakeIndex(Heading);
            var newtable = DataTableLocal.Create(newheading);

            foreach (var row in this.GetRows()) //TODO:Enumerable
            {
                var newrow = row.Project(joinhdng, cmpndx);
                if (!odict.ContainsKey(newrow))
                {
                    newtable.AddRow(row.Project(newheading, movndx));
                }
            }
            Logger.WriteLine(4, "[Antijoin={0}]", newtable);
            return(newtable);
        }
예제 #3
0
        public override DataTable Read(string file, DataHeading heading)
        {
            var path = GetPath(file);

            if (!File.Exists(path))
            {
                return(null);
            }
            var table = DataTableLocal.Create(heading);

            using (var rdr = new TextFieldParser(path)
            {
                TextFieldType = FieldType.Delimited,
                Delimiters = new string[] { "," },
            }) {
                for (var id = 0; !rdr.EndOfData; ++id)
                {
                    var row = rdr.ReadFields();
                    if (id > 0)
                    {
                        if (_hasid)
                        {
                            row = (new string[] { id.ToString() })
                                  .Concat(row).ToArray();
                        }
                        try {
                            table.AddRow(row);
                        } catch (Exception ex) {
                            throw ProgramError.Fatal("Source Csv", "Error in row {0} of {1}: {2}", id, path, ex.Message);
                        }
                    }
                }
            }
            return(table);
        }
예제 #4
0
        // Create a Table by converting a value
        // Each row has its own heading, which must match.
        public RelationValue TableC(HeadingValue hdgarg, params TypedValue[] valueargs)
        {
            Logger.Assert(valueargs.Length == 1, "TableC");
            var       heading  = hdgarg.AsHeading();
            var       value    = valueargs[0];
            DataTable newtable = null;

            if (value.DataType is DataTypeTuple)
            {
                newtable = DataTableLocal.Create(heading, new DataRow[] {
                    value.AsRow()
                });
            }
            else if (value.DataType is DataTypeUser)
            {
                var user = value as UserValue;
                newtable = DataTableLocal.Create(heading, new DataRow[] {
                    DataRow.Create(heading, user.Value)
                });
            }
            else if (value.DataType is DataTypeRelation)
            {
                newtable = value.AsTable();
            }
            Logger.Assert(newtable != null, "TableC");
            Logger.WriteLine(3, "[Table={0}]", newtable);
            return(RelationValue.Create(newtable));
        }
예제 #5
0
        // natural join
        private DataTableLocal Join(DataTableLocal other)
        {
            var newtable = GeneralisedJoin(other, Heading.Union(other.Heading), Heading.Intersect(other.Heading));

            Logger.WriteLine(4, "[Join={0}]", newtable);
            return(newtable);
        }
예제 #6
0
        // factories -------------------------------------------------------

        // Create new empty table
        public new static DataTableLocal Create(DataHeading heading)
        {
            DataTableLocal newtable = new DataTableLocal()
            {
                DataType = DataTypeRelation.Get(heading),
            };

            return(newtable);
        }
예제 #7
0
        // Build index on key
        // Note: keys overwrite so only last one left
        // TODO: index with duplicates for join
        void BuildIndex(DataTableLocal table, DataHeading keyhdg, Dictionary <DataRow, int> dict)
        {
            var ndx = keyhdg.MakeIndex(table.Heading);

            foreach (var row in table.GetRows())
            {
                var values = Enumerable.Range(0, keyhdg.Degree).Select(x => row.Values[ndx[x]]).ToArray();
                dict[DataRow.Create(keyhdg, values)] = row.Order;
            }
        }
예제 #8
0
        // Create new table and add tuples to it
        public new static DataTableLocal Create(DataHeading heading, IEnumerable <ExpressionEval> texprs)
        {
            DataTableLocal newtable = DataTableLocal.Create(heading);

            foreach (var expr in texprs)
            {
                newtable.AddRow(expr.Evaluate().AsRow());
            }
            return(newtable);
        }
예제 #9
0
        // Create new table as a copy (the other might be a different kind)
        public new static DataTableLocal Create(DataHeading heading, IEnumerable <DataRow> rows)
        {
            DataTableLocal newtable = DataTableLocal.Create(heading);

            foreach (var row in rows)
            {
                newtable.AddRow(row);
            }
            return(newtable);
        }
예제 #10
0
        public void SetListEnd()
        {
            Logger.Assert(_valueholder.DataType is DataTypeRelation);
            var datatype = _valueholder.DataType;
            var rows     = _valueholder._list.Select(t => DataRow.Create(_valueholder.DataType.Heading, t));
            var table    = DataTableLocal.Create(_valueholder.DataType.Heading, rows);

            _valueholder._values[_valueholder._colidx] = RelationValue.Create(table);
            _valueholder._list = null;
        }
예제 #11
0
        public override DataTable Read(string file, DataHeading heading)
        {
            var newtable = DataTableLocal.Create(heading);

            Console.WriteLine(file);
            var line = Console.ReadLine();

            newtable.AddRow(DataRow.Create(heading, line));
            return(newtable);
        }
예제 #12
0
        // Generalised Set via naive cross product
        // Handles all cases, projecting onto common heading, not necessarily optimal
        DataTableLocal GeneralisedSet(DataTableLocal other, DataHeading newheading, JoinOps joinops)
        {
            Logger.WriteLine(4, "GenSet L={0} R={1} new={2} j={3}", this.Heading, other.Heading, newheading, joinops);

            var ldict = new Dictionary <DataRow, int>();
            var rdict = new Dictionary <DataRow, int>();

            switch (joinops)
            {
            case JoinOps.MINUS:
            case JoinOps.INTERSECT:
                BuildIndex(other, newheading, rdict);
                break;

            case JoinOps.SYMDIFF:
                BuildIndex(this, newheading, ldict);
                BuildIndex(other, newheading, rdict);
                break;
            }

            var newtable = DataTableLocal.Create(newheading);

            if (joinops == JoinOps.UNION || rdict.Count > 0)
            {
                var lmovndx = newheading.MakeIndex(Heading);
                foreach (var row in this.GetRows()) //TODO:Enumerable
                {
                    var newrow = row.Project(newheading, lmovndx);
                    var ok     = (joinops == JoinOps.MINUS || joinops == JoinOps.SYMDIFF) ? !rdict.ContainsKey(newrow)
            : (joinops == JoinOps.INTERSECT) ? rdict.ContainsKey(newrow)
            : true;
                    if (ok)
                    {
                        newtable.AddRow(newrow);
                    }
                }
            }
            if (joinops == JoinOps.UNION || ldict.Count > 0)
            {
                var rmovndx = newheading.MakeIndex(other.Heading);
                foreach (var row in other.GetRows()) //TODO:Enumerable
                {
                    var newrow = row.Project(newheading, rmovndx);
                    var ok     = (joinops == JoinOps.SYMDIFF) ? !ldict.ContainsKey(newrow)
            : true;
                    if (ok)
                    {
                        newtable.AddRow(newrow);
                    }
                }
            }
            Logger.WriteLine(4, "[GenSet={0}]", newtable);
            return(newtable);
        }
예제 #13
0
        // relation representing heading
        public RelationValue Schema(RelationValue relarg)
        {
            var heading = DataHeading.Create("Name:text", "Type:text");
            var table   = DataTableLocal.Create(heading);

            foreach (var col in relarg.Value.Heading.Columns)
            {
                table.AddRow(DataRow.Create(heading, col.Name, col.DataType.Name));
            }
            return(RelationValue.Create(table));
        }
예제 #14
0
        void Write(DataTable table)
        {
            var tbl = DataTableLocal.Convert(table);

            //Write(Persist.RelationSignature);
            Write(tbl.Cardinality);
            foreach (var row in tbl.GetRows())
            {
                Write(row);
            }
        }
예제 #15
0
        // note that the heading implies the order of values -- which is critical!

        // read a table -- heading already known
        DataTable ReadTable(DataHeading heading)
        {
            //Logger.Assert(_reader.ReadInt32() == Persist.RelationSignature);
            var table       = DataTableLocal.Create(heading);
            var cardinality = _reader.ReadInt32();

            while (cardinality-- > 0)
            {
                table.AddRow(ReadRow(heading));
            }
            return(table);
        }
예제 #16
0
        // Project onto named columns
        public override DataTable Project(ExpressionEval[] exprs)
        {
            var newheading = DataHeading.Create(exprs);
            var newtable   = DataTableLocal.Create(newheading);
            var newexprs   = newtable.Heading.Reorder(exprs);

            foreach (var row in GetRows()) //TODO:Enumerable
            {
                newtable.AddRow(row.Transform(newheading, newexprs));
            }
            Logger.WriteLine(4, "[Project={0}]", newtable);
            return(newtable);
        }
예제 #17
0
        // sequence of integers
        public RelationValue Sequence(NumberValue countarg)
        {
            var heading = DataHeading.Create("N:number");
            var table   = DataTableLocal.Create(heading);
            var n       = Decimal.Zero;
            var count   = (int)countarg.Value;

            for (var i = 0; i < count; ++i)
            {
                table.AddRow(DataRow.Create(heading, new TypedValue[] { NumberValue.Create(n) }));
                n += 1;
            }
            return(RelationValue.Create(table));
        }
예제 #18
0
        // Transform -- new table containing new columns generated by expressions
        public override DataTable Transform(DataHeading newheading, ExpressionEval[] exprs)
        {
            Logger.WriteLine(4, "Transform {0} exprs={1}", newheading, exprs.Count());
            Logger.Assert(exprs.Count() == newheading.Degree, "degree");
            var newtable = DataTableLocal.Create(newheading);
            var newexprs = newtable.Heading.Reorder(exprs);

            foreach (var row in GetRows()) //TODO:Enumerable
            {
                newtable.AddRow(row.Transform(newheading, newexprs));
            }
            Logger.WriteLine(4, "[{0}]", newtable);
            return(newtable);
        }
예제 #19
0
        // Take -- take some rows, discard the rest
        public override DataTable Take(NumberValue value)
        {
            var newtable = DataTableLocal.Create(Heading);
            var count    = value.Value;

            foreach (var row in GetRows()) //TODO:Enumerable
            {
                if (count-- > 0)
                {
                    newtable.AddRow(row);
                }
            }
            return(newtable);
        }
예제 #20
0
        // Restrict -- new table containing rows that pass the test
        public override DataTable Restrict(ExpressionEval expr)
        {
            var newtable = DataTableLocal.Create(Heading);

            foreach (var row in GetRows()) //TODO:Enumerable
            {
                if (expr.EvalPred(row).Value)
                {
                    newtable.AddRow(row);
                }
            }
            Logger.WriteLine(4, "Restrict {0}", newtable);
            return(newtable);
        }
예제 #21
0
        // Transform with ordered calculations - different algorithm
        // 1. Build index
        // 2. Read input file using index
        // 3. Transform and write output file
        public override DataTable TransformOrdered(DataHeading newheading, ExpressionEval[] exprs, ExpressionEval[] orderexps)
        {
            Logger.WriteLine(4, "TransformOrdered {0} exprs={1},{2}", newheading, exprs.Count(), orderexps.Count());

            var numacc   = exprs.Where(e => e.HasFold).Sum(e => e.AccumCount);
            var newtable = DataTableLocal.Create(newheading);
            var newexprs = newtable.Heading.Reorder(exprs);
            var ordidx   = OrderedIndex.Create(orderexps, Heading);
            // list of indexes of not-folded columns
            var notfold = exprs.Where(e => !e.HasFold)
                          .Select(e => newheading.FindIndex(e.Name)).ToArray();

            // Build index
            for (var ord = 0; ord < Cardinality; ++ord) //TODO:Enumerable
            {
                ordidx.Add(GetRow(ord), ord);
            }
            AccumulatorBlock accblk = null;

            // Read in index order, with access to ordering info
            DataRow lastrow = null;

            foreach (var ord in ordidx.RowOrdinals)
            {
                var oldrow = _rows[ord];
                oldrow.OrderedIndex = ordidx; // so row functions can access it
                // if there is a group break, reset the accumulators
                if (ordidx.IsBreak)
                {
                    accblk = AccumulatorBlock.Create(numacc);
                }
                DataRow newrow = oldrow.TransformAggregate(newheading, accblk, newexprs);

                // save the current row, output it on group break or when any non-fold column has changed
                // any rows not output will have identical non-fold cols so only running sums are lost
                var nfchg = (lastrow != null && !notfold.All(x => newrow.Values[x].Equals(lastrow.Values[x])));
                if (nfchg || (lastrow != null && ordidx.IsBreak))
                {
                    newtable.AddRaw(lastrow);
                }
                lastrow = newrow; // guaranteed to be different!
            }
            if (lastrow != null)
            {
                newtable.AddRaw(lastrow);
            }
            Logger.WriteLine(4, "[{0}]", newtable);
            return(newtable);
        }
예제 #22
0
        // add rows in this if there is a match in the other on join columns
        private DataTableLocal Semijoin(DataTableLocal other)
        {
            var cmpndx   = other.Heading.MakeIndex(Heading);
            var newtable = DataTableLocal.Create(Heading);

            foreach (var row in GetRows()) //TODO:Enumerable
            {
                if (other.HasMatch(row, cmpndx))
                {
                    newtable.AddRow(row);
                }
            }
            Logger.WriteLine(4, "[Matching={0}]", newtable);
            return(newtable);
        }
예제 #23
0
        // add rows in this if there is a match in the other on join columns
        private DataTableLocal Divide(DataTableLocal other, DataHeading newheading)
        {
            var cmpndx   = other.Heading.MakeIndex(Heading);
            var movendx  = newheading.MakeIndex(Heading);
            var newtable = DataTableLocal.Create(newheading);

            foreach (var row in GetRows()) //TODO:Enumerable
            {
                if (other.HasMatch(row, cmpndx))
                {
                    newtable.AddRow(row.Project(newheading, movendx));
                }
            }
            Logger.WriteLine(4, "[Matching={0}]", newtable);
            return(newtable);
        }
예제 #24
0
        // Rename some columns, data unchanged
        // It can be possible to copy and graft on new heading, but for now just don't
        public override DataTable Rename(ExpressionEval[] exprs)
        {
            Logger.Assert(exprs.Length == Degree, "reorder mismatch");
            // note: this is an explicit heading. Order matters.
            var newheading = Heading.Rename(exprs);
            var newtable   = DataTableLocal.Create(newheading);
            var newexprs   = newtable.Heading.Reorder(exprs);

            foreach (var row in GetRows())
            {
                newtable.AddRow(row.Transform(newheading, newexprs));
            }
            //newtable.AddRow(DataRow.Create(heading, row.Values));
            Logger.WriteLine(4, "[Rename={0}]", newtable);
            return(newtable);
        }
예제 #25
0
        // Make connection to database based on available flags and current status
        // does not return on error
        void ConnectDatabase()
        {
            if (_status > CatalogStatus.Started)
            {
                return;                             // just the once
            }
            Logger.Assert(_status == CatalogStatus.Started, _status);
            Logger.WriteLine(2, $"Catalog Connect database {this}");

            // create empty catalog
            var table = DataTableLocal.Create(_catalogtableheading);

            GlobalVars.AddEntry(CatalogTableName, table.DataType, EntryKinds.Value,
                                EntryFlags.Public | EntryFlags.System, RelationValue.Create(table));
            GlobalVars.FindEntry(CatalogTableName).Flags |= EntryFlags.Database;

            // Sql or not? Open it.
            var ext = Path.GetExtension(DatabasePath);

            if (ext == "")
            {
                DatabasePath = Path.ChangeExtension(DatabasePath, (SqlFlag) ? DefaultSqlDatabaseExtension : DefaultDatabaseExtension);
            }
            SqlFlag     |= (ext == DefaultSqlDatabaseExtension || DatabaseKind != DatabaseKinds.Memory);
            DatabaseName = Path.GetFileNameWithoutExtension(DatabasePath);
            if (SqlFlag)
            {
                if (DatabaseKind == DatabaseKinds.Memory)
                {
                    DatabaseKind = DatabaseKinds.Sqlite;
                }
                Logger.WriteLine(3, "Catalog database={0} kind={1}", DatabasePath, DatabaseKind);
                if (!SqlTarget.Open(DatabasePath, DatabaseKind))
                {
                    throw ProgramError.Fatal("Catalog", "Cannot open database: {0} ({1})", DatabasePath, DatabaseKind);
                }
            }
            else
            {
                if (LoadFlag && !Directory.Exists(DatabasePath))
                {
                    throw ProgramError.Fatal("Catalog", "Database does not exist: {0}", DatabasePath);
                }
            }
            _status = CatalogStatus.Connected;
            Logger.WriteLine(3, "[CC {0}]", this);
        }
예제 #26
0
        DataTableLocal Read(DataHeading heading)
        {
            var schema = GetSchema();
            var scols  = schema.Columns;
            var rows   = schema.Rows;
            var newtab = DataTableLocal.Create(heading);

            foreach (System.Data.DataRow row in rows)
            {
                var values = Enumerable.Range(0, scols.Count)
                             .Select(x => TypedValue.Convert(heading.Columns[x].DataType, row.IsNull(x) ? null : row[x]))
                             .ToArray();
                var newrow = DataRow.Create(heading, values);
                newtab.AddRow(newrow);
            }
            return(newtab);
        }
예제 #27
0
        // Rows from both tables projected on common heading
        private DataTableLocal Union(DataTableLocal other, DataHeading newheading)
        {
            var rmovendx = newheading.MakeIndex(Heading);
            var lmovendx = newheading.MakeIndex(other.Heading);
            var newtable = DataTableLocal.Create(newheading);

            foreach (var row in this.GetRows()) //TODO:Enumerable
            {
                newtable.AddRow(row.Project(newheading, lmovendx));
            }
            foreach (var row in other.GetRows()) //TODO:Enumerable
            {
                newtable.AddRow(row.Project(this.Heading, rmovendx));
            }
            Logger.WriteLine(4, "[Union={0}]", newtable);
            return(newtable);
        }
예제 #28
0
        public override DataTable Read(string table, DataHeading heading)
        {
            Logger.WriteLine(2, "Sql Read '{0}'", table);
            if (table == "*")
            {
                return(Read(heading));
            }
            var tabnew = DataTableLocal.Create(heading);

            for (var reader = Open(table); reader.Read();)
            {
                var values = heading.Columns.Select(c => MakeValue(reader, c.Name, c.DataType)).ToArray();
                var row    = DataRow.Create(heading, values);
                tabnew.AddRow(row);
            }
            Close();
            return(tabnew);
        }
예제 #29
0
        // Invoke a do block with its own scope level
        public TypedValue DoBlock(CodeValue exprarg, PointerValue accblkarg)
        {
            Logger.WriteLine(3, "DoBlock {0}", exprarg);
            _catvars = _catvars.PushScope();
            var accblk = accblkarg.Value as AccumulatorBlock;
            var expr   = exprarg.Value as ExpressionEval;
            var ret    = expr.Evaluator.Exec(exprarg.Value.Code, null, null, accblk);

            // If the return value is an unresolved sql table then resolve it now
            // before exiting the local variable scope (which it may need)
            if (ret is RelationValue && !(ret.AsTable() is DataTableLocal))
            {
                ret = RelationValue.Create(DataTableLocal.Convert(ret.AsTable()));
            }
            _catvars = _catvars.PopScope();
            Logger.WriteLine(3, "[Do {0}]", ret);
            return(ret);
        }
예제 #30
0
        // set difference
        private DataTableLocal Minus(DataTableLocal other)
        {
            if (!this.Heading.Equals(other.Heading))
            {
                throw new EvaluatorException("tables have different headings");
            }
            var newtable = DataTableLocal.Create(this.Heading);

            foreach (var row in this.GetRows()) //TODO:Enumerable
            {
                if (!other.Contains(row))
                {
                    newtable.AddRow(row);
                }
            }
            Logger.WriteLine(4, "[Minus={0}]", newtable);
            return(newtable);
        }