// Get a catalog value by entry from database or catalog public TypedValue GetValue(CatalogEntry entry) { if (entry.IsDatabase) { if (_catalog.SqlFlag) { // Database sql comes from external table var table = DataTableSql.Create(entry.Name, entry.DataType.Heading); return(RelationValue.Create(table)); } else if (!entry.IsLoaded) // lazy load // Database non-sql lazy loaded from store on path, then in catalog { var value = Persist.Create(_catalog.DatabasePath, true).Load(entry.Name); if (entry.DataType != value.DataType) { throw ProgramError.Fatal("Catalog", "Type mismatch for variable {0}", entry.Name); } entry.IsLoaded = true; return(Persist.Create(_catalog.DatabasePath, true).Load(entry.Name)); } } // Non-database exists only in the catalog return(entry.Value); }
// Create a row from a heading by converting a value public TupleValue RowC(TypedValue hdgarg, TypedValue[] valuearg) { var heading = hdgarg.AsHeading(); var value = valuearg[0]; DataRow newrow = null; if (value.DataType is DataTypeTuple) { newrow = value.AsRow(); } else if (value.DataType is DataTypeUser) { var user = value as UserValue; newrow = DataRow.Create(user.Heading, user.Value); } else if (value.DataType is DataTypeRelation) { var rel = value.AsTable(); newrow = rel.GetRows().FirstOrDefault(); if (newrow == null) { throw ProgramError.Fatal("Builtin", "relation is empty"); } } Logger.Assert(newrow != null, "RowT"); Logger.WriteLine(3, "[Row={0}]", newrow); return(TupleValue.Create(newrow)); }
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); }
//--- updates // Execute an update using a JOIN op // Only INSERT and DELETE actually supported public override DataTable UpdateJoin(DataTable other, JoinOps joinops) { switch (joinops) { case JoinOps.UNION: if (other is DataTableSql) { InsertValuesQuery(other as DataTableSql); } else { InsertValuesSingly(other); } return(this); case JoinOps.MINUS: if (other is DataTableSql) { DeleteValuesQuery(other as DataTableSql); } else { DeleteValuesSingly(other); } return(this); } throw ProgramError.Fatal("Sql data", "join operation not supported: {0}", joinops); }
public NumberValue BinaryGet(BinaryValue value, NumberValue index) { if (index.Value < 0 || index.Value > value.Value.Length) { throw ProgramError.Fatal("Binary", "get index out of range"); } return(NumberValue.Create(value.Value[(int)index.Value])); }
// Called by the #catalog directive public void Directive() { if (_status > CatalogStatus.Connected) { throw ProgramError.Fatal("Catalog", "invalid catalog options"); } //Connect(true); }
// maybe trigger a crash public VoidValue Assert(BoolValue condition, TextValue message) { if (!condition.Value) { throw ProgramError.Fatal("Assert", message.Value); } return(VoidValue.Default); }
public TimeValue Time(TextValue value) { DateTime t; if (DateTime.TryParse(value.Value, out t)) { return(TimeValue.Create(t)); } throw ProgramError.Fatal("Convert", "not a valid time/date"); }
// Obtain a text value by reading from the console/standard input output public TextValue Read() { var input = _input.ReadLine(); if (input == null) { throw ProgramError.Fatal("Read", "input not available"); } return(TextValue.Create(input)); }
// Parse string as number public NumberValue Number(TextValue value) { decimal d; if (Decimal.TryParse(value.Value, out d)) { return(NumberValue.Create(d)); } throw ProgramError.Fatal("Convert", "not a valid number"); }
// Peek the type of a variable in the database public DataType Peek() { if (_reader.ReadString() != Persist.Signature) { throw ProgramError.Fatal("Catalog", "load found invalid signature"); } var type = ReadDataType(); return(type); }
// read the base part of a data type DataType ReadBaseType() { var name = _reader.ReadString(); var type = DataTypes.Find(name); if (type == null) { throw ProgramError.Fatal("Storage", "Unknown type: '{0}'", name); } return(type); }
public BinaryValue BinarySet(BinaryValue value, NumberValue index, NumberValue newvalue) { if (index.Value < 0 || index.Value > value.Value.Length) { throw ProgramError.Fatal("Binary", "set index out of range"); } var b = value.Value.Clone() as byte[]; b[(int)index.Value] = (byte)newvalue.Value; return(BinaryValue.Create(b)); }
protected override DbDataReader Open(string table) { var cmd = new SqlCommand(String.Format("select * from {0}", table), _connection); try { _connection.Open(); } catch (Exception ex) { throw ProgramError.Fatal("Source Sql", ex.Message); } return(cmd.ExecuteReader()); }
///================================================================= /// /// public BoolValue Bool(TextValue value) { if (String.Equals(value.Value, "true", StringComparison.InvariantCultureIgnoreCase)) { return(BoolValue.True); } if (String.Equals(value.Value, "false", StringComparison.InvariantCultureIgnoreCase)) { return(BoolValue.False); } throw ProgramError.Fatal("Convert", "not a valid boolean"); }
///================================================================= /// /// binary operations /// public BinaryValue Binary(TypedValue value) { if (value.DataType == DataTypes.Text) { return(BinaryValue.Default); // TODO: convert text to binary } if (value.DataType == DataTypes.Number) { var size = (int)((NumberValue)value).Value; return(BinaryValue.Create(new byte[size])); } throw ProgramError.Fatal("Binary", "invalid arg type"); }
// Create a persister, in memory or to a path public static Persist Create(string basepath, bool cancreate) { if (!Directory.Exists(basepath)) { if (!cancreate) { throw ProgramError.Fatal("Storage", "database does not exist: " + basepath); } } Directory.CreateDirectory(basepath); return(new Persist { _basepath = basepath }); }
// Store typed value on file stream public void Store(string name, TypedValue value) { var path = Path.Combine(_basepath, name + "." + VariableExtension); Logger.WriteLine(3, "Storing {0} {1}", name, value); try { using (var writer = new BinaryWriter(File.Open(path, FileMode.Create))) { var w = PersistWriter.Create(writer); w.Store(value); } } catch (Exception ex) { throw ProgramError.Fatal("Storage", "cannot store '{0}' : {1}", name, ex.Message); } }
// Load the value of a variable from the database // Complements Store public TypedValue Load() { if (_reader.ReadString() != Persist.Signature) { throw ProgramError.Fatal("Catalog", "load found invalid signature"); } var value = ReadValue(); if (_reader.ReadString() != Persist.Signature) { throw ProgramError.Fatal("Catalog", "load found invalid signature"); } return(value); }
// Import a linked or externally held relvar public VoidValue Import(TextValue sourcearg, TextValue namearg, TextValue whatarg, TextValue locatorarg) { if (sourcearg.Value == Catalog.DefaultDatabaseSource) { if (!_catvars.Catalog.LinkRelvar(namearg.Value)) { throw ProgramError.Fatal("Connect", "cannot link to '{0}'", namearg.Value); } } else if (!_catvars.Catalog.ImportRelvar(sourcearg.Value, namearg.Value, whatarg.Value, locatorarg.Value)) { throw ProgramError.Fatal("Connect", "cannot import from '{0}'", namearg.Value); } return(VoidValue.Default); }
// Get the value of a relation by importing some other format // Entry previously created by peeking public bool ImportRelvar(string source, string name, string what, string locator) { var entry = GlobalVars.FindEntry(name); Logger.Assert(entry != null, name); var heading = entry.DataType.Heading; var stream = DataSourceStream.Create(source, locator); var table = stream.Read(what, heading); if (table == null || !heading.Equals(table.Heading)) { throw ProgramError.Fatal("Catalog", "{0} table not found: '{1}'", source, stream.GetPath(what)); } GlobalVars.SetValue(entry, RelationValue.Create(table)); return(true); }
// Value replaces existing. Supports assignment. // Compiler is responsible for checking type and mutability state public void SetValue(string name, TypedValue value) { if (_catalog.IsSystem(name)) { throw ProgramError.Fatal("Catalog", "cannot set '{0}'", name); } var entry = FindEntry(name); if (entry == null) { AddEntry(name, value.DataType, EntryKinds.Value); entry = FindEntry(name); } Logger.Assert(entry != null); SetValue(entry, value); }
// 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); }
// Factory method public static DataSourceOdbc Create(string locator) { var ds = new DataSourceOdbc { _locator = locator, }; try { ds._connection = new OdbcConnection(locator); } catch (Exception ex) { throw ProgramError.Fatal("Source Odbc", ex.Message); } ds._convdict = new Dictionary <string, ConversionTypes> { { "CHAR", ConversionTypes.String }, { "VARCHAR", ConversionTypes.String }, { "NCHAR", ConversionTypes.String }, { "NVARCHAR", ConversionTypes.String }, { "INTEGER", ConversionTypes.Int }, }; return(ds); }
public void LoadFromTable() { Logger.WriteLine(2, "Load catalog for '{0}'", DatabaseName); var centry = GlobalVars.FindEntry(CatalogTableName); var table = GlobalVars.GetValue(centry).AsTable(); foreach (var row in table.GetRows()) { var blob = (row.Values[3] as BinaryValue).Value; // BUG: argLess is an attribute of a symbol but not of an ExpressionBlock, so does not round trip var entry = CatalogEntry.FromBinary(blob); PersistentVars.Add(entry); if (entry.IsDatabase) { if (!LinkRelvar(entry.Name)) { throw ProgramError.Fatal("Catalog", "cannot add '{0}'", entry.Name); } } } }
// Get the value of a relation from a database // Entry previously created by peeking public bool LinkRelvar(string name) { var entry = GlobalVars.FindEntry(name); Logger.Assert(entry != null && entry.IsDatabase); var heading = entry.DataType.Heading; if (SqlFlag) { var sqlheading = SqlTarget.Current.GetTableHeading(name); if (sqlheading == null) { throw ProgramError.Fatal("Catalog", "sql table not found: '{0}'", name); } // TODO: smarter test, but still may not match exactly //if (!heading.Equals(sqlheading)) if (heading.Degree != sqlheading.Degree) { throw ProgramError.Fatal("Catalog", "sql table schema mismatch: '{0}'", name); } var table = DataTableSql.Create(name, heading); GlobalVars.SetValue(entry, RelationValue.Create(table)); } else { var tablev = Persist.Create(DatabasePath, false).Load(name); if (tablev == null) { throw ProgramError.Fatal("Catalog", "local table not found: '{0}'", name); } if (!heading.Equals(tablev.Heading)) { throw ProgramError.Fatal("Catalog", "local table schema mismatch: '{0}'", name); } GlobalVars.SetValue(entry, RelationValue.Create(tablev.AsTable())); } return(true); }
// Factory method public static DataSourceOleDb Create(string locator) { var ds = new DataSourceOleDb { _locator = locator, }; try { ds._connection = new OleDbConnection(locator); } catch (Exception ex) { throw ProgramError.Fatal("Source OleDb", ex.Message); } ds._convdict = new Dictionary <string, ConversionTypes> { { "DBTYPE_BOOL", ConversionTypes.Bool }, { "DBTYPE_I4", ConversionTypes.Int }, { "DBTYPE_DATE", ConversionTypes.DateTime }, { "DBTYPE_WVARCHAR", ConversionTypes.String }, { "DBTYPE_WVARLONGCHAR", ConversionTypes.String }, }; ds._schemadict = new Dictionary <string, ConversionTypes> { { "_TABLE", ConversionTypes.Bool }, }; return(ds); }
// Final step is to load or create catalog in connected database void EnableCatalog() { if (_status > CatalogStatus.Connected) { return; // just the once } Logger.WriteLine(3, $"Catalog Enable {this}"); Logger.Assert(_status == CatalogStatus.Connected, _status); // load or create catalog (but must start session first) if (LoadFlag) { if (!LinkRelvar(CatalogTableName)) { throw ProgramError.Fatal("Catalog", "cannot load catalog for '{0}'", DatabaseName); } LoadFromTable(); _status = CatalogStatus.Cataloguing; } else if (SaveFlag) { StoreToTable(); // create empty catalog _status = CatalogStatus.Cataloguing; } }
public static DataSourceSql Create(string locator) { var ds = new DataSourceSql { _locator = locator, }; try { ds._connection = new SqlConnection(locator); } catch (Exception ex) { throw ProgramError.Fatal("Source Sql", ex.Message); } ds._convdict = new Dictionary <string, ConversionTypes> { { "char", ConversionTypes.String }, { "varchar", ConversionTypes.String }, { "nchar", ConversionTypes.String }, { "nvarchar", ConversionTypes.String }, { "text", ConversionTypes.String }, { "bit", ConversionTypes.Bool }, { "int", ConversionTypes.Int }, { "bigint", ConversionTypes.Int }, { "smallint", ConversionTypes.Int }, { "tinyint", ConversionTypes.Int }, { "numeric", ConversionTypes.Decimal }, { "decimal", ConversionTypes.Decimal }, { "money", ConversionTypes.Decimal }, { "smallmoney", ConversionTypes.Decimal }, { "date", ConversionTypes.DateTime }, { "datetime", ConversionTypes.DateTime }, { "time", ConversionTypes.DateTime }, { "datetime2", ConversionTypes.DateTime }, { "smalldatetime", ConversionTypes.DateTime }, { "datetimeoffset", ConversionTypes.DateTime }, }; return(ds); }
// trigger an error public VoidValue Fail(TextValue source, TextValue message) { throw ProgramError.Fatal(source.Value, message.Value); }