/********************************************************************************************* * Copyright 2021 - Volian Enterprises, Inc. All rights reserved. * Volian Enterprises - Proprietary Information - DO NOT COPY OR DISTRIBUTE * ------------------------------------------------------------------------------ * $Workfile: RODBInterface.cs $ $Revision: 48 $ * $Author: Kathy $ $Date: 9/06/05 11:25a $ * * $History: RODBInterface.cs $ * * ***************** Version 48 ***************** * User: Kathy Date: 9/06/05 Time: 11:25a * Updated in $/LibSource/RODBInterface * B2005-035 * * ***************** Version 47 ***************** * User: Jsj Date: 5/03/05 Time: 11:45a * Updated in $/LibSource/RODBInterface * * ***************** Version 46 ***************** * User: Kathy Date: 7/15/04 Time: 11:10a * Updated in $/LibSource/RODBInterface * Fix B2004-016 * * ***************** Version 45 ***************** * User: Jsj Date: 5/19/04 Time: 11:11a * Updated in $/LibSource/RODBInterface * fixed typo in warning message * * ***************** Version 44 ***************** * User: Jsj Date: 5/13/04 Time: 2:19p * Updated in $/LibSource/RODBInterface * RO FST will skip records that do not have a valid parent. * * ***************** Version 43 ***************** * User: Jsj Date: 5/11/04 Time: 9:28a * Updated in $/LibSource/RODBInterface * We were getting multiple tree entries after creating the FST file. * * ***************** Version 42 ***************** * User: Jsj Date: 4/08/04 Time: 9:42a * Updated in $/LibSource/RODBInterface * Optimized and added new read functions to speed up RO.FST file * creation. * * ***************** Version 41 ***************** * User: Jsj Date: 3/19/04 Time: 9:40a * Updated in $/LibSource/RODBInterface * bug fix, was using parent node's group definition instead of the * current node's group definition * B2004-008 * * ***************** Version 40 ***************** * User: Jsj Date: 1/12/04 Time: 12:08p * Updated in $/LibSource/RODBInterface * changed SQL Server catalog name from"RO" to "VEPROMS RO" * * ***************** Version 39 ***************** * User: Jsj Date: 1/07/04 Time: 2:17p * Updated in $/LibSource/RODBInterface * allow use of SQL Server * * ***************** Version 38 ***************** * User: Kathy Date: 5/30/03 Time: 12:47p * Updated in $/LibSource/RODBInterface * B2003-040: flag inserted groups have no children for xml * * ***************** Version 37 ***************** * User: Kathy Date: 5/21/03 Time: 12:44p * Updated in $/LibSource/RODBInterface * B2003-041: field name changes fixes. * * ***************** Version 36 ***************** * User: Kathy Date: 5/07/03 Time: 1:57p * Updated in $/LibSource/RODBInterface * B2003-033 fix * * ***************** Version 35 ***************** * User: Jsj Date: 4/14/03 Time: 2:59p * Updated in $/LibSource/RODBInterface * changes to help speed up RO FST file creation * * ***************** Version 34 ***************** * User: Kathy Date: 4/04/03 Time: 9:39a * Updated in $/LibSource/RODBInterface * B2003-030: flag parent's HasChild attribute for new ros * * ***************** Version 33 ***************** * User: Kathy Date: 3/13/03 Time: 1:17p * Updated in $/LibSource/RODBInterface * master different than local fieldname, use local * * ***************** Version 32 ***************** * User: Kathy Date: 1/27/03 Time: 2:12p * Updated in $/LibSource/RODBInterface * test oledb * * ***************** Version 31 ***************** * User: Kathy Date: 12/17/02 Time: 2:32p * Updated in $/LibSource/RODBInterface * new top group with apostrophe failed * * ***************** Version 30 ***************** * User: Kathy Date: 12/17/02 Time: 11:05a * Updated in $/LibSource/RODBInterface * fixed bug on apostrophe in field def (schema string) * * ***************** Version 29 ***************** * User: Kathy Date: 12/10/02 Time: 2:24p * Updated in $/LibSource/RODBInterface * fieldname special chars & various bug fixes * * ***************** Version 28 ***************** * User: Kathy Date: 12/06/02 Time: 11:57a * Updated in $/LibSource/RODBInterface * mods for SQL Server * * ***************** Version 27 ***************** * User: Kathy Date: 12/02/02 Time: 8:28a * Updated in $/LibSource/RODBInterface * fieldname replace chars * * ***************** Version 26 ***************** * User: Kathy Date: 12/02/02 Time: 6:11a * Updated in $/LibSource/RODBInterface * Fix some bugs and add status bar on long ops * * ***************** Version 25 ***************** * User: Jsj Date: 11/27/02 Time: 12:46p * Updated in $/LibSource/RODBInterface * modifications for RO.FST file creation * * ***************** Version 24 ***************** * User: Kathy Date: 11/26/02 Time: 12:56p * Updated in $/LibSource/RODBInterface * fixed single quote crash in accpageid * * ***************** Version 23 ***************** * User: Kathy Date: 11/11/02 Time: 7:15a * Updated in $/LibSource/RODBInterface * Added RODB_ReadRO to read an RO given a recid/table name * * ***************** Version 22 ***************** * User: Kathy Date: 10/24/02 Time: 11:16a * Updated in $/LibSource/RODBInterface * delete hi-level group (table) * * ***************** Version 21 ***************** * User: Kathy Date: 10/15/02 Time: 2:16p * Updated in $/LibSource/RODBInterface * minor bug fixes & new group (database, i.e. table level) * * ***************** Version 20 ***************** * User: Kathy Date: 10/10/02 Time: 1:04p * Updated in $/LibSource/RODBInterface * xmltree=tree control * * ***************** Version 19 ***************** * User: Kathy Date: 10/10/02 Time: 10:56a * Updated in $/LibSource/RODBInterface * console.writeline->Messagebox * * ***************** Version 18 ***************** * User: Kathy Date: 10/10/02 Time: 10:00a * Updated in $/LibSource/RODBInterface * delete bug fix & accessory page id support * * ***************** Version 17 ***************** * User: Kathy Date: 10/07/02 Time: 11:25a * Updated in $/LibSource/RODBInterface * image file saving of xml using xmltextwriter was missing sometext * * ***************** Version 16 ***************** * User: Kathy Date: 10/02/02 Time: 1:41p * Updated in $/LibSource/RODBInterface * tie tree to insert/delete changes (round 1) * * ***************** Version 15 ***************** * User: Jsj Date: 10/01/02 Time: 4:45p * Updated in $/LibSource/RODBInterface * hooks for passed in database path * * ***************** Version 14 ***************** * User: Kathy Date: 9/27/02 Time: 1:22p * Updated in $/LibSource/RODBInterface * remove using vlnxml * * ***************** Version 13 ***************** * User: Kathy Date: 9/27/02 Time: 1:18p * Updated in $/LibSource/RODBInterface * fix digit as first char in fieldname & recurse through tree adjusting * for modified field names * * ***************** Version 12 ***************** * User: Jsj Date: 9/26/02 Time: 11:13a * Updated in $/LibSource/RODBInterface * added VLNXML reference * * ***************** Version 11 ***************** * User: Kathy Date: 9/25/02 Time: 9:55a * Updated in $/LibSource/RODBInterface * generate xml strings for writing to database by using xmltextwriter * * ***************** Version 10 ***************** * User: Kathy Date: 9/19/02 Time: 10:02a * Updated in $/LibSource/RODBInterface * minor changes for schema and other bug fixes * * ***************** Version 9 ***************** * User: Kathy Date: 9/11/02 Time: 1:14p * Updated in $/LibSource/RODBInterface * vlnxml * * ***************** Version 8 ***************** * User: Kathy Date: 9/10/02 Time: 12:54p * Updated in $/LibSource/RODBInterface * menu titles * * ***************** Version 7 ***************** * User: Kathy Date: 9/06/02 Time: 11:43a * Updated in $/LibSource/RODBInterface * datetimestamp * * ***************** Version 6 ***************** * User: Kathy Date: 8/30/02 Time: 11:56a * Updated in $/LibSource/RODBInterface * new/update ro field records. * * ***************** Version 5 ***************** * User: Kathy Date: 8/30/02 Time: 9:43a * Updated in $/LibSource/RODBInterface * compile * * ***************** Version 4 ***************** * User: Jsj Date: 8/28/02 Time: 3:40p * Updated in $/LibSource/RODBInterface * added a create table function * * ***************** Version 3 ***************** * User: Jsj Date: 8/28/02 Time: 3:03p * Updated in $/LibSource/RODBInterface * read connection strings from a text file * * ***************** Version 2 ***************** * User: Kathy Date: 8/28/02 Time: 10:52a * Updated in $/LibSource/RODBInterface * development *********************************************************************************************/ using System; using System.Collections; using System.IO; using System.Data; using System.Xml; using System.Xml.XPath; using System.Xml.Schema; using System.Text; using System.Windows.Forms; using DBEncapsulation; using ROFields; using VlnStatus; using System.Collections.Specialized; using Org.Mentalis.Files; using System.Data.SqlClient; using System.Collections.Generic; namespace RODBInterface { /// /// Summary description for Class1 /// public enum RecordType : uint { Master = 0, SubDatabase = 1, Schema = 2, Group = 3, GroupSchema = 4, RRO = 5, SchemaStart = 6, SchemaEnd = 7, ConvertedToSql = 8 } /// /// The following class handles generation of sql strings to get/put requested parts of /// XML RO Tree. And performs the database access using the VLN_DB class. /// public abstract partial class RODB { #region Properties public DBEncapsulation.DBEncapsulate DBE; public VlnXmlDocument ROXml; public string schemastart; public string schemaend; public string lastTable = ""; public HybridDictionary dicFldTypes; public string RODirectoryPath; public int dbProviderType = 0; public string strDatabaseConnectionCommand; public string dbServerPath = ""; public string dbServerUserName = ""; public string dbServerPassword = ""; public enum DB_PROVIDER { ACCESS, SQL_SERVER, ORACLE }; private string _MyDBID; public string MyDBID { get { return _MyDBID; } set { _MyDBID = value; } } private string _MyRecID; public string MyRecID { get { return _MyRecID; } set { _MyRecID = value; } } private bool _OnlyConnectOnce=false; public bool OnlyConnectOnce { get { return _OnlyConnectOnce; } set { _OnlyConnectOnce = value; } } // C2021-026 used to access in the list of P/C Children private static string[] _PCChildList = null; public static string[] PCChildList { get { return _PCChildList; } set { _PCChildList = value; } } #endregion #region abstracts // need these for each method that must be defined for each database type public abstract string RODB_GetNextGroupTable(); public abstract string RODB_GetNextRecId(string table); public abstract bool RODB_GetRootGroups(VlnXmlElement root); public abstract bool RODB_DeleteGroup(XmlNode group, string tbname, string toprecid); public abstract bool RODB_DeleteRO(XmlNode group); public abstract bool RODB_WriteGroup(XmlNode group, VlnXmlElement master); public abstract bool RODB_InsertGroup(VlnXmlElement group); public abstract string RODB_AddNewTable(string TblName, string newgrpname); public abstract bool RODB_CopyFieldDefs(string fromtb, string totb, int type); public abstract bool RODB_GetGroupAndSubgroups(VlnXmlElement node, StringBuilder sb); public abstract bool RODB_GetChildData(VlnXmlElement node, bool CheckChildCount); public abstract bool IsDuplicateAccPageID(VlnXmlElement ro, string newacc); public abstract VlnXmlElement RODB_ReadRO(string tbl, string recid); public abstract bool RODB_WriteRO(VlnXmlElement ro, bool movedRO = false); public abstract bool RODB_InsertRO(VlnXmlElement ro); public abstract ushort RODB_GetFieldType(VlnXmlElement elem, string TableName, string Fld); public abstract ArrayList RODB_GetFields(VlnXmlElement elem, uint rtype, bool refresh = false); public abstract string RODB_GetSchemaPiece(string Recid, string table); public abstract bool RODB_NewSchemaPiece(string recid, string parentid, string table, string schpiece, uint rtype); public abstract bool RODB_WriteSchemaPiece(string Recid, string table, string schpiece); public abstract bool RODB_ProcessRROFieldChange(VlnXmlElement child, string oldname, string newname, uint editlevel, VlnStatusMessage StatMsgWindow, bool combofield); public abstract bool RODB_UpdateFieldRecord(ROField myrof, VlnXmlElement myelem, string strschema, string oldname, string newname, uint editlevel, bool combofield); public abstract XmlSchema RODB_GetGroupSchema(VlnXmlElement elem); public abstract XmlSchema RODB_GetSchema(VlnXmlElement elem); public abstract int RODB_GetNumberOfROValueRecords(string tablename); public abstract int RODB_GetNumberOfGroupRecords(string tablename); public abstract string RODB_GetDBNameForAbout(); public abstract string RODB_GetDBServerForAbout(); public abstract string RODB_HasBeenConverted(); public abstract bool RODB_WriteSqlConnectToAccess(string newConectStr); #endregion public RODB() { } #region GeneralDB public void GetDbServerInfo(string ROdir) { string strServerProvider; string ROiniPath = ROdir + "\\ROAPP.INI"; // Get the database Provider name - default to Access IniReader in1 = new IniReader(ROiniPath); strServerProvider = in1.ReadString("Database Server", "Driver", "ACCESS"); strServerProvider = strServerProvider.ToUpper(); if (strServerProvider.Equals("SQL SERVER")) dbProviderType = (int)DB_PROVIDER.SQL_SERVER; else if (strServerProvider.Equals("ORACLE")) dbProviderType = (int)DB_PROVIDER.ORACLE; else // default to ACCESS dbProviderType = (int)DB_PROVIDER.ACCESS; // Get the database server path dbServerPath = in1.ReadString("Database Server", "Path", ROdir); dbServerUserName = in1.ReadString("Database Server", "UserID", ""); dbServerPassword = in1.ReadString("Database Server", "Password", ""); if (dbProviderType.Equals((int)DB_PROVIDER.ACCESS)) { if (dbServerUserName.Equals("")) dbServerUserName = "Admin"; // default user name for Access } //else if (dbServerUserName.Equals("") || (dbServerUserName.Length > 0 && dbServerPassword.Equals(""))) //{ // userpass pwdlg = new userpass(dbServerUserName); // // If using SQL Server or Oracle // // prompt for a user name and password. // pwdlg.Text = strServerProvider + pwdlg.Text; // if (pwdlg.ShowDialog() == DialogResult.OK) // { // dbServerUserName = pwdlg.uname; // dbServerPassword = pwdlg.pword; // } // else // { // dbServerUserName = ""; // dbServerPassword = ""; // } //} } public void BuildConnectionString(string ropath, string DataConnectionPath) { GetDbServerInfo(ropath); if (!dbProviderType.Equals((int)DB_PROVIDER.SQL_SERVER)) { strDatabaseConnectionCommand = "Provider=Microsoft.Jet.OLEDB.4.0;Password=\"\";User ID=Admin;Data Source=" + DataConnectionPath + "\\ROMaster.mdb;Mode=Share Deny None;Extended Properties=\"\";Jet OLEDB:System database=\"\";Jet OLEDB:Registry Path=\"\";Jet OLEDB:Database Password=\"\";Jet OLEDB:Engine Type=5;Jet OLEDB:Database Locking Mode=1;Jet OLEDB:Global Partial Bulk Ops=2;Jet OLEDB:Global Bulk Transactions=1;Jet OLEDB:New Database Password=\"\";Jet OLEDB:Create System Database=False;Jet OLEDB:Encrypt Database=False;Jet OLEDB:Don't Copy Locale on Compact=False;Jet OLEDB:Compact Without Replica Repair=False;Jet OLEDB:SFP=False"; } } #endregion #region XML public VlnXmlDocument RODB_GetRoot() { // Create an xmldoc and initialize it with a root node ROXml = new VlnXmlDocument(); XmlNode elem = ROXml.CreateNode(XmlNodeType.Element, "RO_Root", ""); ROXml.AppendChild(elem); return ROXml; } public string ParseEleName(string info) { string elemname; // need to find element type too. int issingle = info.IndexOf("Single"); int idx1 = info.IndexOf("element name="); if (idx1 > 0) { elemname = info.Substring(idx1 + 14, info.Length - idx1 - 14); idx1 = elemname.IndexOf("\""); elemname = CvtFldToUserFld(elemname.Substring(0, idx1)); // if we have a choice element, remove the last character (it was added to the // field names in order to allow for unique fields names for the choice items. if (info.IndexOf("xsd:choice") > 0) { string trun = elemname.Remove((elemname.Length) - 1, 1); return trun; } return elemname; } return null; } // Given an element to start at, get the fields in use. Pass in the element you're // on, the available list for this group & a string representing 'FieldsInUse' or // 'GroupFieldsInUse'. public ArrayList RODB_GetFieldsInUse(VlnXmlElement elem, ArrayList avail, string strFieldsInUse, ref string origFieldsInUse, bool RemoveFromAvailList) { VlnXmlElement startelem = elem; // if this element doesn't have any fields in use, walk up the tree until // we find them. string FieldsInUse = ""; if (startelem.HasAttribute(strFieldsInUse) == false) { VlnXmlElement parent; parent = (VlnXmlElement)startelem.ParentNode; while (parent != null && FieldsInUse == "") { FieldsInUse = parent.GetAttribute(strFieldsInUse); if (parent.Name != "RO_Root") parent = (VlnXmlElement)parent.ParentNode; else parent = null; } } else FieldsInUse = startelem.GetAttribute(strFieldsInUse); origFieldsInUse = FieldsInUse; // make a copy to compare to later. ArrayList inuse = new ArrayList(); // if there are no fields in use (may be inserting a top group) // return an empty list. if (FieldsInUse == "") return inuse; // Go through the FieldsInUse list and move elements from the avail list // to the inuse list int strpos = 0; string recid; recid = FieldsInUse.Substring(strpos, 8); MyRecID = recid; while (recid != null) { // find it in avail list. Remove it from there & add to inuse list for (int i = 0; i < avail.Count; i++) { ROField rof = (ROField)avail[i]; string lrecid = rof.GetRecID; if (lrecid == recid) { // remove it from avail list & add it to inuse list ROField inuserof = new ROField(rof.GetFieldname, rof.GetRecID, rof.GetMasterRecID, rof.GetFieldType); inuse.Add((object)inuserof); if (RemoveFromAvailList) avail.RemoveAt(i); break; } } strpos = strpos + 9; if (strpos > FieldsInUse.Length) recid = null; else { recid = FieldsInUse.Substring(strpos, 8); } } return inuse; } //C2021-026 adding ability to have field values based on Parent/Child applicability // This reads the database and returns a list of the field where applicability was enabled public ArrayList RODB_GetApplicabilityEnabledFields(VlnXmlElement elem, ArrayList fieldsInUse, ref string origApplcFields, bool pcApplicabilityEnabled) { ArrayList newApplicList = new ArrayList(); if (!pcApplicabilityEnabled) { origApplcFields = null; return newApplicList; } VlnXmlElement startelem = elem; string atribApplicFields = "ApplicabilityEnabled"; //xml attribute containing list of field recids // if this element doesn't have any fields in use, walk up the tree until // we find them. string applicFields = ""; if (startelem.HasAttribute(atribApplicFields) == false) { VlnXmlElement parent; parent = (VlnXmlElement)startelem.ParentNode; while (parent != null && applicFields == "") { applicFields = parent.GetAttribute(atribApplicFields); if (parent.Name != "RO_Root") parent = (VlnXmlElement)parent.ParentNode; else parent = null; } } else applicFields = startelem.GetAttribute(atribApplicFields); origApplcFields = applicFields; // make a copy to compare to later. // if there are no fields with applicability (may be inserting a top group) // return an empty list. if (applicFields == "") return newApplicList; // Go through the FieldsInUse list and copy elements to newApplicList int strpos = 0; string recid; recid = applicFields.Substring(strpos, 8); MyRecID = recid; while (recid != null) { // find it in avail list and add to newApplicList for (int i = 0; i < fieldsInUse.Count; i++) { ROField rof = (ROField)fieldsInUse[i]; string lrecid = rof.GetRecID; if (lrecid == recid) { // add to newApplilcList if it is not already there list ROField inuserof = new ROField(rof.GetFieldname, rof.GetRecID, rof.GetMasterRecID, rof.GetFieldType); bool addit = true; foreach (ROField arof in newApplicList) { if (arof.GetRecID == inuserof.GetRecID) { addit = false; //this field is already in the list break; } } if (addit) newApplicList.Add((object)inuserof); break; } } strpos = strpos + 9; if (strpos > applicFields.Length) recid = null; else { recid = applicFields.Substring(strpos, 8); } } return newApplicList; } public string CvtUserFldToFld(string fldname) { if (fldname.Length < 2) return fldname; // a digit cannot start an xml fieldname, prepend a "__" to it. string tmp0; if (char.IsDigit(fldname, 0)) tmp0 = "__" + fldname; else tmp0 = fldname; // an xml fieldname cannot have a space, change it to a "__" string tmpstr = tmp0.Replace(" ", "__"); int len = tmpstr.Length; int cnt = 0; // this is also our sequence that tells us the follow 3 digits is the ascii number (base 10) // of the character we replaced. string OKpunch = "-._"; string outstr = ""; int decval; while (cnt < len) { char tmpchr = tmpstr[cnt]; if (!char.IsLetterOrDigit(tmpchr) && (OKpunch.IndexOf(tmpchr) == -1)) { decval = tmpchr; outstr += OKpunch + decval.ToString("D3"); } else { outstr += tmpchr.ToString(); } cnt++; } return outstr; } public string CvtFldToUserFld(string fldname) { string tmpstr0; if (fldname.Length < 2) return fldname; // an xml element name cannot begin with a digit. we had prepended a "__" if (fldname.Substring(0, 2) == "__" && char.IsDigit(fldname, 2)) tmpstr0 = fldname.Substring(2, fldname.Length - 2); else tmpstr0 = fldname; // an xml element name cannot have a space, we converted to a "__" string tmpstr = tmpstr0.Replace("__", " "); int len = tmpstr.Length; int cur = 0; // this is also our sequence that tells us the follow 3 digits is the ascii number (base 10) // of the character we replaced. string OKpunch = "-._"; string outstr = ""; int decval, indx; if (tmpstr.Length < 6) indx = -1; else indx = tmpstr.IndexOf(OKpunch, cur); string asc_spchar; while (indx >= 0) { outstr += tmpstr.Substring(cur, indx - cur); asc_spchar = tmpstr.Substring(indx + 3, 3); decval = System.Convert.ToInt16(asc_spchar, 10); outstr += System.Convert.ToChar(decval).ToString(); cur = indx + 6; if (cur + 6 > len) indx = -1; else indx = tmpstr.IndexOf(OKpunch, cur); } if (cur < len) outstr += tmpstr.Substring(cur, len - cur); return outstr; } // Process the given field type. // return the type value used in the RO.FST file public ushort GetFSTreturnType(ushort fldtype, string fldname, VlnXmlElement elem) { ushort rtnval = 0; /* * Here are the possible field types: * public enum FieldTypes: uint { Nil=0, SingleTxt=1, VariableTxt=2, FrmtSingleTxt=4, XYPlot=8, Table=10, Image=20, MultiTxt=40, Combination=128, MultiFld=100 } */ switch ((uint)fldtype) { case 1: // Fixed length text case 2: // Variable length text case 4: // formatted text case 40: // Multi line text rtnval = 1; break; case 10: // Table rtnval = 2; break; case 8: // X/Y Plot rtnval = 4; break; case 32: // image (intergrated graphics) - this is the HEX representation rtnval = 8; break; } return rtnval; } public string GenerateXmlString(XmlNode node, bool isgroup) // KBR not sure - see end of method { string retstr; XmlTextWriter xmlTextWriter; StringWriter strWriter = new StringWriter(); xmlTextWriter = new XmlTextWriter(strWriter); VlnXmlElement enode; XmlNode kid; kid = node.FirstChild; enode = (VlnXmlElement)node; if (isgroup == true) { xmlTextWriter.WriteStartElement("vlnGroup"); if (enode.HasAttribute("RetVal")) { xmlTextWriter.WriteStartAttribute("RetVal", null); xmlTextWriter.WriteString(enode.GetAttribute("RetVal")); xmlTextWriter.WriteEndAttribute(); } if (enode.HasAttribute("MenuItem")) { xmlTextWriter.WriteStartAttribute("MenuItem", null); xmlTextWriter.WriteString(enode.GetAttribute("MenuItem")); xmlTextWriter.WriteEndAttribute(); } if (enode.HasAttribute("FieldsInUse")) { xmlTextWriter.WriteStartAttribute("FieldsInUse", null); xmlTextWriter.WriteString(enode.GetAttribute("FieldsInUse")); xmlTextWriter.WriteEndAttribute(); } if (enode.HasAttribute("ApplicabilityEnabled")) //C2021-026 save field applicability { xmlTextWriter.WriteStartAttribute("ApplicabilityEnabled", null); xmlTextWriter.WriteString(enode.GetAttribute("ApplicabilityEnabled")); xmlTextWriter.WriteEndAttribute(); } if (enode.HasAttribute("GroupMenuItem")) { xmlTextWriter.WriteStartAttribute("GroupMenuItem", null); xmlTextWriter.WriteString(enode.GetAttribute("GroupMenuItem")); xmlTextWriter.WriteEndAttribute(); } if (enode.HasAttribute("GroupFieldsInUse")) { xmlTextWriter.WriteStartAttribute("GroupFieldsInUse", null); xmlTextWriter.WriteString(enode.GetAttribute("GroupFieldsInUse")); xmlTextWriter.WriteEndAttribute(); } if (enode.HasAttribute("AccPageID")) { xmlTextWriter.WriteStartAttribute("AccPageID", null); xmlTextWriter.WriteString(enode.GetAttribute("AccPageID")); xmlTextWriter.WriteEndAttribute(); } if (enode.HasAttribute("AccPageIDPrefix")) { xmlTextWriter.WriteStartAttribute("AccPageIDPrefix", null); xmlTextWriter.WriteString(enode.GetAttribute("AccPageIDPrefix")); xmlTextWriter.WriteEndAttribute(); } xmlTextWriter.WriteStartAttribute("MenuTitle", null); xmlTextWriter.WriteString(enode.GetAttribute("MenuTitle")); xmlTextWriter.WriteEndAttribute(); while (kid != null) { if ((kid is XmlText) || (kid.ChildNodes.Count == 1 && kid.Name != "vlnGroup")) kid.WriteTo(xmlTextWriter); kid = kid.NextSibling; } } else { xmlTextWriter.WriteStartElement(node.Name); xmlTextWriter.WriteStartAttribute("MenuTitle", null); xmlTextWriter.WriteString(enode.GetAttribute("MenuTitle")); xmlTextWriter.WriteEndAttribute(); while (kid != null) { kid.WriteTo(xmlTextWriter); kid = kid.NextSibling; } } xmlTextWriter.WriteEndElement(); // vlnGroup or top of RO. xmlTextWriter.Flush(); xmlTextWriter.Close(); retstr = strWriter.ToString(); // replace the single quote because ODBC fails if it's in a string because // the single quote represents the beg/end of string when sending string to // ODBC. retstr = retstr.Replace("\'", "'"); // KBR - not sure if this method should be in RODB class or db specific class return (retstr); } // Create a new field record in master and reference in the current table. // pass in current rodb object, the xml element creating and editlevel // is a recordType of either Group (group field definitions) or rro for // the ro definition. the string apd represents an append string which is // appended to the fieldname for combo types, otherwise it's null public bool RODB_NewFieldRecord(ROField myrof, VlnXmlElement myelem, string strschema, uint editlevel, string apd) { bool success; // get a new record id for this and save it in the master table. string mrecid = RODB_GetNextRecId("ROMaster"); // get recid in ROMaster for group, so that we can set the parent field. // walk up the tree until we find a 'MasterRecID' attribute. VlnXmlElement parent; parent = myelem; while (parent != null) { if (parent.HasAttribute("MasterRecID")) break; parent = (VlnXmlElement)parent.ParentNode; } success = RODB_NewSchemaPiece(mrecid, parent.GetAttribute("MasterRecID"), "ROMaster", strschema, editlevel); if (success != true) return false; // also reference it from the local table. string lrecid = RODB_GetNextRecId(myelem.GetAttribute("Table")); myrof.SetRecID(lrecid); myrof.SetMasterRecID(mrecid); StringBuilder strbld = new StringBuilder(); strbld.Append(mrecid); strbld.Append(" "); string strtype = myrof.GetFieldType.ToString(); strbld.Append(strtype.PadLeft(3, '0')); strbld.Append(" "); strbld.Append(myrof.MakeFieldName(myrof.GetFieldname)); if (apd != null) strbld.Append(apd); // Need ParentID field, get by looking up xml tree to find parentID attribute = "00000000", then // use this recid. parent = myelem; while (parent.GetAttribute("ParentID") != "00000000") { parent = (VlnXmlElement)parent.ParentNode; } success = RODB_NewSchemaPiece(lrecid, parent.GetAttribute("RecID"), myelem.GetAttribute("Table"), strbld.ToString(), editlevel); return success; } // C2021-026 rename any P/C Child fields public string DoReplaceParentChildField(string infstr, string oldName, string newName) { string rtnInfoStr = infstr; if (PCChildList == null) return rtnInfoStr; int pcChildIdx = 0; // children indexing starts at one so initialize with zero foreach (string chld in PCChildList) { pcChildIdx++; string csufx = string.Format("_PCCHILD{0}", pcChildIdx); // Create child field name string oldFldNameChild = oldName.Insert(oldName.Length - 1, CvtUserFldToFld(csufx)); string newFldNameChild = newName.Insert(newName.Length - 1, CvtUserFldToFld(csufx)); rtnInfoStr = rtnInfoStr.Replace(oldFldNameChild, newFldNameChild); } return rtnInfoStr; } public string DoCmbFieldReplace(string repstring, string oname, string nname, string letter) { string cmboname, cmbnname; cmboname = oname.Insert(oname.Length - 1, letter); cmbnname = nname.Insert(nname.Length - 1, letter); string rtnstr = repstring.Replace(cmboname, cmbnname); rtnstr = DoReplaceParentChildField(rtnstr, cmboname, cmbnname); // C2021-026 create child fields in combo group return rtnstr; } // RODB_UpdateNamesInROs: goes through subtree (top node is 'fld') and if this // updated field is used (either in [Group]FieldsInUse or was used in parent, then // 1) if group node, check for attributes using "" and if found, update // to " // 2) if group edit, modify this node's xml data with the new fieldname, // otherwise, edit 'ROs' under this to replace with // Input: VlnXmlElement fld: start processing at this node. // string myrecid: local recid to be used for check to see if used (in FieldsInUse // or GroupFieldsInUse. // string oldname, newname - old and new field names // string myrecid - local record storing field name // uint editlevel - if editting groups, do check for for item 1 above in // Group attributes, otherwise do in // bool parentused - set to false from caller, this is recursive and will // be set appropriately for recursive calls. public bool RODB_UpdateFieldNames(VlnXmlElement fld, string myrecid, string oldname, string newname, uint editlevel, bool parentused, VlnStatusMessage StatMsgWindow, bool combofield) { bool success; bool useAtLevel = false; XmlNode node; VlnXmlElement child; string fldinuse; if (editlevel == (uint)RecordType.Schema) fldinuse = "FieldsInUse"; else fldinuse = "GroupFieldsInUse"; // Do the current level before walking through any children groups. if (fld.Name == "vlnGroup") { if (fld.HasAttribute(fldinuse)) { // if recid not in here, don't process for this node. string fiu = fld.GetAttribute(fldinuse); if (fiu.IndexOf(myrecid) >= 0) useAtLevel = true; } if (useAtLevel == true || parentused == true) useAtLevel = true; if (useAtLevel == true) { string haskids, kidsloaded; haskids = fld.GetAttribute("HasChild"); kidsloaded = fld.GetAttribute("ChildLoaded"); if (haskids == "True" && kidsloaded == "False") { success = RODB_GetChildData(fld, true); if (success == false) return false; fld.SetAttribute("ChildLoaded", "True"); } parentused = true; // for kids of this group. success = RODB_ProcessRROFieldChange(fld, oldname, newname, editlevel, StatMsgWindow, combofield); if (success == false) return false; } } node = (XmlNode)fld.FirstChild; while (node != null) { if (node is VlnXmlElement) { useAtLevel = false; child = (VlnXmlElement)node; // If this is a group menu edit, process group nodes, by recursive // call and then modify data on group record. // For both, when hitting a group node, check that it either doesn't // have 'FieldsInUse' or 'GroupFieldsInUse' or that if it does, // this record id is in the list -> only process these, otherwise // the field is not used. if (child.Name == "vlnGroup") { // see if inuse for this one, either defined here or from parent. if (child.HasAttribute(fldinuse)) { // if recid not in here, don't process for this node. Still // need to check children because they may redefine fields in use. string fiu = child.GetAttribute(fldinuse); if (fiu.IndexOf(myrecid) >= 0) useAtLevel = true; } if (useAtLevel == false && parentused == true) useAtLevel = true; // update this record if it doesn't have it's own , then do kids // of it. success = RODB_UpdateFieldNames(child, myrecid, oldname, newname, editlevel, useAtLevel, StatMsgWindow, combofield); if (success == false) return false; } } node = node.NextSibling; } return true; } // check if the name entered is one used for setting up // the new graphics or setpoint databases. public bool RODB_CheckForStandardName(string oname) { string oldname = CvtFldToUserFld(oname); if (oldname.CompareTo("Name") == 0) return true; if (oldname.CompareTo("Image ID") == 0) return true; if (oldname.CompareTo("Image") == 0) return true; if (oldname.CompareTo("Setpoint ID") == 0) return true; if (oldname.CompareTo("Setpoint Value") == 0) return true; if (oldname.CompareTo("Associated System/Component") == 0) return true; if (oldname.CompareTo("Applicability") == 0) return true; if (oldname.CompareTo("Revision") == 0) return true; if (oldname.CompareTo("Short Description") == 0) return true; if (oldname.CompareTo("Description") == 0) return true; if (oldname.CompareTo("Key Assumptions") == 0) return true; if (oldname.CompareTo("Basis") == 0) return true; if (oldname.CompareTo("References") == 0) return true; if (oldname.CompareTo("Group") == 0) return true; if (oldname.CompareTo("Parameter") == 0) return true; return false; } #endregion } /// /// The following class handles generation of sql strings to get/put requested parts of /// XML RO Tree. And performs the database access using the VLN_DB class. This class is /// to be used for MS Access /// public partial class AccessRODB : RODB { public DBEncapsulation.OLEDB_DBEncap DBE_OLEDB; public AccessRODB(string rODirectoyPath) { RODirectoryPath = rODirectoyPath; BuildConnectionString(rODirectoyPath, rODirectoyPath); DBE_OLEDB = new OLEDB_DBEncap(); DBE = DBE_OLEDB; try { DBE.Connection(strDatabaseConnectionCommand); } catch (Exception e) { MessageBox.Show(e.Message, "Setup of OLEDB/ODBC"); } } public override string RODB_GetDBNameForAbout() { return ("Database: RoMaster"); } public override string RODB_GetDBServerForAbout() { return ("Microsoft Access"); } public override string RODB_HasBeenConverted() { try { DBE.OpenConnection(); } catch (Exception e) { MessageBox.Show(e.Message, "Could not open database connection"); // MessageBox.Show(e.StackTrace,"Debug"); return null; } string constring = null; string strHasBeen = "SELECT Info FROM ROMaster where RecType=" + (uint)RecordType.ConvertedToSql; try { DBE.Command(strHasBeen); DBE.Reader(); if (DBE.Read()) { constring = DBE.GetString(0); DBE.ReaderClose(); DBE.CommandDispose(); } } catch (Exception ex) { } DBE.CloseConnection(); return constring; } public override bool RODB_WriteSqlConnectToAccess(string newConectStr) { //try //{ // DBE.OpenConnection(); //} //catch (Exception e) //{ // MessageBox.Show(e.Message, "Could not open database connection"); // // MessageBox.Show(e.StackTrace,"Debug"); // return false; //} string dt = string.Format("{0:yyyyMMddHHmmss}", System.DateTime.Now); string strUpdate = "UPDATE ROMaster SET Info = '" + newConectStr + "'"; // note that '8' for rectype flags database converted: strUpdate = strUpdate + ", ModDateTime = '" + dt + "' WHERE RecType=" + (uint)RecordType.ConvertedToSql; try { DBE.Command(strUpdate); DBE.Reader(); DBE.ReaderClose(); DBE.CommandDispose(); } catch (Exception ex) { return false; } return true; } // get the next table name & update it to the next possible. public override string RODB_GetNextGroupTable() { // read record type of master for this table. This is where the highest recid is stored. // Update the recid by 1, write it out and return the new recid. string strGetNxt = "SELECT Info FROM ROMaster where RecID = '00000001' and RecType=" + (uint)RecordType.Master; string rettable = null; try { DBE.Command(strGetNxt); DBE.Reader(); if (DBE.Read()) { rettable = DBE.GetString(0); string nxttable = rettable.Substring(2, 6); int ltbl = System.Convert.ToInt32(nxttable, 10); ltbl++; nxttable = ltbl.ToString("d6"); // this format "d6" should pad left with zeros string newstr = "RO" + nxttable; DBE.ReaderClose(); DBE.CommandDispose(); string dt = string.Format("{0:yyyyMMddHHmmss}", System.DateTime.Now); string strUpdate = "UPDATE ROMaster SET Info = '" + newstr + "'"; strUpdate = strUpdate + ", ModDateTime = '" + dt + "' WHERE RecID = '00000001' and RecType=" + (uint)RecordType.Master; DBE.Command(strUpdate); DBE.Reader(); DBE.ReaderClose(); DBE.CommandDispose(); return rettable; } } catch (Exception e) { MessageBox.Show(e.Message, "Getting new record id"); } return null; } // get the next recid for this table & update it. public override string RODB_GetNextRecId(string table) { // read record type of master for this table. This is where the highest recid is stored. // Update the recid by 1, write it out and return the new recid. string strGetNxt = "SELECT Info FROM " + table + " where RecID = '00000000' and RecType=" + (uint)RecordType.Master; try { DBE.Command(strGetNxt); DBE.Reader(); if (DBE.Read()) { string RecID = DBE.GetString(0); int lrecid = System.Convert.ToInt32(RecID, 16); lrecid++; RecID = lrecid.ToString("x"); // need an 8 char string so pad left with zero string padstr = RecID.PadLeft(8, '0'); DBE.ReaderClose(); DBE.CommandDispose(); string dt = string.Format("{0:yyyyMMddHHmmss}", System.DateTime.Now); string strUpdate = "UPDATE " + table + " SET Info = '" + padstr + "'"; strUpdate = strUpdate + ", ModDateTime = '" + dt + "' WHERE RecID = '00000000' and RecType=" + (uint)RecordType.Master; DBE.Command(strUpdate); DBE.Reader(); DBE.ReaderClose(); DBE.CommandDispose(); return padstr; } } catch (Exception e) { MessageBox.Show(e.Message, "Getting new record id"); } return null; } // pass in root node. This will get Groups from Root node. This is a special case because // the list of top level groups is off of the ROMaster database. public override bool RODB_GetRootGroups(VlnXmlElement root) { ShowCount.GetRootGroups++; string table; string group; string title; // Get menu fields to display try { DBE.OpenConnection(); } catch (Exception e) { MessageBox.Show(e.Message, "Could not open database connection"); // MessageBox.Show(e.StackTrace,"Debug"); return false; } string strGetGroups = "SELECT RecID,Info FROM ROMaster where RecType = " + (uint)RecordType.SubDatabase; strGetGroups += " ORDER BY RecID ASC"; DBE.Command(strGetGroups); DBE.Reader(); SortedList mySL = new SortedList(); while (DBE.Read()) { // Parse info string, it has group name & table name. Store in a sorted // list, sorting by Group Name. string mrecid = DBE.GetString(0); group = DBE.GetString(1); mySL.Add(mrecid, group); } DBE.CommandDispose(); DBE.ReaderClose(); // Now, for each group, i.e. table, make xml elements for the top level groups by // reading in the Xml Element for the group from each table. for (int i = 0; i < mySL.Count; i++) { group = mySL.GetByIndex(i).ToString(); int grnamindx = group.IndexOf("\t"); if (grnamindx == -1) {// no tab, default to RO000001 table = "RO000001"; title = group; } else { StringBuilder tablesb = new StringBuilder(70); tablesb.Append(group); tablesb.Remove(0, grnamindx + 1); table = tablesb.ToString(); title = group.Substring(0, grnamindx); } strGetGroups = "SELECT RecID,Info FROM " + table + " where RecType = " + (uint)RecordType.Group; strGetGroups = strGetGroups + " and ParentID = '00000000'"; strGetGroups += " ORDER BY RecID ASC"; try { DBE.Command(strGetGroups); DBE.Reader(); if (DBE.Read()) { string RecID = DBE.GetString(0); string Info = DBE.GetString(1); XmlTextReader rdr = new XmlTextReader(Info, XmlNodeType.Element, null); XmlNode nd = ROXml.ReadNode(rdr); VlnXmlElement elem = (VlnXmlElement)nd; elem.MyROID = RecID; root.AppendChild(elem); elem.SetAttribute("RecID", RecID); elem.SetAttribute("ParentID", "00000000"); elem.SetAttribute("Table", table); elem.SetAttribute("MasterRecID", mySL.GetKey(i).ToString()); //elem.SetAttribute("MenuTitle", elem.InnerText); } } catch (Exception e) { MessageBox.Show(e.Message, "Error getting group data"); // try to continue on with the next group - may be one missing table. } DBE.CommandDispose(); DBE.ReaderClose(); } // get child count for each group. XmlNode node = root.FirstChild; while (node != null) { if (node is VlnXmlElement) { VlnXmlElement child = (VlnXmlElement)node; //get child count for each table listed in innertext. string strGetSubCount = "SELECT COUNT (RecID) as cnt FROM " + child.GetAttribute("Table") + " WHERE "; strGetSubCount = strGetSubCount + "ParentID='" + child.GetAttribute("RecID") + "'"; try { DBE.Command(strGetSubCount); DBE.Reader(); } catch (Exception e) { MessageBox.Show(e.Message, "Error reading RO Data"); return false; } if (DBE.Read()) { int cnt = DBE.GetInt32(0); if (cnt > 0) child.SetAttribute("HasChild", "True"); else child.SetAttribute("HasChild", "False"); child.SetAttribute("ChildLoaded", "False"); } DBE.CommandDispose(); DBE.ReaderClose(); } node = node.NextSibling; } // for the beginning and end schema element, go to the master & read it from there. Store these to be used // by all of the databases. string strGetSchemaPiece; schemastart = null; strGetSchemaPiece = "SELECT Info From ROMaster where (ParentID='00000000' and RecType = " + (uint)RecordType.SchemaStart + ")"; DBE.Command(strGetSchemaPiece); DBE.Reader(); if (DBE.Read()) schemastart = DBE.GetString(0); else { DBE.CommandDispose(); DBE.ReaderClose(); return false; } DBE.CommandDispose(); DBE.ReaderClose(); schemaend = null; strGetSchemaPiece = "SELECT Info From ROMaster where (ParentID='00000000' and RecType = " + (uint)RecordType.SchemaEnd + ")"; DBE.Command(strGetSchemaPiece); DBE.Reader(); if (DBE.Read()) schemaend = DBE.GetString(0); else { DBE.CommandDispose(); DBE.ReaderClose(); return false; } DBE.CommandDispose(); DBE.ReaderClose(); return true; } public override bool RODB_DeleteGroup(XmlNode group, string tbname, string toprecid) { VlnXmlElement egroup = null; string strDel; strDel = "DELETE FROM ROMaster WHERE "; // delete table entry in ROMaster if (group != null) { egroup = (VlnXmlElement)group; strDel = strDel + "RecID='" + egroup.GetAttribute("MasterRecID") + "'"; } else strDel = strDel + "RecID='" + toprecid + "'"; try { DBE.Command(strDel); DBE.Reader(); DBE.Read(); } catch (Exception e) { MessageBox.Show(e.Message, "Error When deleting SubGroup ROs."); DBE.CommandDispose(); DBE.ReaderClose(); return false; } DBE.CommandDispose(); DBE.ReaderClose(); // now remove the table. if (egroup != null) strDel = "DROP TABLE " + egroup.GetAttribute("Table"); else strDel = "DROP TABLE " + tbname; try { DBE.Command(strDel); DBE.Reader(); DBE.Read(); } catch (Exception e) { MessageBox.Show(e.Message, "Error When deleting SubGroup ROs."); DBE.CommandDispose(); DBE.ReaderClose(); return false; } DBE.CommandDispose(); DBE.ReaderClose(); return true; } // Delete from database either the group or RO from input node. public override bool RODB_DeleteRO(XmlNode group) { // delete from database and then delete from tree. delete group and all // subgroups & ros beneath it. delete subgroups by calling this. // note that if just an ro is passed in, it will only delete it. XmlNode node = group.FirstChild; VlnXmlElement child; VlnXmlElement egroup = (VlnXmlElement)group; string strDelSub; if (group.Name == "vlnGroup") { while (node != null) { if (node is VlnXmlElement) { child = (VlnXmlElement)node; // if this is a group, call this again. if (child.Name == "vlnGroup") { bool success = RODB_DeleteRO(node); if (success == false) { MessageBox.Show("error in RODB_DeleteGroup"); return false; } } } node = node.NextSibling; } // delete all db records that have the ParentID = to this group RecID. // (All subgroups should be processed from above recursion. strDelSub = "DELETE FROM " + egroup.GetAttribute("Table") + " WHERE "; strDelSub = strDelSub + "ParentID='" + egroup.GetAttribute("RecID") + "'"; try { DBE.Command(strDelSub); DBE.Reader(); DBE.Read(); } catch (Exception e) { MessageBox.Show(e.Message, "Error When deleting SubGroup ROs."); DBE.CommandDispose(); DBE.ReaderClose(); return false; } DBE.CommandDispose(); DBE.ReaderClose(); } // now delete this ro or group, i.e. the one passed in. strDelSub = "DELETE FROM " + egroup.GetAttribute("Table") + " WHERE "; strDelSub = strDelSub + "RecID='" + egroup.GetAttribute("RecID") + "'"; try { DBE.Command(strDelSub); DBE.Reader(); DBE.Read(); } catch (Exception e) { MessageBox.Show(e.Message, "Error When deleting this RO."); DBE.CommandDispose(); DBE.ReaderClose(); return false; } DBE.CommandDispose(); DBE.ReaderClose(); return true; } //public string GenerateXmlString(XmlNode node, bool isgroup) // KBR not sure - see end of method //{ // string retstr; // XmlTextWriter xmlTextWriter; // StringWriter strWriter = new StringWriter(); // xmlTextWriter = new XmlTextWriter(strWriter); // VlnXmlElement enode; // XmlNode kid; // kid = node.FirstChild; // enode = (VlnXmlElement)node; // if (isgroup == true) // { // xmlTextWriter.WriteStartElement("vlnGroup"); // if (enode.HasAttribute("RetVal")) // { // xmlTextWriter.WriteStartAttribute("RetVal", null); // xmlTextWriter.WriteString(enode.GetAttribute("RetVal")); // xmlTextWriter.WriteEndAttribute(); // } // if (enode.HasAttribute("MenuItem")) // { // xmlTextWriter.WriteStartAttribute("MenuItem", null); // xmlTextWriter.WriteString(enode.GetAttribute("MenuItem")); // xmlTextWriter.WriteEndAttribute(); // } // if (enode.HasAttribute("FieldsInUse")) // { // xmlTextWriter.WriteStartAttribute("FieldsInUse", null); // xmlTextWriter.WriteString(enode.GetAttribute("FieldsInUse")); // xmlTextWriter.WriteEndAttribute(); // } // if (enode.HasAttribute("GroupMenuItem")) // { // xmlTextWriter.WriteStartAttribute("GroupMenuItem", null); // xmlTextWriter.WriteString(enode.GetAttribute("GroupMenuItem")); // xmlTextWriter.WriteEndAttribute(); // } // if (enode.HasAttribute("GroupFieldsInUse")) // { // xmlTextWriter.WriteStartAttribute("GroupFieldsInUse", null); // xmlTextWriter.WriteString(enode.GetAttribute("GroupFieldsInUse")); // xmlTextWriter.WriteEndAttribute(); // } // if (enode.HasAttribute("AccPageID")) // { // xmlTextWriter.WriteStartAttribute("AccPageID", null); // xmlTextWriter.WriteString(enode.GetAttribute("AccPageID")); // xmlTextWriter.WriteEndAttribute(); // } // if (enode.HasAttribute("AccPageIDPrefix")) // { // xmlTextWriter.WriteStartAttribute("AccPageIDPrefix", null); // xmlTextWriter.WriteString(enode.GetAttribute("AccPageIDPrefix")); // xmlTextWriter.WriteEndAttribute(); // } // xmlTextWriter.WriteStartAttribute("MenuTitle", null); // xmlTextWriter.WriteString(enode.GetAttribute("MenuTitle")); // xmlTextWriter.WriteEndAttribute(); // while (kid != null) // { // if ((kid is XmlText) || (kid.ChildNodes.Count == 1 && kid.Name != "vlnGroup")) // kid.WriteTo(xmlTextWriter); // kid = kid.NextSibling; // } // } // else // { // xmlTextWriter.WriteStartElement(node.Name); // xmlTextWriter.WriteStartAttribute("MenuTitle", null); // xmlTextWriter.WriteString(enode.GetAttribute("MenuTitle")); // xmlTextWriter.WriteEndAttribute(); // while (kid != null) // { // kid.WriteTo(xmlTextWriter); // kid = kid.NextSibling; // } // } // xmlTextWriter.WriteEndElement(); // vlnGroup or top of RO. // xmlTextWriter.Flush(); // xmlTextWriter.Close(); // retstr = strWriter.ToString(); // // replace the single quote because ODBC fails if it's in a string because // // the single quote represents the beg/end of string when sending string to // // ODBC. // retstr = retstr.Replace("\'", "'"); // KBR - not sure if this method should be in RODB class or db specific class // return (retstr); //} public override bool RODB_WriteGroup(XmlNode group, VlnXmlElement master) { bool retval = true; string dt = string.Format("{0:yyyyMMddHHmmss}", System.DateTime.Now); string xmlstr = GenerateXmlString(group, true); string strUpdate = "UPDATE " + master.GetAttribute("Table") + " SET Info = '" + xmlstr + "'"; strUpdate = strUpdate + ", ModDateTime = '" + dt + "' WHERE RecID='" + master.GetAttribute("RecID") + "'"; try { DBE.Command(strUpdate); DBE.Reader(); } catch (Exception e) { MessageBox.Show(e.Message, "Error on write group"); retval = false; } DBE.ReaderClose(); DBE.CommandDispose(); return retval; } public override bool RODB_InsertGroup(VlnXmlElement group) { bool retval = true; string dt = string.Format("{0:yyyyMMddHHmmss}", System.DateTime.Now); string xmlstr = GenerateXmlString(group, true); string strInsert = "INSERT INTO " + group.GetAttribute("Table") + "(RecID, RecType, ParentID, ModDateTime, Info) "; strInsert = strInsert + " VALUES ('" + group.GetAttribute("RecID") + "'," + (uint)RecordType.Group + ",'"; strInsert = strInsert + group.GetAttribute("ParentID") + "','" + dt + "','" + xmlstr + "');"; try { DBE.Command(strInsert); DBE.Reader(); } catch (Exception e) { MessageBox.Show(e.Message, "Error on insert group"); retval = false; } DBE.ReaderClose(); DBE.CommandDispose(); return retval; } // add a new database table, add a record to master to point to it. return // that record number. public override string RODB_AddNewTable(string TblName, string newgrpname) { bool retval = false; // create the table. this is done by doing a select into the new table // from the RoMaster because using the create table command didn't have // a datatype that was compatible between sql & ms-access (for the memo // field 'Info'). string strMkTable = "SELECT * INTO " + TblName; strMkTable = strMkTable + " FROM ROMaster WHERE RecID = '00000000';"; try { DBE.Command(strMkTable); DBE.Reader(); retval = true; } catch (Exception e) { MessageBox.Show(e.Message, "Error creating table."); } DBE.ReaderClose(); DBE.CommandDispose(); // return if error on table create. if (retval == false) return null; // remove the first record. It was inserted just to have something to copy to // create the table. (see previous comment) string strDel = "DELETE FROM " + TblName + " WHERE RecID = '00000000'"; try { DBE.Command(strDel); DBE.Reader(); DBE.Read(); } catch (Exception e) { MessageBox.Show(e.Message, "Error When deleting SubGroup ROs."); DBE.CommandDispose(); DBE.ReaderClose(); return null; } DBE.CommandDispose(); DBE.ReaderClose(); // now insert the first record string dt = string.Format("{0:yyyyMMddHHmmss}", System.DateTime.Now); string strInsert = "INSERT INTO " + TblName + "( RecID, RecType, ParentID, ModDateTime, Info ) "; strInsert = strInsert + " VALUES ('00000000', 0,'00000000','" + dt + "','00000001');"; retval = false; try { DBE.Command(strInsert); DBE.Reader(); retval = true; } catch (Exception e) { MessageBox.Show(e.Message, "Error creating table."); } DBE.ReaderClose(); DBE.CommandDispose(); // return if error on insert of master record of new table, otherwise add // this table reference to the master. if (retval == false) return null; string recid = RODB_GetNextRecId("ROMaster"); string info = CvtUserFldToFld(newgrpname) + "\t" + TblName; strInsert = "INSERT INTO ROMaster ( RecID, RecType, ParentID, ModDateTime, Info ) "; strInsert = strInsert + " VALUES ('" + recid + "', 1,'00000001','" + dt + "','" + info + "');"; retval = false; try { DBE.Command(strInsert); DBE.Reader(); retval = true; } catch (Exception e) { MessageBox.Show(e.Message, "Error writing new table to master."); } DBE.ReaderClose(); DBE.CommandDispose(); if (retval == false) return null; else return recid; } // Copy over field definitions from the ROMaster to the input table. public override bool RODB_CopyFieldDefs(string fromtb, string totb, int type) { ArrayList retlist = new ArrayList(); string strGetFields; string Info; string RecID; string name; uint ftype; ROField rof; bool success; // select all of the field definition records in this table. strGetFields = "SELECT RecID, Info from ROMaster where RecType = 2"; DBE.Command(strGetFields); DBE.Reader(); while (DBE.Read()) { RecID = DBE.GetString(0); Info = DBE.GetString(1); // it's defined in the local table if the first character is "<" which starts // the schema definition string. name = ParseEleName(Info); if (name != null) { // what type of schema element? rof = new ROField(name, RecID, null, 0); ftype = rof.ParseFieldType(Info); rof.SetFieldType(ftype); retlist.Add((object)rof); } } DBE.ReaderClose(); DBE.CommandDispose(); // using this list, add new records for field definition references to the new // table. for (int i = 0; i < retlist.Count; i++) { rof = (ROField)retlist[i]; if (rof.GetFieldname != null) { string mrecid = rof.GetRecID; string lrecid = RODB_GetNextRecId(totb); StringBuilder strbld = new StringBuilder(); strbld.Append(mrecid); strbld.Append(" "); string strtype = rof.GetFieldType.ToString(); strbld.Append(strtype.PadLeft(3, '0')); strbld.Append(" "); if (strtype == "128") // append an 'a' for combo type strbld.Append(rof.MakeFieldName(rof.GetFieldname) + "a"); else strbld.Append(rof.MakeFieldName(rof.GetFieldname)); // add new field. success = RODB_NewSchemaPiece(lrecid, "00000002", totb, strbld.ToString(), 2); if (success == false) return false; } } return true; } // This is simular to GetChildData() but this function reads in // all the subgroups for the given node // Note that this function is designed to be call for the // root node (i.e. it gets all of group and RO data for a given // database table) public override bool RODB_GetGroupAndSubgroups(VlnXmlElement node, StringBuilder sb) { VlnStatusBar StatBar = new VlnStatusBar("Reading from the Database"); string tablename = node.GetAttribute("Table"); string strGetChildData = "SELECT * FROM " + tablename; strGetChildData = strGetChildData + " where (RecType = 3 or RecType = 5) AND ParentID <> '00000002' ORDER BY ParentID,RecID ASC"; HybridDictionary dicGroups = new HybridDictionary(); dicGroups.Add(node.GetAttribute("RecID").ToString(), node); StatBar.BarMax = RODB_GetNumberOfGroupRecords(tablename); //get number of groups StatBar.BarStepValue = 5; StatBar.StatMsg = node.InnerText; DBE.Command(strGetChildData); DBE.Reader(); // skip the first record - it's the node that we passed in if (!DBE.Read()) { DBE.ReaderClose(); StatBar.PerformStep(1); return false; } while (DBE.Read()) { string RecID = DBE.GetString(0); int RecType = DBE.GetInt32(1); string ParID = DBE.GetString(2); string AccPageID = DBE.GetString(3); string Info = DBE.GetString(5); if (!ParID.Equals(node.GetAttribute("RecID"))) { if (!dicGroups.Contains(ParID)) { if (sb.Length == 0) { sb.AppendLine("The following records were skipped."); sb.AppendLine("The parent for these RO's was missing."); sb.AppendLine(); } string strMBText = "RecID: " + RecID + "\n\n Table: " + tablename + "\n"; sb.AppendLine(strMBText); // MessageBox.Show(strMBText, "Warning - Orphan RO Record"); continue; // skip - no parent for this node } node = (VlnXmlElement)dicGroups[ParID]; node.SetAttribute("HasChild", "True"); node.SetAttribute("ChildLoaded", "True"); } else { node.SetAttribute("ChildLoaded", "True"); } if (RecType == (uint)RecordType.Group) { VlnXmlElement elem; StatBar.PerformStep(); try { XmlTextReader rdr = new XmlTextReader(Info, XmlNodeType.Element, null); XmlNode nd = ROXml.ReadNode(rdr); elem = (VlnXmlElement)nd; } catch (Exception e) { MessageBox.Show(e.Message, "Error reading Xml Group From data"); DBE.ReaderClose(); return false; } elem.MyROID = RecID; elem.SetAttribute("RecID", RecID); elem.SetAttribute("ParentID", node.GetAttribute("RecID")); elem.SetAttribute("Table", node.GetAttribute("Table")); if (!dicGroups.Contains(RecID)) { node.AppendChild(elem); dicGroups.Add(RecID, elem); } // The Parameter Display Data is stored along with the group. This data // was migrated over so that the data was not lost, but there is no // User Interface to get to it. So remove the xml elements from the // group part of tree. All valid group data only has one sublevel of // data defining the group name. XmlNode grp = (XmlNode)elem; XmlNode kid = grp.FirstChild; XmlNode tmpkid; while (kid != null) { tmpkid = kid.NextSibling; if (kid is VlnXmlElement) if (kid.ChildNodes.Count > 1) grp.RemoveChild(kid); kid = tmpkid; } } // Store data in the VlnXmlElement as an RO else if (RecType == (uint)RecordType.RRO) { //Create the reader. XmlNode ro; try { //B2022-043 &pos; was missing the ; if (Info != null) Info = Info.Replace("'", "\'"); // B2021-071: crash when getting/saving field names XmlTextReader roreader = new XmlTextReader(Info, XmlNodeType.Element, null); ro = ROXml.ReadNode(roreader); } catch (Exception e) { MessageBox.Show(e.Message, "Error reading Xml RRO From data"); DBE.ReaderClose(); return false; } VlnXmlElement elem = (VlnXmlElement)ro; node.AppendChild(ro); elem.MyROID = RecID; elem.SetAttribute("RecID", RecID); elem.SetAttribute("ParentID", node.GetAttribute("RecID")); elem.SetAttribute("Table", node.GetAttribute("Table")); elem.SetAttribute("AccPageID", AccPageID); } } DBE.ReaderClose(); dicGroups = null; StatBar.Dispose(); return true; } public override bool RODB_GetChildData(VlnXmlElement node, bool CheckChildCount) { ShowCount.GetChildData++; // get menu fields to display here. string tablename = node.GetAttribute("Table"); string strGetChildData = "SELECT RecID,RecType,AccPageID, Info FROM " + tablename + " where "; strGetChildData = strGetChildData + "(RecType = " + (uint)RecordType.Group + " or RecType = "; strGetChildData = strGetChildData + (uint)RecordType.RRO + ") and "; strGetChildData = strGetChildData + "ParentID='" + node.GetAttribute("RecID") + "'"; strGetChildData += " ORDER BY RecID ASC"; //bool readit=false; DBE.Command(strGetChildData); DBE.Reader(); while (DBE.Read()) { ShowCount.Children++; //get count for attribute element string RecID = DBE.GetString(0); int RecType = DBE.GetInt32(1); MyRecID = RecID; string AccPageID = DBE.GetString(2); string Info = DBE.GetString(3); //B2022-043 &pos; was missing the ; Info = Info.Replace("'", "\'"); // B2021-071: crash when getting/saving field names node.SetAttribute("HasChild", "True"); // Store data in the VlnXmlElement as a subgroup if (RecType == (uint)RecordType.Group) { VlnXmlElement elem; try { XmlTextReader rdr = new XmlTextReader(Info, XmlNodeType.Element, null); XmlNode nd = ROXml.ReadNode(rdr); elem = (VlnXmlElement)nd; } catch (Exception e) { MessageBox.Show(e.Message, "Error reading Xml Group From data"); DBE.ReaderClose(); return false; } node.AppendChild(elem); elem.MyROID = RecID; elem.SetAttribute("RecID", RecID); elem.SetAttribute("ParentID", node.GetAttribute("RecID")); elem.SetAttribute("Table", node.GetAttribute("Table")); // The Parameter Display Data is stored along with the group. This data // was migrated over so that the data was not lost, but there is no // User Interface to get to it. So remove the xml elements from the // group part of tree. All valid group data only has one sublevel of // data defining the group name. XmlNode grp = (XmlNode)elem; XmlNode kid = grp.FirstChild; XmlNode tmpkid; while (kid != null) { tmpkid = kid.NextSibling; if (kid is VlnXmlElement) if (kid.ChildNodes.Count > 1) grp.RemoveChild(kid); kid = tmpkid; } } // Store data in the VlnXmlElement as an RO else if (RecType == (uint)RecordType.RRO) { //Create the reader. XmlNode ro; try { XmlTextReader roreader = new XmlTextReader(Info, XmlNodeType.Element, null); ro = ROXml.ReadNode(roreader); } catch (Exception e) { MessageBox.Show(e.Message, "Error reading Xml RRO From data"); DBE.ReaderClose(); return false; } VlnXmlElement elem = (VlnXmlElement)ro; elem.MyROID = RecID; node.AppendChild(ro); elem.SetAttribute("RecID", RecID); elem.SetAttribute("ParentID", node.GetAttribute("RecID")); elem.SetAttribute("Table", node.GetAttribute("Table")); elem.SetAttribute("AccPageID", AccPageID); } } DBE.ReaderClose(); // get child count for each subgroup. if (CheckChildCount) { //A different approach - Look for grandchildren and set the haschildren attribute //Build a query to get a list of children with children string strGetSubCount = "SELECT R1.ParentID,COUNT(*) AS CNT FROM " + tablename + " R1 " + "INNER JOIN " + tablename + " R2 ON R1.ParentID = R2.RecID " + "WHERE (R1.RecType = " + (uint)RecordType.Group + " or R1.RecType=" + (uint)RecordType.RRO + ") " + "and R2.ParentID ='" + node.GetAttribute("RecID") + "' group by R1.ParentID;"; try { DBE.Command(strGetSubCount); DBE.Reader(); } catch (Exception e) { MessageBox.Show(e.Message, "Error reading data"); } //Build a Dictionary of Children with Children from the query results HybridDictionary dicChild = new HybridDictionary(); while (DBE.Read()) dicChild[DBE.GetString(0)] = DBE.GetInt32(1);//This adds the entry and sets the value DBE.CommandDispose(); DBE.ReaderClose(); XmlNode child = node.FirstChild; while (child != null) //Look at each child node { if (child is VlnXmlElement) { VlnXmlElement echild = (VlnXmlElement)child; if (echild.Name == "vlnGroup") { //If the dictionary contains an entry, the child has children echild.SetAttribute("HasChild", (dicChild.Contains(echild.GetAttribute("RecID"))) ? "True" : "False"); echild.SetAttribute("ChildLoaded", "False"); } } child = child.NextSibling; } dicChild = null; } node.SetAttribute("ChildLoaded", "True"); return true; } public override bool IsDuplicateAccPageID(VlnXmlElement ro, string newacc) { string strcheck, inacc = null; bool isdup = false; int indx = newacc.IndexOf("'"); if (indx >= 0) inacc = newacc.Insert(indx, "'"); else inacc = newacc; strcheck = "SELECT Count(RecID) AS CNT FROM " + ro.GetAttribute("Table") + " WHERE AccPageID = '" + inacc + "'"; if (ro.HasAttribute("RecID")) // new ro's don't have recid defined yet before this test. strcheck = strcheck + " AND (NOT RecID = '" + ro.GetAttribute("RecID") + "')"; try { DBE.Command(strcheck); DBE.Reader(); } catch (Exception e) { MessageBox.Show(e.Message, "Error on check"); return true; } if (DBE.Read()) { int cnt = DBE.GetInt32(0); if (cnt > 0) isdup = true; else isdup = false; } DBE.CommandDispose(); DBE.ReaderClose(); return isdup; } public override VlnXmlElement RODB_ReadRO(string tbl, string recid) { ShowCount.ReadRo++; VlnXmlElement retele = null; string readstr = "SELECT ParentID, AccPageID, Info FROM " + tbl + " WHERE " + ((recid == null) ? "RecType=3 and ParentID = '00000000'" : ("RecID = '" + recid + "'")); try { DBE.Command(readstr); DBE.Reader(); // With the additional check for a recid=null, in the WHERE statement (above), we now longer need to check and skip for a null recid - jsj 4-17-2015 //if (recid == null) // DBE.Read(); // skip the first parentID record of 00000000 if (DBE.Read()) { string ParentID = DBE.GetString(0); string AccPageID = DBE.GetString(1); string Info = DBE.GetString(2); // Store data in the VlnXmlElement XmlTextReader rdr = new XmlTextReader(Info, XmlNodeType.Element, null); XmlNode nd = ROXml.ReadNode(rdr); retele = (VlnXmlElement)nd; retele.SetAttribute("RecID", recid); retele.SetAttribute("ParentID", ParentID); retele.SetAttribute("Table", tbl); if (retele.Name != "vlnGroup") retele.SetAttribute("AccPageID", AccPageID); } DBE.CommandDispose(); DBE.ReaderClose(); // if this is a group, see if children. // if the DBE.Read() cannot find the RO, then retele remains a NULL // the null check was added to prevent a null reference error if (retele != null && retele.Name == "vlnGroup") { string strGetSubCount = "SELECT COUNT (RecID) as cnt FROM " + tbl + " WHERE "; strGetSubCount = strGetSubCount + "ParentID='" + recid + "'"; DBE.Command(strGetSubCount); DBE.Reader(); if (DBE.Read()) { int cnt = DBE.GetInt32(0); if (cnt > 0) retele.SetAttribute("HasChild", "True"); else retele.SetAttribute("HasChild", "False"); retele.SetAttribute("ChildLoaded", "False"); } DBE.CommandDispose(); DBE.ReaderClose(); } } catch (Exception e) { MessageBox.Show(e.Message, "Error on Read of RO"); return null; } return retele; } public override bool RODB_WriteRO(VlnXmlElement ro, bool movedRO = false) { bool success; if (ro.Name == "vlnGroup") { success = RODB_WriteGroup(ro, ro); return success; } else { string wraccid = null; string accid = ro.GetAttribute("AccPageID"); int quote = accid.IndexOf("'"); if (quote >= 0) wraccid = accid.Insert(quote, "'"); else wraccid = accid; string dt = string.Format("{0:yyyyMMddHHmmss}", System.DateTime.Now); string xmlstr = GenerateXmlString(ro, false); string strUpdate = "UPDATE " + ro.GetAttribute("Table") + " SET Info = '" + xmlstr + "'"; if (movedRO) { VlnXmlElement parent = (VlnXmlElement)ro.ParentNode; ro.SetAttribute("ParentID", parent.GetAttribute("RecID")); strUpdate += ", ParentID = '" + ro.GetAttribute("ParentID") + "'"; } strUpdate = strUpdate + ", ModDateTime = '" + dt + "', AccPageID = '" + wraccid + "' WHERE RecID='" + ro.GetAttribute("RecID") + "'"; try { DBE.Command(strUpdate); DBE.Reader(); success = true; } catch (Exception e) { MessageBox.Show(e.Message, "Database Write Error"); success = false; } DBE.ReaderClose(); DBE.CommandDispose(); } return success; } public override bool RODB_InsertRO(VlnXmlElement ro) { bool success = false; string strInsert = null; string dt = string.Format("{0:yyyyMMddHHmmss}", System.DateTime.Now); VlnXmlElement parent = (VlnXmlElement)ro.ParentNode; string lrecid = RODB_GetNextRecId(parent.GetAttribute("Table")); ro.SetAttribute("Table", parent.GetAttribute("Table")); ro.SetAttribute("RecID", lrecid); ro.SetAttribute("ParentID", parent.GetAttribute("RecID")); string haskids = parent.GetAttribute("HasChild"); if (haskids == "False" || haskids == "") { parent.SetAttribute("HasChild", "True"); parent.SetAttribute("ChildLoaded", "True"); } string xmlstr = GenerateXmlString(ro, false); string wraccid = null; if (ro.HasAttribute("AccPageID")) { string accid = ro.GetAttribute("AccPageID"); int quote = accid.IndexOf("'"); if (quote >= 0) wraccid = accid.Insert(quote, "'"); else wraccid = accid; } if (ro.Name == "vlnGroup") { // add attribute to flag that this does not have xml children, i.e. any // other subgroups or ros under it. ro.SetAttribute("HasChild", "False"); if (ro.HasAttribute("AccPageID")) { // Code is never reached, but this was noticed - this next line should likely be: // strInsert = "INSERT INTO " + parent.GetAttribute("Table") + "( RecID, RecType, ParentID, AccPageID, ModDateTime, Info ) "; strInsert = "INSERT INTO " + parent.GetAttribute("Table") + "( RecID, RecType, ParentID, ModDateTime, AccPageID, Info ) "; strInsert = strInsert + " VALUES ('" + ro.GetAttribute("RecID") + "'," + (uint)RecordType.Group + ",'" + ro.GetAttribute("ParentID"); strInsert = strInsert + "','" + wraccid + "','" + dt + "','" + xmlstr + "');"; } else { strInsert = "INSERT INTO " + parent.GetAttribute("Table") + "( RecID, RecType, ParentID, ModDateTime, Info ) "; strInsert = strInsert + " VALUES ('" + ro.GetAttribute("RecID") + "'," + (uint)RecordType.Group + ",'" + ro.GetAttribute("ParentID"); strInsert = strInsert + "','" + dt + "','" + xmlstr + "');"; } } else { strInsert = "INSERT INTO " + parent.GetAttribute("Table") + "( RecID, RecType, ParentID, AccPageId, ModDateTime, Info ) "; strInsert = strInsert + " VALUES ('" + ro.GetAttribute("RecID") + "'," + (uint)RecordType.RRO + ",'" + ro.GetAttribute("ParentID"); strInsert = strInsert + "','" + wraccid + "','" + dt + "','" + xmlstr + "');"; } try { DBE.Command(strInsert); DBE.Reader(); success = true; } catch (Exception e) { MessageBox.Show(e.Message, "Database Write Error"); } DBE.ReaderClose(); DBE.CommandDispose(); return success; } public override ushort RODB_GetFieldType(VlnXmlElement elem, string TableName, string Fld) { string strGetFields; string Info; string RecID; string name; string tmpname; ushort ftype = 0; ROField rof; if (TableName != lastTable) { lastTable = TableName; dicFldTypes = new HybridDictionary(); // select all of the field definition records in this table. // strGetFields = "SELECT RecID, Info from " + elem.GetAttribute("Table"); strGetFields = "SELECT RecID, Info from " + TableName; strGetFields = strGetFields + " where RecType = 2"; // + rtype.ToString(); DBE.Command(strGetFields); DBE.Reader(); // NOTE !!!! // This function does not handle Combo type fields (128). while (DBE.Read())// && ftype == 0) { RecID = DBE.GetString(0); Info = DBE.GetString(1); // it's defined in the local table if the first character is "<" which starts // the schema definition string. if ("<" == Info.Substring(0, 1)) { name = ParseEleName(Info); if (name != null) { tmpname = CvtUserFldToFld(name); //if (tmpname.Equals(Fld)) //{ rof = new ROField(name, RecID, null, 0); // uint tmpfldtype = rof.ParseFieldType(Info); ftype = GetFSTreturnType(System.Convert.ToUInt16(rof.ParseFieldType(Info)), tmpname, elem); dicFldTypes[tmpname] = ftype; //} } } else { // references master, but what we need is here: the field name and // the the field type. Just parse this from the info field. string parsename; // string strftype; // strftype = Info.Substring(9,3); parsename = Info.Substring(13, Info.Length - 13); //if (parsename.Equals(Fld)) //{ ftype = GetFSTreturnType(System.Convert.ToUInt16(Info.Substring(9, 3)), parsename, elem); dicFldTypes[parsename] = ftype; //} } } DBE.ReaderClose(); DBE.CommandDispose(); } ftype = ((ushort)dicFldTypes[Fld]); return ftype; } // For the given element's table, get all of the RO fields defined in this table. public override ArrayList RODB_GetFields(VlnXmlElement elem, uint rtype, bool refresh = false) { string table = elem.GetAttribute("Table"); if (!FieldDefinitions.ContainsKey(table)) FieldDefinitions.Add(table, RODB_GetFieldsFromDB(elem)); else if (refresh) { FieldDefinitions.Remove(table); FieldDefinitions.Add(table, RODB_GetFieldsFromDB(elem)); } return FieldDefinitions[table]; } private Dictionary _FieldDefinitions = null; public Dictionary FieldDefinitions { get { if (_FieldDefinitions == null) _FieldDefinitions = new Dictionary(); return _FieldDefinitions; } set { _FieldDefinitions = value; } } private ArrayList RODB_GetFieldsFromDB(VlnXmlElement elem) { ShowCount.GetFields++; ArrayList retlist = new ArrayList(); string strGetFields; string Info; string RecID; string name; uint ftype; ROField rof; // select all of the field definition records in this table. strGetFields = "SELECT RecID, Info from " + elem.GetAttribute("Table"); strGetFields = strGetFields + " where RecType = 2"; // + rtype.ToString(); DBE.Command(strGetFields); DBE.Reader(); while (DBE.Read()) { ShowCount.RoFields++; RecID = DBE.GetString(0); MyRecID = RecID; Info = DBE.GetString(1); // it's defined in the local table if the first character is "<" which starts // the schema definition string. if ("<" == Info.Substring(0, 1)) { name = ParseEleName(Info); if (name != null) { // what type of schema element? rof = new ROField(name, RecID, null, 0); ftype = rof.ParseFieldType(Info); rof.SetFieldType(ftype); retlist.Add((object)rof); } } else { // the recid points to a field definition (schema) in the master - use it to get // the schema element from the master and copy it. string parsename; string masterrecid; string strftype; masterrecid = Info.Substring(0, 8); strftype = Info.Substring(9, 3); ftype = System.Convert.ToUInt32(Info.Substring(9, 3)); parsename = CvtFldToUserFld(Info.Substring(13, Info.Length - 13)); // if we have a choice element, remove the last character (it was added to the // field names in order to allow for unique fields names for the choice items. if (ftype == (uint)FieldTypes.Combination) { string tparsename = parsename.Remove((parsename.Length) - 1, 1); // remove the choice string and the space parsename = tparsename; } rof = new ROField(parsename, RecID, masterrecid, ftype); retlist.Add((object)rof); } } DBE.ReaderClose(); DBE.CommandDispose(); return retlist; } public override string RODB_GetSchemaPiece(string Recid, string table) { string strGetSchemaPiece; string Info; strGetSchemaPiece = "SELECT Info From " + table + " where (RecID = '" + Recid + "')"; DBE.Command(strGetSchemaPiece); DBE.Reader(); if (DBE.Read()) Info = DBE.GetString(0); else Info = null; DBE.ReaderClose(); DBE.CommandDispose(); return Info?.Replace("'", "\'"); } public override bool RODB_NewSchemaPiece(string recid, string parentid, string table, string schpiece, uint rtype) { string strSchemaPiece; bool success = true; string dt = string.Format("{0:yyyyMMddHHmmss}", System.DateTime.Now); strSchemaPiece = "INSERT INTO " + table + " (RecID, RecType, ParentID, ModDateTime, Info) VALUES ('"; // B2004-016: at one point all fields are returned using a record type of 2 (Schema) - // but the insertion code did not account for this when inserting a type of 4 (GroupSchema) - i.e. // RecordType of 4 is no longer used, all fields (whether schema or group) are defined // as RecordTYpe of 2. //strSchemaPiece = strSchemaPiece + recid + "', " + rtype.ToString() + ", '" + parentid + "', '" + dt + "', '" + schpiece.Replace("\'","'") + "');"; strSchemaPiece = strSchemaPiece + recid + "', 2, '" + parentid + "', '" + dt + "', '" + schpiece.Replace("\'", "'") + "');"; DBE.Command(strSchemaPiece); try { DBE.Command(strSchemaPiece); DBE.Reader(); } catch (Exception e) { success = false; MessageBox.Show(e.Message, "Database Write Error"); } DBE.ReaderClose(); DBE.CommandDispose(); return success; } public override bool RODB_WriteSchemaPiece(string Recid, string table, string schpiece) { string strWriteSchemaPiece; bool success = true; string dt = string.Format("{0:yyyyMMddHHmmss}", System.DateTime.Now); strWriteSchemaPiece = "UPDATE " + table + " SET " + table + ".Info = '" + schpiece.Replace("\'", "'") + "'"; strWriteSchemaPiece = strWriteSchemaPiece + ", ModDateTime = '" + dt + "' WHERE RecID = '" + Recid + "';"; try { DBE.Command(strWriteSchemaPiece); DBE.Reader(); } catch (Exception e) { success = false; MessageBox.Show(e.Message, "Database Update Error"); } DBE.ReaderClose(); DBE.CommandDispose(); return success; } public override bool RODB_ProcessRROFieldChange(VlnXmlElement child, string oldname, string newname, uint editlevel, VlnStatusMessage StatMsgWindow, bool combofield) { bool success; string str; string info; string tinfo1, tinfo2, tinfo3, tinfo4; string dt; string onameOpen, nnameOpen, onameClose, nnameClose, onameComma, nnameComma; string onameOpenX, nnameOpenX; onameOpen = "<" + oldname + ">"; nnameOpen = "<" + newname + ">"; onameOpenX = "<" + oldname + ">"; nnameOpenX = "<" + newname + ">"; onameComma = "<" + oldname + ","; // if format in attribute nnameComma = "<" + newname + ","; onameClose = ""; nnameClose = ""; dt = string.Format("{0:yyyyMMddHHmmss}", System.DateTime.Now); try { // first do the string replace for the group node. This will change any // attributes which may have changed. str = "SELECT Info From " + child.GetAttribute("Table") + " where (RecID = '" + child.GetAttribute("RecID") + "')"; DBE.Command(str); DBE.Reader(); if (DBE.Read()) info = DBE.GetString(0); else info = null; DBE.ReaderClose(); DBE.CommandDispose(); tinfo1 = info.Replace(onameOpen, nnameOpen); tinfo2 = tinfo1.Replace(onameClose, nnameClose); tinfo3 = tinfo2.Replace(onameComma, nnameComma); tinfo4 = tinfo3.Replace(onameOpenX, nnameOpenX); if (tinfo4 != info) { StatMsgWindow.StatusMessage = child.GetAttribute("MenuTitle"); str = "UPDATE " + child.GetAttribute("Table") + " SET Info = '" + tinfo4 + "'"; str = str + ", ModDateTime = '" + dt + "' WHERE RecID = '" + child.GetAttribute("RecID") + "';"; DBE.Command(str); DBE.Reader(); DBE.ReaderClose(); DBE.CommandDispose(); if (child.Name == "vlnGroup" && child.ParentNode.Name != "RO_Root") { XmlNodeList nodeList; nodeList = child.SelectNodes(oldname); foreach (XmlNode nod in nodeList) { XmlNode newnode = ROXml.CreateNode(XmlNodeType.Element, newname, ""); newnode.InnerXml = nod.InnerXml; child.ReplaceChild(newnode, nod); } } // if at top, replace strings in attributes for xml node. Only needs done // for top node because remainder are done in xml string replace for entire // node and written to database, but XML tree is deleted from memory and // reread in as needed. if (child.ParentNode.Name == "RO_Root") { string tmp, tmp1; tmp = child.GetAttribute("RetVal"); if (tmp != null) { tmp1 = tmp.Replace(onameOpen, nnameOpen); child.SetAttribute("RetVal", tmp1); } tmp = child.GetAttribute("MenuItem"); if (tmp != null) { string conameOpen = "<" + oldname + ","; string cnnameOpen = "<" + newname + ","; tmp1 = tmp.Replace(onameOpen, nnameOpen); string tmp2 = tmp1.Replace(conameOpen, cnnameOpen); child.SetAttribute("MenuItem", tmp2); } tmp = child.GetAttribute("AccPageID"); if (tmp != null) { tmp1 = tmp.Replace(onameOpen, nnameOpen); child.SetAttribute("AccPageID", tmp1); } tmp = child.GetAttribute("GroupMenuItem"); if (tmp != null) { tmp1 = tmp.Replace(onameOpen, nnameOpen); child.SetAttribute("GroupMenuItem", tmp1); } } } // if this was an RO field definition change, need to go through the XML for // the ROs too. if (editlevel == (uint)RecordType.Schema) { XmlNode chldnode = (XmlNode)child.FirstChild; VlnXmlElement echild; while (chldnode != null) { if (chldnode is VlnXmlElement) { echild = (VlnXmlElement)chldnode; if (echild.Name != "vlnGroup") { // If this is a group defintion subtree it will only have one // child, which is the text definition for the subgroup. Don't // include these in the tree. int levelCnt = chldnode.ChildNodes.Count; string TheMenuTitle = echild.GetAttribute("MenuTitle"); if ((levelCnt >= 1) && !TheMenuTitle.Equals("")) { // read record, do string replace in info & write record. Also, replace // the xml node with a node with the new name. str = "SELECT Info From " + echild.GetAttribute("Table") + " where (RecID = '" + echild.GetAttribute("RecID") + "')"; DBE.Command(str); DBE.Reader(); if (DBE.Read()) info = DBE.GetString(0); else info = null; DBE.ReaderClose(); DBE.CommandDispose(); if (info != null) info = info.Replace("\'", "&apos"); // B2021-071: crash when getting/saving field names if (combofield == false) { tinfo1 = info.Replace(onameOpen, nnameOpen); tinfo1 = DoReplaceParentChildField(tinfo1, onameOpen, nnameOpen); //C2021-0226 also update Parent/Child fields tinfo2 = tinfo1.Replace(onameClose, nnameClose); tinfo2 = DoReplaceParentChildField(tinfo2, onameClose, nnameClose); //C2021-0226 also update Parent/Child fields XmlNodeList nodeList; nodeList = echild.SelectNodes(oldname); foreach (XmlNode nod in nodeList) { XmlNode newnode = ROXml.CreateNode(XmlNodeType.Element, newname, ""); newnode.InnerXml = nod.InnerXml; echild.ReplaceChild(newnode, nod); } } else // need a,b,c,d yikes { string nma, nmb, nmc, nmd; nma = DoCmbFieldReplace(info, onameOpen, nnameOpen, "a"); nmb = DoCmbFieldReplace(nma, onameOpen, nnameOpen, "b"); nmc = DoCmbFieldReplace(nmb, onameOpen, nnameOpen, "c"); nmd = DoCmbFieldReplace(nmc, onameOpen, nnameOpen, "d"); nma = DoCmbFieldReplace(nmd, onameClose, nnameClose, "a"); nmb = DoCmbFieldReplace(nma, onameClose, nnameClose, "b"); nmc = DoCmbFieldReplace(nmb, onameClose, nnameClose, "c"); tinfo2 = DoCmbFieldReplace(nmc, onameClose, nnameClose, "d"); // replace the combo nodes with the new name, do a-d in case there are more than // one value field stored for this combo type for (char tmplet = 'a'; tmplet < 'e'; tmplet++) { XmlNodeList nodeList; nodeList = echild.SelectNodes(oldname + tmplet.ToString()); foreach (XmlNode nod in nodeList) { XmlNode newnode = ROXml.CreateNode(XmlNodeType.Element, newname + tmplet, ""); newnode.InnerXml = nod.InnerXml; echild.ReplaceChild(newnode, nod); } } } StatMsgWindow.StatusMessage = echild.GetAttribute("MenuTitle"); str = "UPDATE " + echild.GetAttribute("Table") + " SET Info = '" + tinfo2 + "'"; str = str + ", ModDateTime = '" + dt + "' WHERE RecID = '" + echild.GetAttribute("RecID") + "';"; DBE.Command(str); DBE.Reader(); DBE.ReaderClose(); DBE.CommandDispose(); } } } chldnode = chldnode.NextSibling; } } return true; } catch (Exception e) { success = false; MessageBox.Show(e.Message, "Database Update Error"); } return success; } public override bool RODB_UpdateFieldRecord(ROField myrof, VlnXmlElement myelem, string strschema, string oldname, string newname, uint editlevel, bool combofield) { bool success = false; // If this is a generic definition that was modified, i.e. from ROMaster, ask // the user whether to update the generic field definition or make it local. if (myrof.GetMasterRecID != null) { // if field is defined in the ROMaster, and we change the field name - // first check if it is using one of the names used to define new // setpoint or graphics databases. If so, make it a local change only! bool changegeneric = true; if (oldname != newname) { // if this is one of the standard names - don't let them save it. bool isused = RODB_CheckForStandardName(oldname); if (isused == true) { MessageBox.Show("The field name is used to define new Setpoints or Graphics Database.\n The update will be for this local (database) group only.", "Field name modification."); changegeneric = false; } } // if standard name, from above check, don't ask user if it is generic // or not. if (changegeneric != false) { // B2021-072: don't update name if user selects No on dialog. This is actually misleading, because Yes updates // Generic definition, i.e. all Groups, and No updates only Local definition, i.e. just this Group Added a // Cancel button to Cancel from this dialog and return to previous dialog. Added more information to the // dialog to inform user of this string dmsg = "Update Generic definition?\r\n\r\n Yes - updates Generic definitions, \r\n No - updates Local definitions, \r\n Cancel - returns to previous dialog." + "\r\n\r\n 'Generic' updates definition in ALL groups that use the name\r\n 'Local' updates definition only in the selected group."; System.Windows.Forms.DialogResult result = MessageBox.Show(dmsg, "Referenced Object Definition", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); if (result == DialogResult.Cancel) return false; if (result == DialogResult.No) changegeneric = false; } if (changegeneric == true) { success = RODB_WriteSchemaPiece(myrof.GetMasterRecID, "ROMaster", strschema); if (success != true) return false; // if change in fieldname, need to go through all of the databases to // adjust for it. if (oldname != newname) { VlnStatusMessage StatMsgWindow = new VlnStatusMessage("Status of RO Field Change"); // get root xml element // loop through each subgroup under root. VlnXmlElement topgroup; topgroup = (VlnXmlElement)ROXml.FirstChild.FirstChild; string sqlstr, recid, tbl; while (topgroup != null) { tbl = topgroup.GetAttribute("Table"); // get the recid of this field definition from the current table. sqlstr = "SELECT RecID FROM " + tbl; sqlstr = sqlstr + " WHERE (((" + tbl + ".RecType) = 2) AND ((" + tbl + ".Info) like ('"; sqlstr = sqlstr + myrof.GetMasterRecID + "%')));"; DBE.Command(sqlstr); DBE.Reader(); if (DBE.Read()) recid = DBE.GetString(0); else recid = null; DBE.ReaderClose(); DBE.CommandDispose(); if (recid != null) { // update the local field definition record StringBuilder strbld = new StringBuilder(); strbld.Append(myrof.GetMasterRecID); strbld.Append(" "); string strtype = myrof.GetFieldType.ToString(); strbld.Append(strtype.PadLeft(3, '0')); strbld.Append(" "); strbld.Append(myrof.MakeFieldName(myrof.GetFieldname)); success = RODB_WriteSchemaPiece(recid, topgroup.GetAttribute("Table"), strbld.ToString()); topgroup.SetAttribute("TreeNotData", "True"); // Update subelements too. if (success == true) success = RODB_UpdateFieldNames(topgroup, recid, oldname, newname, editlevel, false, StatMsgWindow, combofield); //topgroup = (VlnXmlElement)topgroup.NextSibling; } topgroup = (VlnXmlElement)topgroup.NextSibling; // B2021-071: infinite loop (moved this from above loop } StatMsgWindow.Dispose(); } } else // change local { // modify the current to have the definition local. success = RODB_WriteSchemaPiece(myrof.GetRecID, myelem.GetAttribute("Table"), strschema); // get top group node in tree. and from there process fields if // there was a change in fieldname text if (success == true && oldname != newname) { VlnStatusMessage StatMsgWindow = new VlnStatusMessage("Status of RO Field Change"); // get top node - the one immediately below the RO_Root. VlnXmlElement parent, startEle; parent = myelem; startEle = myelem; while (parent.Name != "RO_Root") { startEle = parent; parent = (VlnXmlElement)parent.ParentNode; } startEle.SetAttribute("TreeNotData", "True"); success = RODB_UpdateFieldNames(startEle, myrof.GetRecID, oldname, newname, editlevel, false, StatMsgWindow, combofield); StatMsgWindow.Dispose(); } } } else { success = RODB_WriteSchemaPiece(myrof.GetRecID, myelem.GetAttribute("Table"), strschema); // changed the fieldname, change xml text. if (success == true && oldname != newname) { VlnStatusMessage StatMsgWindow = new VlnStatusMessage("Status of RO Field Change"); // get top node - the one immediately below the RO_Root. VlnXmlElement parent, startEle; parent = myelem; startEle = myelem; while (parent.Name != "RO_Root") { startEle = parent; parent = (VlnXmlElement)parent.ParentNode; } startEle.SetAttribute("TreeNotData", "True"); success = RODB_UpdateFieldNames(startEle, myrof.GetRecID, oldname, newname, editlevel, false, StatMsgWindow, combofield); StatMsgWindow.Dispose(); } } return success; } public override XmlSchema RODB_GetGroupSchema(VlnXmlElement elem) { XmlSchema myschema; VlnXmlElement parent; string entireschema; // if at top of tree, use this group schema information (fields in use). but if not, // the parent node defines the schema for the subgroups. if (elem.ParentNode.Name == "RO_Root") parent = elem; else parent = elem; // bug fix B2004-008 // need to use the current node's group definition all the time // parent = (VlnXmlElement) elem.ParentNode; while (parent != null) { if (parent.HasAttribute("GroupFieldsInUse") == true) break; // if we've looped to the top, just set the parent to null. (B2004-015) if (parent.ParentNode is VlnXmlElement) parent = (VlnXmlElement)parent.ParentNode; else parent = null; } if (parent == null) return null; // The group schema never gets saved as an attribute. it's always read in, because // it's not used as often as the ro schema. So for the Group Schema, we're looking // for 'GroupFieldsInUse'. // otherwise, read in schema definitions for those 'FieldsInUse'. string strGetSchemaPiece; entireschema = null; string GroupFieldsInUse = parent.GetAttribute("GroupFieldsInUse"); int strpos = 0; string Info; // For each item in use, get its xmlschema text. If unique to this group, the definition // exists local to this table. Otherwise, go back to the master. string recid; recid = GroupFieldsInUse.Substring(0, 8); while (recid != null) { strGetSchemaPiece = "SELECT Info From " + elem.GetAttribute("Table") + " where (RecID = '" + recid + "')"; DBE.Command(strGetSchemaPiece); DBE.Reader(); if (DBE.Read()) { Info = DBE.GetString(0); // if the info string has "<", i.e. an opening XML schema bracket, use // this text as the field definition, otherwise, go to the master to get // it. if ("<" == Info.Substring(0, 1)) { // use this field definition, else get from the master. entireschema = entireschema + Info; } else { string recidpart = Info.Substring(0, 8); strGetSchemaPiece = "SELECT Info From RoMaster where (RecID = '" + recidpart + "')"; DBE.ReaderClose(); DBE.CommandDispose(); DBE.Command(strGetSchemaPiece); DBE.Reader(); if (DBE.Read()) { Info = DBE.GetString(0); entireschema = entireschema + Info; } } DBE.ReaderClose(); DBE.CommandDispose(); strpos = strpos + 9; if (strpos > GroupFieldsInUse.Length) recid = null; else recid = GroupFieldsInUse.Substring(strpos, 8); } DBE.ReaderClose(); DBE.CommandDispose(); } entireschema = schemastart + entireschema + schemaend; XmlTextReader schemareader = new XmlTextReader(entireschema, XmlNodeType.Element, null); try { myschema = XmlSchema.Read(schemareader, null); return myschema; } catch (Exception e) { MessageBox.Show(e.Message, "Schema Error"); return null; } } public override XmlSchema RODB_GetSchema(VlnXmlElement elem) { XmlSchema myschema; VlnXmlElement parent; string entireschema; XmlNode nparent; nparent = elem; //.ParentNode; if (nparent is VlnXmlDocument) { // at top already. use this one. parent = elem; } else { parent = (VlnXmlElement)nparent; while (parent != null) { if (parent.HasAttribute("Schema") == true) break; if (parent.HasAttribute("FieldsInUse") == true) break; parent = (VlnXmlElement)parent.ParentNode; } } // if the schema has already been read in, just use it from the schema attribute, // otherwise, read in schema definitions for those 'FieldsInUse'. if (parent.HasAttribute("Schema")) { entireschema = parent.GetAttribute("Schema"); } else { string strGetSchemaPiece; entireschema = null; string FieldsInUse = parent.GetAttribute("FieldsInUse"); int strpos = 0; string Info; // For each item in use, get its xmlschema text. If unique to this group, the definition // exists local to this table. Otherwise, go back to the master. string recid; recid = FieldsInUse.Substring(0, 8); while (recid != null) { strGetSchemaPiece = "SELECT Info From " + elem.GetAttribute("Table") + " where (RecID = '" + recid + "')"; DBE.Command(strGetSchemaPiece); DBE.Reader(); if (DBE.Read()) { Info = DBE.GetString(0); // if the info string has "<", i.e. an opening XML schema bracket, use // this text as the field definition, otherwise, go to the master to get // it. if ("<" == Info.Substring(0, 1)) { // use this field definition, else get from the master. entireschema = entireschema + Info; } else { string recidpart = Info.Substring(0, 8); string localfieldname = Info.Substring(13, Info.Length - 13); strGetSchemaPiece = "SELECT Info From RoMaster where (RecID = '" + recidpart + "')"; DBE.ReaderClose(); DBE.CommandDispose(); DBE.Command(strGetSchemaPiece); DBE.Reader(); if (DBE.Read()) { // check if field name is same, if not, use local name. string goodname; Info = DBE.GetString(0); int indx1 = Info.IndexOf("\""); int indx2 = Info.IndexOf("\"", indx1 + 1); string masterfieldname = Info.Substring(indx1 + 1, indx2 - indx1 - 1); if (localfieldname != masterfieldname) goodname = Info.Replace(masterfieldname, localfieldname); else goodname = Info; entireschema = entireschema + goodname; } } DBE.ReaderClose(); DBE.CommandDispose(); strpos = strpos + 9; if (strpos > FieldsInUse.Length) recid = null; else recid = FieldsInUse.Substring(strpos, 8); } } DBE.ReaderClose(); DBE.CommandDispose(); entireschema = schemastart + entireschema + schemaend; } XmlTextReader schemareader = new XmlTextReader(entireschema, XmlNodeType.Element, null); try { myschema = XmlSchema.Read(schemareader, null); parent.SetAttribute("Schema", entireschema); return myschema; } catch (Exception e) { MessageBox.Show(e.Message, "Schema Read Error"); return null; } } public override int RODB_GetNumberOfROValueRecords(string tablename) { // get menu fields to display here. string strGetRoCount = "SELECT COUNT(RecType) AS NumRecs FROM " + tablename; strGetRoCount += " WHERE RecType = " + (uint)RecordType.RRO; DBE.Command(strGetRoCount); DBE.Reader(); DBE.Read(); int ROCnt = DBE.GetInt32(0); DBE.ReaderClose(); DBE.CommandDispose(); return ROCnt; } public override int RODB_GetNumberOfGroupRecords(string tablename) { // get menu fields to display here. string strGetGrpCount = "SELECT COUNT(RecType) AS NumRecs FROM " + tablename; strGetGrpCount += " WHERE RecType = " + (uint)RecordType.Group; DBE.Command(strGetGrpCount); DBE.Reader(); DBE.Read(); int GrpCnt = DBE.GetInt32(0); DBE.ReaderClose(); DBE.CommandDispose(); return GrpCnt; } } }