commit b6d5ec4ece0a2a0eb13c33cd00c9ffeada74b94a Author: Daniel Romischer Date: Thu Jul 21 16:55:03 2016 -0400 Initial Commit diff --git a/Components/Advantage.Data.Provider.dll b/Components/Advantage.Data.Provider.dll new file mode 100644 index 0000000..209048c Binary files /dev/null and b/Components/Advantage.Data.Provider.dll differ diff --git a/Components/Devart.Data.PostgreSql.dll b/Components/Devart.Data.PostgreSql.dll new file mode 100644 index 0000000..4b10954 Binary files /dev/null and b/Components/Devart.Data.PostgreSql.dll differ diff --git a/Components/Devart.Data.dll b/Components/Devart.Data.dll new file mode 100644 index 0000000..07e4cdb Binary files /dev/null and b/Components/Devart.Data.dll differ diff --git a/DB.cs b/DB.cs new file mode 100644 index 0000000..cfb4dd8 --- /dev/null +++ b/DB.cs @@ -0,0 +1,311 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics; +using System.Data.Common; +using System.Data; + +namespace Sdaleo +{ + /// + /// Serves as our main Class for interacting with the DB + /// + public class DB + { + private IConnectDb _ConnectionStrObj = null; + private DbConnection _DbConnection = null; + + /// + /// Static DB Object Creator + /// + /// pass a valid Connection String Object + /// a new DB Object + public static DB Create(IConnectDb ConnectionStrObj) + { + return new DB(ConnectionStrObj); + } + + #region Construction + + /// + /// Construct out DB Class with a valid Connection String Obj + /// + /// pass a valid Connection String Object + public DB(IConnectDb ConnectionStrObj) + { + if(ConnectionStrObj == null || !ConnectionStrObj.IsValid) + throw new Exception("Invalid Connection Object Passed in."); + + _ConnectionStrObj = ConnectionStrObj; + } + + /// + /// Private Constructor * Used for Transaction Processing * + /// + /// A valid Connection Object that is in a Transaction State + private DB(DbConnection dbConnection) + { + if (dbConnection == null) + throw new Exception("Invalid Connection Passed in."); + } + + #endregion + + #region NonQuery + + /// + /// Use this to Run SQL with the ExecuteNonQuery() Command Object + /// + /// SQL Text/Commands to execute + /// the result of the ExecuteNonQuery() operation + public DBRetVal ExecuteNonQuery(string SqlCommandText) + { + DBRetVal retVal = new DBRetVal(); + try + { + using (DbConnection conn = DBMS.CreateDbConnection(_ConnectionStrObj.DBType, _ConnectionStrObj.ConnectionString)) + { + conn.Open(); + using (DbCommand cmd = conn.CreateCommand()) + { + cmd.CommandText = SqlCommandText; + if(_ConnectionStrObj.SupportsTimeouts) + cmd.CommandTimeout = (int) _ConnectionStrObj.Timeouts.CommandTimeout; + int nRows = cmd.ExecuteNonQuery(); + retVal.SetNonQueryRetVal(nRows); + } + } + } + catch (Exception e) + { + retVal = DBMS.CreateErrorDBRetVal(_ConnectionStrObj.DBType, e); + } + return retVal; + } + + /// + /// Use this to Run SQL with the ExecuteNonQuery() Command Object + /// + /// SQL Text/Commands to execute + /// Allows the use of DBMS Independent parameters + /// the result of the ExecuteNonQuery() operation + public DBRetVal ExecuteNonQuery(string SqlCommandText, DBMSIndParameter[] parameters) + { + DBRetVal retVal = new DBRetVal(); + try + { + using (DbConnection conn = DBMS.CreateDbConnection(_ConnectionStrObj.DBType, _ConnectionStrObj.ConnectionString)) + { + conn.Open(); + using (DbCommand cmd = conn.CreateCommand()) + { + cmd.CommandText = SqlCommandText; + if (_ConnectionStrObj.SupportsTimeouts) + cmd.CommandTimeout = (int)_ConnectionStrObj.Timeouts.CommandTimeout; + + // Add DBMS Specific Parameters + foreach (DbParameter parameter in DBMS.CreateDbParameter(_ConnectionStrObj.DBType, parameters)) + cmd.Parameters.Add(parameter); + + int nRows = cmd.ExecuteNonQuery(); + retVal.SetNonQueryRetVal(nRows); + } + } + } + catch (Exception e) + { + retVal = DBMS.CreateErrorDBRetVal(_ConnectionStrObj.DBType, e); + } + return retVal; + } + + #endregion + + #region ExecuteScalar + + /// + /// Use this to Run SQL with the ExecuteScalar() Command Object + /// + /// SQL Text to execute + /// the result of the ExecuteScalar() operation + public DBRetVal ExecuteScalar(string SqlText) + { + DBRetVal retVal = new DBRetVal(); + try + { + using (DbConnection conn = DBMS.CreateDbConnection(_ConnectionStrObj.DBType, _ConnectionStrObj.ConnectionString)) + { + conn.Open(); + using (DbCommand cmd = conn.CreateCommand()) + { + cmd.CommandText = SqlText; + if (_ConnectionStrObj.SupportsTimeouts) + cmd.CommandTimeout = (int)_ConnectionStrObj.Timeouts.CommandTimeout; + object oResult = cmd.ExecuteScalar(); + retVal.SetScalarRetVal(oResult); + } + } + } + catch (Exception e) + { + retVal = DBMS.CreateErrorDBRetVal(_ConnectionStrObj.DBType, e); + } + return retVal; + } + + /// + /// Use this to Run SQL with the ExecuteScalar() Command Object + /// + /// SQL Text to execute + /// Allows the use of DBMS Independent parameters + /// the result of the ExecuteScalar() operation + public DBRetVal ExecuteScalar(string SqlText, DBMSIndParameter[] parameters) + { + DBRetVal retVal = new DBRetVal(); + try + { + using (DbConnection conn = DBMS.CreateDbConnection(_ConnectionStrObj.DBType, _ConnectionStrObj.ConnectionString)) + { + conn.Open(); + using (DbCommand cmd = conn.CreateCommand()) + { + cmd.CommandText = SqlText; + if (_ConnectionStrObj.SupportsTimeouts) + cmd.CommandTimeout = (int)_ConnectionStrObj.Timeouts.CommandTimeout; + + // Add DBMS Specific Parameters + foreach (DbParameter parameter in DBMS.CreateDbParameter(_ConnectionStrObj.DBType, parameters)) + cmd.Parameters.Add(parameter); + + object oResult = cmd.ExecuteScalar(); + retVal.SetScalarRetVal(oResult); + } + } + } + catch (Exception e) + { + retVal = DBMS.CreateErrorDBRetVal(_ConnectionStrObj.DBType, e); + } + return retVal; + } + + #endregion + + #region DataTable + + /// + /// Use this to Run SQL with the DataAdapter Fill() + /// + /// SQL Text to execute + /// the result of the DataAdapter Fill() operation + public DBRetVal FillDataTable(string SqlText) + { + DBRetVal retVal = new DBRetVal(); + try + { + using (DbConnection conn = DBMS.CreateDbConnection(_ConnectionStrObj.DBType, _ConnectionStrObj.ConnectionString)) + { + conn.Open(); + using (DbCommand cmd = conn.CreateCommand()) + { + cmd.CommandText = SqlText; + if (_ConnectionStrObj.SupportsTimeouts) + cmd.CommandTimeout = (int)_ConnectionStrObj.Timeouts.CommandTimeout; + + using (DbDataAdapter dataAdapter = DBMS.CreateDbDataAdapter(_ConnectionStrObj.DBType, cmd)) + { + DataTable dt = new DataTable(); + dataAdapter.Fill(dt); + retVal.SetDataTableRetVal(dt); + } + } + } + } + catch (Exception e) + { + retVal = DBMS.CreateErrorDBRetVal(_ConnectionStrObj.DBType, e); + } + return retVal; + } + + /// + /// Use this to Run SQL with the DataAdapter Fill() + /// + /// SQL Text to execute + /// Allows the use of DBMS Independent parameters + /// the result of the DataAdapter Fill() operation + public DBRetVal FillDataTable(string SqlText, DBMSIndParameter[] parameters) + { + DBRetVal retVal = new DBRetVal(); + try + { + using (DbConnection conn = DBMS.CreateDbConnection(_ConnectionStrObj.DBType, _ConnectionStrObj.ConnectionString)) + { + conn.Open(); + using (DbCommand cmd = conn.CreateCommand()) + { + cmd.CommandText = SqlText; + if (_ConnectionStrObj.SupportsTimeouts) + cmd.CommandTimeout = (int)_ConnectionStrObj.Timeouts.CommandTimeout; + + // Add DBMS Specific Parameters + foreach (DbParameter parameter in DBMS.CreateDbParameter(_ConnectionStrObj.DBType, parameters)) + cmd.Parameters.Add(parameter); + + using (DbDataAdapter dataAdapter = DBMS.CreateDbDataAdapter(_ConnectionStrObj.DBType, cmd)) + { + DataTable dt = new DataTable(); + dataAdapter.Fill(dt); + retVal.SetDataTableRetVal(dt); + } + } + } + } + catch (Exception e) + { + retVal = DBMS.CreateErrorDBRetVal(_ConnectionStrObj.DBType, e); + } + return retVal; + } + + #endregion + + #region Transaction + + /// + /// Use this to run multiple DB Steps and group them into a Single Transaction + /// + /// an array of Transaction Steps to execute + /// the result of Transaction + public DBRetVal StartTransaction(TransactionStep[] transactionSteps) + { + DBRetVal retVal = new DBRetVal(); + try + { + DB db = new DB(_ConnectionStrObj); + + // Enter Transaction + + foreach (TransactionStep step in transactionSteps) + { + // Iterate thru each Transaction Step-By-Step + retVal = step(retVal, db); + + // Stop The Transaction + if (retVal.ErrorOccured) // Have to Leave the Transaction as well + break; + } + + // Leave Transaction + } + catch (Exception e) + { + retVal = DBMS.CreateErrorDBRetVal(_ConnectionStrObj.DBType, e); + } + return retVal; + } + + #endregion + } +} diff --git a/DBError.cs b/DBError.cs new file mode 100644 index 0000000..4787430 --- /dev/null +++ b/DBError.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data.SqlClient; +using System.Collections; + +namespace Sdaleo +{ + /// + /// Our Custom Database Error Class that DB Functions Return to External Callers + /// + public class DBError + { + public int nError { get; set; } + public string ErrorMsg { get; set; } + public ICollection Errors { get; set; } + + public DBError() + { + nError = -1; + ErrorMsg = String.Empty; + Errors = null; + } + public DBError(int nError, string ErrorMsg, ICollection Errors) + { + this.nError = nError; + this.ErrorMsg = ErrorMsg; + this.Errors = Errors; + } + + /// + /// Used internally to quickly create a custom error object + /// + /// The Error Message to Display + private const int DATABASE_LAYER_ERROR_NUMBER = 1978; + internal static DBError Create(string ErrorMsg) + { + return new DBError(DATABASE_LAYER_ERROR_NUMBER, ErrorMsg, null); + } + + public bool ErrorOccured { get { return (nError != -1 && !String.IsNullOrEmpty(ErrorMsg)); } } + public int GetErrorCount { get { if (Errors != null) { return Errors.Count; } return 0; } } + public List GetAllErrorNumbers + { + get + { + if (Errors != null) + { + List list = new List(); + + // * DBMS SPECIFIC * + // TO DO + foreach (SqlError error in Errors) + list.Add(error.Number); + // + + return list; + } + return null; + } + } + } +} diff --git a/DBInstallOrUpdate.cs b/DBInstallOrUpdate.cs new file mode 100644 index 0000000..1d88991 --- /dev/null +++ b/DBInstallOrUpdate.cs @@ -0,0 +1,256 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Sdaleo.Internal; + +namespace Sdaleo +{ + /// + /// Specify what type of update/install to do. + /// All_IF_EXISTS, will check for script existence and only run the ones that exist + /// + public enum InstallOrUpdateType + { + ALL_IF_EXISTS, + TABLES, + VIEWS, + SPROCS, + } + + /// + /// Helper class to Install or Update a Database, + /// Before using this class set via DBResources a DBResource that points to SQL Script Files + /// to use in the Install/Update Process, or pass the DBResource in via one of the Constructors + /// ~SQL Script Files, contain SQL Snippets that are broken down to Commands and Identifiers as + /// specified in the internal class SQLParser. Using these commands and Identifiers, + /// you can Install/Update a SQL Server or SQLCE Database with ease + /// + public class DBInstallOrUpdate + { + #region Public and Private Members + + // Public + public uint CurMajorVersion { get; private set; } + public uint CurMinorVersion { get; private set; } + public uint CurRevisionNumber { get; private set; } + + // Private + private IConnectDb _DBCredential { get; set; } + private string _uniqueName { get; set; } + private DBResource _DBResouce { get; set; } + private string _VersioningTableName { get; set; } + + // SQLScripts + private string[] _TableScripts = null; + private string[] _ViewScripts = null; + private string[] _SprocScripts = null; + + #endregion + + #region Constructors + + /// + /// Construct a DBInstallOrUpdate Object in order to install tables, views, sprocs, or + /// update an existing database + /// + /// Pass in a DBCredential Object to use in this class + /// specify a unique name, that was used when registering a DBResource via DBResources + /// Running Application's Current Major Product Version Number (for use in installs/upgrades) + /// Running Application's Current Minor Product Version Number (for use in installs/upgrades) + /// Running Application's Current Revision Number (for use in installs/upgrades) + /// Pass in a Table Name that will be created/updated to contain the latest Application Version Information *used for Update* + public DBInstallOrUpdate(IConnectDb DBCredential, string uniqueName, uint CurMajorVersion, uint CurMinorVersion, uint CurRevisionNumber, string VersioningTableName = "Versioning") + { + if (!DBCredential.IsValid || String.IsNullOrEmpty(uniqueName)) + throw new ArgumentException("DBCredential or uniqueName is Invalid"); + + // Make sure DBResource exists + DBResources.GetDBResource(uniqueName); + + // Set all Private Members + ConstructorSetsPrivateMembers(DBCredential, uniqueName, CurMajorVersion, CurMinorVersion, CurRevisionNumber, VersioningTableName); + } + + /// + /// Construct a DBInstallOrUpdate Object in order to install tables, views, sprocs, or + /// update an existing database + /// + /// Pass in a DBCredential Object to use in this class + /// pass in a valid DBResource that points to valid SQL Script Locations + /// specify a unique name to use, that describes the dbResource used to register the resource + /// Running Application's Current Major Product Version Number (for use in installs/upgrades) + /// Running Application's Current Minor Product Version Number (for use in installs/upgrades) + /// Running Application's Current Revision Number (for use in installs/upgrades) + /// Pass in a Table Name that will be created/updated to contain the latest Application Version Information *used for Update* + public DBInstallOrUpdate(IConnectDb DBCredential, DBResource dbResource, string uniqueName, uint CurMajorVersion, uint CurMinorVersion, uint CurRevisionNumber, string VersioningTableName = "Versioning") + { + if (!DBCredential.IsValid || String.IsNullOrEmpty(uniqueName)) + throw new ArgumentException("DBCredential or uniqueName is Invalid"); + + // Add the DBResource + DBResources.AddDBResource(uniqueName, dbResource); + + // Set all Private Members + ConstructorSetsPrivateMembers(DBCredential, uniqueName, CurMajorVersion, CurMinorVersion, CurRevisionNumber, VersioningTableName); + } + + /// + /// Broken out of the Constructors, to centralize member initialization + /// + private void ConstructorSetsPrivateMembers(IConnectDb DBCredential, string uniqueName, uint CurMajorVersion, uint CurMinorVersion, uint CurRevisionNumber, string VersioningTableName) + { + this._DBCredential = DBCredential; + this._uniqueName = uniqueName; + this.CurMajorVersion = CurMajorVersion; + this.CurMinorVersion = CurMinorVersion; + this.CurRevisionNumber = CurRevisionNumber; + this._VersioningTableName = VersioningTableName; + + // Retrieve Scripts + this._TableScripts = DBResources.GetTableDBResourceScripts(_uniqueName); + this._ViewScripts = DBResources.GetViewsDBResourceScripts(_uniqueName); + this._SprocScripts = DBResources.GetSprocsDBResourceScripts(_uniqueName); + } + + #endregion + + #region Public Methods and Properties + + /// + /// + /// + /// + /// + public DBError InstallOrUpdate(InstallOrUpdateType type) + { + DBError dbError; + if (!HasVersioningTable) + dbError = InstallDatabase(type); + else + dbError = UpdateDatabase(type); + return dbError; + } + + /// + /// + /// + /// + private bool HasVersioningTable + { + get + { + return true; // for now + } + } + + #endregion + + #region private Helper Functions + + /// + /// + /// + /// + /// + private DBError InstallDatabase(InstallOrUpdateType type) + { + DBError dbError = new DBError(); + + // Install Tables first + if ((type == InstallOrUpdateType.TABLES || type == InstallOrUpdateType.ALL_IF_EXISTS) && + (_TableScripts != null)) + dbError = ExecuteSpecificMySQLCommandsTypesInSQLScripts(null, _TableScripts); + if (dbError.ErrorOccured) return dbError; + + // Install Views Next + if ((type == InstallOrUpdateType.VIEWS || type == InstallOrUpdateType.ALL_IF_EXISTS) && + (_TableScripts != null)) + dbError = ExecuteSpecificMySQLCommandsTypesInSQLScripts(null, _ViewScripts); + if (dbError.ErrorOccured) return dbError; + + // Install Sprocs Next + if ((type == InstallOrUpdateType.VIEWS || type == InstallOrUpdateType.ALL_IF_EXISTS) && + (_SprocScripts != null)) + dbError = ExecuteSpecificMySQLCommandsTypesInSQLScripts(null, _SprocScripts); + if (dbError.ErrorOccured) return dbError; + + return new DBError(); + } + + /// + /// + /// + /// + /// + private DBError UpdateDatabase(InstallOrUpdateType type) + { + DBError dbError = new DBError(); + + // Install Tables first + if ((type == InstallOrUpdateType.TABLES || type == InstallOrUpdateType.ALL_IF_EXISTS) && + (_TableScripts != null)) + dbError = ExecuteSpecificMySQLCommandsTypesInSQLScripts(null, _TableScripts); + if (dbError.ErrorOccured) return dbError; + + // Install Views Next + if ((type == InstallOrUpdateType.VIEWS || type == InstallOrUpdateType.ALL_IF_EXISTS) && + (_TableScripts != null)) + dbError = ExecuteSpecificMySQLCommandsTypesInSQLScripts(null, _ViewScripts); + if (dbError.ErrorOccured) return dbError; + + // Install Sprocs Next + if ((type == InstallOrUpdateType.VIEWS || type == InstallOrUpdateType.ALL_IF_EXISTS) && + (_SprocScripts != null)) + dbError = ExecuteSpecificMySQLCommandsTypesInSQLScripts(null, _SprocScripts); + if (dbError.ErrorOccured) return dbError; + + return new DBError(); + } + + /// + /// + /// + /// + /// + /// + private DBError ExecuteSpecificMySQLCommandsTypesInSQLScripts(MySQLCommandType[] types, string[] FRLCS_ScriptFiles) + { + foreach (string scriptFile in FRLCS_ScriptFiles) + { + // Retrieve the Commands N' Identifiers for the Script + MySQLCommand[] commands = null; + MySQLIdentifier[] identifiers = null; + if (!GetCommandsAndIdentifiersFromSqlScript(scriptFile, out commands, out identifiers)) + { + // argh.. .this should not happen + } + + // Only Execute certain types/Versions???? + DBError dbError = commands[0].ExecuteScriptBlock(_DBCredential); + if (dbError.ErrorOccured) + { + //commands[0].Line_CommandStart + + } + } + return null; + } + + /// + /// Uses DBResources and SQLParser to parse an SQLScript into MySQLCommands and MySQLIdentifiers + /// + /// the FRLCS full resource file and path to the script to parse + /// returns out MySQLCommands found in script + /// returns out MySQLIdentities found in script + /// true if commands and identifiers were fetched, false otherwise + private bool GetCommandsAndIdentifiersFromSqlScript(string FRLCS_Script, out MySQLCommand[] commands, out MySQLIdentifier[] identifiers) + { + string[] ScriptContents = DBResources.Read_FRLCS_Script(_uniqueName, FRLCS_Script); + SQLParser.ParseSQLScriptForMySQLCommandsAndIdentifiers(ScriptContents, out commands, out identifiers); + return ((commands != null) && (identifiers != null) && (commands.Length != 0) && (identifiers.Length != 0)); + } + + #endregion + } +} diff --git a/DBResources.cs b/DBResources.cs new file mode 100644 index 0000000..b0480e2 --- /dev/null +++ b/DBResources.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Reflection; +using System.IO; + +namespace Sdaleo +{ + /// + /// For SQL Server you can fill all locations, for SQLCE there are no Views,Sprocs + /// FullResourceLocationContainingScripts, is the full resource folder where the sql scripts are located + /// f.e. Application.DatabaseLayer.SQLScripts + /// SQLScript_FileExt specifies which files to look for (f.e. .sql or .sqlce) + /// + public struct DBResource + { + public Assembly AssemblyContainingResources; + public string FullResourceLocationContaingScripts_Tables; + public string FullResourceLocationContaingScripts_Views; + public string FullResourceLocationContaingScripts_Sprocs; + public string SQLScript_FileExt; + + /// + /// Useful for SQLCE DBResources, which only contains Tables + /// + /// the assembly that contains the resources + /// The Location of where the table .sqlce scripts are located, can be blank, if not used, but that would not make sense + /// file extension of the scripts, like .sqlce + public DBResource(Assembly asm, string FRLCS_Tables, string FileExt = ".sqlce") + { + this.AssemblyContainingResources = asm; + this.FullResourceLocationContaingScripts_Tables = FRLCS_Tables; + this.FullResourceLocationContaingScripts_Views = String.Empty; + this.FullResourceLocationContaingScripts_Sprocs = String.Empty; + this.SQLScript_FileExt = FileExt; + } + + /// + /// Useful for SQLServer DBResources, which can contain Tables, Views, Sprocs + /// + /// the assembly that contains the resources + /// The Location of where the table .sql scripts are located, can be blank, if not used + /// The Location of where the views .sql scripts are located, can be blank, if not used + /// The Location of where the sprocs .sql scripts are located, can be blank, if not used + /// file extension of the scripts, like .sql + public DBResource(Assembly asm, string FRLCS_Tables, string FRLCS_Views, string FRLCS_Sprocs, string FileExt = ".sql") + { + this.AssemblyContainingResources = asm; + this.FullResourceLocationContaingScripts_Tables = FRLCS_Tables; + this.FullResourceLocationContaingScripts_Views = FRLCS_Views; + this.FullResourceLocationContaingScripts_Sprocs = FRLCS_Sprocs; + this.SQLScript_FileExt = FileExt; + } + } + + /// + /// This class allows external callers to set SQL Resource Scripts, + /// for easy table, view, sprocs creation and updating + /// + public static class DBResources + { + #region Private Statics + + private static Dictionary _DBResources = new Dictionary(); + + #endregion + + #region DBResource Add/Get/Delete + + /// + /// Used to Add a DBResource into DatabaseLayer + /// + /// Unique Name to identify the Resource by + /// a DBResource structure that must contain the assembly and at least one resource, and the file extension for the scripts + /// true if added, false otherwise + public static bool AddDBResource(string uniqueName, DBResource dbResource) + { + if (!String.IsNullOrEmpty(uniqueName) && !_DBResources.ContainsKey(uniqueName)) + { + _DBResources.Add(uniqueName, dbResource); + return true; + } + return false; + } + + /// + /// Used to Delete a DBResource from DatabaseLayer + /// + /// Unique Name to identify the Resource by + /// true if deleted, false otherwise + public static bool DeleteDBResource(string uniqueName) + { + if (!String.IsNullOrEmpty(uniqueName) && _DBResources.ContainsKey(uniqueName)) + { + _DBResources.Remove(uniqueName); + return true; + } + return false; + } + + /// + /// Used to Retrieve a DBResource from DatabaseLayer + /// + /// Unique Name to identify the Resource by + /// the DBResource that was previously added by AddDBResource(), otherwise throws an error + public static DBResource GetDBResource(string uniqueName) + { + if (!String.IsNullOrEmpty(uniqueName) && _DBResources.ContainsKey(uniqueName)) + return _DBResources[uniqueName]; + else + throw new Exception("DBResource not found. Call AddDBResource First"); + } + + #endregion + + #region Internal Table, View, Sprocs, Resource Getter Functions + + /// + /// Returns the Table Scripts for a specified DBResource + /// + /// Unique Name to identify the Resource by + /// an array of FRLCS Script Names + internal static string[] GetTableDBResourceScripts(string uniqueName) + { + if (!String.IsNullOrEmpty(GetDBResource(uniqueName).FullResourceLocationContaingScripts_Tables)) + return GetScriptsFromResourceLocation(GetDBResource(uniqueName).AssemblyContainingResources, GetDBResource(uniqueName).FullResourceLocationContaingScripts_Tables, GetDBResource(uniqueName).SQLScript_FileExt); + return null; + } + + /// + /// Returns the Views Scripts for a specified DBResource + /// + /// Unique Name to identify the Resource by + /// an array of FRLCS Script Names + internal static string[] GetViewsDBResourceScripts(string uniqueName) + { + if (!String.IsNullOrEmpty(GetDBResource(uniqueName).FullResourceLocationContaingScripts_Views)) + return GetScriptsFromResourceLocation(GetDBResource(uniqueName).AssemblyContainingResources, GetDBResource(uniqueName).FullResourceLocationContaingScripts_Views, GetDBResource(uniqueName).SQLScript_FileExt); + return null; + } + + /// + /// Returns the Sprocs Scripts for a specified DBResource + /// + /// Unique Name to identify the Resource by + /// an array of FRLCS Script Names + internal static string[] GetSprocsDBResourceScripts(string uniqueName) + { + if(!String.IsNullOrEmpty(GetDBResource(uniqueName).FullResourceLocationContaingScripts_Sprocs)) + return GetScriptsFromResourceLocation(GetDBResource(uniqueName).AssemblyContainingResources, GetDBResource(uniqueName).FullResourceLocationContaingScripts_Sprocs, GetDBResource(uniqueName).SQLScript_FileExt); + return null; + } + + #endregion + + #region Internal ReadScript + + /// + /// Use this to read the contents of a Script from a specified Resource + /// + /// Unique Name to identify the Resource by + /// the Full Resource Location Name N Path of the Script to read + /// the contents of the script, split by '\n', or null if not found + internal static string[] Read_FRLCS_Script(string uniqueName, string FRLCS_Script_Name) + { + using (StreamReader stream = new StreamReader(GetDBResource(uniqueName).AssemblyContainingResources.GetManifestResourceStream(FRLCS_Script_Name))) + { + if (stream != null) + { + string txtContent = stream.ReadToEnd(); + + // Get Rid of carriage returns and new lines + string[] retVal = txtContent.Replace("\r","").Split('\n'); + + // iterate each line and trim whitespaces + for (int i = 0; i < retVal.Length; ++i) + retVal[i] = retVal[i].Trim(); + + return retVal; + } + } + return null; + } + + #endregion + + #region Private Static Helper Functions + + /// + /// Returns the Scripts found from the specified Resource Location + /// + /// a FRLCS Path to where the Scripts are located + /// File Extension used by the scripts + /// the FRLCS names of the Scripts, or null if none found + private static string[] GetScriptsFromResourceLocation(Assembly asm, string ResourceLocation, string FileExt) + { + List scriptsFRLCS = new List(); + string[] resourceNames = asm.GetManifestResourceNames(); + foreach (string ResourceName in resourceNames) + { + if (ResourceName.StartsWith(ResourceLocation) && ResourceName.EndsWith(FileExt)) + scriptsFRLCS.Add(ResourceName); // found + } + scriptsFRLCS.Sort(); + return scriptsFRLCS.ToArray(); + } + + #endregion + } +} diff --git a/DBRetVal.cs b/DBRetVal.cs new file mode 100644 index 0000000..7733e7c --- /dev/null +++ b/DBRetVal.cs @@ -0,0 +1,235 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data; +using System.Collections; + +namespace Sdaleo +{ + /// + /// Used by Callers to determine DB Operation Outcome + /// + public enum DBRetValEnum + { + VALUE_FETCHED, + VALUE_NOTFETCHED, + NQ_NO_ROWS_AFFECTED, + NQ_ONE_ROW_AFFECTED, + NQ_MULTIPLE_ROWS_AFFECTED, + FAILED + } + + /// + /// Our Database RetVal Class that DB Callers use to get Values + /// + public class DBRetVal : DBError + { + public DBRetValEnum Result { get; private set; } + + // * Return Values from various DB Calls * + private DataTable RetVal_datatable { get; set; } + private String RetVal_string { get; set; } + private int RetVal_int { get; set; } // for NQ calls + + // * Internal Mode * + private enum Mode + { + MODE_INIT, + MODE_VALUE_DT, + MODE_VALUE_STR, + MODE_NQ_INT, + } + private Mode _Mode = Mode.MODE_INIT; + + /// + /// Initialize DBRetVal + /// + public DBRetVal() + : base() + { + _Mode = Mode.MODE_INIT; + Result = DBRetValEnum.FAILED; + RetVal_datatable = null; + RetVal_string = String.Empty; + RetVal_int = Int32.MinValue; + } + + /// + /// Initialize DBRetVal with Error Info + /// + public DBRetVal(int nError, string ErrorMsg, ICollection Errors) + : base(nError, ErrorMsg, Errors) + { + _Mode = Mode.MODE_INIT; + Result = DBRetValEnum.FAILED; + RetVal_datatable = null; + RetVal_string = String.Empty; + RetVal_int = Int32.MinValue; + } + + #region Validator + + /// + /// Returns True if the Return value of this object is valid + /// + public bool IsValid + { + get + { + bool bIsValid = false; + switch (_Mode) + { + case Mode.MODE_INIT: + bIsValid = false; + break; + + case Mode.MODE_NQ_INT: + bIsValid = (RetVal_int != Int32.MinValue) && (Result != DBRetValEnum.FAILED) && (Result != DBRetValEnum.VALUE_NOTFETCHED); + break; + + case Mode.MODE_VALUE_DT: + bIsValid = (RetVal_datatable != null) && (Result != DBRetValEnum.FAILED) && (Result != DBRetValEnum.VALUE_NOTFETCHED); + break; + + case Mode.MODE_VALUE_STR: + bIsValid = !String.IsNullOrEmpty(RetVal_string) && (Result != DBRetValEnum.FAILED) && (Result != DBRetValEnum.VALUE_NOTFETCHED); + break; + + default: + bIsValid = false; + break; + } + + // Double-check that there are no errors in DBError as well, + if (bIsValid) + bIsValid = !ErrorOccured; + return bIsValid; + } + } + + #endregion + + #region Getters + + /// + /// Get the DataTable Return Value + /// + /// valid datatable or throws Exception, if in invalid state + public DataTable GetDataTableRetVal() + { + if (_Mode == Mode.MODE_VALUE_DT) + { + return RetVal_datatable; + } + else + { + throw new Exception(String.Format("Invalid State {0}. Can not call GetRetVal() for DataTable right now", _Mode.ToString())); + } + } + + /// + /// Get the Scalar/String Return Value + /// + /// valid string or throws Exception, if in invalid state + public string GetScalarRetVal() + { + if (_Mode == Mode.MODE_VALUE_STR) + { + return RetVal_string; + } + else + { + throw new Exception(String.Format("Invalid State {0}. Can not call GetRetVal() for String right now", _Mode.ToString())); + } + } + + /// + /// Get the NQ Return Value + /// + /// valid nRows or throws Exception, if in invalid state + public int GetNonQueryRetVal() + { + if (_Mode == Mode.MODE_NQ_INT) + { + return RetVal_int; + } + else + { + throw new Exception(String.Format("Invalid State {0}. Can not call GetRetValNQ() right now", _Mode.ToString())); + } + } + + #endregion + + #region Internal Setters + + /// + /// Set the Return Value to a DataTable + /// + /// a valid DataTable + /// a result to pass out * can not be NQ enum * + internal void SetDataTableRetVal(DataTable datatable) + { + _Mode = Mode.MODE_VALUE_DT; + if (datatable == null || (datatable.Rows.Count == 0)) + { + Result = DBRetValEnum.VALUE_NOTFETCHED; + } + else + { + Result = DBRetValEnum.VALUE_FETCHED; + RetVal_datatable = datatable; + } + + // Clear Others + RetVal_string = String.Empty; + RetVal_int = Int32.MinValue; + } + + /// + /// Set the Return Value to a String (pass in an object to be converted) + /// + /// a object that should be converted to a String + internal void SetScalarRetVal(object o) + { + _Mode = Mode.MODE_VALUE_STR; + if (o == null || (o.ToString() == String.Empty)) + { + Result = DBRetValEnum.VALUE_NOTFETCHED; + } + else + { + RetVal_string = o.ToString(); + Result = DBRetValEnum.VALUE_FETCHED; + } + + // Clear Others + RetVal_datatable = null; + RetVal_int = Int32.MinValue; + } + + /// + /// Set the Return Value for a NQ Query + /// + /// number of rows affected + internal void SetNonQueryRetVal(int nRows) + { + _Mode = Mode.MODE_NQ_INT; + RetVal_int = nRows; + if (nRows <= 0) + Result = DBRetValEnum.NQ_NO_ROWS_AFFECTED; + else if (nRows == 1) + Result = DBRetValEnum.NQ_ONE_ROW_AFFECTED; + else + Result = DBRetValEnum.NQ_MULTIPLE_ROWS_AFFECTED; + + // Clear Others + RetVal_datatable = null; + RetVal_string = String.Empty; + } + + #endregion + + } +} diff --git a/Definitions.cs b/Definitions.cs new file mode 100644 index 0000000..52fd7e2 --- /dev/null +++ b/Definitions.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo +{ + /// + /// DB Management Systems + /// + public enum DBSystem + { + SQL_SERVER, + SQL_CE, + ADVANTAGE, + CTREE, + MYSQL, + POSTGRES + } + + /// + /// Allows us to pass DBMS Independent Parameters to DB Functions + /// + public struct DBMSIndParameter + { + public string parameterName { get; set; } + public object Value { get; set; } + } + + /// + /// Transaction Delegate, Used to group multiple DB Steps into a + /// Single Transaction + /// + /// The Result of a prior TransactionStep is passed down + /// the DB(Connection) object that should be used in the next step + /// + public delegate DBRetVal TransactionStep(DBRetVal prevStepRetVal, DB db); +} diff --git a/Interfaces.cs b/Interfaces.cs new file mode 100644 index 0000000..02432cf --- /dev/null +++ b/Interfaces.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo +{ + /// + /// Expose the most basic connection string information for various DB Types + /// + public interface IConnectDb + { + // Validity & Type + DBSystem DBType { get; } + bool IsValid { get; } + + // Connection Properties + string ConnectionString { get; } + string DataSource { get; } + string User { get; } + + // Exposes Interfaces, if DB Type Supports it + bool SupportsDBMS { get; } + IamDBMS DBMS { get; } + bool SupportsTimeouts { get; } + IsupportTimeouts Timeouts { get; } + } + + /// + /// Expose DBMS specific Instance and DB information + /// + public interface IamDBMS + { + // DBMS have instances + string Server { get; } + string Instance { get; } + + // DBMS have multiple databases + string Database { get; } + bool IsDatabaseSet { get; } + bool IsDatabaseSetAndNonSystem { get; } + bool IsDatabaseSetAndNonDefault { get; } + IConnectDb WithDatabase(string strDatabaseName); + IConnectDb WithoutDatabase(); + } + + /// + /// Expose DB Timeout information + /// + public interface IsupportTimeouts + { + uint CommandTimeout { get; set; } + uint ConnectionTimeout { get; set; } + IConnectDb WithConnectionTimeout(uint nConnectionTimeout); + IConnectDb WithCommandTimeout(uint nCommandTimeout); + IConnectDb WithTimeouts(uint nConnectionTimeout, uint nCommandTimeout); + } +} diff --git a/Internal/DBMS.cs b/Internal/DBMS.cs new file mode 100644 index 0000000..bec045b --- /dev/null +++ b/Internal/DBMS.cs @@ -0,0 +1,266 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data.Common; + +using System.Data.SqlClient; +using System.Collections; +using System.Data.SqlServerCe; +using Sdaleo.Systems; +using Devart.Data.PostgreSql; + +namespace Sdaleo +{ + /// + /// This class is a Object factory wrapper class around our DBMS + /// + internal static class DBMS + { + /// + /// Creates a Connection Object depending on the type of DBMS we are using + /// + /// the DBSystem you want parameters for + /// Must pass in a valid Connection String + /// a valid connection * Caller Must Dispose of the Object *, or null if system is not available + internal static DbConnection CreateDbConnection(DBSystem dbsystem, string ConnectionStr) + { + DbConnection connection = null; + if (!String.IsNullOrEmpty(ConnectionStr)) + { + switch (dbsystem) + { + case DBSystem.SQL_SERVER: + if(SystemAvailable.Check(dbsystem)) + connection = (DbConnection)new SqlConnection(ConnectionStr); + break; + + case DBSystem.SQL_CE: + if (SystemAvailable.Check(dbsystem)) + connection = (DbConnection)new SqlCeConnection(ConnectionStr); + break; + + case DBSystem.ADVANTAGE: + if (SystemAvailable.Check(dbsystem)) + connection = (DbConnection)new SqlCeConnection(ConnectionStr); + break; + + case DBSystem.CTREE: + if (SystemAvailable.Check(dbsystem)) + connection = (DbConnection)new SqlCeConnection(ConnectionStr); + break; + + case DBSystem.MYSQL: + if (SystemAvailable.Check(dbsystem)) + connection = (DbConnection)new SqlCeConnection(ConnectionStr); + break; + + case DBSystem.POSTGRES: + if (SystemAvailable.Check(dbsystem)) + connection = (DbConnection)new PgSqlConnection(ConnectionStr); + break; + } + } + return connection; + } + + /// + /// Creates a DataAdapter depending on the type of DBMS we are using + /// + /// the DBSystem you want a DataAdapter for + /// pass in a valid Command Object for the DBMS + /// a valid DataAdapter * Caller Must Dispose of the Object *, or null if system is not available + internal static DbDataAdapter CreateDbDataAdapter(DBSystem dbsystem, DbCommand dbcommand) + { + DbDataAdapter dbDataAdapter = null; + switch (dbsystem) + { + case DBSystem.SQL_SERVER: + if (SystemAvailable.Check(dbsystem)) + dbDataAdapter = new SqlDataAdapter((SqlCommand) dbcommand); + break; + + case DBSystem.SQL_CE: + if (SystemAvailable.Check(dbsystem)) + dbDataAdapter = new SqlCeDataAdapter((SqlCeCommand) dbcommand); + break; + + case DBSystem.ADVANTAGE: + if (SystemAvailable.Check(dbsystem)) + dbDataAdapter = new SqlCeDataAdapter((SqlCeCommand)dbcommand); + break; + + case DBSystem.CTREE: + if (SystemAvailable.Check(dbsystem)) + dbDataAdapter = new SqlCeDataAdapter((SqlCeCommand)dbcommand); + break; + + case DBSystem.MYSQL: + if (SystemAvailable.Check(dbsystem)) + dbDataAdapter = new SqlCeDataAdapter((SqlCeCommand)dbcommand); + break; + + case DBSystem.POSTGRES: + if (SystemAvailable.Check(dbsystem)) + dbDataAdapter = new PgSqlDataAdapter((PgSqlCommand)dbcommand); + break; + } + return dbDataAdapter; + } + + /// + /// Creates an Error Object to be returned to the Caller, fills values depending on DBMS + /// + /// the DBSystem you want an Error for + /// the exception being thrown by the DBMS + /// a DBRetVal Object filled with the Error Data, or null if system is not available + internal static DBRetVal CreateErrorDBRetVal(DBSystem dbsystem, Exception e) + { + DBRetVal retVal = null; + switch (dbsystem) + { + case DBSystem.SQL_SERVER: + { + if (SystemAvailable.Check(dbsystem)) + { + SqlException ex = e as SqlException; + if (ex != null) + retVal = new DBRetVal(ex.Number, ex.Message, ex.Errors); + } + } + break; + + case DBSystem.SQL_CE: + { + if (SystemAvailable.Check(dbsystem)) + { + SqlCeException ex = e as SqlCeException; + if (ex != null) + retVal = new DBRetVal(ex.NativeError, ex.Message, ex.Errors); + } + } + break; + + case DBSystem.ADVANTAGE: + { + if (SystemAvailable.Check(dbsystem)) + { + SqlCeException ex = e as SqlCeException; + if (ex != null) + retVal = new DBRetVal(ex.NativeError, ex.Message, ex.Errors); + } + } + break; + + case DBSystem.CTREE: + { + if (SystemAvailable.Check(dbsystem)) + { + SqlCeException ex = e as SqlCeException; + if (ex != null) + retVal = new DBRetVal(ex.NativeError, ex.Message, ex.Errors); + } + } + break; + + case DBSystem.MYSQL: + { + if (SystemAvailable.Check(dbsystem)) + { + SqlCeException ex = e as SqlCeException; + if (ex != null) + retVal = new DBRetVal(ex.NativeError, ex.Message, ex.Errors); + } + } + break; + + case DBSystem.POSTGRES: + { + if (SystemAvailable.Check(dbsystem)) + { + PgSqlException ex = e as PgSqlException; + if (ex != null) + retVal = new DBRetVal(0, ex.Message, null); + } + } + break; + } + return retVal; + } + + /// + /// Creates a DBMS Specific Parameter Array from a DMBS Independent Parameter Array + /// + /// the DBSystem you want parameters for + /// a valid DBMSIndependent Param array + /// a DBMS Specific Parameter Array + internal static DbParameter[] CreateDbParameter(DBSystem dbsystem, DBMSIndParameter[] parameters) + { + List param_s = new List(); + + // Convert the Parameters + foreach (DBMSIndParameter parameter in parameters) + { + switch (dbsystem) + { + case DBSystem.SQL_SERVER: + { + if (SystemAvailable.Check(dbsystem)) + { + param_s.Add(new SqlParameter(parameter.parameterName, parameter.Value)); + } + } + break; + + case DBSystem.SQL_CE: + { + if (SystemAvailable.Check(dbsystem)) + { + param_s.Add(new SqlCeParameter(parameter.parameterName, parameter.Value)); + } + } + break; + + case DBSystem.ADVANTAGE: + { + if (SystemAvailable.Check(dbsystem)) + { + param_s.Add(new SqlCeParameter(parameter.parameterName, parameter.Value)); + } + } + break; + + case DBSystem.CTREE: + { + if (SystemAvailable.Check(dbsystem)) + { + param_s.Add(new SqlCeParameter(parameter.parameterName, parameter.Value)); + } + } + break; + + case DBSystem.MYSQL: + { + if (SystemAvailable.Check(dbsystem)) + { + param_s.Add(new SqlCeParameter(parameter.parameterName, parameter.Value)); + } + } + break; + + case DBSystem.POSTGRES: + { + if (SystemAvailable.Check(dbsystem)) + { + param_s.Add(new PgSqlParameter(parameter.parameterName, parameter.Value)); + } + } + break; + } + } + + // Return the Parameter + return param_s.ToArray(); + } + } +} diff --git a/Internal/ObjTool.cs b/Internal/ObjTool.cs new file mode 100644 index 0000000..a5d42b4 --- /dev/null +++ b/Internal/ObjTool.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo +{ + /// + /// Useful Utilities around objects + /// + internal static class ObjTool + { + /// + /// Returns true if passed in object is valid and is not empty + /// + /// an object to validate + /// true if valid, false otherwise + internal static bool IsNotNullAndNotEmpty(object oToValidate) + { + if ((oToValidate != null) && (oToValidate.ToString() != String.Empty)) + return true; + else + return false; + } + + /// + /// Convert a string to an Object of Type T + /// + /// Should be a System Type like string, bool, int32, double, decimal, etc... + /// String Value to Convert + /// an converted Object of Type t, or T Default if error occured + internal static T ConvertStringToObj(string strToConvert) + { + + // Create a Default Type T + T retVal = default(T); + + try + { + #region Conversion + + if (retVal is Char) + { + retVal = (T)((object)strToConvert[0]); + } + else if (retVal is String) + { + retVal = (T)((object)strToConvert); + } + else if (retVal is Decimal) + { + retVal = (T)((object)Decimal.Parse(strToConvert)); + } + else if (retVal is Int32) + { + retVal = (T)((object)Int32.Parse(strToConvert)); + } + else if (retVal is Int64) + { + retVal = (T)((object)Int64.Parse(strToConvert)); + } + else if (retVal is Single) + { + retVal = (T)((object)Single.Parse(strToConvert)); + } + else if (retVal is Double) + { + retVal = (T)((object)Double.Parse(strToConvert)); + } + else if (retVal is Boolean) + { + retVal = (T)((object)Boolean.Parse(strToConvert)); + } + else if (retVal is DateTime) + { + retVal = (T)((object)DateTime.Parse(strToConvert)); + } +#if NET40 + else if (retVal is Guid) + { + retVal = (T)((object)Guid.Parse(strToConvert)); + } +#endif + else if (retVal is IntPtr) + { + retVal = (T)((object)Int32.Parse(strToConvert)); + } + else if (retVal is UInt32) + { + retVal = (T)((object)UInt32.Parse(strToConvert)); + } + else if (retVal is UInt64) + { + retVal = (T)((object)UInt64.Parse(strToConvert)); + } + else + { + retVal = (T)((object)(strToConvert)); + } + + #endregion + } + catch (Exception) { /* ignore */ } + + // return T + return retVal; + } + } +} diff --git a/Internal/RegKey.cs b/Internal/RegKey.cs new file mode 100644 index 0000000..d15d9b4 --- /dev/null +++ b/Internal/RegKey.cs @@ -0,0 +1,416 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Win32; + +namespace Sdaleo +{ + #region RegKey Enums + + internal enum HKEYRoot + { + ClassesRoot, + CurrentUser, + LocalMachine, + } + + internal enum KeySub + { + Software, + Custom + } + + #endregion + + /// + /// Wrapper Class around Registry Functionallity, + /// allows for easy reading/writing to the registry, especially HKEY_CURRENT_USER\Software + /// ~If you use this class directly make sure to call dispose(), + /// otherwise, use the Public Static Helper Functions to do the work for you + /// + internal class RegKey : IDisposable + { + private RegistryKey _RegKey; + private bool _disposed = false; + + #region Constructors + + /// + /// Opens the specified Key in CURRENT_USER\Software\Key. + /// + /// Specify Key to Open + /// Set to true to Open, false to Create if not Exists + internal RegKey(string Key, bool bReadOnly = true) : this(HKEYRoot.CurrentUser, KeySub.Software, Key, bReadOnly) { } + + /// + /// Use this to Open or Automatically Create a Registry Key + /// + /// specify registry root + /// specify a sub or custom + /// key you want to open / create + /// true if you want to force only reading it + private RegKey(HKEYRoot root, KeySub sub, string Key, bool bReadOnly) + { + string KeyToOpen = String.Empty; + if (sub == KeySub.Custom) + KeyToOpen = Key; + else + KeyToOpen = sub.ToString() + "\\" + Key; + + // Read Only Permission + RegistryKeyPermissionCheck permission = RegistryKeyPermissionCheck.ReadSubTree; + if (!bReadOnly) + permission = RegistryKeyPermissionCheck.ReadWriteSubTree; + + // Open or Create, if it doesn't exist and we have writable set + switch (root) + { + case HKEYRoot.ClassesRoot: + if (bReadOnly) + _RegKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(KeyToOpen); + else + _RegKey = Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(KeyToOpen, permission); + break; + + case HKEYRoot.CurrentUser: + if (bReadOnly) + _RegKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(KeyToOpen, permission); + else + _RegKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(KeyToOpen, permission); + break; + + case HKEYRoot.LocalMachine: + if (bReadOnly) + _RegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(KeyToOpen, permission); + else + _RegKey = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(KeyToOpen, permission); + break; + } + } + + /// + /// Finalizer + /// + ~RegKey() + { +#if NET40 + if (_RegKey != null) + _RegKey.Dispose(); +#endif + _RegKey = null; + } + + #endregion + + #region GetValue Registry Functions + + /// + /// Generic Registry KeyValue Getter Function + /// + /// Should be a System Type like string, bool, int32, double, decimal, etc... + /// The Value to get from the Registry + /// Default value to use if nothing was retrieved * Error occured * + /// Value found or Default Value + internal T GetVal(string strKeyValue, T DefaultValue) + { + T retVal = DefaultValue; + try + { + if (_RegKey != null) + { + object keyvalue = _RegKey.GetValue(strKeyValue); + string strvalue = string.Empty; + if (ObjTool.IsNotNullAndNotEmpty(keyvalue)) + { + #region First Handle the Value as a string + + // Handle Multi-Strings + if (keyvalue is object[]) + { + string keyVal2 = string.Empty; + string[] strVal2 = (string[])keyvalue; + foreach (string str in strVal2) + { + keyVal2 += str; + } + strvalue = keyVal2; + } + else + { + // Handle Single-Strings + strvalue = keyvalue.ToString(); + } + + #endregion + + // Now cast the Object Return type * Handle each object differently * + retVal = ObjTool.ConvertStringToObj(strvalue); + } + } + } + catch (Exception) { /* ignore */ } + return retVal; + } + + /// + /// Binary Registry KeyValue Getter Function + /// + /// The Value to get from the Registry + /// an array of Bytes found in the Registry, or null if none found, or error occured + internal byte[] GetVal(string strKeyValue) + { + byte[] retVal = null; + try + { + string StringValue = GetVal(strKeyValue, String.Empty); + if (!String.IsNullOrEmpty(StringValue)) + { + Byte[] ByteValue = new Byte[StringValue.Length]; + for (int i = 0; i < ByteValue.Length; ++i) + { + string strByte = Convert.ToString(StringValue[i]); + ByteValue[i] = byte.Parse(strByte); + } + retVal = ByteValue; + } + } + catch (Exception) { /* ignore */ } + return retVal; + } + + #endregion + + #region SetValue Registry Functions + + /// + /// Generic Registry KeyValue Setter Function + /// + /// Should be a System Type like string, bool, int32, double, decimal, etc... + /// The Value to write to in the Registry + /// The Value to set to the Registry + /// true if successful, false otherwise + internal bool SetVal(string strKeyValue, T Value) + { + bool bRetVal = false; + try + { + if (_RegKey != null) + { + if (Value is Int32) + { + _RegKey.SetValue(strKeyValue, Value, RegistryValueKind.DWord); + } + else if (Value is Int64) + { + _RegKey.SetValue(strKeyValue, Value, RegistryValueKind.QWord); + } + else + { + _RegKey.SetValue(strKeyValue, Value, RegistryValueKind.String); + } + bRetVal = true; + } + } + catch (Exception) { /* ignore */ } + return bRetVal; + } + + /// + /// Generic Registry KeyValue Setter Function + /// + /// The Value to write to in the Registry + /// A binary array of bytes to write to the Registry + /// true if successful, false otherwise + internal bool SetVal(string strKeyValue, byte[] ByteValue) + { + try + { + _RegKey.SetValue(strKeyValue, ByteValue, RegistryValueKind.Binary); + return true; + } + catch (Exception) { /* ignore */ } + return false; + } + + #endregion + + #region Public Static Helper Functions + + /// + /// Generic Static Registry Writer Function * Allows writing to HKEY\CURRENT_USER\SOFTWARE * + /// + /// Should be a System Type like string, bool, int32, double, decimal, etc... + /// SubKey i.e. Microsoft, Microsoft\Windows + /// Value to write to + /// Value to write + /// true if successful, false otherwise + internal static bool SetKey(String SubKey, String KeyValue, T Value) + { + bool bRetVal = false; + using (RegKey reg = new RegKey(HKEYRoot.CurrentUser, KeySub.Software, SubKey, false)) + { + bRetVal = reg.SetVal(KeyValue, Value); + } + return bRetVal; + } + + /// + /// Generic Static Registry Writer For Binary Function * Allows writing to HKEY\CURRENT_USER\SOFTWARE * + /// + /// SubKey i.e. Microsoft, Microsoft\Windows + /// Value to write to + /// Binary Value to write + /// true if successful, false otherwise + internal static bool SetKey(String SubKey, String KeyValue, byte[] ByteValue) + { + bool bRetVal = false; + using (RegKey reg = new RegKey(HKEYRoot.CurrentUser, KeySub.Software, SubKey, false)) + { + bRetVal = reg.SetVal(KeyValue, ByteValue); + } + return bRetVal; + } + + /// + /// Generic Static Registry Writer Function * Allows writing to any key * + /// + /// Should be a System Type like string, bool, int32, double, decimal, etc... + /// RootKey as defined in this Class + /// SubKey i.e. Software, Software\Microsoft + /// Value to write to + /// Value to write + /// true if successful, false otherwise + internal static bool SetKey(HKEYRoot rootKey, String SubKey, String KeyValue, T Value) + { + bool bRetVal = false; + using (RegKey reg = new RegKey(rootKey, KeySub.Custom, SubKey, false)) + { + bRetVal = reg.SetVal(KeyValue, Value); + } + return bRetVal; + } + + /// + /// Generic Static Registry Writer For Binary Function * Allows writing to any key * + /// + /// RootKey as defined in this Class + /// SubKey i.e. Software, Software\Microsoft + /// Value to write to + /// Binary Value to write + /// true if successful, false otherwise + internal static bool SetKey(HKEYRoot rootKey, String SubKey, String KeyValue, byte[] ByteValue) + { + bool bRetVal = false; + using (RegKey reg = new RegKey(rootKey, KeySub.Custom, SubKey, false)) + { + bRetVal = reg.SetVal(KeyValue, ByteValue); + } + return bRetVal; + } + + /// + /// Generic Static Registry Reader Function * Allows reading from HKEY\CURRENT_USER\SOFTWARE * + /// + /// Should be a System Type like string, bool, int32, double, decimal, etc... + /// SubKey i.e. Microsoft, Microsoft\Windows + /// Value to write to + /// Default Value to return if none found or error occured + /// true if successful, false otherwise + internal static T GetKey(String SubKey, String KeyValue, T DefaultValue) + { + T tRetVal = default(T); + using (RegKey reg = new RegKey(HKEYRoot.CurrentUser, KeySub.Software, SubKey, true)) + { + tRetVal = reg.GetVal(KeyValue, DefaultValue); + } + return tRetVal; + } + + /// + /// Generic Static Registry Reader For Binary Function * Allows reading from HKEY\CURRENT_USER\SOFTWARE * + /// + /// SubKey i.e. Microsoft, Microsoft\Windows + /// Value to write to + /// true if successful, false otherwise + internal static Byte[] GetKey(String SubKey, String KeyValue) + { + Byte[] retByte = null; + using (RegKey reg = new RegKey(HKEYRoot.CurrentUser, KeySub.Software, SubKey, true)) + { + retByte = reg.GetVal(KeyValue); + } + return retByte; + } + + /// + /// Generic Static Registry Reader Function * Allows reading from any key * + /// + /// Should be a System Type like string, bool, int32, double, decimal, etc... + /// RootKey as defined in this Class + /// SubKey i.e. Software, Software\Microsoft + /// Value to write to + /// Default Value to return if none found or error occured + /// true if successful, false otherwise + internal static T GetKey(HKEYRoot rootKey, String SubKey, String KeyValue, T DefaultValue) + { + T tRetVal = default(T); + using (RegKey reg = new RegKey(rootKey, KeySub.Custom, SubKey, true)) + { + tRetVal = reg.GetVal(KeyValue, DefaultValue); + } + return tRetVal; + } + + /// + /// Generic Static Registry Reader For Binary Function * Allows reading from any key * + /// + /// Should be a System Type like string, bool, int32, double, decimal, etc... + /// RootKey as defined in this Class + /// SubKey i.e. Software, Software\Microsoft + /// Value to write to + /// true if successful, false otherwise + internal static Byte[] GetKey(HKEYRoot rootKey, String SubKey, String KeyValue) + { + Byte[] retByte = null; + using (RegKey reg = new RegKey(rootKey, KeySub.Custom, SubKey, true)) + { + retByte = reg.GetVal(KeyValue); + } + return retByte; + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + Dispose(true); + + // Use SupressFinalize in case a subclass + // of this type implements a finalizer + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { +#if NET40 + if (_RegKey != null) + _RegKey.Dispose(); +#endif + } + + // Indicate that the instance has been disposed. + _RegKey = null; + _disposed = true; + } + } + + #endregion + } +} diff --git a/Internal/SQLParser.cs b/Internal/SQLParser.cs new file mode 100644 index 0000000..41065e7 --- /dev/null +++ b/Internal/SQLParser.cs @@ -0,0 +1,462 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics; +using System.Text.RegularExpressions; + +/// +/// MySQLCommands are embedded in SQL Scripts as follows: +///--# [Command] [Version] [Arg1] [Arg2] ... [Arg3] +///--# +///~ Serves as the Command End Marker! +///-- Possible Commands are, PRE_CREATE,CREATE,POST_CREATE,PRE_ALTER,ALTER,POST_ALTER,PRE_DROP,DROP,POST_DROP,RENAME +///-- Command Execution is as follows. +/// +///-- CREATE must exists. +///-- For New Install: *Script ID does not exist* -- WILL ALWAYS TAKE ONLY LATEST VERSION for CREATE, runs PRE-CREATEs and POST-CREATEs accordingly +///-- PRE-CREATE, CREATE, POST-CREATE (If you want nothing done, leave command blank) +///-- Allow Versions to use *, so that we can say for all [0.*.*] call this PRE-CREATE, or POST-CREATE +/// +///-- For Update Install: *Script ID exists* - Will check db where to start and execute until to highest version of CREATE was reached +///-- PRE-DROP, DROP, POST-DROP, PRE-RENAME, RENAME, POST-RENAME, PRE-ALTER, ALTER, POST-ALTER, for each respective version +/// +///-- Versioning is done as follows: +/// (Major version).(Minor version).(Revision number) +/// +/// MySQLIdentifiers are embedded in SQL Scripts as follows: +///--$ [Identifier] [Value], Identifier structure +/// +///--$ [ScriptId] [Guid]! +///-- Each script is versioned on it's own, so that is what we store in the db. +///-- Give each script a UNIQUE GUID. +///-- We will then store the ScriptID guid in the versioning table, along side the highest version of the script that most recently ran!, +///-- ~this way we can always know if something has to be done for each database object, +/// +namespace Sdaleo.Internal +{ + /// + /// + /// + public enum MySQLCommandType + { + PRE_CREATE, + CREATE, + POST_CREATE, + PRE_ALTER, + ALTER, + POST_ALTER, + PRE_DROP, + DROP, + POST_DROP, + PRE_RENAME, + RENAME, + POST_RENAME, + } + + /// + /// Custom SQL Commands that are part of an SQL Script. + /// They start as follows: + /// --# [Command] [Version] [Arg1] [Arg2] ... [Arg3] + /// + /// and end as follows: + /// --# + /// ~Serves as the Command End Marker! + /// Everything in between is SQL. + /// + internal class MySQLCommand + { + #region Members N' Properties + + // Line Specifics + internal uint Line_CommandStart { get; private set; } + internal uint Line_CommandEnd { get; private set; } + internal string[] SQLScriptBlock { get; private set; } + + // Command Specifics + internal MySQLCommandType Command { get; private set; } + internal string Version + { + get + { + if (_Versioning != null) + return _Versioning.Version; + else + return String.Empty; + } + } + internal Versioning _Versioning = null; + internal string[] Arguments = null; + + /// + /// Returns true if there are Lines between CommandStart and CommandEnd, + /// this indicates that it contains sql in between + /// + internal bool ContainsSQLScript + { + get + { + if (Line_CommandStart >= Line_CommandEnd) + return false; + else if ((Line_CommandStart + 1) == Line_CommandEnd) + return false; + else if ((SQLScriptBlock != null) && (SQLScriptBlock.Length > 0)) + return true; + else + return false; + } + } + + #endregion + + #region Internal Execute + + internal DBError ExecuteScriptBlock(IConnectDb credential) + { + DBError dbError = DBError.Create("No Script Block to Execute"); + if ((SQLScriptBlock != null) && (SQLScriptBlock.Length > 0)) + { + foreach (string sqlLine in SQLScriptBlock) + { + DB db = DB.Create(credential); + dbError = db.ExecuteNonQuery(sqlLine); + if (dbError.ErrorOccured) + break; + } + } + return dbError; + } + + #endregion + + #region Construction + + /// + /// Used to Parse a SQLCommand from an SQL Script + /// + /// Specifies the line of code where the Command is located --# [Command] [Version] [Arg1] [Arg2] ... [Arg3] + /// The String of Line_CommandStart, that contains all the Command Values the --# [Command] [Version] [Arg1] [Arg2] ... [Arg3] string + /// Specifies the line of code where the Command ends --# + internal MySQLCommand(uint Line_CommandStart, string Line_CommandStartString, uint Line_CommandEnd, string[] sqlScriptBlock) + { + this.Line_CommandStart = Line_CommandStart; + this.Line_CommandEnd = Line_CommandEnd; + ParseLine_CommandStartString(Line_CommandStartString); + this.SQLScriptBlock = sqlScriptBlock; + } + + /// + /// Parses a CommmandStartString and fills the values for this class + /// + /// a line that contains a CommandStartString + private void ParseLine_CommandStartString(string LineCommandStartString) + { + /// --# [Command] [Version] [Arg1] [Arg2] ... [Arg3] + /// --# [Create] [1.0.0] [Arg1] [Arg2] + Regex rx = new Regex(@"\[([\w\a-\?\.\*\+]+)\]"); + MatchCollection matches = rx.Matches(LineCommandStartString); + if (matches.Count < 2) + throw new ArgumentException("LineIdentifierString is Invalid"); + + // Get the Command and Command Version + string m1 = matches[0].ToString().Trim(new char[] { '[', ']' }); + string m2 = matches[1].ToString().Trim(new char[] { '[', ']' }); + this.Command = (MySQLCommandType)Enum.Parse(typeof(MySQLCommandType), m1.ToUpper()); + this._Versioning = new Versioning(m2); + + // Get Optional Arguments + int nArguments = matches.Count - 2; + if (nArguments > 0) + { + Arguments = new string[nArguments]; + for (int i = 0; i < nArguments; ++i) + Arguments[i] = matches[2 + i].ToString().Trim(new char[] { '[', ']' }); + } + } + + #endregion + + #region Internal Statics + + internal const string IDENTIFY_SQLSCRIPT_COMMAND = "--#"; + + /// + /// Returns true if the passed in line is a MySQLCommandStartLine + /// + /// line to check + /// true if MySQLCommandStartLine, false otherwise + internal static bool IsMySQLCommandStartLine(string line) + { + string lineTrimed = line.Trim(); + if (lineTrimed.StartsWith(IDENTIFY_SQLSCRIPT_COMMAND) && lineTrimed.Length != IDENTIFY_SQLSCRIPT_COMMAND.Length) + return true; + return false; + } + + /// + /// Returns ture if the passed in line is a MySQLCommandEndLine + /// + /// line to check + /// true if MySQLCommandEndLine, false otherwise + internal static bool IsMySQLCommandEndLine(string line) + { + string lineTrimed = line.Trim(); + if (lineTrimed.StartsWith(IDENTIFY_SQLSCRIPT_COMMAND) && lineTrimed.Length == IDENTIFY_SQLSCRIPT_COMMAND.Length) + return true; + return false; + } + + #endregion + } + + /// + /// + /// + public enum MySQLIdentifierType + { + SCRIPTID, + SCRIPTVERSION, + } + + /// + /// Custom SQL Identifiers that are part of an SQL Script. + /// They start as follows: + /// --$ [Identifier] [Value] + /// + public class MySQLIdentifier + { + #region Members N' Properties + + // Line Specifics + internal uint Line_IdentifierStart { get; private set; } + + // Identifier Specifics + internal MySQLIdentifierType Identity { get; private set; } + internal string Value { get; private set; } + + #endregion + + #region Construction + + /// + /// Used to Parse a SQLCommand from an SQL Script + /// + /// Specifies the line of code where the Identifier is located --$ [Identifier] [Value] + /// The String of Line_IdentifierString, that contains all the Identifier Values the --$ [Identifier] [Value] string + internal MySQLIdentifier(uint Line_IdentifierStart, string Line_IdentifierString) + { + this.Line_IdentifierStart = Line_IdentifierStart; + ParseLine_IndentifierStartString(Line_IdentifierString); + } + + /// + /// Parses a LineIdentifierString and fills the values for this class + /// + /// a line that contains a LineIdentifierString + private void ParseLine_IndentifierStartString(string LineIdentifierString) + { + /// --$ [Identifier] [Value] + /// --$ [ScriptID] [12312-312321-3213] + Regex rx = new Regex(@"\[([\w\a-\?\.\*\+]+)\]"); + MatchCollection matches = rx.Matches(LineIdentifierString); + if (matches.Count < 2) + throw new ArgumentException("LineIdentifierString is Invalid"); + + // Get the Identity and Value + string m1 = matches[0].ToString().Trim(new char[] { '[', ']' }); + string m2 = matches[1].ToString().Trim(new char[] { '[', ']' }); + this.Identity = (MySQLIdentifierType)Enum.Parse(typeof(MySQLIdentifierType), m1.ToUpper()); + this.Value = m2; + } + + #endregion + + #region Internal Statics + + internal const string IDENTIFY_SQLSCRIPT_IDENTIFIER = "--$"; + + /// + /// Returns true if the passed in line is a MySQLIdentifier + /// + /// line to check + /// true if MySQLIdentifier, false otherwise + internal static bool IsMySQLIdentifier(string line) + { + string lineTrimed = line.Trim(); + if (lineTrimed.StartsWith(IDENTIFY_SQLSCRIPT_IDENTIFIER) && lineTrimed.Length != IDENTIFY_SQLSCRIPT_IDENTIFIER.Length) + return true; + return false; + } + + #endregion + } + + /// + /// Helper class that parses an SQL Script for Commands and Identifiers, + /// for processing. + /// + internal static class SQLParser + { + /// + /// Iterates thru the Identifiers and returns the value of the first identifier that matches the identity. + /// + /// the value of the first matched identity, String.Empty if not found + internal static string GetValueForFirstFoundMySQLIdentifierType(MySQLIdentifierType Identity, MySQLIdentifier[] identifiers) + { + if (identifiers != null && identifiers.Length > 0) + { + foreach (MySQLIdentifier identifier in identifiers) + { + if (identifier.Identity == Identity) + return identifier.Value; + } + } + return String.Empty; + } + + /// + /// Parses an SQLScript for MySQLCommand Objects + /// + /// a string array from an sql script + /// all MySQLCommand objects found, if any, otherwise, empty [] + /// all MySQLIdentifier objects found, if any, otherwise, empty [] + internal static void ParseSQLScriptForMySQLCommandsAndIdentifiers(string[] sqlscript, out MySQLCommand[] commands, out MySQLIdentifier[] identifiers) + { + // Result set + commands = null; + identifiers = null; + List CommandsFound = new List(); + List IdentifiersFound = new List(); + + // intermediary variables + int nStartLine = -1; + string strStartLine = String.Empty; + + // Iterate thru all lines + for (int i = 0; i < sqlscript.Length; ++i) + { + string curLine = sqlscript[i]; + + /// Parse for + /// --$ [Identifier] [Value] + if (MySQLIdentifier.IsMySQLIdentifier(curLine)) + { + IdentifiersFound.Add(new MySQLIdentifier((uint)i, curLine)); + continue; + } + + /// Parse for + /// --# [Command] [Version] [Arg1] [Arg2] ... [Arg3] + /// ... + /// --# + if (MySQLCommand.IsMySQLCommandStartLine(curLine)) + { + nStartLine = i; + strStartLine = curLine; + continue; + } + else if (MySQLCommand.IsMySQLCommandEndLine(curLine)) + { + // Something is wrong with the script! + if ((nStartLine == -1) || String.IsNullOrEmpty(strStartLine)) + { + Debug.Assert(false); + } + else + { + if (nStartLine == i || nStartLine == i + 1) + { + Debug.Assert(false); // There is no SQLCodeBlock! = something is wrong with the script + nStartLine = -1; + strStartLine = String.Empty; + continue; + } + + // Create the SQLScriptBlock + List sqlScriptBlock = new List(); + for (int j = nStartLine; j < i; ++j) + sqlScriptBlock.Add(sqlscript[j]); + + // Convert the SQLScriptBlock into Executable Code + string[] executableSQLCodeBlock = GetExecutableSqlTextFromSQLScriptBlock(sqlScriptBlock.ToArray()); + + // Create the Commands Object that now contains the Executable SQL Code + CommandsFound.Add(new MySQLCommand((uint)nStartLine, strStartLine, (uint)i, executableSQLCodeBlock)); + nStartLine = -1; + strStartLine = String.Empty; + } + continue; + } + } + + // Delegate to Propertly Sort the MySQLCommands, First, by Command, then by Version + System.Comparison comparer = delegate(MySQLCommand x, MySQLCommand y) + { + // First Compare the Command, + int nCompare = x.Command.CompareTo(y.Command); + + // If equal, compare the versioning + if(nCompare == 0) + nCompare = x._Versioning.CompareTo(y._Versioning); + + return nCompare; + }; + CommandsFound.Sort(comparer); + + // Pass out Result set + commands = CommandsFound.ToArray(); + identifiers = IdentifiersFound.ToArray(); + } + + /// + /// Use this to Parse an SQL Script Block (a block of code, contained inside a MySQLCommand. + /// It Ignores Comment Lines, and also breaks out the SQL Script by GO Statements. + /// + /// an unprocessed Script block from an SQL Script + /// a ADO.Net Friend sql script block that can be executed + internal static string[] GetExecutableSqlTextFromSQLScriptBlock(string[] sqlscriptBlock) + { + + bool bIsInCommentMode = false; + StringBuilder sbSQLLines = new StringBuilder(); + List sbSQLBrokenOut = new List(); + foreach (string line in sqlscriptBlock) + { + // Let's deal with comments, which allows us to put comments in our SQL Scripts + if (bIsInCommentMode) + { + if (line.StartsWith("*/") || line.EndsWith("*/")) + bIsInCommentMode = false; + continue; + } + else if (line.StartsWith("/*") && !line.EndsWith("*/")) + { + bIsInCommentMode = true; // skip lines until end of comment + continue; + } + else if (line.StartsWith("/*") && line.EndsWith("*/")) + continue; // skip single comment line + else if (line.StartsWith("--")) + continue; // skip single comment line + + // We break out GO stmts to allow execution seperatly + if ((line.Length == 2) && line.ToUpper().StartsWith("GO")) + { + if (sbSQLLines.Length > 0) + sbSQLBrokenOut.Add(sbSQLLines.ToString()); + sbSQLLines.Remove(0, sbSQLLines.Length); // clear sbSQLLines + continue; + } + + // Ready to use the SQL Line + sbSQLLines.Append((line + " ")); + } + + if (sbSQLLines.Length > 0) + sbSQLBrokenOut.Add(sbSQLLines.ToString()); + + // Return the 'GO' Broken out SQL Script Block + return sbSQLBrokenOut.ToArray(); + } + } +} diff --git a/Internal/SecuredPassword.cs b/Internal/SecuredPassword.cs new file mode 100644 index 0000000..81e779c --- /dev/null +++ b/Internal/SecuredPassword.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo +{ + /// + /// This class allows us to Secure a Password from spying eyes + /// * Only allow specific callers to actually retrieve the password unencrypted * + /// + internal class SecuredPassword + { + private string _Password; + internal string Password + { + get + { + return _Password; + //if (SecureDAL.IsInternal) + // return _Password; + //else + // return Encryption.EncryptText(_Password); + } + set + { + _Password = value; + } + } + } +} diff --git a/Internal/UDL.cs b/Internal/UDL.cs new file mode 100644 index 0000000..db16921 --- /dev/null +++ b/Internal/UDL.cs @@ -0,0 +1,562 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace Sdaleo +{ + /// + /// Core Class to Parse / Generate a UDL String + /// + internal class UDL : ICloneable, IComparable + { + #region Internal ReadWrite Properties + + /// + /// Credential Object can point to different databases + /// + internal string DataBase { get; set; } + + /// + /// Default Connection Timeout + /// + internal const uint DEFAULT_CONNECTION_TIMEOUT_UDL = 15; + + /// + /// Allow Caller to set connection timeout + /// + internal uint ConnectionTimeout = DEFAULT_CONNECTION_TIMEOUT_UDL; + + /// + /// Defaulted to 'true'. When set uses the ConnectionTimeout value, when false it won't + /// + internal bool UseConnectionTimeout = true; + + // * Secured Password * + private SecuredPassword _Password = new SecuredPassword(); + + /// + /// Secured Password Object that stores the password in a secure manner in memory + /// + internal string Password + { + get + { + return _Password.Password; + } + private set + { + _Password.Password = value; + } + } + + /// + /// + /// + internal string DataSource + { + get + { + if (!String.IsNullOrEmpty(ServerAddress) && !String.IsNullOrEmpty(InstanceName)) + return ServerAddress + "\\" + InstanceName; + else if (!String.IsNullOrEmpty(ServerAddress)) + return ServerAddress; + else + return string.Empty; + } + private set + { + if (!String.IsNullOrEmpty(value)) + { + string[] values = value.Split('\\'); + if (values.Length == 2) + { + ServerAddress = values[0]; + InstanceName = values[1]; + } + else if (value.Length > 2) + { + int nIndx = value.LastIndexOf('\\'); + ServerAddress = value.Substring(0, nIndx); + InstanceName = value.Substring(nIndx + 1); + } + else + { + ServerAddress = value; + } + } + } + } + + #endregion + + #region Internal ReadOnly Properties + + #region ReadOnly String Getters + + /// + /// + /// + internal string Username { get; private set; } + + /// + /// + /// + internal string ServerAddress { get; private set; } + + /// + /// + /// + internal string InstanceName { get; private set; } + + /// + /// + /// + internal string IntegratedSecurity { get; private set; } + + /// + /// + /// + internal string AttachDBFilename { get; private set; } + + #endregion + + #region ReadOnly Bool Getters + + /// + /// + /// + internal bool TrustedConnection { get; private set; } + + /// + /// + /// + internal bool PersistSecurityInfo { get; private set; } + + /// + /// + /// + internal bool UserInstance { get; private set; } + + /// + /// + /// + internal bool Encrypt { get; private set; } + + #endregion + + #endregion + + #region Constructors + + /// + /// Construction (Set all UDL Settings via Connection String) + /// + /// Pass in a valid Connection String To correctly instantiate the UDL Object + internal UDL(String ConnectionString) + { + Parse(ConnectionString); + } + + #region SQL CE Constructors + + /// + /// Construction SQL CE (Set common UDL Settings for SQL CE) + /// + /// + /// + /// + internal UDL(string FileNameNPath, string Password) + { + this.DataSource = FileNameNPath; + UseConnectionTimeout = false; + if (!String.IsNullOrEmpty(Password)) + { + this.Password = Password; + this.Encrypt = true; + } + } + + #endregion + + #region SQL Server Constructors + + /// + /// Construction SQL Server (Using SQL Login Credential) + /// + /// Name of Database To Use + /// Username to Connect With + /// Password to Connect With + /// ServerAddress to use as DataSource + /// Name of Instance to use as DataSource + internal UDL(string DataBase, string Username, string Password, string ServerAddress, string InstanceName) + { + this.DataBase = DataBase.Trim(); + this.Username = Username.Trim(); + this.Password = Password; + this.ServerAddress = (String.IsNullOrEmpty(ServerAddress)) ? "." : ServerAddress.Trim().ToUpper(); + this.InstanceName = InstanceName.Trim().ToUpper(); + } + + /// + /// Construction SQL Server (Set common UDL Settings for SQL Server) + /// + /// Name of Database To Use + /// Username to Connect With + /// Password to Connect With + /// ServerAddress to use as DataSource + /// Name of Instance to use as DataSource + /// Set to True to use Windows Authentication instead of SQL Auth + internal UDL(string DataBase, string Username, string Password, string ServerAddress, string InstanceName, bool TrustedConnection) + { + this.DataBase = DataBase.Trim(); + this.Username = Username.Trim(); + this.Password = Password; + this.ServerAddress = (String.IsNullOrEmpty(ServerAddress)) ? "." : ServerAddress.Trim().ToUpper(); + this.InstanceName = InstanceName.Trim().ToUpper(); + this.TrustedConnection = TrustedConnection; + this.IntegratedSecurity = TrustedConnection ? "SSPI" : ""; + } + + /// + /// Construction SQL Server (Set all UDL Settings for SQL Server) + /// + /// Name of Database To Use + /// Username to Connect With + /// Password to Connect With + /// ServerAddress to use as DataSource + /// Name of Instance to use as DataSource + /// Set to SQL Express .mdf file to attach to (Creates a User Instance) + /// Set to True to use Windows Authentication instead of SQL Auth + /// Legacy Setting that Persists the Security Information + internal UDL(string DataBase, string Username, string Password, string ServerAddress, string InstanceName, + string AttachDBFilename, bool TrustedConnection, bool PersistSecurityInfo) + { + this.DataBase = DataBase.Trim(); + this.Username = Username.Trim(); + this.Password = Password; + this.ServerAddress = (String.IsNullOrEmpty(ServerAddress)) ? "." : ServerAddress.Trim().ToUpper(); + this.InstanceName = InstanceName.Trim().ToUpper(); + this.AttachDBFilename = AttachDBFilename.Trim(); + this.UserInstance = !String.IsNullOrEmpty(AttachDBFilename); + this.TrustedConnection = TrustedConnection; + this.IntegratedSecurity = TrustedConnection? "SSPI" : ""; + this.PersistSecurityInfo = PersistSecurityInfo; + } + + #endregion + + #endregion + + #region Connection String N' Parse + + /// + /// Returns the Connection String formed from the UDL Properties + /// + /// + /// + /// Data Source=myServerAddress;Initial Catalog=myDataBase;User Id=myUsername;Password=myPassword; + /// Server=myServerAddress;Database=myDataBase;User ID=myUsername;Password=myPassword;Trusted_Connection=False; + /// Data Source=myServerAddress;Initial Catalog=myDataBase;Integrated Security=SSPI; + /// Server=myServerAddress;Database=myDataBase;Trusted_Connection=True; + /// Server=myServerName\theInstanceName;Database=myDataBase;Trusted_Connection=True; + /// Data Source=myServerAddress;Initial Catalog=myDataBase;Integrated Security=SSPI;User ID=myDomain\myUsername;Password=myPassword; + /// + internal string ConnectionString + { + get + { + string strUDL = String.Empty; + + // * Data Source Must Always be Specified * + if (!String.IsNullOrEmpty(ServerAddress) && !String.IsNullOrEmpty(InstanceName)) + { + strUDL = String.Format(@"Data Source={0}\{1};", ServerAddress, InstanceName); + } + else if (!String.IsNullOrEmpty(ServerAddress)) + { + strUDL = String.Format(@"Data Source={0};", ServerAddress); + } + else + throw new Exception("Invalid DataSource Parameter"); + + // Add Database? + if (!String.IsNullOrEmpty(DataBase)) + { + string strAddMore = String.Format(@"Initial Catalog={0};", DataBase); + strUDL += strAddMore; + } + + // Add User Information? + if (!String.IsNullOrEmpty(Username)) + { + string strAddMore = String.Format(@"User ID={0};", Username); + strUDL += strAddMore; + } + + // Add Password Information? + if (!String.IsNullOrEmpty(Password)) + { + string strAddMore = String.Format(@"Password={0};", Password); + strUDL += strAddMore; + } + + // Should we use User Instance? + if (UserInstance && !String.IsNullOrEmpty(AttachDBFilename)) + { + string strAddMore = String.Format(@"User Instance={0};AttachDBFilename={1}", UserInstance.ToString(), AttachDBFilename); + strUDL += strAddMore; + } + + // Should we use Integrated Security? + if (TrustedConnection && !String.IsNullOrEmpty(IntegratedSecurity)) + { + string strAddMore = String.Format(@"Trusted_Connection={0};Integrated Security={1}", TrustedConnection.ToString(), IntegratedSecurity); + strUDL += strAddMore; + } + + // Persist Security Info? + if (PersistSecurityInfo) + { + string strAddMore = String.Format(@"Persist Security Info={0};", PersistSecurityInfo.ToString()); + strUDL += strAddMore; + } + + // SQL CE Encryption + if (Encrypt) + { + string strAddMore = "Encrypt=TRUE;Encryption Mode=platform default;"; + strUDL += strAddMore; + } + + // At the end, specifically add the connection timeout * If asked to * + if (UseConnectionTimeout) + { + string strAddMore = String.Format(@"Connection Timeout={0};", ConnectionTimeout.ToString()); + strUDL += strAddMore; + } + return strUDL; + } + } + + /// + /// Returns a Connection String for use with Legacy ADO + /// + internal string ConnectionStringADO + { + get + { + // Force Persist Security Info + bool bPersistSecurity = PersistSecurityInfo; + PersistSecurityInfo = true; + string retString = "Provider=SQLOLEDB.1;OLE DB Services=-2;" + ConnectionString; + PersistSecurityInfo = bPersistSecurity; + return retString; + } + } + + /// + /// Parses (fills in) UDL properties from the passed in Connection String + /// + /// + private void Parse(String ConnectionString) + { + if (!String.IsNullOrEmpty(ConnectionString)) + { + String[] tokens = ConnectionString.Split(';'); + foreach (string Pair in tokens) + { + string[] KeyValuePair = Pair.Split('='); + try + { + switch (KeyValuePair[0].ToUpper().Trim()) + { + case "INITIAL CATALOG": + DataBase = KeyValuePair[1].Trim(); + break; + + case "USER ID": + Username = KeyValuePair[1].Trim(); + break; + + case "PASSWORD": + Password = KeyValuePair[1]; + break; + + case "DATA SOURCE": + DataSource = KeyValuePair[1].Trim(); + break; + + case "ATTACHDBFILENAME": + AttachDBFilename = KeyValuePair[1].Trim(); + break; + + case "USER INSTANCE": + UserInstance = Boolean.Parse(KeyValuePair[1].Trim()); + break; + + case "CONNECTION TIMEOUT": + ConnectionTimeout = UInt32.Parse(KeyValuePair[1].Trim()); + break; + + case "TRUSTED_CONNECTION": + TrustedConnection = Boolean.Parse(KeyValuePair[1].Trim()); + break; + + case "INTEGRATED SECURITY": + IntegratedSecurity = KeyValuePair[1].Trim().ToUpper(); + break; + + case "PERSIST SECURITY INFO": + PersistSecurityInfo = Boolean.Parse(KeyValuePair[1].Trim()); + break; + + case "ENCRYPT": + Encrypt = true; + break; + + case "ENCRYPTION MODE": + Encrypt = true; + break; + + } + } + catch (Exception) { /* ignore and continue iteration */ } + } + } + } + + #endregion + + #region ICloneable Members + + /// + /// + /// + /// + public object Clone() + { + return new UDL(this.ConnectionString); + } + + #endregion + + #region IComparable Members + + /// + /// + /// + /// + /// + public int CompareTo(object obj) + { + UDL otherUDL = obj as UDL; + if (otherUDL != null) + { + int nCompare = String.Compare(this.ConnectionString, otherUDL.ConnectionString, true); + return nCompare; + } + else + { + throw new ArgumentException("Object is not a UDL"); + } + } + + #endregion + + #region UDL File Reading / Writing + + /// + /// Use this to Parse a UDL object from a text File + /// + /// Full Path to File to Read and Parse + /// true if the Text file is encrypted, false otherwise + /// a valid UDL object if successful, null otherwise + internal static UDL UDLReadInFromFile(string FileNameNPath, bool bFileIsEncrypted) + { + if (!File.Exists(FileNameNPath)) + return null; + + try + { + // Read In the file + string UDLFileContents = string.Empty; + FileStream fs = new FileStream(FileNameNPath, FileMode.Open); + StreamReader sr = new StreamReader(fs, Encoding.Unicode); + string line; + while ((line = sr.ReadLine()) != null) + { + // UDL File is encrypted * Decrypt line by line * + //if (bFileIsEncrypted) + //line = Encryption.DecryptText(line); + + if (line.StartsWith("[oledb]") || + line.StartsWith(";")) + continue; // skip first 2 lines + + // Read the line + UDLFileContents += line; + } + sr.Close(); + fs.Close(); + + UDLFileContents = UDLFileContents.Trim(); + if (String.IsNullOrEmpty(UDLFileContents)) + return null; + + // Parse out the UDL Info + UDL udl = new UDL(UDLFileContents); + return udl; + } + catch (Exception) {/* ignore */} + return null; + } + + /// + /// Use this to Write a UDL Object to a Text File + /// + /// Full Path to File to Write To + /// UDL Object to write out + /// True to encrypt File Contents, False Otherwise + /// true if successful, false otherwise + internal static bool UDLWriteOutToToFile(string FileNameNPath, UDL udl, bool bEncryptFile) + { + try + { + string UDLFileContents = string.Empty; + + // Create the Directory (if it doesn't exist) * Otherwise an error occurs * + if (!Directory.Exists(Path.GetDirectoryName(FileNameNPath))) + Directory.CreateDirectory(Path.GetDirectoryName(FileNameNPath)); + + // Write to File + FileStream fs = new FileStream(FileNameNPath, FileMode.Create); + StreamWriter sw = new StreamWriter(fs, Encoding.Unicode); + + // UDL File is Encrypted Now, so we encrypte Line-by-line + if (bEncryptFile) + { + // sw.WriteLine(Encryption.EncryptText("[oledb]")); + // sw.WriteLine(Encryption.EncryptText("; Everything after this line is an OLE DB initstring")); + // write out the Connection string, + // sw.WriteLine(Encryption.EncryptText(udl.ConnectionStringLegacy)); + } + else + { + sw.WriteLine("[oledb]"); + sw.WriteLine("; Everything after this line is an OLE DB initstring"); + sw.WriteLine(udl.ConnectionString); + } + + sw.Close(); + fs.Close(); + return true; + } + catch (Exception) { /* ignore */ } + return false; + } + + #endregion + } +} diff --git a/Internal/Versioning.cs b/Internal/Versioning.cs new file mode 100644 index 0000000..09245a0 --- /dev/null +++ b/Internal/Versioning.cs @@ -0,0 +1,443 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics; +using System.IO; + +namespace Sdaleo.Internal +{ + /// + /// Interface of Versioning, to check if the passed in version is supported by the Versioning Object + /// + internal interface IVersionSupported + { + bool IsSupported(string Version); + bool IsSupported(Versioning Version); + } + + /// + /// Allows us to easily wrap Versioning Functionallity, + /// into Objects. + /// [Major version].[Minor version].[Build number] + /// --------------------------------------------------- + /// Major version can be any valid uint as well as * + /// Minor version can be any valid uint as well as * + /// Build number can be any valid uint as well as * + /// + internal class Versioning : ICloneable, IComparable, IVersionSupported + { + #region Internal consts + + internal const int STAR_ALL = -1; + + #endregion + + #region Private Members + + private int _MajorVersion = STAR_ALL; + private int _MinorVersion = STAR_ALL; + private int _BuildNumber = STAR_ALL; + + #endregion + + #region Construction + + /// + /// Use this to initialize the class with a version string, can not contain multiple versions seperated by ";" + /// + /// any version string in the format [Major].[Minor].[Build], like 5.3.3 or 5.4.* + internal Versioning(string strVersion) + { + if (!IsValidVersionStr(strVersion) || strVersion.Contains(";")) + throw new ArgumentException("Invalid Version String"); + ParseVersion(strVersion, out this._MajorVersion, out this._MinorVersion, out this._BuildNumber); + } + + /// + /// Initialize Versioning with a single MajorVersion and MinorVersion. + /// + /// Major Version + /// Minor Version + internal Versioning(int MajorVersion, int MinorVersion) + { + if (MajorVersion >= STAR_ALL && MinorVersion >= STAR_ALL) + { + _MajorVersion = MajorVersion; + _MinorVersion = MinorVersion; + } + else + throw new ArgumentException("MajorVersion or MinorVersion is invalid"); + } + + /// + /// Initialize Versioning with a single MajorVersion,MinorVersion, and BuildNumber. + /// + /// Major Version + /// Minor Version + /// Build Number + internal Versioning(int MajorVersion, int MinorVersion, int BuildNumber) + { + if (MajorVersion >= STAR_ALL && MinorVersion >= STAR_ALL && _BuildNumber >= STAR_ALL) + { + _MajorVersion = MajorVersion; + _MinorVersion = MinorVersion; + _BuildNumber = BuildNumber; + } + else + throw new ArgumentException("MajorVersion,MinorVersion, or BuildNumber is invalid"); + } + + #endregion + + #region Versioning Getter/Setter + + /// + /// Set/Retrieve Version + /// + internal String Version + { + get + { + return VersionToVersionString(_MajorVersion, _MinorVersion, _BuildNumber); + } + set + { + if (IsValidVersionStr(value) && !value.Contains(";")) + ParseVersion(value, out this._MajorVersion, out this._MinorVersion, out this._BuildNumber); + else + throw new ArgumentException("Invalid Version String"); + } + } + + #endregion + + #region internal Static Helpers + + /// + /// Gets a Versioning object for the Version Information of a File + /// + /// Full File Name and Path + /// returns a new Versioning Object for a File, or null if error occured + internal static Versioning GetFileVersioning(string FileNameNPath) + { + if (!string.IsNullOrEmpty(FileNameNPath) && File.Exists(FileNameNPath)) + { + try + { + FileVersionInfo info = FileVersionInfo.GetVersionInfo(FileNameNPath); + return new Versioning(info.FileMajorPart, info.FileMinorPart, info.FileBuildPart); + } + catch (Exception) { /* ignore */ } + } + return null; + } + + /// + /// Parses out a single Version from a string + /// + /// pass in a Version format [Major].[Minor].[Build], like 5.3.3 or 5.4.* + /// returns an int or STAR_ALL, or UNINITIALIZED, if error occured + /// returns an int or STAR_ALL, or UNINITIALIZED, if error occured + /// returns an int or STAR_ALL, or UNINITIALIZED, if error occured + internal static void ParseVersion(string strVersion, out int MajorVersion, out int MinorVersion, out int BuildNumber) + { + if (!IsValidVersionStr(strVersion) || strVersion.Contains(";")) + throw new ArgumentException("Invalid Version String"); + + MajorVersion = STAR_ALL; + MinorVersion = STAR_ALL; + BuildNumber = STAR_ALL; + string[] MajorMinorPossBuildVersion = strVersion.Split('.'); + try + { + for (int i = 0; i < MajorMinorPossBuildVersion.Length; ++i) + { + if (i == 0) + { + if (MajorMinorPossBuildVersion[0] != "*") + MajorVersion = int.Parse(MajorMinorPossBuildVersion[0]); + } + else if (i == 1) + { + if (MajorMinorPossBuildVersion[1] != "*") + MinorVersion = int.Parse(MajorMinorPossBuildVersion[1]); + } + else if (i == 2) + { + if (MajorMinorPossBuildVersion[2] != "*") + BuildNumber = int.Parse(MajorMinorPossBuildVersion[2]); + } + } + + } + catch (Exception) { /* Ignore */ } + } + + /// + /// Turns Version Numbers into a Version String + /// + /// Major Version + /// Minor Version, can be * + /// Build Number, can be * or UNINITIALIZED + /// the Version String + internal static string VersionToVersionString(int MajorVersion, int MinorVersion = STAR_ALL, int BuildNumber = STAR_ALL) + { + string strRetVal = String.Empty; + if (MajorVersion >= STAR_ALL) + { + // Major Version + if (MajorVersion == STAR_ALL) + strRetVal += "*"; + else + strRetVal += MajorVersion.ToString(); + + // Minor Version + if (MinorVersion >= STAR_ALL) + { + strRetVal += "."; + if (MinorVersion == STAR_ALL) + strRetVal += "*"; + else + strRetVal += MinorVersion.ToString(); + } + + // Build Number + if (BuildNumber >= STAR_ALL) + { + strRetVal += "."; + if (BuildNumber == STAR_ALL) + strRetVal += "*"; + else + strRetVal += BuildNumber.ToString(); + } + } + return strRetVal; + } + + #endregion + + #region Validation + + private const string CharSet_AllowedNumeric = "0123456789"; + private const string CharSet_AllowedVersionChars = CharSet_AllowedNumeric + "*;."; + + /// + /// Generic Function to use with Allowed Character Sets above + /// + /// string to evaluate + /// Pass in one of the legal character consts declared above + /// true if valid, false otherwise + private static bool ContainsOnlyLegalChars(string TextToEvaluate, string TextToEvaluateWith) + { + foreach (char c in TextToEvaluate.ToCharArray()) + { + bool bFound = (TextToEvaluateWith.IndexOf(c) >= 0); + if (!bFound) + return false; + } + return true; + } + + /// + /// Used to Validate a Version string of format 12.1.12;12.2.*;12.2.1 + /// + /// a Version String + /// true if valid, false otherwise + public static bool IsValidVersionStr(string VersionStr) + { + if (String.IsNullOrEmpty(VersionStr)) + { + return false; + } + else if (VersionStr.Length < 1 && VersionStr.Length > 50) // restrice Version String Length + { + return false; + } + else if (!ContainsOnlyLegalChars(VersionStr, CharSet_AllowedVersionChars)) + { + return false; + } + else + { + return true; + } + } + + #endregion + + #region ICloneable Members + public object Clone() + { + Versioning versioning = new Versioning(this._MajorVersion, this._MinorVersion, this._BuildNumber); + return versioning; + } + #endregion + + #region IComparable Members + + public int CompareTo(object obj) + { + if (obj is Versioning) + { + Versioning v = (Versioning)obj; + //*.*.* + //*.2.* + //1.*.* + //1.1.* + //1.1.1 + //2.2.2 + //2.2.* + int nCompare = 0; + nCompare = this._MajorVersion.CompareTo(v._MajorVersion); + if (nCompare == 0) + nCompare = this._MinorVersion.CompareTo(v._MinorVersion); + if (nCompare == 0) + nCompare = this._BuildNumber.CompareTo(v._BuildNumber); + return nCompare; + } + else + { + throw new ArgumentException("object is not a Versioning"); + } + } + + #endregion + + #region IVersionSupported Members + + /// + /// Returns true if the Version String passed in is supported/matches Versioning for this object + /// + /// a Version string to validate against + /// true if supported, false otherwise + public bool IsSupported(string Version) + { + Versioning version = new Versioning(Version); + return IsSupported(version); + } + + /// + /// Returns true if the Version passed in is supported/matches Versioning for this object + /// + /// a Version Object to validate against + /// true if supported, false otherwise + public bool IsSupported(Versioning Version) + { + if (Version != null) + { + int nCompare = this.CompareTo(Version); + if (nCompare == 0) + { + return true; + } + else if (nCompare == 1) + { + return false; + } + else if (nCompare == -1) + { + if (((this._MajorVersion == STAR_ALL) || (this._MajorVersion == Version._MajorVersion)) && + ((this._MinorVersion == STAR_ALL) || (this._MinorVersion == Version._MinorVersion)) && + ((this._BuildNumber == STAR_ALL) || (this._BuildNumber == Version._BuildNumber)) + ) + { + return true; + } + else + { + return false; + } + } + } + return false; + } + + #endregion + } + + /// + /// Allows us to easily parse/sort/search multiple versioning classes + /// + internal static class Versionings + { + /// + /// Used to parse multiple ";" seperated versions from a string + /// + /// single/multiple version strings, seperated by ";", in the format [Major].[Minor].[Build], like 5.3.3 or 5.4.* + /// a sorted array of versionings or null if error occured + internal static Versioning[] ParseVersions(string strVersions) + { + if (!Versioning.IsValidVersionStr(strVersions)) + return null; + + List RetValueVersions = new List(); + string[] Versions = strVersions.Split(';'); + foreach (string Version in Versions) + RetValueVersions.Add(new Versioning(Version)); + + RetValueVersions.Sort(); + return RetValueVersions.ToArray(); + } + + #region IsSupportedFile + + /// + /// Use this to find out if a File Version is supported by the passed in Versions string + /// + /// single/multiple version strings, seperated by ";", in the format [Major].[Minor].[Build], like 5.3.3 or 5.4.* + /// Full File Name and Path + /// true if the File Version is supported by the Versions string + internal static bool IsSupportedFile(string strVersions, string FileNameNPath) + { + return IsSupported(ParseVersions(strVersions), Versioning.GetFileVersioning(FileNameNPath)); + } + + /// + /// Use this to find out if a File Version is supported by the passed in Versions [] + /// + /// single/multiple versioning objects + /// Full File Name and Path + /// true if the File Version is supported by the Versions string + internal static bool IsSupportedFile(Versioning[] Versions, string FileNameNPath) + { + return IsSupported(Versions, Versioning.GetFileVersioning(FileNameNPath)); + } + + #endregion + + #region IsSupported + + /// + /// Pass in a Versions string, and a Version to check against. Returns true, if the Version is IVersionSupported by + /// the passed in Versions string. + /// + /// single/multiple version strings, seperated by ";", in the format [Major].[Minor].[Build], like 5.3.3 or 5.4.* + /// any version string in the format [Major].[Minor].[Build], like 5.3.3 or 5.4.* + /// true, if a Versioning Object in the Versions returns true for IVersionSupported, false otherwise + internal static bool IsSupported(string strVersions, string strVersion) + { + return IsSupported(ParseVersions(strVersions), new Versioning(strVersion)); + } + + /// + /// Pass in a single/multipe Versions object, and a Version object to check against. Returns true, if the Version is IVersionSupported by + /// the passed in Versions Objects. + /// + /// single/multiple versioning objects + /// single versioning object + /// true, if a Versioning Object in the Versions returns true for IVersionSupported, false otherwise + internal static bool IsSupported(Versioning[] Versions, Versioning Version) + { + // Let IVersionSupported do all the work + foreach (Versioning _version in Versions) + { + if (_version.IsSupported(Version)) + return true; + } + return false; + } + + #endregion + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..3b7aa74 --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DatabaseLayer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DatabaseLayer")] +[assembly: AssemblyCopyright("Copyright © 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f48a9f12-5507-405c-8358-c4365701f2ee")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Sdaleo.csproj b/Sdaleo.csproj new file mode 100644 index 0000000..4b0212f --- /dev/null +++ b/Sdaleo.csproj @@ -0,0 +1,126 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {C919D6D0-E0AE-4D7A-B13D-350FCB4A22FF} + Library + Properties + Sdaleo + Sdaleo + v3.5 + 512 + + + + + + + + + + + + true + full + false + ..\Target\Debug\ + TRACE;DEBUG;NET35 + prompt + 4 + + + pdbonly + true + ..\Target\Release\ + TRACE;NET35 + prompt + 4 + + + + Components\Advantage.Data.Provider.dll + + + Components\Devart.Data.dll + + + Components\Devart.Data.PostgreSql.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Sdaleo.csproj.user b/Sdaleo.csproj.user new file mode 100644 index 0000000..566c009 --- /dev/null +++ b/Sdaleo.csproj.user @@ -0,0 +1,6 @@ + + + + ShowAllFiles + + \ No newline at end of file diff --git a/Sdaleo.csproj.vspscc b/Sdaleo.csproj.vspscc new file mode 100644 index 0000000..feffdec --- /dev/null +++ b/Sdaleo.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/Systems/Advantage/Credential.cs b/Systems/Advantage/Credential.cs new file mode 100644 index 0000000..4f98e4c --- /dev/null +++ b/Systems/Advantage/Credential.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.Advantage +{ + /// + /// Handles SQL CE Credentials, to be + /// used by all our SQL CE Functions + /// + public class AdvantageCredential : IComparable, ICloneable, IConnectDb + { + #region IConnectDb + + /// + /// Let Callers know this is a SQLCE Connection Object + /// + public DBSystem DBType { get { return DBSystem.ADVANTAGE; } } + + /// + /// Check to see if the Credential Object consists of valid input + /// + public bool IsValid + { + get + { + if (!ValidationConsts.IsValidFileNameNPath(DataSource)) + return false; + + // For ADS i believe we always want a user and Password + + //if (!String.IsNullOrEmpty(_UDL.Password) && !ValidationConsts.Generic.IsValidPassword(_UDL.Password)) + // return false; + + return true; + } + } + + /// + /// + /// + public string ConnectionString { get { return _UDL.ConnectionString; } } + + /// + /// SQL CE uses the File Name and Path as the Datasource + /// + public string DataSource { get { return _UDL.DataSource; } } + + /// + /// SQL CE doesn't use User + /// + public string User { get { return _UDL.Username; } } + + /// + /// SQL CE doesn't support DBMS like behaviors + /// + public bool SupportsDBMS { get { return false; } } + + /// + /// SQL CE doesn't support DBMS like behaviors + /// + public IamDBMS DBMS { get { return null; } } + + /// + /// SQL CE doesn't support Timeouts + /// + public bool SupportsTimeouts { get { return false; } } + + /// + /// SQL CE doesn't support Timeouts + /// + public IsupportTimeouts Timeouts { get { return null; } } + + #endregion + + private UDL _UDL = null; + + #region AdvantageCredential Credential Constructors + + /// + /// Create a SQL CE Connection from an UDL Object + /// + /// + internal AdvantageCredential(UDL udl) + { + if (udl != null) + _UDL = udl; + } + + /// + /// Create an Untrusted SQLCE Credential * No Encryption Used * + /// + public AdvantageCredential(string FileNameNPath) + { + _UDL = new UDL(FileNameNPath, String.Empty); + } + + /// + /// Create a Trusted SQLCE Credential * Encryption Used * + /// + public AdvantageCredential(string FileNameNPath, string strPassword) + { + _UDL = new UDL(FileNameNPath, strPassword); + } + + #endregion + + #region ICloneable Members + + public object Clone() + { + AdvantageCredential credential = new AdvantageCredential((UDL)this._UDL.Clone()); + return credential; + } + + #endregion + + #region IComparable Members + + public int CompareTo(object obj) + { + AdvantageCredential otherCredential = obj as AdvantageCredential; + if (otherCredential != null) + { + int nCompare = _UDL.CompareTo(otherCredential._UDL); + return nCompare; + } + else + { + throw new ArgumentException("Object is not a AdvantageCredential"); + } + } + + #endregion + } +} diff --git a/Systems/Advantage/Database.cs b/Systems/Advantage/Database.cs new file mode 100644 index 0000000..27c75fe --- /dev/null +++ b/Systems/Advantage/Database.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.Advantage +{ + class AdvantageDatabase + { + + + } +} diff --git a/Systems/Advantage/General.cs b/Systems/Advantage/General.cs new file mode 100644 index 0000000..00c5225 --- /dev/null +++ b/Systems/Advantage/General.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.Advantage +{ + class General + { + } +} diff --git a/Systems/Advantage/Internal/Validation.cs b/Systems/Advantage/Internal/Validation.cs new file mode 100644 index 0000000..6879476 --- /dev/null +++ b/Systems/Advantage/Internal/Validation.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.Advantage.Internal +{ + class Validation + { + } +} diff --git a/Systems/CTree/Credential.cs b/Systems/CTree/Credential.cs new file mode 100644 index 0000000..4edbecb --- /dev/null +++ b/Systems/CTree/Credential.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.CTree +{ + class Credential + { + } +} diff --git a/Systems/CTree/Database.cs b/Systems/CTree/Database.cs new file mode 100644 index 0000000..b30d12c --- /dev/null +++ b/Systems/CTree/Database.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.CTree +{ + class Database + { + } +} diff --git a/Systems/CTree/General.cs b/Systems/CTree/General.cs new file mode 100644 index 0000000..79c753e --- /dev/null +++ b/Systems/CTree/General.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.CTree +{ + class General + { + } +} diff --git a/Systems/CTree/Internal/Validation.cs b/Systems/CTree/Internal/Validation.cs new file mode 100644 index 0000000..20ec61c --- /dev/null +++ b/Systems/CTree/Internal/Validation.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.CTree.Internal +{ + class Validation + { + } +} diff --git a/Systems/MySql/Credential.cs b/Systems/MySql/Credential.cs new file mode 100644 index 0000000..3e297fe --- /dev/null +++ b/Systems/MySql/Credential.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.MySql +{ + class Credential + { + } +} diff --git a/Systems/MySql/Database.cs b/Systems/MySql/Database.cs new file mode 100644 index 0000000..e29caf3 --- /dev/null +++ b/Systems/MySql/Database.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.MySql +{ + class Database + { + } +} diff --git a/Systems/MySql/General.cs b/Systems/MySql/General.cs new file mode 100644 index 0000000..ffad795 --- /dev/null +++ b/Systems/MySql/General.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.MySql +{ + class General + { + } +} diff --git a/Systems/MySql/Internal/Validation.cs b/Systems/MySql/Internal/Validation.cs new file mode 100644 index 0000000..47cf502 --- /dev/null +++ b/Systems/MySql/Internal/Validation.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.MySql.Internal +{ + class Validation + { + } +} diff --git a/Systems/Postgres/Credential.cs b/Systems/Postgres/Credential.cs new file mode 100644 index 0000000..788cece --- /dev/null +++ b/Systems/Postgres/Credential.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Sdaleo.Systems.Postgres.Internal; + +namespace Sdaleo.Systems.Postgres +{ + /// + /// Handles SQL CE Credentials, to be + /// used by all our SQL CE Functions + /// + public class PgSqlCredential + { + + + } +} diff --git a/Systems/Postgres/Database.cs b/Systems/Postgres/Database.cs new file mode 100644 index 0000000..31d620f --- /dev/null +++ b/Systems/Postgres/Database.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.Postgres +{ + class Database + { + } +} diff --git a/Systems/Postgres/General.cs b/Systems/Postgres/General.cs new file mode 100644 index 0000000..0460858 --- /dev/null +++ b/Systems/Postgres/General.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.Postgres +{ + class General + { + } +} diff --git a/Systems/Postgres/Internal/Validation.cs b/Systems/Postgres/Internal/Validation.cs new file mode 100644 index 0000000..99731b3 --- /dev/null +++ b/Systems/Postgres/Internal/Validation.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.Postgres.Internal +{ + /// + /// Central Location for Postgres Input Validation + /// + internal class Validation + { + #region Private Character Validation Declaration + + private const string CharSet_AllowedCharsAlphaNum = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + private const string CharSet_AllowedCharsServerName = CharSet_AllowedCharsAlphaNum + ":\\ _!@#$%^&()-+{}[],.;`~"; + private const string CharSet_AllowedCharsInstanceName = CharSet_AllowedCharsAlphaNum + ":\\ _!@#$%^&()-+{}[],.;`~"; + private const string CharSet_AllowedCharsPassword = CharSet_AllowedCharsAlphaNum + "_!@#$%^&()-+{}[],.;`~"; + private const string CharSet_AllowedCharsTableName = CharSet_AllowedCharsAlphaNum + " -_"; + + /// + /// Generic Function to use with Allowed Character Sets above + /// + /// string to evaluate + /// Pass in one of the legal character consts declared above + /// true if valid, false otherwise + private static bool ContainsOnlyLegalChars(string TextToEvaluate, string TextToEvaluateWith) + { + foreach (char c in TextToEvaluate.ToCharArray()) + { + bool bFound = (TextToEvaluateWith.IndexOf(c) >= 0); + if (!bFound) + return false; + } + return true; + } + + #endregion + + #region Name Validators + + /// + /// Main Validation Function to validate Server Names + /// + /// Name of a Server + /// true if valid, false otherise + internal static bool IsValidServerName(string strServerName) + { + if (String.IsNullOrEmpty(strServerName)) + { + return false; + } + else if (strServerName.Length < 1 || strServerName.Length > 248) // limit server Name length + { + return false; + } + else if (!ContainsOnlyLegalChars(strServerName, CharSet_AllowedCharsServerName)) + { + return false; + } + else + { + return true; + } + } + + /// + /// Main Validation Function to validate Instance Names + /// + /// Name of an Instance + /// true if valid, false otherise + internal static bool IsValidInstanceName(string strInstanceName) + { + if (string.IsNullOrEmpty(strInstanceName)) + { + return false; + } + else if (strInstanceName.Length < 1 || strInstanceName.Length > 18) // limit Instance Name length + { + return false; + } + else if (!ContainsOnlyLegalChars(strInstanceName, CharSet_AllowedCharsInstanceName)) + { + return false; + } + else + { + return true; + } + } + + /// + /// Main Validation Function to validate Passwords + /// + /// Password + /// true if valid, false otherise + internal static bool IsValidPassword(string strPassword) + { + if (String.IsNullOrEmpty(strPassword)) + { + return false; + } + else if (strPassword.Length < 1 || strPassword.Length > 40) // limit Password Length + { + return false; + } + else if (!ContainsOnlyLegalChars(strPassword, CharSet_AllowedCharsPassword)) + { + return false; + } + else + { + return true; + } + } + + /// + /// Main Validation Function to validate TableName + /// + /// Name of Table + /// true if valid, false otherwise + internal static bool IsValidTableName(string strTableName) + { + if (string.IsNullOrEmpty(strTableName)) + { + return false; + } + else if (strTableName.Length < 1 || strTableName.Length > 52) // limit Table Name length + { + return false; + } + else if (!ContainsOnlyLegalChars(strTableName, CharSet_AllowedCharsTableName)) + { + return false; + } + else + { + return true; + } + } + + #endregion + + #region Combination Validators + + /// + /// Validates that the passedin string has both a valid server and a valid Instance + /// + /// a string to check for server and instance + /// true if valid, false otherwise + internal static bool IsValidServerNameAndInstanceName(string strServerNameNInstance) + { + if (!string.IsNullOrEmpty(strServerNameNInstance) && (strServerNameNInstance.IndexOf('\\') >= 0)) + { + + int nIndexLast = strServerNameNInstance.LastIndexOf('\\'); + string[] values = new String[] { strServerNameNInstance.Substring(0, nIndexLast), strServerNameNInstance.Substring(nIndexLast + 1) }; + if (values.Length == 2) + return IsValidServerName(values[0]) && IsValidInstanceName(values[1]); + } + return false; + } + + #endregion + } +} diff --git a/Systems/SQLCE/Credential.cs b/Systems/SQLCE/Credential.cs new file mode 100644 index 0000000..f09629a --- /dev/null +++ b/Systems/SQLCE/Credential.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.SQLCE +{ + /// + /// Handles SQL CE Credentials, to be + /// used by all our SQL CE Functions + /// + public class SQLCECredential : IComparable, ICloneable, IConnectDb + { + #region IConnectDb + + /// + /// Let Callers know this is a SQLCE Connection Object + /// + public DBSystem DBType { get { return DBSystem.SQL_CE; } } + + /// + /// Check to see if the Credential Object consists of valid input + /// + public bool IsValid + { + get + { + if (!ValidationConsts.IsValidFileNameNPath(DataSource)) + return false; + + if (!String.IsNullOrEmpty(_UDL.Password) && !ValidationConsts.Generic.IsValidPassword(_UDL.Password)) + return false; + + return true; + } + } + + /// + /// + /// + public string ConnectionString { get { return _UDL.ConnectionString; } } + + /// + /// SQL CE uses the File Name and Path as the Datasource + /// + public string DataSource { get { return _UDL.DataSource; } } + + /// + /// SQL CE doesn't use User + /// + public string User { get { return _UDL.Username; } } + + /// + /// SQL CE doesn't support DBMS like behaviors + /// + public bool SupportsDBMS { get { return false; } } + + /// + /// SQL CE doesn't support DBMS like behaviors + /// + public IamDBMS DBMS { get { return null; } } + + /// + /// SQL CE doesn't support Timeouts + /// + public bool SupportsTimeouts { get { return false; } } + + /// + /// SQL CE doesn't support Timeouts + /// + public IsupportTimeouts Timeouts { get { return null; } } + + #endregion + + private UDL _UDL = null; + + #region SQLCE Credential Constructors + + /// + /// Create a SQL CE Connection from an UDL Object + /// + /// + internal SQLCECredential(UDL udl) + { + if (udl != null) + _UDL = udl; + } + + /// + /// Create an Untrusted SQLCE Credential * No Encryption Used * + /// + public SQLCECredential(string FileNameNPath) + { + _UDL = new UDL(FileNameNPath, String.Empty); + } + + /// + /// Create a Trusted SQLCE Credential * Encryption Used * + /// + public SQLCECredential(string FileNameNPath, string strPassword) + { + _UDL = new UDL(FileNameNPath, strPassword); + } + + #endregion + + #region ICloneable Members + + public object Clone() + { + SQLCECredential credential = new SQLCECredential((UDL)this._UDL.Clone()); + return credential; + } + + #endregion + + #region IComparable Members + + public int CompareTo(object obj) + { + SQLCECredential otherCredential = obj as SQLCECredential; + if (otherCredential != null) + { + int nCompare = _UDL.CompareTo(otherCredential._UDL); + return nCompare; + } + else + { + throw new ArgumentException("Object is not a SQLCECredential"); + } + } + + #endregion + } +} diff --git a/Systems/SQLCE/Database.cs b/Systems/SQLCE/Database.cs new file mode 100644 index 0000000..feb4f41 --- /dev/null +++ b/Systems/SQLCE/Database.cs @@ -0,0 +1,247 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Data.SqlServerCe; + +namespace Sdaleo.Systems.SQLCE +{ + /// + /// Specific actions for SQL CE Databases + /// + public class SQLCEDatabase + { + #region Database Create / Exists + + /// + /// Checks to see if we can query the specified server for the Database (Existence check) + /// + /// SQL CE Credentials + /// Returns true if the Database Exists, false otherwise + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseExists(IConnectDb credential, out bool bExists) + { + bExists = false; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_CE); + if (dbError.ErrorOccured) + return dbError; + + // Check for File Existence + if (File.Exists(credential.DataSource)) + { + bExists = true; + return dbError; + } + else + return DBError.Create("Database File does not exist"); + } + + /// + /// Create a new Database with the specified Credentials + /// + /// SQL CE Credentials + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseCreate(IConnectDb credential) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_CE); + if (dbError.ErrorOccured) + return dbError; + + // First Create the Directory if it doesn't exists + string path = Path.GetDirectoryName(credential.DataSource); + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + + // Now try to create the database if it doesn't exists + bool bExists = false; + dbError = DatabaseExists(credential, out bExists); + if (!bExists) + { + try + { + using (SqlCeEngine engine = new SqlCeEngine(credential.ConnectionString)) + { + engine.CreateDatabase(); + } + } + catch (SqlCeException e) + { + dbError = DBMS.CreateErrorDBRetVal(DBSystem.SQL_CE, e); + } + } + return dbError; + } + + #endregion + + #region Database Copy / Delete + + /// + /// Copies a specified SQL CE Database to a new specified Database + /// + /// SQL CE Credentials of Source Database + /// SQLCE Credential of Destination Database To be copied To + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseCopy(IConnectDb SourceCredential, IConnectDb DestinationCredential) + { + DBError dbError = ValidationConsts.IsCredentialValid(SourceCredential, DBSystem.SQL_CE); + if (dbError.ErrorOccured) + return dbError; + + dbError = ValidationConsts.IsCredentialValid(DestinationCredential, DBSystem.SQL_CE); + if (dbError.ErrorOccured) + return dbError; + + // Make sure the Source Database exists + bool bExists = false; + dbError = DatabaseExists(SourceCredential, out bExists); + if (!bExists) + return dbError; + + // Make sure the Destination Database does NOT Exist + bExists = false; + dbError = DatabaseExists(DestinationCredential, out bExists); + if (bExists) + return DBError.Create("Destination Credential Database already exists"); + + try + { + File.Copy(SourceCredential.DataSource, DestinationCredential.DataSource); + } + catch (Exception ex) + { + dbError = DBError.Create(ex.Message); + } + return dbError; + } + + /// + /// Delete a specified SQLCE Database + /// + /// SQL CE Credentials + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseDelete(IConnectDb credential) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_CE); + if (dbError.ErrorOccured) + return dbError; + + // Make sure the Source Database exists + bool bExists = false; + dbError = DatabaseExists(credential, out bExists); + if (!bExists) + return dbError; + + try + { + File.Delete(credential.DataSource); + } + catch (Exception ex) + { + dbError = DBError.Create(ex.Message); + } + return dbError; + } + + #endregion + + #region Database Integrity + + /// + /// Shrinks the specified Database to reclaim wasted space + /// + /// SQL CE Credentials + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseShrink(IConnectDb credential) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_CE); + if (dbError.ErrorOccured) + return dbError; + + // Now try to shrink the database if it exists + bool bExists = false; + dbError = DatabaseExists(credential, out bExists); + if (bExists) + { + try + { + using (SqlCeEngine engine = new SqlCeEngine(credential.ConnectionString)) + { + engine.Shrink(); + } + } + catch (SqlCeException e) + { + dbError = DBMS.CreateErrorDBRetVal(DBSystem.SQL_CE, e); + } + } + return dbError; + } + + /// + /// Verifies the specified Database in case it is corrupted + /// + /// SQL CE Credentials + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseVerify(IConnectDb credential) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_CE); + if (dbError.ErrorOccured) + return dbError; + + // Now try to repair the database if it exists + bool bExists = false; + dbError = DatabaseExists(credential, out bExists); + if (bExists) + { + try + { + using (SqlCeEngine engine = new SqlCeEngine(credential.ConnectionString)) + { + engine.Verify(); + } + } + catch (SqlCeException e) + { + dbError = DBMS.CreateErrorDBRetVal(DBSystem.SQL_CE, e); + } + } + return dbError; + } + + /// + /// Repairs the specified Database in case it is corrupted + /// + /// SQL CE Credentials + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseRepair(IConnectDb credential) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_CE); + if (dbError.ErrorOccured) + return dbError; + + // Now try to repair the database if it exists + bool bExists = false; + dbError = DatabaseExists(credential, out bExists); + if (bExists) + { + try + { + using (SqlCeEngine engine = new SqlCeEngine(credential.ConnectionString)) + { + // Specify null destination connection string for in-place repair + engine.Repair(null, RepairOption.RecoverAllPossibleRows); + } + } + catch (SqlCeException e) + { + dbError = DBMS.CreateErrorDBRetVal(DBSystem.SQL_CE, e); + } + } + return dbError; + } + + #endregion + } +} diff --git a/Systems/SQLCE/General.cs b/Systems/SQLCE/General.cs new file mode 100644 index 0000000..c5f10b5 --- /dev/null +++ b/Systems/SQLCE/General.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.SQLCE +{ + /// + /// General SQL CE Functions + /// + public class SQLCEGeneral + { + /// + /// Quick Check function to see if the passed in credential allows us to connect to the database, + /// It also verifies that there are any Tables in the Database + /// + /// SQL CE Credentials + /// Returns true if successfull in connecting to the database + /// DBError Object with ErrorOccured, if error Occured + public static DBError SQLCECheckConnection(IConnectDb credential, out bool CanConnect) + { + CanConnect = false; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_CE); + if (dbError.ErrorOccured) + return dbError; + + // First Verify that the Database Exists + bool bExists = false; + dbError = SQLCEDatabase.DatabaseExists(credential, out bExists); + if (!bExists) + return dbError; + + //// + // TODO: Make sure that we can read any tables from the db + //// + + return null; + } + + } +} diff --git a/Systems/SQLCE/Internal/ErrorConst.cs b/Systems/SQLCE/Internal/ErrorConst.cs new file mode 100644 index 0000000..5c1d579 --- /dev/null +++ b/Systems/SQLCE/Internal/ErrorConst.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.SQLCE +{ + /// + /// SQL CE Database Error Constants to Use to handle specific Errors + /// + internal static class ErrorConst + { + + } +} diff --git a/Systems/SQLCE/Internal/Validation.cs b/Systems/SQLCE/Internal/Validation.cs new file mode 100644 index 0000000..3d0ddef --- /dev/null +++ b/Systems/SQLCE/Internal/Validation.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Sdaleo.Systems; + +namespace Sdaleo.Systems.SQLCE +{ + /// + /// SQL CE Custom Validation + /// + internal static class Validation + { + /// + /// validate SQL CE Table Names + /// + /// + /// + public static DBError IsValidTableName(string strTableName) + { + if (string.IsNullOrEmpty(strTableName)) + { + return DBError.Create("TableName is null"); + } + else if (strTableName.Length < 1 || strTableName.Length > 52) // limit Table Name length + { + return DBError.Create("TableName length is invalid"); + } + else if (!ValidationConsts.ContainsOnlyLegalChars(strTableName, ValidationConsts.CharSet_AllowedTableNames)) + { + return DBError.Create("TableName contains illegal characters"); + } + else + { + return new DBError(); + } + } + } +} diff --git a/Systems/SQLCE/Table.cs b/Systems/SQLCE/Table.cs new file mode 100644 index 0000000..49331c9 --- /dev/null +++ b/Systems/SQLCE/Table.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data; + +namespace Sdaleo.Systems.SQLCE +{ + /// + /// Specific actions for SQL CE Tables in a Database + /// + public class SQLCETable + { + /// + /// Returns all the Table Names for the specified SQL CE Credential + /// + /// SQL CE Credentials + /// array of table names, or null if error occured + /// DBError Object with ErrorOccured, if error Occured + public static DBError Tables(IConnectDb credential, out string[] Tables) + { + Tables = null; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_CE); + if (dbError.ErrorOccured) + return dbError; + + // Execute the Query + string sql = "Select [TABLE_NAME] From INFORMATION_SCHEMA.TABLES Order By [TABLE_NAME]"; + DB db = DB.Create(credential); + DBRetVal retVal = db.FillDataTable(sql); + if (retVal.IsValid) + { + List retList = new List(); + foreach (DataRow row in retVal.GetDataTableRetVal().Rows) + retList.Add(row["TABLE_NAME"].ToString()); + Tables = retList.ToArray(); + } + return retVal; + } + + /// + /// Check to see if the Table Exists on the specified SQL CE Credentials + /// + /// SQL CE Credentials + /// Specify the TableName to check for (required) + /// true if exists, false otherwise + /// DBError Object with ErrorOccured, if error Occured + public static DBError TableExists(IConnectDb credential, string TableName, out bool bExists) + { + bExists = false; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_CE); + if (dbError.ErrorOccured) + return dbError; + + dbError = Validation.IsValidTableName(TableName); + if (dbError.ErrorOccured) + return dbError; + + // Execute the Query + string sql = String.Format("Select [TABLE_NAME] From INFORMATION_SCHEMA.TABLES Where [TABLE_NAME] = '{0}' Order By [TABLE_NAME]", TableName); + DB db = DB.Create(credential); + DBRetVal retVal = db.ExecuteScalar(sql); + bExists = !retVal.IsValid; + return retVal; + } + + /// + /// Changes the Table Name for the specified Table + /// + /// SSQL CE Credentials + /// Name of Table (required) + /// Name of Table New (required) + /// DBError Object with ErrorOccured, if error Occured + public static DBError TableRename(IConnectDb credential, string TableName, string TableNameNew) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_CE); + if (dbError.ErrorOccured) + return dbError; + + dbError = Validation.IsValidTableName(TableName); + if (dbError.ErrorOccured) + return dbError; + + dbError = Validation.IsValidTableName(TableNameNew); + if (dbError.ErrorOccured) + return dbError; + + // Execute the Query + string sql = String.Format("sp_rename @objname = '{0}', @newname = '{1}', @objtype = 'OBJECT'", TableName, TableNameNew); + DB db = DB.Create(credential); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + } +} diff --git a/Systems/SQLServer/Credential.cs b/Systems/SQLServer/Credential.cs new file mode 100644 index 0000000..862bbdf --- /dev/null +++ b/Systems/SQLServer/Credential.cs @@ -0,0 +1,279 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.SQLServer +{ + /// + /// Handles SQL Server Credentials, to be + /// used by all our SQL Server Functions + /// + public class SQLServerCredential : IComparable, ICloneable, IConnectDb, IamDBMS, IsupportTimeouts + { + #region IConnectDb + + /// + /// Let Callers know this is a SQL Server Connection Object + /// + public DBSystem DBType { get { return DBSystem.SQL_SERVER; } } + + /// + /// Check to see if the Credential Object consists of valid input + /// + public bool IsValid + { + get + { + if (!Validation.IsValidDataSource(_UDL.DataSource)) + return false; + + if (!_UDL.TrustedConnection && !ValidationConsts.Generic.IsValidUserCredential(_UDL.Username, _UDL.Password)) + return false; + + if (!String.IsNullOrEmpty(_UDL.DataBase) && IsDatabaseSet) + return false; + + return true; + } + } + + /// + /// + /// + public string ConnectionString { get { return _UDL.ConnectionString; } } + + /// + /// SQL Server uses Server N' Instance + /// + public string DataSource { get { return _UDL.DataSource; } } + + /// + /// SQL Server requires a user + /// + public string User { get { return _UDL.Username; } } + + /// + /// SQL Server supports is a DBMS + /// + public bool SupportsDBMS { get { return true; } } + + /// + /// SQL Server is a DBMS + /// + public IamDBMS DBMS { get { return this; } } + + /// + /// SQL Server supports Timeouts + /// + public bool SupportsTimeouts { get { return true; } } + + /// + /// SQL Server supports Timeouts + /// + public IsupportTimeouts Timeouts { get { return this; } } + + #endregion + + private UDL _UDL = null; + + #region SQL Server Credential Constructors + + /// + /// Create a SQL Server Connection from an UDL Object + /// + /// + internal SQLServerCredential(UDL udl) + { + if (udl != null) + _UDL = udl; + } + + /// + /// Create an Untrusted SQLServer Credential with an Initial DB Specified + /// + public SQLServerCredential(string strServer, string strInstance, string strDatabase, string strUser, string strPassword) + { + _UDL = new UDL(strDatabase, strUser, strPassword, strServer, strInstance); + } + + /// + /// Create an Untrusted SQLServer Credential with no Initial DB Specified + /// + public SQLServerCredential(string strServer, string strInstance, string strUser, string strPassword) + { + _UDL = new UDL(String.Empty, strUser, strPassword, strServer, strInstance); + } + + /// + /// Create a Trusted SQLServer Credential with an Initial DB Specified + /// + public SQLServerCredential(string strServer, string strInstance, string strDatabase) + { + _UDL = new UDL(strDatabase, String.Empty, String.Empty, strServer, strInstance, true); + } + + /// + /// Create a Trusted SQLServer Credential with no Initial DB Specified + /// + public SQLServerCredential(string strServer, string strInstance) + { + _UDL = new UDL(String.Empty, String.Empty, String.Empty, strServer, strInstance, true); + } + + /// + /// Create a Trusted SQLServer Credential with SQLExpress on the Local Machine to Attach a DB File (Creates a User Instance) + /// + /// + public SQLServerCredential(string strAttachSQLDBFile) + { + _UDL = new UDL(String.Empty, String.Empty, String.Empty, String.Empty, "SQLEXPRESS", strAttachSQLDBFile, true, false); + } + + #endregion + + #region IamDBMS + + public string Server { get { return _UDL.ServerAddress; } } + public string Instance { get { return _UDL.InstanceName; } } + public string Database { get { return _UDL.DataBase; } } + + public bool IsDatabaseSet + { + get + { + DBError dbError = Validation.IsValidDatabaseName(Database); + return !dbError.ErrorOccured; + } + } + + public bool IsDatabaseSetAndNonSystem + { + get + { + if (IsDatabaseSet && !SQLServerUtilities.IsSystemDatabaseName(Database)) + return true; + return false; + } + } + + public bool IsDatabaseSetAndNonDefault + { + get + { + if (IsDatabaseSet && !SQLServerUtilities.IsDefaultDatabaseName(Database)) + return true; + return false; + } + } + + /// + /// Use this to quickly create a new SQLServerCredential with a different DatabaseName + /// + /// Name of Database To Set + /// a new SQLServerCredential Object + public IConnectDb WithDatabase(string strDatabaseName) + { + // Create a new Credential Object and change the DatabaseName + SQLServerCredential credential = (SQLServerCredential)Clone(); + credential._UDL.DataBase = strDatabaseName; + return credential; + } + + /// + /// Use this to quickly create a new SQLServerCredential with no DatabaseName defined + /// + /// a new SQLServerCredential Object + public IConnectDb WithoutDatabase() + { + return WithDatabase(String.Empty); + } + + #endregion + + #region IsupportTimeouts + + public const int DEFAULT_COMMAND_TIMEOUT = 45; + private uint _CommandTimeout = DEFAULT_COMMAND_TIMEOUT; + public uint CommandTimeout + { + get { return _CommandTimeout; } + set { _CommandTimeout = value; } + } + + public uint ConnectionTimeout { get { return _UDL.ConnectionTimeout; } set { _UDL.ConnectionTimeout = value; } } + + /// + /// Use this to quickly create a new SQLServerCredential with a different connection timeout + /// + /// Specify the Connection Timeout + /// a new SQLServerCredential Object + public IConnectDb WithConnectionTimeout(uint nConnectionTimeout) + { + // Create a new Credential Object and change the Timeouts + SQLServerCredential credential = (SQLServerCredential)Clone(); + credential.ConnectionTimeout = nConnectionTimeout; + return credential; + } + + /// + /// Use this to quickly create a new SQLServerCredential with a different command timeout + /// + /// Specify the Command Timeout + /// a new SQLServerCredential Object + public IConnectDb WithCommandTimeout(uint nCommandTimeout) + { + // Create a new Credential Object and change the Timeouts + SQLServerCredential credential = (SQLServerCredential)Clone(); + credential.CommandTimeout = nCommandTimeout; + return credential; + } + + /// + /// Use this to quickly create a new SQLServerCredential with different Timeouts + /// + /// Specify the Connection Timeout + /// Specify the Command Timeout + /// a new SQLServerCredential Object + public IConnectDb WithTimeouts(uint nConnectionTimeout, uint nCommandTimeout) + { + // Create a new Credential Object and change the Timeouts + SQLServerCredential credential = (SQLServerCredential)Clone(); + credential.ConnectionTimeout = nConnectionTimeout; + credential.CommandTimeout = nCommandTimeout; + return credential; + } + + #endregion + + #region ICloneable Members + + public object Clone() + { + SQLServerCredential credential = new SQLServerCredential((UDL)this._UDL.Clone()); + credential.CommandTimeout = this.CommandTimeout; + return credential; + } + + #endregion + + #region IComparable Members + + public int CompareTo(object obj) + { + SQLServerCredential otherCredential = obj as SQLServerCredential; + if (otherCredential != null) + { + int nCompare = _UDL.CompareTo(otherCredential._UDL); + return nCompare; + } + else + { + throw new ArgumentException("Object is not a SQLServerCredential"); + } + } + + #endregion + } + +} diff --git a/Systems/SQLServer/Database.cs b/Systems/SQLServer/Database.cs new file mode 100644 index 0000000..7ff703b --- /dev/null +++ b/Systems/SQLServer/Database.cs @@ -0,0 +1,572 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data; + +namespace Sdaleo.Systems.SQLServer +{ + + /// + /// Specific actions for SQL Server Databases + /// + public class SQLServerDatabase + { + #region Database List + + /// + /// Returns a array of any found Databases on the specified SQL Server intance + /// + /// SQL Server Credentials + /// list of Databases if any found, or null if not + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabasesListAll(IConnectDb credential, out string[] DatabaseList) + { + DatabaseList = null; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + // Execute the Query + string sql = "SELECT [name] FROM sys.databases"; + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.FillDataTable(sql); + if (retVal.IsValid) + { + List DataBaseNames = new List(); + foreach (DataRow row in retVal.GetDataTableRetVal().Rows) + DataBaseNames.Add(row["name"].ToString()); + DatabaseList = DataBaseNames.ToArray(); + } + return retVal; + } + + /// + /// Returns a array of any found Databases that are NOT SQL Default Databases (like master, model, etc); + /// + /// SQL Server Credentials + /// list of Databases if any found, or null if not + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabasesListNonDefault(IConnectDb credential, out string[] DatabaseList) + { + DatabaseList = null; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + // Look for all Databases that are Non-Default + string[] DatabaseListAll = null; + DBError retVal = DatabasesListAll(credential, out DatabaseListAll); + if(!retVal.ErrorOccured && DatabaseListAll != null) + { + List DatabaseListNonDefault = new List(); + foreach (string DatabaseName in DatabaseListAll) + { + if(!SQLServerUtilities.IsDefaultDatabaseName(DatabaseName)) + DatabaseListNonDefault.Add(DatabaseName); + } + DatabaseList = DatabaseListNonDefault.ToArray(); + } + return retVal; + } + + #endregion + + #region Alter Database + + /// + /// Use this to Raise the specified Database to it's highest Compatibility Level as allowed + /// on the specified SQLServer (2005/2008/etc.) + /// + /// SQL Server Credentials with Database Info + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseRaiseCompatibility(IConnectDb credential) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + // How to change compatibility level has changed in sql server 2008 (so we'll try to + // use the newer way of doing it if we can. + string sql = string.Empty; + SQLServerVersion ServerVersion; + DBError dberror = SQLServerGeneral.GetSQLServerVersion(credential, out ServerVersion); + if (dberror.ErrorOccured) + return dberror; + + switch (ServerVersion) + { + case SQLServerVersion.SQL_SERVER_2008: + sql = String.Format("ALTER DATABASE [{0}] SET COMPATIBILITY_LEVEL = {1}", credential.DBMS.Database, (int)ServerVersion); + break; + + default: + sql = String.Format("EXEC sp_dbcmptlevel [{0}], {1}", credential.DBMS.Database, (int)ServerVersion); + break; + } + + // Execute the Query and return result + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + + /// + /// Allows the caller to set the Database into Single User Mode. This is * microsoft recommended * + /// for certain type of operations on the Database to make sure nobody else can use the DB. + /// Note: If Database is in Use * This will timeout + /// + /// SQL Server Credentials with Database Info + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseSetToSingleUserMode(IConnectDb credential) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + // Execute the Query and return result + string sql = String.Format("ALTER DATABASE [{0}] SET SINGLE_USER", credential.DBMS.Database); + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + + /// + /// Allows the caller to set the Database into Multi User Mode. This should be called + /// if the caller called DatabaseSetToSingleUserMode() previously + /// + /// SQL Server Credentials with Database Info + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseSetToMultiUserMode(IConnectDb credential) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + // Execute the Query and return result + string sql = String.Format("ALTER DATABASE [{0}] SET MULTI_USER", credential.DBMS.Database); + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + + /// + /// Calls DBCC SHRINKDATABASE and DBCC UPDATEUSAGE on the passed in Database + /// + /// SQL Server Credentials with Database Info + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseShrink(IConnectDb credential) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + // Execute the Query and return result + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + string sql = String.Format("DBCC SHRINKDATABASE ([{0}])", credential.DBMS.Database); + DBRetVal retVal = db.ExecuteNonQuery(sql); + if (!retVal.ErrorOccured) + { + sql = String.Format("DBCC UPDATEUSAGE ([{0}])", credential.DBMS.Database); + retVal = db.ExecuteNonQuery(sql); + } + return retVal; + } + + /// + /// Iterates all tables on the database and enables/disables all trigers for each table + /// + /// SQL Server Credentials with Database Info + /// true to enable, false to disable + /// DBError Object with ErrorOccured, if error Occured + public static DBError EnableDisableAllTriggers(IConnectDb credential, bool bEnable) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + // Get All Table Names from the Database + string[] TableNames = null; + DBError dberror = SQLServerTable.Tables(credential, out TableNames); + if (dberror.ErrorOccured) + return dberror; + + // Execute the Query and return result + DB db = DB.Create(credential); + DBRetVal retVal = new DBRetVal(); + foreach (string TableName in TableNames) + { + // Execute the Query for each Table + string sql = String.Format("ALTER TABLE [{0}] {1} TRIGGER ALL", TableName, (bEnable ? "ENABLE" : "DISABLE")); + retVal = db.ExecuteNonQuery(sql); + if (retVal.ErrorOccured) + break; + } + return retVal; + } + + #endregion + + #region Databae Create / Exists + + /// + /// Checks to see if we can query the specified server for the Database (Existence check) + /// + /// SQL Server Credentials with Database Info + /// Returns true if the Database Exists, false otherwise + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseExists(IConnectDb credential, out bool bExists) + { + bExists = false; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + // Execute the Query and return result + string sql = String.Format("EXEC sp_helpdb @dbname = [{0}]", credential.DBMS.Database); + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.ExecuteNonQuery(sql); + bExists = !retVal.ErrorOccured; + return retVal; + } + + /// + /// Create a new Database with the specified DatabaseName in the specified DataPath, if specified, or DefaultPath otherwise + /// + /// SQL Server Credentials with Database Info + /// Data Path to Create Database in (not required) + /// true to allow Attach Database when error occurs, false otherwise + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseCreate(IConnectDb credential, string DataPath, bool TryAttachDBOnError) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + // if DataPath is empty, get default datapath for SQL ServerInstance + if (String.IsNullOrEmpty(DataPath)) + SQLServerGeneral.SQLServerDefaultPath(credential.DBMS.WithoutDatabase(), out DataPath); + + // Fill in Database FileName and Path Details + string sql = String.Format("CREATE DATABASE [{0}] ", credential.DBMS.Database); + if (!String.IsNullOrEmpty(DataPath)) + sql += String.Format(@"ON (NAME = [{0}_dat], FILENAME = '{1}\{0}.dat') LOG ON (NAME = [{0}_log], FILENAME = '{1}\{0}_log.ldf')", credential.DBMS.Database, DataPath); + + // Execute the Command + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.ExecuteNonQuery(sql); + + // Upon DB Creation error, see if we could possibly attach the DB + bool bErrorOccuredThatCouldMaybeBeResolvedByAttaching = false; + if (retVal.ErrorOccured && !retVal.GetAllErrorNumbers.Contains(ErrorConst.ERROR_DB_ALREADY_EXISTS) && ( + retVal.GetAllErrorNumbers.Contains(ErrorConst.ERROR_DB_SOME_FILE_NAMES_COULD_NOT_BE_CREATED) || + retVal.GetAllErrorNumbers.Contains(ErrorConst.ERROR_DB_CAN_NOT_CREATE_FILE_BECAUSE_IT_ALREADY_EXISTS) || + retVal.GetAllErrorNumbers.Contains(ErrorConst.ERROR_DB_THERE_ALREADY_IS_AN_OBJECT_IN_THE_DB_WITH_THIS_NAME))) + { + bErrorOccuredThatCouldMaybeBeResolvedByAttaching = true; + } + + // Upon Error, and if we are allowed to attach && datapath is valid, try to attach + if (retVal.ErrorOccured && TryAttachDBOnError && bErrorOccuredThatCouldMaybeBeResolvedByAttaching && !String.IsNullOrEmpty(DataPath)) + { + String[] strFileNames = new String[] + { + string.Format(@"{1}\{0}.dat", credential.DBMS.Database, DataPath), + string.Format(@"{1}\{0}_log.ldf", credential.DBMS.Database, DataPath) + }; + DBError retValError = DatabaseAttach(credential, strFileNames); + return retValError; + } + + return retVal; + } + + #endregion + + #region Database Attach / Dettach + + /// + /// Attaches a Database to an SQL Server Instance + /// + /// SQL Server Credentials with Database Info + /// Pass in the filenames when attaching Database (required) + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseAttach(IConnectDb credential, string[] strFileNames) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if ((strFileNames == null || strFileNames.Length == 0)) + return DBError.Create("Invalid FileNames Passed In"); + + // Generate the SQL Query + string sql = String.Format("EXEC sp_attach_db @dbname = [{0}]", credential.DBMS.Database); + for (int i = 0; i < strFileNames.Length; ++i) + sql = sql + String.Format(", @filename{0:d1} = '{1}'", (i + 1), strFileNames[i]); + + // Execute the Query + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.ExecuteNonQuery(sql); + + // If Error Occured try renaming dat files to mdf * legacy code * + bool bRetryAttachingErrorOccured = false; + if (retVal.ErrorOccured && + (retVal.GetAllErrorNumbers.Contains(ErrorConst.ERROR_DB_THERE_ALREADY_IS_AN_OBJECT_IN_THE_DB_WITH_THIS_NAME) || + retVal.GetAllErrorNumbers.Contains(ErrorConst.ERROR_DB_DEVICE_ACTIVATION_FAILED))) + { + bRetryAttachingErrorOccured = true; + } + + // Retry on Attach if failure occured & + // filenames contain .dat files & we have an attach specific error * LEGACY CODE Usuage * + if (retVal.ErrorOccured && bRetryAttachingErrorOccured) + { + bool bRetry = false; + List retryArr = new List(); + foreach (string strFileName in strFileNames) + { + if (strFileName.Contains(".dat")) + { + strFileName.Replace(".dat", ".mdf"); + bRetry = true; + } + retryArr.Add(strFileName); + } + + // Only do an actually retry if .dat files were replaced + if (bRetry) + return DatabaseAttach(credential, retryArr.ToArray()); + } + return retVal; + } + + /// + /// Dettaches a Database from an SQL Server Instance + /// + /// SQL Server Credentials with Database Info + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseDettach(IConnectDb credential) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + // Execute the Query and return result + string sql = String.Format("sp_detach_db @dbname = [{0}]", credential.DBMS.Database); + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + + #endregion + + #region Database Copy + + /// + /// Copies a specified Database on the specified SQLServer into a new specified Database + /// + /// SQL Server Credentials with Database Info + /// Name of Database To be copied To (required) + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseCopy(IConnectDb credential, string DatabaseNameDest) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + dbError = Validation.IsValidDatabaseName(DatabaseNameDest); + if (dbError.ErrorOccured) + return dbError; + + + string strDefaultPath; + DBError dberror = SQLServerGeneral.SQLServerDefaultPath(credential, out strDefaultPath); + if (dberror.ErrorOccured) + return dberror; + + // First Step - Backup the source database to a custom Backup file + string sql = String.Format(@"BACKUP DATABASE [{0}] TO DISK = '{1}\{0}.DB Backup' WITH INIT, NAME = '{0} Backup', PASSWORD = 'dbCopy Backup', MEDIAPASSWORD = 'XaseY 1-33', INIT , FORMAT", credential.DBMS.Database, strDefaultPath); + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.ExecuteNonQuery(sql); + if (retVal.ErrorOccured) + return retVal; + + // Second Step - Retrieve the dat & log Logical Names for the newly backed-up Database + string strDataLogical = string.Empty; + string strLogLogical = string.Empty; + sql = String.Format(@"RESTORE FILELISTONLY FROM DISK = '{0}\{1}.DB Backup' WITH FILE = 1, PASSWORD = 'dbCopy Backup', MEDIAPASSWORD = 'XaseY 1-33'", strDefaultPath, credential.DBMS.Database); + retVal = db.FillDataTable(sql); + if (!retVal.IsValid) + return retVal; + foreach (DataRow row in retVal.GetDataTableRetVal().Rows) + { + switch (row["Type"].ToString()) + { + case "D": + strDataLogical = row["LogicalName"].ToString(); + break; + + case "L": + strLogLogical = row["LogicalName"].ToString(); + break; + } + } + if (String.IsNullOrEmpty(strDataLogical) || String.IsNullOrEmpty(strLogLogical)) + return DBError.Create("DataLogical or LogLogical could not be found"); + + // Third Step - Restore Backup file to the new Database name + sql = String.Format(@"RESTORE DATABASE [{0}] FROM DISK = '{1}\{2}.DB Backup' WITH FILE = 1, PASSWORD = 'dbCopy Backup', MEDIAPASSWORD = 'XaseY 1-33', MOVE '{3}' TO '{1}\{0}.dat', MOVE '{4}' TO '{1}\{0}_log.ldf', RECOVERY, REPLACE", DatabaseNameDest, strDefaultPath, credential.DBMS.Database, strDataLogical, strLogLogical); + retVal = db.ExecuteNonQuery(sql); + if (retVal.ErrorOccured) + { + // try again + retVal = db.ExecuteNonQuery(sql); + if (!retVal.IsValid) + return retVal; + } + + // Fourth Step - Try to Delete the Backup file (No Need to have a potentially massive data file just sitting there + // ~SQL Server blocked access to procedure 'sys.xp_cmdshell' of component 'xp_cmdshell' because this component is turned off as part of the + // security configuration for this server. A system administrator can enable the use of 'xp_cmdshell' by using sp_configure. + // For more information about enabling 'xp_cmdshell', see "Surface Area Configuration" in SQL Server Books Online + // sql = String.Format("exec master.dbo.xp_cmdshell 'del /Q /F \"{0}\\{1}.DB Backup\"'", strDefaultPath, DatabaseNameSrc); + // db.ExecuteNonQuery(sql); + + // Legacy Usuage, we are leaving the Backup File behind (*leaking the file* so to speak) + return retVal; + } + + /// + /// Copies a specified Database on the specified SQLServer into a new specified Database onto a different specified Instance * Must be on Same Server * + /// + /// SQL Server Credentials with Database Info to be copied from (required) + /// SQL Server Credentials with Database Info to be copied to (required) + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseCopySepInst(IConnectDb credentialSrc, IConnectDb credentialDst) + { + DBError dbError = ValidationConsts.IsCredentialValid(credentialSrc, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credentialSrc.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + dbError = ValidationConsts.IsCredentialValid(credentialDst, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credentialDst.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (String.Compare(credentialSrc.DBMS.Server, credentialDst.DBMS.Server, true) != 0) + return DBError.Create("Must be on the Same Server"); + + if (String.Compare(credentialSrc.DBMS.Instance, credentialDst.DBMS.Instance, true) == 0) + return DBError.Create("Can not be the same Instance"); + + // Get Src Default Path *of the DB* + string strDefaultPathSrc; + DBError dberror = SQLServerGeneral.SQLServerDefaultPath(credentialSrc, out strDefaultPathSrc); + if (dberror.ErrorOccured) + return dberror; + + // Get Dest Default Path *of the Server* + string strDefaultPathDest; + dberror = SQLServerGeneral.SQLServerDefaultPath(credentialDst, out strDefaultPathDest); + if (dberror.ErrorOccured) + return dberror; + + // Make sure that both Paths aren't the same *Two instances should never have the same path!* + if (strDefaultPathSrc.ToUpper() == strDefaultPathDest.ToUpper()) + return DBError.Create(String.Format("The File Path of the Source Database {0} and the Destination Database {1} on Server {1} are identical.", credentialSrc.DBMS.Database, credentialDst.DBMS.Database, credentialDst.DBMS.Server)); + + // Create Src N' Dest Connections * No Limit on the Command timeout * + // Could be very large database that we are trying to copy + DB dbSrc = DB.Create(credentialSrc.DBMS.WithoutDatabase().Timeouts.WithCommandTimeout(0)); + DB dbDst = DB.Create(credentialDst.DBMS.WithoutDatabase().Timeouts.WithCommandTimeout(0)); + + // First Step - Backup the source database to a custom DB Backup file to the DESTINATION path + string sql = String.Format(@"BACKUP DATABASE [{0}] TO DISK = '{1}\{0}.DB Backup' WITH INIT, NAME = '{0} Backup', PASSWORD = 'dbCopy Backup', MEDIAPASSWORD = 'XaseY 1-33', INIT , FORMAT", credentialSrc.DBMS.Database, strDefaultPathSrc); + DBRetVal retVal = dbSrc.ExecuteNonQuery(sql); + if (retVal.ErrorOccured) + return retVal; + + // Second Step - Retrieve the dat & log Logical Names for the newly backed-up Database File + string strDataLogical = string.Empty; + string strLogLogical = string.Empty; + sql = String.Format(@"RESTORE FILELISTONLY FROM DISK = '{0}\{1}.DB Backup' WITH FILE = 1, PASSWORD = 'dbCopy Backup', MEDIAPASSWORD = 'XaseY 1-33'", strDefaultPathSrc, credentialSrc.DBMS.Database); + retVal = dbSrc.FillDataTable(sql); + if (!retVal.IsValid) + return retVal; + foreach (DataRow row in retVal.GetDataTableRetVal().Rows) + { + switch (row["Type"].ToString()) + { + case "D": + strDataLogical = row["LogicalName"].ToString(); + break; + + case "L": + strLogLogical = row["LogicalName"].ToString(); + break; + } + } + if (String.IsNullOrEmpty(strDataLogical) || String.IsNullOrEmpty(strLogLogical)) + return DBError.Create(String.Format("The retrieval of Logical Names for Database '{0}' failed for Server Instance '{1}' in Path '{2}'.", credentialSrc.DBMS.Database, credentialSrc.DataSource, strDefaultPathDest)); + + // Third Step - Restore Backup file to the new Database name onto the new (Dest) instance + sql = String.Format(@"RESTORE DATABASE [{0}] FROM DISK = '{1}\{2}.DB Backup' WITH FILE = 1, PASSWORD = 'dbCopy Backup', MEDIAPASSWORD = 'XaseY 1-33', MOVE '{3}' TO '{5}\{0}.dat', MOVE '{4}' TO '{5}\{0}_log.ldf', RECOVERY, REPLACE", credentialDst.DBMS.Database, strDefaultPathSrc, credentialSrc.DBMS.Database, strDataLogical, strLogLogical, strDefaultPathDest); + retVal = dbDst.ExecuteNonQuery(sql); + if (!retVal.ErrorOccured) + { + // try again + retVal = dbDst.ExecuteNonQuery(sql); + if (!retVal.IsValid) + return retVal; + } + + // Fourth Step - Try to Delete the Backup file (No Need to have a potentially massive data file just sitting there + // ~SQL Server blocked access to procedure 'sys.xp_cmdshell' of component 'xp_cmdshell' because this component is turned off as part of the + // security configuration for this server. A system administrator can enable the use of 'xp_cmdshell' by using sp_configure. + // For more information about enabling 'xp_cmdshell', see "Surface Area Configuration" in SQL Server Books Online + // sql = String.Format("exec master.dbo.xp_cmdshell 'del /Q /F \"{0}\\{1}.DB Backup\"'", strDefaultPath, DatabaseNameSrc); + // db.RunSQLCommandTextExecuteNonQuery(sql); + + // Legacy Usuage, we are leaving the Backup File behind (*leaking the file* so to speak) + return retVal; + } + + #endregion + } +} diff --git a/Systems/SQLServer/General.cs b/Systems/SQLServer/General.cs new file mode 100644 index 0000000..d3274aa --- /dev/null +++ b/Systems/SQLServer/General.cs @@ -0,0 +1,482 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data; +using System.Net; +using System.ServiceProcess; + +namespace Sdaleo.Systems.SQLServer +{ + #region SQLServer General Enums + + /// + /// SQL Server Versions as specified by SQL Server + /// + public enum SQLServerVersion + { + SQL_SERVER_2000 = 80, + SQL_SERVER_2005 = 90, + SQL_SERVER_2008 = 100, + } + + #endregion + + /// + /// General SQL Server Functions + /// + public class SQLServerGeneral + { + #region SQL Version Functions + + /// + /// Retrieves the SQL Server Version Information from the specified SQL Server Instance + /// (* Prefered Function to use *) + /// + /// SQL Server Credentials + /// we pass out the SQL Server Specific Version + /// DBError Object with ErrorOccured, if error Occured + public static DBError GetSQLServerVersion(IConnectDb credential, out SQLServerVersion version) + { + version = SQLServerVersion.SQL_SERVER_2000; // Default behavior + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + int nVersion = (int)SQLServerVersion.SQL_SERVER_2000; + DBError dberror = GetSQLServerVersion(credential, out nVersion); + if (dberror.ErrorOccured) + return dberror; + + // SQLServerVersion numbers are multiple of 10's + nVersion = nVersion * 10; + try + { + version = (SQLServerVersion)Enum.Parse(typeof(SQLServerVersion), nVersion.ToString()); + } + catch (Exception e) + { + dberror = DBError.Create(e.Message); + } + return dberror; + } + + /// + /// Retrieves the SQL Server Version String Information from the specified SQL Server Instance + /// + /// SQL Server Credentials + /// we pass out the SQL Server Specific Version String + /// DBError Object with ErrorOccured, if error Occured + public static DBError GetSQLServerVersion(IConnectDb credential, out string strVersion) + { + strVersion = string.Empty; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + // Execute the Query + string sql = "EXEC sp_server_info @attribute_id = 2"; + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.FillDataTable(sql); + if (retVal.IsValid) + { + strVersion = retVal.GetDataTableRetVal().Rows[0]["attribute_value"].ToString(); + strVersion.Replace("\t", ""); // remove tabs + } + return retVal; + } + + /// + /// Retrieves the SQL Server Version Integer Information from the specified SQL Server Instance + /// + /// SQL Server Credentials + /// we pass out the SQL Server Specific Version Int + /// DBError Object with ErrorOccured, if error Occured + public static DBError GetSQLServerVersion(IConnectDb credential, out int nVersion) + { + nVersion = 0; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + // Execute the Query + string sql = "SELECT CONVERT(char(20), SERVERPROPERTY('ProductVersion'))"; + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.ExecuteScalar(sql); + if(retVal.IsValid) + { + string strVersion = retVal.GetScalarRetVal(); + String[] strVersionSplit = strVersion.Split('.'); + int.TryParse(strVersionSplit[0], out nVersion); + } + return retVal; + } + + #endregion + + #region SQL File N' Disk functions + + /// + /// Retrieves the default path for the SQL Server Instance or for the Database on the SQL Server. + /// Leave Database blank in the credential to find the default path for the Server. + /// + /// SQL Server Credentials + /// default path found or "" if not + /// DBError Object with ErrorOccured, if error Occured + public static DBError SQLServerDefaultPath(IConnectDb credential, out string DefaultPath) + { + DefaultPath = string.Empty; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + // Get the Path for the default Path for the Database if Specified + string sql = String.Empty; + if (credential.DBMS.IsDatabaseSetAndNonSystem) + sql = String.Format("SELECT filename FROM [{0}]..sysfiles", credential.DBMS.Database); + else + sql = "SELECT filename FROM master..sysfiles where [name]='master'"; + + // Execute the Query + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.ExecuteScalar(sql); + if ((retVal.IsValid) && !String.IsNullOrEmpty(retVal.GetScalarRetVal())) + { + string strResult = retVal.GetScalarRetVal(); + int indx = strResult.LastIndexOf('\\'); + if (indx >= 0) + strResult = strResult.Remove(indx); + DefaultPath = strResult; + } + return retVal; + } + + /// + /// Function retries an array of the Fixed HardDrives/Disks that are available on the Server + /// + /// SQL Server Credentials + /// an array of all the fixed disk's drive letters (i.e. C), empty list, if error occured + /// DBError Object with ErrorOccured, if error Occured + public static DBError SQLServerFixedDisks(IConnectDb credential, out string[] fixedDisks) + { + fixedDisks = null; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + // Execute the Query + string sql = "EXEC master..xp_fixeddrives"; + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.FillDataTable(sql); + List retList = new List(); + if (retVal.IsValid) + { + foreach (DataRow row in retVal.GetDataTableRetVal().Rows) + retList.Add(row["drive"].ToString()); + } + fixedDisks = retList.ToArray(); + return retVal; + } + + /// + /// Function retries an array of directories for the specified Path on the specified SQL Server + /// + /// SQL Server Credentials + /// a valid path that exists on the server, i.e. C:\Program Files + /// an array of all directories found in the specified path, empty list if no directories found or if error occured + /// DBError Object with ErrorOccured, if error Occured + public static DBError SQLServerGetDirectoriesInPath(IConnectDb credential, string Path, out string[] Directories) + { + Directories = null; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + // Execute the Query + string sql = String.Format("EXEC master..xp_dirtree '{0}', 1, 1", Path); + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.FillDataTable(sql); + List retList = new List(); + if (retVal.IsValid) + { + foreach (DataRow row in retVal.GetDataTableRetVal().Rows) + { + bool bIsDirectory = (row["file"].ToString() == "0"); + if (bIsDirectory) + retList.Add(row["subdirectory"].ToString()); + } + } + Directories = retList.ToArray(); + return retVal; + } + + /// + /// Function retries an array of files for the specified Path on the specified SQL Server + /// + /// SQL Server Credentials + /// a valid path that exists on the server, i.e. C:\Program Files + /// an array of all files found in the specified path, empty list if no files found or if error occured + /// DBError Object with ErrorOccured, if error Occured + public static DBError SQLServerGetFilesInPath(IConnectDb credential, string Path, out string[] Files) + { + Files = null; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + // Execute the Query + string sql = String.Format("EXEC master..xp_dirtree '{0}', 1, 1", Path); + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.FillDataTable(sql); + List retList = new List(); + if (retVal.IsValid) + { + foreach (DataRow row in retVal.GetDataTableRetVal().Rows) + { + bool bIsFile = (row["file"].ToString() == "1"); + if (bIsFile) + retList.Add(row["subdirectory"].ToString()); + } + } + Files = retList.ToArray(); + return retVal; + } + + #endregion + + #region SQL Connection Checkers + + /// + /// Quick Check function to see if the passed in credential allows us to connect to the server + /// If Credential contains a Database, then it will verify the Database's Existence + /// + /// SQL Server Credentials + /// Specify the ConnectionTimout + /// Returns true if successfull in connecting to the server + /// DBError Object with ErrorOccured, if error Occured + public static DBError SQLServerCheckConnection(IConnectDb credential, uint nConnectionTimeout, out bool CanConnect) + { + // the SQL Server should at least have a master db, so this list should never be empty, + // if it is, an error must have occured, either with the credential or with the server + CanConnect = false; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + // Execute Query + string[] Databases = null; + DBError dberror = SQLServerDatabase.DatabasesListAll(credential.DBMS.WithoutDatabase().Timeouts.WithConnectionTimeout(nConnectionTimeout), out Databases); + if (dberror.ErrorOccured || (Databases == null) || (Databases.Length == 0)) + CanConnect = false; + else + CanConnect = true; + + // Check Database Existence, if specified + if (CanConnect) + { + dbError = Validation.IsValidDatabaseName(credential.DBMS.Database); + if (!dberror.ErrorOccured) + { + // Verify that the Database exists + bool bFound = false; + foreach (string db in Databases) + { + if (db.ToUpper() == credential.DBMS.Database.ToUpper()) + { + bFound = true; + break; + } + } + + // Let the Caller know if they can connect to the Database + CanConnect = bFound; + } + } + return dberror; + } + + /// + /// Quick Check function to see if the passed in credential allows us to connect to the + /// server, read some data, as well as check SysAdmin Rights for the passed in Credential + /// If Credential contains a Database, then it will verify the Database's Existence + /// + /// SQL Server Credentials + /// Specify the ConnectionTimout + /// true, if passed in credential connects and is a sysadmin, false otherwise + /// DBError Object with ErrorOccured, if error Occured + public static DBError SQLServerCheckConnectionNCredential(IConnectDb credential, uint nConnectionTimeout, out bool IsValid) + { + IsValid = false; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + DBError dberror = SQLServerCheckConnection(credential, nConnectionTimeout, out IsValid); + if (dberror.ErrorOccured || !IsValid) + return dberror; + + // Now also make sure that the credential is a SysAdmin + dberror = SQLServerSecurity.LoginIsSysAdmin(credential, credential.User, out IsValid); + return dberror; + } + + #endregion + + #region SQL Browse + + /// + /// Returns a array of any found valid SQL Server intances * Using the SQLBrowse Functionallity * + /// If SQLBrowse fails, will look in the Registry + /// This Function can take a long time, depending on the Network + /// + /// list of valid SQLServers or null if error occured + public static string[] SQLServerNamesAndInstaces() + { + // Call the SQL Browse Function + List validSQLServerInstances = new List(); + string[] SQLServersRaw = SQLInfoEnumerator.EnumerateSQLServers(); + foreach (string SQLServerRaw in SQLServersRaw) + { + // Target name is empty - so add any valid instances found + if (Validation.IsValidServerNameAndInstanceName(SQLServerRaw)) + validSQLServerInstances.Add(SQLServerRaw); + } + + // Last thing to try if EnumerateSQLServers() failed is to query the registry + // for all possible SQL Server Installations there * and return those * + if (validSQLServerInstances.Count == 0) + { + string strInstalledInstances = RegKey.GetKey(HKEYRoot.LocalMachine, "Microsoft\\Microsoft SQL Server", "InstalledInstances", String.Empty); + if (!String.IsNullOrEmpty(strInstalledInstances)) + { + string MachineName = Dns.GetHostName(); + // Add any Registry Found Instances + string[] Instances = strInstalledInstances.Split(' '); + foreach (string Instance in Instances) + validSQLServerInstances.Add(MachineName + "\\" + Instance); + } + } + return validSQLServerInstances.ToArray(); + } + + #endregion + + #region SQL Service Functions + + /// + /// Use this to start a SQL Service on the specified Server. You must have Windows admin/SController rights to + /// that machine in order for this function to work + /// + /// Name of the SQL Server or SQL ServerNInstance you want to start (required) + /// Set to Value > 0 to force a wait for the specified amount of seconds(not required) + /// true if Service was started or was already running, false if an error occured + public static bool SQLServerServiceStart(string ServerOrServerNInstance, int WaitTimeoutInSeconds) + { + string Server = string.Empty; + string Instance = string.Empty; + if (String.IsNullOrEmpty(ServerOrServerNInstance)) + return false; + + if (!SQLServerUtilities.SplitServerOrServerNInstance(ServerOrServerNInstance, out Server, out Instance)) + return false; + + // Construct the proper service name + string Service = string.Empty; + if (!String.IsNullOrEmpty(Instance)) + Service = String.Format("MSSQL${0}", Instance); + else + Service = "MSSQLSERVER"; + + string MachineName = Dns.GetHostName(); + bool bIsOnThisMachine = (MachineName.ToLower() == Server.ToLower()); + try + { + ServiceController service = null; + if (bIsOnThisMachine) + service = new ServiceController(Service); + else + service = new ServiceController(Service, Server); + + bool bStartService = (service.Status != ServiceControllerStatus.Running); + if (bStartService) + { + service.Start(); + if (WaitTimeoutInSeconds > 0) + { + TimeSpan timeout = TimeSpan.FromSeconds(WaitTimeoutInSeconds); + service.WaitForStatus(ServiceControllerStatus.Running, timeout); + return (service.Status == ServiceControllerStatus.Running); + } + } + return true; + } + catch (Exception) { /* ignore */ } + return false; + } + + /// + /// Use this to stop a SQL Service on the specified Server. You must have Windows admin/SController rights to + /// that machine in order for this function to work + /// + /// Name of the SQL Server or SQL ServerNInstance you want to stop (required) + /// Set to Value > 0 to force a wait for the specified amount of seconds(not required) + /// true if Service was stopped or was already stopped, false if an error occured + public static bool SQLServerServiceStop(string ServerOrServerNInstance, int WaitTimeoutInSeconds) + { + string Server = string.Empty; + string Instance = string.Empty; + if (String.IsNullOrEmpty(ServerOrServerNInstance)) + return false; + + if (!SQLServerUtilities.SplitServerOrServerNInstance(ServerOrServerNInstance, out Server, out Instance)) + return false; + + // Construct the proper service name + string Service = string.Empty; + if (!String.IsNullOrEmpty(Instance)) + Service = String.Format("MSSQL${0}", Instance); + else + Service = "MSSQLSERVER"; + + string MachineName = Dns.GetHostName(); + bool bIsOnThisMachine = (MachineName.ToLower() == Server.ToLower()); + try + { + ServiceController service = null; + if (bIsOnThisMachine) + service = new ServiceController(Service); + else + service = new ServiceController(Service, Server); + + bool bStopService = (service.Status != ServiceControllerStatus.Stopped); + if (bStopService) + { + service.Stop(); + if (WaitTimeoutInSeconds > 0) + { + TimeSpan timeout = TimeSpan.FromSeconds(WaitTimeoutInSeconds); + service.WaitForStatus(ServiceControllerStatus.Stopped, timeout); + return (service.Status == ServiceControllerStatus.Stopped); + } + } + return true; + } + catch (Exception) { /* ignore */ } + return false; + } + + /// + /// Use this to restart a SQL Service on the specified Server. You must have Windows admin/SController rights to + /// that machine in order for this function to work + /// + /// Name of the SQL Server or SQL ServerNInstance you want to restart (required) + /// Set to Value > 0 to force a wait for the specified amount of seconds(not required) + /// true if Service was restared successfully, false if an error occured + public static bool SQLServerServiceRestart(string ServerOrServerNInstance, int WaitTimeoutInSeconds) + { + return SQLServerServiceStop(ServerOrServerNInstance, WaitTimeoutInSeconds) && SQLServerServiceStart(ServerOrServerNInstance, WaitTimeoutInSeconds); + } + + #endregion + } +} diff --git a/Systems/SQLServer/Internal/ErrorConst.cs b/Systems/SQLServer/Internal/ErrorConst.cs new file mode 100644 index 0000000..cf2a765 --- /dev/null +++ b/Systems/SQLServer/Internal/ErrorConst.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.SQLServer +{ + /// + /// Database Error Constants to Use to handle specific Error + /// + internal static class ErrorConst + { + public const int ERROR_DB_ALREADY_EXISTS = 1801; + public const int ERROR_DB_SOME_FILE_NAMES_COULD_NOT_BE_CREATED = 1802; + public const int ERROR_DB_CAN_NOT_CREATE_FILE_BECAUSE_IT_ALREADY_EXISTS = 5170; + public const int ERROR_DB_THERE_ALREADY_IS_AN_OBJECT_IN_THE_DB_WITH_THIS_NAME = 3092; + public const int ERROR_DB_DEVICE_ACTIVATION_FAILED = 5105; + } +} diff --git a/Systems/SQLServer/Internal/SQLInfoEnumerator.cs b/Systems/SQLServer/Internal/SQLInfoEnumerator.cs new file mode 100644 index 0000000..1574dba --- /dev/null +++ b/Systems/SQLServer/Internal/SQLInfoEnumerator.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; + +namespace Sdaleo.Systems.SQLServer +{ + /// + /// Summary description for SQLInfoEnumerator. + /// This class Enumerates a network for SQL Server instances and returns a list. + /// For a given SQL Server instance a list of all available databases is returned + /// For more information see + /// + /// + /// + internal class SQLInfoEnumerator + { + #region ODBC32 external function definitions + + [DllImport("odbc32.dll")] + private static extern short SQLAllocHandle(short handleType, IntPtr inputHandle, out IntPtr outputHandlePtr); + + [DllImport("odbc32.dll")] + private static extern short SQLSetEnvAttr(IntPtr environmentHandle, int attribute, IntPtr valuePtr, int stringLength); + + [DllImport("odbc32.dll")] + private static extern short SQLFreeHandle(short hType, IntPtr Handle); + + [DllImport("odbc32.dll", CharSet = CharSet.Ansi)] + private static extern short SQLBrowseConnect(IntPtr handleConnection, StringBuilder inConnection, short stringLength, StringBuilder outConnection, short bufferLength, out short stringLength2Ptr); + + #endregion + + #region Constants + + private const string SQL_DRIVER_STR = "DRIVER={SQL SERVER};"; + private const short SQL_SUCCESS = 0; + private const short SQL_SUCCESS_WITH_INFO = 1; + private const short SQL_HANDLE_ENV = 1; + private const short SQL_HANDLE_DBC = 2; + private const int SQL_ATTR_ODBC_VERSION = 200; + private const int SQL_OV_ODBC3 = 3; + private const short SQL_NEED_DATA = 99; + private const short DEFAULT_RESULT_SIZE = 1024; + private const string START_STR = "{"; + private const string END_STR = "}"; + + #endregion + + /// + /// Enumerate the SQL Servers returning a list (if any exist) + /// + /// + internal static string[] EnumerateSQLServers() + { + return RetrieveInformation(SQL_DRIVER_STR); + } + + /// + /// Enumerate the specified SQL server returning a list of databases (if any exist) + /// + /// + internal static string[] EnumerateSQLServersDatabases(string SQLServerNInstance) + { + return RetrieveInformation(SQL_DRIVER_STR + "SERVER=" + SQLServerNInstance + ";"); + } + + /// + /// Enumerate the specified SQL server returning a list of databases (if any exist) + /// + /// + internal static string[] EnumerateSQLServersDatabases(string SQLServerNInstance, string Username, string Password) + { + return RetrieveInformation(SQL_DRIVER_STR + "SERVER=" + SQLServerNInstance + ";" + "UID=" + Username + ";" + "PWD=" + Password + ";"); + } + + /// + /// Enumerate for SQLServer/Databases based on the passed information it the string + /// The more information provided to SQLBrowseConnect the more granular it gets so + /// if only DRIVER=SQL SERVER passed then a list of all SQL Servers is returned + /// If DRIVER=SQL SERVER;Server=ServerName is passed then a list of all Databases on the + /// servers is returned etc + /// + /// A valid string to query for + /// + private static string[] RetrieveInformation(string InputParam) + { + IntPtr m_environmentHandle = IntPtr.Zero; + IntPtr m_connectionHandle = IntPtr.Zero; + + StringBuilder inConnection = new StringBuilder(InputParam); + short stringLength = (short)inConnection.Length; + + StringBuilder outConnection = new StringBuilder(DEFAULT_RESULT_SIZE); + + short stringLength2Ptr = 0; + bool bConnectSuccessful = false; + + try + { + // Prepare the SQL Environment Handles + if ((IsSQLSuccess(SQLAllocHandle(SQL_HANDLE_ENV, m_environmentHandle, out m_environmentHandle))) && + (IsSQLSuccess(SQLSetEnvAttr(m_environmentHandle, SQL_ATTR_ODBC_VERSION, (IntPtr)SQL_OV_ODBC3, 0))) && + (IsSQLSuccess(SQLAllocHandle(SQL_HANDLE_DBC, m_environmentHandle, out m_connectionHandle)))) + { + + // Fetch the Data * First get the size of the buffer, then call it to get the buffer * + if (IsSQLDataSuccess(SQLBrowseConnect(m_connectionHandle, inConnection, stringLength, null, 0, out stringLength2Ptr)) && + IsSQLDataSuccess(SQLBrowseConnect(m_connectionHandle, inConnection, stringLength, outConnection, stringLength2Ptr, out stringLength2Ptr)) + ) + { + bConnectSuccessful = true; + } + } + } + catch { /* ignore */ } + finally + { + FreeConnection(m_connectionHandle); + FreeConnection(m_environmentHandle); + } + + if (bConnectSuccessful && outConnection.ToString() != "") + { + return ParseSQLOutConnection(outConnection.ToString()); + } + else + { + return null; + } + } + + #region Helper Functions + + /// + /// For quick SQL Return value evaluation + /// + private static bool IsSQLSuccess(short SQL_VALUE) + { + if (SQL_VALUE == SQL_SUCCESS || SQL_VALUE == SQL_SUCCESS_WITH_INFO) + return true; + else + return false; + } + + /// + /// For quick SQL Return value evaluation + /// + private static bool IsSQLDataSuccess(short SQL_VALUE) + { + if (SQL_VALUE == SQL_SUCCESS || SQL_VALUE == SQL_SUCCESS_WITH_INFO || SQL_VALUE == SQL_NEED_DATA) + return true; + else + return false; + } + + /// + /// Parse an outConnection string returned from SQLBrowseConnect + /// + /// string to parse + /// Parsed Server names, or Empty Array if none found + private static string[] ParseSQLOutConnection(string outConnection) + { + int m_Start = outConnection.IndexOf(START_STR) + 1; + int m_lenString = outConnection.IndexOf(END_STR) - m_Start; + if ((m_Start > 0) && (m_lenString > 0)) + { + outConnection = outConnection.Substring(m_Start, m_lenString); + } + else + { + outConnection = string.Empty; + } + return outConnection.Split(",".ToCharArray()); + } + + /// + /// Call this to Free a SQL handle + /// + private static void FreeConnection(IntPtr handleToFree) + { + if (handleToFree != IntPtr.Zero) + SQLFreeHandle(SQL_HANDLE_DBC, handleToFree); + } + + #endregion + } +} diff --git a/Systems/SQLServer/Internal/Validation.cs b/Systems/SQLServer/Internal/Validation.cs new file mode 100644 index 0000000..e644b32 --- /dev/null +++ b/Systems/SQLServer/Internal/Validation.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.SQLServer +{ + /// + /// Central Location for SQL Server Input Validation + /// + internal class Validation + { + /// + /// Main Validation Function to validate DatabaseName + /// + /// Name of Database + /// true if valid, false otherise + internal static DBError IsValidDatabaseName(string strDatabaseName) + { + if (string.IsNullOrEmpty(strDatabaseName)) + { + return DBError.Create("DatabaseName is null"); + } + else if (strDatabaseName.Length < 1 || strDatabaseName.Length > 52) // limit database Name length + { + return DBError.Create("DatabaseName length is invalid"); + } + else if (!ValidationConsts.ContainsOnlyLegalChars(strDatabaseName, ValidationConsts.CharSet_AllowedDatabaseNames)) + { + return DBError.Create("DatabaseName contains illegal characters"); + } + else + { + return new DBError(); + } + } + + /// + /// validate SQL Server Table Names + /// + /// + /// + public static DBError IsValidTableName(string strTableName) + { + if (string.IsNullOrEmpty(strTableName)) + { + return DBError.Create("TableName is null"); + } + else if (strTableName.Length < 1 || strTableName.Length > 52) // limit Table Name length + { + return DBError.Create("TableName length is invalid"); + } + else if (!ValidationConsts.ContainsOnlyLegalChars(strTableName, ValidationConsts.CharSet_AllowedTableNames)) + { + return DBError.Create("TableName contains illegal characters"); + } + else + { + return new DBError(); + } + } + + /// + /// Validates a DataSource String which can include a Server and Instance, or just be a Server + /// + /// a DataSource String + /// true if valid, false otherise + internal static bool IsValidDataSource(string strDataSource) + { + if (!string.IsNullOrEmpty(strDataSource) && (strDataSource.IndexOf('\\') >= 0)) + { + string[] values = strDataSource.Split('\\'); + if (values.Length == 2) + return ValidationConsts.Generic.IsValidServerName(values[0]) && ValidationConsts.Generic.IsValidInstanceName(values[1]); + } + else if (!string.IsNullOrEmpty(strDataSource) && (strDataSource.IndexOf('\\') == 0)) + { + return ValidationConsts.Generic.IsValidServerName(strDataSource); + } + return false; + } + + /// + /// Validates that the passedin string has both a valid server and a valid Instance + /// + /// a string to check for server and instance + /// true if valid, false otherwise + internal static bool IsValidServerNameAndInstanceName(string strServerNameNInstance) + { + if (!string.IsNullOrEmpty(strServerNameNInstance) && (strServerNameNInstance.IndexOf('\\') >= 0)) + { + string[] values = strServerNameNInstance.Split('\\'); + if (values.Length == 2) + return ValidationConsts.Generic.IsValidServerName(values[0]) && ValidationConsts.Generic.IsValidInstanceName(values[1]); + } + return false; + } + + } +} diff --git a/Systems/SQLServer/Security.cs b/Systems/SQLServer/Security.cs new file mode 100644 index 0000000..d8c20b7 --- /dev/null +++ b/Systems/SQLServer/Security.cs @@ -0,0 +1,778 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data; + +namespace Sdaleo.Systems.SQLServer +{ + #region SQLServer Security Enums + + /// + /// Server Roles as specified in SQL Server + /// + public enum SQLServerRole + { + sysadmin, + securityadmin, + serveradmin, + setupadmin, + processadmin, + diskadmin, + dbcreator, + bulkadmin, + } + + /// + /// User Roles as specified in SQL Server + /// + public enum SQLServerUserRole + { + db_accessadmin, + db_backupoperator, + db_datareader, + db_datawriter, + db_ddladmin, + db_denydatareader, + db_denydatawriter, + db_owner, + db_securityadmin, + } + + /// + /// These are the SQL Actions you can take on + /// SQLTablePermissions or SQLServerDatabasePermissions + /// + public enum SQLServerPermissionAction + { + GRANT, + REVOKE, + DENY + } + + /// + /// User Permissions on any User Database ('_' must be stripped before using in in sql) + /// + public enum SQLServerDatabasePermission + { + CREATE_DATABASE, // <--- permission only allowed on 'Master' Database + CONNECT, + CREATE_TABLE, + CREATE_DEFAULT, + CREATE_FUNCTION, + CREATE_PROCEDURE, + CREATE_RULE, + CREATE_VIEW, + BACKUP_DATABASE, + BACKUP_LOG + } + + #endregion + + /// + /// Security/Permission SQL Server Related + /// + public class SQLServerSecurity + { + #region Internal Security Helper Functions + + /// + /// We must strip out the '_' on the SQLServerDatabasePermission Enum to use it in an SQL Query + /// + internal static string SQLServerDatabasePermission_ToString(SQLServerDatabasePermission DatabasePermission) + { + return DatabasePermission.ToString().Replace('_', ' '); + } + + /// + /// Quick Helper function to get an SQLServerDatabasePermission[] that has all Permissions defined + /// + internal static SQLServerDatabasePermission[] SQLServerDatabasePermission_ToArray() + { + return (SQLServerDatabasePermission[])Enum.GetValues(typeof(SQLServerDatabasePermission)); + } + + /// + /// Returns generated SQL Database Permissions string for the specified Database,Username with the specified permissions + /// + /// Name of an existing User (required) + /// Permission Action to take (required) + /// array of User Database permissions (required) + /// Some User Permission require to be executed ONLY on the Master Database, set to true if this is sql is being generated for 'master' + /// a Database permission string or empty string if error occured + internal static string BuildSQLServerDatabasePermissionsStr(string Username, SQLServerDatabasePermission[] databasePermissions, SQLServerPermissionAction Action, bool bIsMasterDB) + { + if (String.IsNullOrEmpty(Username) || (databasePermissions == null)) + return string.Empty; + + // add Action + string sql = Action.ToString() + " "; + + // add each permission individually + for (int i = 0; i < databasePermissions.Length; ++i) + { + // Skip certain permissions, unless this is the Master DB + if ((databasePermissions[i] == SQLServerDatabasePermission.CREATE_DATABASE) && !bIsMasterDB) + continue; + + sql += SQLServerDatabasePermission_ToString(databasePermissions[i]); + bool bIsLast = (i == (databasePermissions.Length - 1)); + if (!bIsLast) + sql += ","; + } + + // add action adjective + if (Action == SQLServerPermissionAction.REVOKE) + sql += " FROM "; + else + sql += " TO "; + + // add user + sql += string.Format("[{0}]", Username); + + return sql; + } + + #endregion + + #region Database User Role + + /// + /// Use this to add a specified User Role to a specified User in the DB + /// + /// SQL Server Credentials with Database Info + /// an existing Username to add role to (required) + /// Role to add to specified MemberName + /// DBError Object with ErrorOccured, if error Occured + public DBError DatabaseUserRoleAdd(IConnectDb credential, string Username, SQLServerUserRole Role) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(Username)) + return DBError.Create("Invalid Username Passed In"); + + // Execute the Query + string sql = String.Format("sp_addrolemember @membername = '{0}', @rolename = '{1}'", Username, Role.ToString()); + DB db = DB.Create(credential); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + + /// + /// Use this to drop a specified User Role from a specified User in the DB + /// + /// SQL Server Credentials with Database Info + /// an existing Username to drop role from (required) + /// Role to drop from specified MemberName + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseUserRoleDrop(IConnectDb credential, string Username, SQLServerUserRole Role) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(Username)) + return DBError.Create("Invalid Username Passed In"); + + // Execute and return the Query + string sql = String.Format("sp_droprolemember @membername = '{0}', @rolename = '{1}'", Username, Role.ToString()); + DB db = DB.Create(credential); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + + #endregion + + #region Database User + + /// + /// Use this to query if the Username already exists as an SQL Database User (Does not query Server users ONLY DB Users) + /// + /// SQL Server Credentials with Database Info + /// Specify the Username to Query for (required) + /// True if the User exists in the specified Database, False otherwise + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseUserExists(IConnectDb credential, string Username, out bool bExists) + { + bExists = false; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(Username)) + return DBError.Create("Invalid Username Passed In"); + + // Execute the Query and return + string sql = string.Format("SELECT [name] FROM sys.database_principals WHERE [type_desc]='SQL_USER' and [name] = '{0}'", Username); + DB db = DB.Create(credential); + DBRetVal retVal = db.ExecuteScalar(sql); + bExists = retVal.IsValid; + return retVal; + } + + /// + /// Use this to retrieve a list of all the Database users for the specified SQL Server with DB Credentials + /// + /// SQL Server Credentials with Database Info + /// a list of Database User, or Null if error occured + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseUsers(IConnectDb credential, out string[] Users) + { + Users = null; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + // Execute the Query + string sql = "SELECT [name] FROM sys.database_principals WHERE [type_desc]='SQL_USER'"; + DB db = DB.Create(credential); + DBRetVal retVal = db.FillDataTable(sql); + if (retVal.IsValid) + { + List retList = new List(); + foreach (DataRow row in retVal.GetDataTableRetVal().Rows) + retList.Add(row["name"].ToString()); + Users = retList.ToArray(); + } + return retVal; + } + + /// + /// Add a new Username to the Specified Database for the specified Login + /// + /// SQL Server Credentials + /// Specify the Username for the database (can be same as LoginName) (required) + /// Specify the LoginName (valid SQL Server Login Name) to create Username for (required) + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseUserAdd(IConnectDb credential, string Username, string LoginName) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(Username)) + return DBError.Create("Invalid Username Passed In"); + + if (!ValidationConsts.Generic.IsValidUserName(LoginName)) + return DBError.Create("Invalid LoginName Passed In"); + + // Execute the Query + string sql = string.Format("CREATE USER [{0}] FOR LOGIN [{1}] WITH DEFAULT_SCHEMA = [{0}]", Username, LoginName); + DB db = DB.Create(credential); + DBRetVal retVal = db.ExecuteNonQuery(sql); + if (!retVal.ErrorOccured) + { + // Since SQL 2005, We should create a SCHEMA for each User + sql = string.Format("CREATE SCHEMA [{0}] AUTHORIZATION [{0}]", Username); + retVal = db.ExecuteNonQuery(sql); + } + return retVal; + } + + /// + /// Drops an existing Username from the Specified Database + /// + /// SQL Server Credentials with Database Info + /// Specify the Username for the database (required) + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseUserDrop(IConnectDb credential, string Username) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(Username)) + return DBError.Create("Invalid Username Passed In"); + + // Since SQL 2005, We must drop the SCHEMA first for each User + string sql = string.Format("DROP SCHEMA [{0}]", Username); + DB db = DB.Create(credential); + DBRetVal retVal = db.ExecuteNonQuery(sql); + if (!retVal.ErrorOccured) + { + sql = string.Format("DROP USER [{0}]", Username); + retVal = db.ExecuteNonQuery(sql); + } + return retVal; + } + + #endregion + + #region Database User Permission + + /// + /// Automatically grant,deny,revoke all permissions on the database for the specified user + /// + /// SQL Server Credentials with Database Info + /// Specify the Username for the database (required) + /// GRANT,DENY, or REVOKE 'Permission_All' Permission on that db + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseUserPermissionsAll(IConnectDb credential, string Username, SQLServerPermissionAction action) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(Username)) + return DBError.Create("Invalid Username Passed In"); + + // Execute and return + return DatabaseUserPermissions(credential, Username, SQLServerDatabasePermission_ToArray(), action); + } + + /// + /// Allows you to specify permissions to grant,deny,revoke on the database for the specified user + /// + /// SQL Server Credentials with Database Info + /// Specify the Username for the database (required) + /// an array of permissions to take action on on db + /// GRANT,DENY, or REVOKE specified Permissions on that db + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseUserPermissions(IConnectDb credential, string Username, SQLServerDatabasePermission[] permissions, SQLServerPermissionAction action) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(Username)) + return DBError.Create("Invalid Username Passed In"); + + // Execute the Query + string sql = BuildSQLServerDatabasePermissionsStr(Username, permissions, action, SQLServerUtilities.IsSQLServerMasterDatabaseName(credential.DBMS.Database)); + DB db = DB.Create(credential); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + + #endregion + + #region Database Ownership + + /// + /// Changes the Specified Database's Ownership to be owned by the specified LoginName + /// + /// SQL Server Credentials with Database Info + /// Specify the Login Name to To take over Database Ownership for (required) + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseChangeOwnership(IConnectDb credential, string LoginName) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(LoginName)) + return DBError.Create("Invalid LoginName Passed In"); + + // Make sure that Login doesn't already own that Database + bool bContinue = true; + string[] ownedDBs = null; + DBError dberror = DatabasesOwnedByLogin(credential.DBMS.WithoutDatabase(), LoginName, out ownedDBs); + if (!dberror.ErrorOccured && ownedDBs != null) + { + foreach (string dbName in ownedDBs) + { + if (dbName.ToLower() == credential.DBMS.Database.ToLower()) + { + bContinue = false; + break; + } + } + } + + // Change the Database Ownership + if (bContinue) + { + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + string sql = String.Format("ALTER Authorization On Database::[{0}] To [{1}])", credential.DBMS.Database, LoginName); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + return dberror; + } + + /// + /// Retrieve the SQL Login that is the Owner of the specified Database for the specified SQL Server + /// + /// SQL Server Credentials with Database Info + /// Name of DB Owner + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabaseOwner(IConnectDb credential, out string Owner) + { + Owner = String.Empty; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + // Execute the Query + DB db = DB.Create(credential); + string sql = String.Format("Select suser_sname(owner_sid) from sys.databases where [name] = '{0}'", credential.DBMS.Database); + DBRetVal retVal = db.ExecuteScalar(sql); + if (retVal.IsValid) + Owner = retVal.GetScalarRetVal(); + return retVal; + } + + /// + /// Use this to retrieve all Databases that are owned by the specified Login for the specified SQL Server + /// + /// SQL Server Credentials + /// Specify the Login Name to Query Database Ownership for (required) + /// DatabaseNames that are owned by this Login, null if none are found or error occured + /// DBError Object with ErrorOccured, if error Occured + public static DBError DatabasesOwnedByLogin(IConnectDb credential, string LoginName, out string[] DatabasesOwned) + { + DatabasesOwned = null; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(LoginName)) + return DBError.Create("Invalid LoginName Passed In"); + + // Execute the Query + string sql = String.Format("Select [name] from sys.databases where [owner_sid] = SUSER_SID('{0}')", LoginName); + DB db = DB.Create(credential); + DBRetVal retVal = db.FillDataTable(sql); + if (retVal.IsValid) + { + List retList = new List(); + foreach (DataRow row in retVal.GetDataTableRetVal().Rows) + retList.Add(row["name"].ToString()); + DatabasesOwned = retList.ToArray(); + } + return retVal; + } + + #endregion + + #region Login Roles + + /// + /// Use this to add a specified Server Role to a specified Login in the DB + /// + /// SQL Server Credentials + /// existing login name to add server role to (required) + /// Role to add to specified LoginName + /// DBError Object with ErrorOccured, if error Occured + public static DBError LoginRoleAdd(IConnectDb credential, string LoginName, SQLServerRole Role) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(LoginName)) + return DBError.Create("Invalid LoginName Passed In"); + + // Execute the Query and Return + string sql = String.Format("sp_addsrvrolemember @loginame = '{0}', @rolename = '{1}'", LoginName, Role.ToString()); + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + + /// + /// Use this to drop a specified Server Role from a specified Login in the DB + /// + /// SQL Server Credentials + /// existing login name to drop server role from (required) + /// Role to drop from a specified LoginName + /// DBError Object with ErrorOccured, if error Occured + public static DBError LoginRoleDrop(IConnectDb credential, string LoginName, SQLServerRole Role) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(LoginName)) + return DBError.Create("Invalid LoginName Passed In"); + + // Execute Query + string sql = String.Format("sp_dropsrvrolemember @loginame = '{0}', @rolename = '{1}'", LoginName, Role.ToString()); + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + + /// + /// Use this to query the SQLServer for the roles that are defined for the specified LoginName + /// + /// SQL Server Credentials + /// existing login name to query server roles for + /// Roles Corresponding the the ServerLogin + /// DBError Object with ErrorOccured, if error Occured + public static DBError LoginRoles(IConnectDb credential, string LoginName, out SQLServerRole[] Roles) + { + Roles = null; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(LoginName)) + return DBError.Create("Invalid LoginName Passed In"); + + // Build SQL String + string sql = "SELECT * FROM sys.server_role_members rm JOIN sys.server_principals Roles ON "; + sql += "rm.role_principal_id = Roles.principal_id JOIN sys.server_principals Logins ON "; + sql += "rm.member_principal_id = Logins.principal_id "; + sql += String.Format("Where Logins.name = '{0}'", LoginName); + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + + // Fetch the Data + DBRetVal retVal = db.FillDataTable(sql); + if (retVal.IsValid) + { + List retList = new List(); + foreach (DataRow row in retVal.GetDataTableRetVal().Rows) + { + SQLServerRole role = (SQLServerRole)Enum.Parse(typeof(SQLServerRole), row["name"].ToString()); + retList.Add(role); + } + Roles = retList.ToArray(); + } + return retVal; + } + + #endregion + + #region Login + + /// + /// Easy Check to see if the passed in Login has SysAdmin rights (Full Control) + /// + /// SQL Server Credentials + /// existing login name to query sysadmin role for + /// DBError Object with ErrorOccured, if error Occured + public static DBError LoginIsSysAdmin(IConnectDb credential, string LoginName, out bool IsAdmin) + { + IsAdmin = false; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(LoginName)) + return DBError.Create("Invalid LoginName Passed In"); + + SQLServerRole[] roles = null; + DBError dberror = LoginRoles(credential, LoginName, out roles); + if (dberror.ErrorOccured) + return dberror; + + IsAdmin = roles.Contains(SQLServerRole.sysadmin); + return dberror; + } + + /// + /// Use this to query if the LoginName already exists as an SQL Server User (Does not query db User ONLY server Users) + /// + /// SQL Server Credentials + /// Specify the Login Name to Query for (required) + /// true if login already exist as an SQL User in the system, false otherwise + /// DBError Object with ErrorOccured, if error Occured + public static DBError LoginExists(IConnectDb credential, string LoginName, out bool bExists) + { + bExists = true; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(LoginName)) + return DBError.Create("Invalid LoginName Passed In"); + + // Execute Query + string sql = string.Format("SELECT [name] FROM sys.sql_logins WHERE [name] = '{0}'", LoginName); + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.ExecuteScalar(sql); + bExists = retVal.IsValid; + return retVal; + } + + /// + /// Use this to retrieve all the SQL Logins for the specified Server + /// + /// SQL Server Credentials + /// All SQL Server Logins on the specified server, or null if error occured + /// DBError Object with ErrorOccured, if error Occured + public static DBError Logins(IConnectDb credential, out string[] ServerLogins) + { + ServerLogins = null; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + string sql = "SELECT [name] FROM sys.sql_logins"; + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.FillDataTable(sql); + if (retVal.IsValid) + { + List retList = new List(); + foreach (DataRow row in retVal.GetDataTableRetVal().Rows) + retList.Add(row["name"].ToString()); + ServerLogins = retList.ToArray(); + } + return retVal; + } + + /// + /// Adds a Login to the SQL Server Instance + /// + /// SQL Server Credentials + /// LoginName (required) + /// LoginPassword (required) + /// DBError Object with ErrorOccured, if error Occured + public static DBError LoginAdd(IConnectDb credential, string LoginName, string LoginPassword) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(LoginName)) + return DBError.Create("Invalid LoginName Passed In"); + + if (!ValidationConsts.Generic.IsValidPassword(LoginPassword)) + return DBError.Create("Invalid LoginPassword Passed In"); + + // Execute the Query + string sql = String.Format("CREATE LOGIN [{0}] WITH PASSWORD = '{1}', CHECK_EXPIRATION = OFF, CHECK_POLICY = OFF", LoginName, LoginPassword); + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + + /// + /// Drops a Login from the SQL Server Instance + /// + /// SQL Server Credentials + /// LoginName (required) + /// Fallback Login used to change ownership to, in case error occurs because LoginName owns Databases (not required) + /// true if successful, false otherwise + public static DBError LoginDrop(IConnectDb credential, string LoginName, string FallbackLoginName) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(LoginName)) + return DBError.Create("Invalid LoginName Passed In"); + + // If User owns Databases, the Login Drop will fail, so + // query for existing databases + string[] ownedDBs = null; + DBError dberror = DatabasesOwnedByLogin(credential, LoginName, out ownedDBs); + + // If Fallback Login was specified, use it to change the ownership on the Databases + if (ValidationConsts.Generic.IsValidUserName(FallbackLoginName) && (ownedDBs != null)) + { + foreach (string ownedDB in ownedDBs) + { + dberror = DatabaseChangeOwnership(credential.DBMS.WithDatabase(ownedDB), FallbackLoginName); + if (dberror.ErrorOccured) + return dberror; + } + + // Query Ownership again + dberror = DatabasesOwnedByLogin(credential, LoginName, out ownedDBs); + } + + // If ther are no Owned DBs, this should succeed + if (ownedDBs == null) + { + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + string sql = String.Format("DROP LOGIN [{0}]", LoginName); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + return dberror; + } + + /// + /// Changes the Password for the Login Name being passed in. The Login Name can be the same name as the User specified + /// via Credential (if that is the case, you must update your credential object, when this function returns true) + /// + /// SQL Server Credentials + /// LoginName to change password for(can be the same/different than the User passed in thru credential) (required) + /// NewLoginPassword (required) + /// true if successful * Password was changed for the passed in LoginName *, false otherwise + public static DBError LoginChangePassword(IConnectDb credential, string LoginName, string NewLoginPassword) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(LoginName)) + return DBError.Create("Invalid LoginName Passed In"); + + if (!ValidationConsts.Generic.IsValidPassword(NewLoginPassword)) + return DBError.Create("Invalid NewLoginPassword Passed In"); + + // Execute the Query and Return + string sql = string.Format("ALTER LOGIN [{0}] WITH PASSWORD = '{1}'", LoginName, NewLoginPassword); + DB db = DB.Create(credential.DBMS.WithoutDatabase()); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + + #endregion + } +} diff --git a/Systems/SQLServer/Table.cs b/Systems/SQLServer/Table.cs new file mode 100644 index 0000000..1624753 --- /dev/null +++ b/Systems/SQLServer/Table.cs @@ -0,0 +1,318 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data; + +namespace Sdaleo.Systems.SQLServer +{ + #region SQLServer Table Enums + + /// + /// User Permissions on a Table + /// + public enum SQLServerTablePermission + { + SELECT, + UPDATE, + INSERT, + DELETE, + REFERENCES, + // EXECUTE // <-- not a table permission + } + + #endregion + + /// + /// Specific actions for SQL Server Tables in a Database + /// + public class SQLServerTable + { + #region Internal Table Helper Functions + + /// + /// We must strip out the '_' on the SQLTablePermission Enum to use it in an SQL Query + /// + internal static string SQLTablePermission_ToString(SQLServerTablePermission TablePermission) + { + return TablePermission.ToString().Replace('_', ' '); + } + + /// + /// Quick Helper function to get an SQLTablePermission[] that has all Permissions defined + /// + internal static SQLServerTablePermission[] SQLServerTablePermission_ToArray() + { + return (SQLServerTablePermission[])Enum.GetValues(typeof(SQLServerTablePermission)); + } + + /// + /// Returns a generated SQL Table Permissions string for the specified Table,Username with the specified permissions + /// + /// Name of a Table(required) + /// Name of an existing User that exists in that Database where the Table Resides (required) + /// Permission Action to take + /// array of permissions + /// a table permission string or empty string if error occured + internal static string BuildSQLServerTablePermissionsStr(String TableName, string Username, SQLServerPermissionAction Action, SQLServerTablePermission[] tablePermissions) + { + if (String.IsNullOrEmpty(TableName) || String.IsNullOrEmpty(Username) || (tablePermissions == null)) + return string.Empty; + + // First the Action + string sql = Action.ToString() + " "; + + // add each permission individually + for (int i = 0; i < tablePermissions.Length; ++i) + { + sql += SQLTablePermission_ToString(tablePermissions[i]); + bool bIsLast = (i == (tablePermissions.Length - 1)); + if (!bIsLast) + sql += ","; + } + + // Add Table + sql += String.Format(" ON [{1}]", TableName); + + // add action adjective + if (Action == SQLServerPermissionAction.REVOKE) + sql += " FROM "; + else + sql += " TO "; + + // add user + sql += string.Format("[{0}]", Username); + + return sql; + } + + #endregion + + #region Table Permission + + /// + /// Automatically grant,deny,revoke all permissions on the specified table for the specified user + /// + /// SQL Server Credentials with Database Info + /// Specify the Username for the database (required) + /// Specify the TableName to set permissions on (required) + /// GRANT,DENY, or REVOKE 'Permission_All' Permission on that db + /// DBError Object with ErrorOccured, if error Occured + public static DBError TableUserPermissionsAll(IConnectDb credential, string Username, string TableName, SQLServerPermissionAction action) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(Username)) + return DBError.Create("Invalid Username Passed In"); + + dbError = Validation.IsValidTableName(TableName); + if (dbError.ErrorOccured) + return dbError; + + // Get All Permissions + SQLServerTablePermission[] permissions = SQLServerTablePermission_ToArray(); + + // Perform the Action + return TableUserPermissions(credential, Username, TableName, permissions, action); + } + + /// + /// Allows you to specify permissions to grant,deny,revoke on the specified table for the specified user + /// + /// SQL Server Credentials with Database Info + /// Specify the Username for the database (required) + /// Specify the TableName to set permissions on (required) + /// an array of permissions to take action on on db + /// GRANT,DENY, or REVOKE specified Permissions on that db + /// DBError Object with ErrorOccured, if error Occured + public static DBError TableUserPermissions(IConnectDb credential, string Username, string TableName, SQLServerTablePermission[] permissions, SQLServerPermissionAction action) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + if (!ValidationConsts.Generic.IsValidUserName(Username)) + return DBError.Create("Invalid Username Passed In"); + + dbError = Validation.IsValidTableName(TableName); + if (dbError.ErrorOccured) + return dbError; + + // Build the SQL and Execute the Query + string sql = BuildSQLServerTablePermissionsStr(TableName, Username, action, permissions); + DB db = DB.Create(credential); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + + #endregion + + #region Table Index + + /// + /// Reindexes all Indexes on the Specified Table. + /// + /// SQL Server Credentials with Database Info + /// Specify the TableName to set permissions on (required) + /// DBError Object with ErrorOccured, if error Occured + public static DBError TableReindex(IConnectDb credential, string TableName) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + dbError = Validation.IsValidTableName(TableName); + if (dbError.ErrorOccured) + return dbError; + + // Execute the Query + string sql = String.Format("DBCC DBREINDEX(\"{0}\", \" \", 90);", TableName); + DB db = DB.Create(credential); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + + /// + /// Runs DBCC INDEXDEFRAG on the Specified Database, Table and Index + /// + /// SQL Server Credentials with Database Info + /// Name of Table (required) + /// Name of Index (required) + /// DBError Object with ErrorOccured, if error Occured + public static DBError TableIndexDefrag(IConnectDb credential, string TableName, string IndexName) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + dbError = Validation.IsValidTableName(TableName); + if (dbError.ErrorOccured) + return dbError; + + if (String.IsNullOrEmpty(IndexName)) + return DBError.Create("Invalid IndexName Passed In"); + + // Execute the Query + string sql = String.Format("DBCC INDEXDEFRAG ([{0}], [{1}], [{2}]) WITH NO_INFOMSGS", credential.DBMS.Database, TableName, IndexName); + DB db = DB.Create(credential); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + + #endregion + + #region Common Table Functions + + /// + /// Returns all the Table Names for the specified Database + /// + /// SQL Server Credentials with Database Info + /// array of table names, or null if error occured + /// DBError Object with ErrorOccured, if error Occured + public static DBError Tables(IConnectDb credential, out string[] Tables) + { + Tables = null; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + // Execute the Query + string sql = "SELECT [name] FROM sys.Tables ORDER BY [name]"; + DB db = DB.Create(credential); + DBRetVal retVal = db.FillDataTable(sql); + if (retVal.IsValid) + { + List retList = new List(); + foreach (DataRow row in retVal.GetDataTableRetVal().Rows) + retList.Add(row["name"].ToString()); + Tables = retList.ToArray(); + } + return retVal; + } + + /// + /// Check to see if the Table Exists on the specified Database + /// + /// SQL Server Credentials with Database Info + /// Specify the TableName to check for (required) + /// true if exists, false otherwise + /// DBError Object with ErrorOccured, if error Occured + public static DBError TableExists(IConnectDb credential, string TableName, out bool bExists) + { + bExists = false; + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + dbError = Validation.IsValidTableName(TableName); + if (dbError.ErrorOccured) + return dbError; + + // Execute the Query + string sql = String.Format("SELECT [name] FROM sys.Tables WHERE [name]='{0}' ORDER BY [name]", TableName); + DB db = DB.Create(credential); + DBRetVal retVal = db.ExecuteScalar(sql); + bExists = !retVal.IsValid; + return retVal; + } + + /// + /// Changes the Table Name for the specified Table + /// + /// SQL Server Credentials with Database Info + /// Name of Table (required) + /// Name of Table New (required) + /// DBError Object with ErrorOccured, if error Occured + public static DBError TableRename(IConnectDb credential, string TableName, string TableNameNew) + { + DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER); + if (dbError.ErrorOccured) + return dbError; + + if (!credential.DBMS.IsDatabaseSetAndNonSystem) + return DBError.Create("Invalid Database Passed In via Credential"); + + dbError = Validation.IsValidTableName(TableName); + if (dbError.ErrorOccured) + return dbError; + + dbError = Validation.IsValidTableName(TableNameNew); + if (dbError.ErrorOccured) + return dbError; + + // Update the Index Names using SMO * UNTESTED * + //Server server = DataType.ConvertCredentialToSMOServer(credential); + //foreach (Index index in server.Databases[credential.Database].Tables[TableName].Indexes) + // index.Name = index.Name.Replace(TableName, TableNameNew); + //server.Databases[credential.Database].Tables[TableName].Alter(); + + // Execute the Query + string sql = String.Format("EXEC sp_rename @objname = [{0}], @newname = [{1}], @objtype = 'OBJECT'", TableName, TableNameNew); + DB db = DB.Create(credential); + DBRetVal retVal = db.ExecuteNonQuery(sql); + return retVal; + } + + #endregion + } +} diff --git a/Systems/SQLServer/Utilities.cs b/Systems/SQLServer/Utilities.cs new file mode 100644 index 0000000..3b5eb29 --- /dev/null +++ b/Systems/SQLServer/Utilities.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Sdaleo.Systems.SQLServer +{ + #region SQLServer Utility Enums + + /// + /// Default Databases that are usually part of an SQL Server + /// + internal enum SQLServerDefaultDatabase + { + master, + model, + msdb, + tempdb, + Northwind, + pubs + } + + #endregion + + /// + /// SQLServer Helper Utilites + /// + public class SQLServerUtilities + { + /// + /// Splits a DataSource String to it's ServerAddress and InstanceName components + /// + /// a DataSource string containing either Server or Server And Instance + /// Returns ServerAddress, if found + /// Returns Instance name, if found + /// True, if successfull, false otherwise + public static bool SplitServerOrServerNInstance(string ServerOrServerNInstance, out string Server, out string Instance) + { + Server = String.Empty; + Instance = String.Empty; + + if (!string.IsNullOrEmpty(ServerOrServerNInstance) && (ServerOrServerNInstance.IndexOf('\\') >= 0)) + { + string[] values = ServerOrServerNInstance.Split('\\'); + if (values.Length == 2) + { + if(ValidationConsts.Generic.IsValidServerName(values[0])) + Server = values[0]; + if(ValidationConsts.Generic.IsValidInstanceName(values[1])) + Instance = values[1]; + return (!String.IsNullOrEmpty(Server) && !String.IsNullOrEmpty(Instance)); + } + else + { + return false; + } + } + else if (!string.IsNullOrEmpty(ServerOrServerNInstance) && (ServerOrServerNInstance.IndexOf('\\') == 0)) + { + if (ValidationConsts.Generic.IsValidServerName(ServerOrServerNInstance)) + Server = ServerOrServerNInstance; + return (!String.IsNullOrEmpty(Server)); + } + return false; + } + + // Easy Access to SQL Master Database + public static string SQLServerMasterDatabaseName { get { return SQLServerDefaultDatabase.master.ToString(); } } + public static bool IsSQLServerMasterDatabaseName(string strDatabaseName) { return (SQLServerMasterDatabaseName.ToUpper() == strDatabaseName.ToUpper()); } + + /// + /// Easy Check for Default Database * Any SQL Server Default Database * + /// + /// Name of Database to check for + /// true if this is an SQL Server Default Database, false otherwise + public static bool IsDefaultDatabaseName(string strDatabaseName) + { + foreach (string strName in Enum.GetNames(typeof(SQLServerDefaultDatabase))) + { + if (strName.ToUpper() == strDatabaseName.ToUpper()) + return true; + } + return false; + } + + /// + /// Easy Check for System Database * Same as Default Database but does not inclue Northwind, or Pubs * + /// + /// Name of Database to check for + /// true if this is an SQL Server System Database, false otherwise + public static bool IsSystemDatabaseName(string strDatabaseName) + { + foreach (string strName in Enum.GetNames(typeof(SQLServerDefaultDatabase))) + { + if (strName.ToUpper() == strDatabaseName.ToUpper() && + (strDatabaseName.ToUpper() != "NORTHWIND") && + (strDatabaseName.ToUpper() != "PUBS")) + return true; + } + return false; + } + } +} diff --git a/Systems/SystemAvailable.cs b/Systems/SystemAvailable.cs new file mode 100644 index 0000000..f10ed2f --- /dev/null +++ b/Systems/SystemAvailable.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Reflection; + +namespace Sdaleo.Systems +{ + /// + /// This class will try to load the needed assembly(s) for the specified DB System. + /// If the Assembly load fails, we know that this system won't work (isn't available) + /// + public static class SystemAvailable + { + /// + /// Keep track of previous checks, no need to do it over and over again + /// + private static Dictionary _PrevCheckMap = new Dictionary(); + + /// + /// Try to load the assembly(s) for the specified DB System + /// + /// DB system to load assembly(s) for + /// true, if successfully loaded, false otherwise + public static bool Check(DBSystem dbsystem) + { + try + { + // Performance Optimization + if (_PrevCheckMap.ContainsKey(dbsystem)) + return _PrevCheckMap[dbsystem]; + + // ... Else we must check + switch (dbsystem) + { + case DBSystem.SQL_SERVER: + { + Assembly asm = Assembly.Load("System.Data"); + _PrevCheckMap[dbsystem] = (asm != null); + return _PrevCheckMap[dbsystem]; + } + + case DBSystem.SQL_CE: + { + Assembly asm = Assembly.Load("System.Data.SqlServerCe"); + _PrevCheckMap[dbsystem] = (asm != null); + return _PrevCheckMap[dbsystem]; + } + + case DBSystem.ADVANTAGE: + { + Assembly asm = Assembly.Load("Advantage.Data.Provider"); + _PrevCheckMap[dbsystem] = (asm != null); + return _PrevCheckMap[dbsystem]; + } + + case DBSystem.CTREE: + { + Assembly asm = Assembly.Load("System.Data.SqlServerCe"); + _PrevCheckMap[dbsystem] = (asm != null); + return _PrevCheckMap[dbsystem]; + } + + case DBSystem.MYSQL: + { + Assembly asm = Assembly.Load("System.Data.SqlServerCe"); + _PrevCheckMap[dbsystem] = (asm != null); + return _PrevCheckMap[dbsystem]; + } + + case DBSystem.POSTGRES: + { + Assembly asm = Assembly.Load("Devart.Data"); + if(asm != null) + asm = Assembly.Load("Devart.Data.PostgreSql"); + _PrevCheckMap[dbsystem] = (asm != null); + return _PrevCheckMap[dbsystem]; + } + + default: + _PrevCheckMap[dbsystem] = false; + return false; + } + } + catch (Exception) { /* ignore */ } + _PrevCheckMap[dbsystem] = false; + return false; + } + } +} diff --git a/Systems/ValidationConsts.cs b/Systems/ValidationConsts.cs new file mode 100644 index 0000000..378d774 --- /dev/null +++ b/Systems/ValidationConsts.cs @@ -0,0 +1,247 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace Sdaleo.Systems +{ + /// + /// Validation Consts used throughout Validation of Parameters + /// + public static class ValidationConsts + { + #region Validation Consts + + // Common + public const string CharSet_CharsNum = "0123456789"; + public const string CharSet_CharsAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + public const string CharSet_CharsAlphaNum = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + public const string CharSet_CharsSambaComputerNames = CharSet_CharsAlphaNum + " -_"; + public const string CharSet_CharsIPAddress = CharSet_CharsNum + "."; + public const string CharSet_CharsSpecialKeyboardAscii = " -_!@#$%^&*()_{}\\|:\":/?.,<>~`*-+[]'"; + + // Not Allowed + public const string CharSet_NotAllowedInFileNames = @"\/:*?<>|" + "\""; + public const string CharSet_NotAllowedInDirectorPaths = @"/*?<>|" + "\""; + + // Allowed + public const string CharSet_AllowedUserNames = CharSet_CharsNum + " -_"; + public const string CharSet_AllowedPasswords = CharSet_CharsNum + CharSet_CharsSpecialKeyboardAscii; + public const string CharSet_AllowedServerNames = CharSet_CharsSambaComputerNames + CharSet_CharsIPAddress; // we allow IP addresses as computer names + public const string CharSet_AllowedInstanceNames = CharSet_CharsAlphaNum + "$-_"; + public const string CharSet_AllowedDatabaseNames = CharSet_CharsAlphaNum + CharSet_CharsSpecialKeyboardAscii; + public const string CharSet_AllowedTableNames = CharSet_CharsNum + " -_"; + + /// + /// Generic Function to use with Allowed Character Sets above + /// + /// string to evaluate + /// Pass in one of the legal character consts sets declared above + /// true if valid, false otherwise + public static bool ContainsOnlyLegalChars(string TextToEvaluate, string TextToEvaluateWith) + { + foreach (char c in TextToEvaluate.ToCharArray()) + { + bool bFound = (TextToEvaluateWith.IndexOf(c) >= 0); + if (!bFound) + return false; + } + return true; + } + + #endregion + + #region CredentialValidation + + /// + /// Use this to validate a credential object against a specific system + /// + /// credential object to validate + /// the system to validate against + /// DBerror that either contains or doesn't contain an error + public static DBError IsCredentialValid(IConnectDb credential, DBSystem system) + { + if (credential == null) + return DBError.Create("Invalid Credential Object Passed In"); + else if (credential.DBType != system) + return DBError.Create("Credential Object doesn't match system"); + else if (!credential.IsValid) + return DBError.Create("Credential is invalid"); + else + return new DBError(); + } + + #endregion + + /// + /// Common Generally Generic Validation Functions that should be the same across the board + /// for all DBMS systems + /// + public static class Generic + { + /// + /// Main Validation Function to validate Usernames + /// + /// Username to validate + /// true if valid, false otherise + public static bool IsValidUserName(string strUserName) + { + if (String.IsNullOrEmpty(strUserName)) + { + return false; + } + else if (strUserName.Length < 1 || strUserName.Length > 128) // limit User Name length + { + return false; + } + else if (!ContainsOnlyLegalChars(strUserName, CharSet_AllowedUserNames)) + { + return false; + } + else + { + return true; + } + } + + /// + /// Main Validation Function to validate Passwords + /// + /// Password to validate + /// true if valid, false otherise + public static bool IsValidPassword(string strPassword) + { + if (String.IsNullOrEmpty(strPassword)) + { + return false; + } + else if (strPassword.Length < 1 || strPassword.Length > 128) // limit Password Length + { + return false; + } + else if (!ContainsOnlyLegalChars(strPassword, CharSet_AllowedPasswords)) + { + return false; + } + else + { + return true; + } + } + + /// + /// Calls IsValidUser && IsValidPassword + /// + /// true if valid, false otherise + internal static bool IsValidUserCredential(string strUserName, string strPassword) + { + return IsValidUserName(strUserName) && IsValidPassword(strPassword); + } + + /// + /// Main Validation Function to validate Server Names + /// + /// Name of a Server + /// true if valid, false otherise + internal static bool IsValidServerName(string strServerName) + { + if (String.IsNullOrEmpty(strServerName)) + { + return false; + } + // The maximum length for NetBIOS names is 15 characters. The maximum length for DNS computer names + // in an Active Directory environment is 24 characters + else if (strServerName.Length < 1 || strServerName.Length > 24) // limit server Name length + { + return false; + } + else if (!ContainsOnlyLegalChars(strServerName, CharSet_AllowedServerNames)) + { + return false; + } + else + { + return true; + } + } + + /// + /// Main Validation Function to validate Instancse Names + /// + /// Name of an Instance + /// true if valid, false otherise + internal static bool IsValidInstanceName(string strInstanceName) + { + if (string.IsNullOrEmpty(strInstanceName)) + { + return false; + } + else if (strInstanceName.Length < 1 || strInstanceName.Length > 16) // limit Instance Name length + { + return false; + } + else if (!ContainsOnlyLegalChars(strInstanceName, CharSet_AllowedInstanceNames)) + { + return false; + } + else + { + return true; + } + } + + } + + #region FileName and Path Validation + + /// + /// Check to see if the filename is valid + /// + /// filename to check + /// true if valid, false otherwise + public static bool IsValidFileName(string Filename) + { + if (!String.IsNullOrEmpty(Filename)) + { + bool bIsValid = !ContainsOnlyLegalChars(Filename, CharSet_NotAllowedInFileNames); + return bIsValid; + } + return false; + } + + /// + /// Check to see if directory path is valid + /// + /// directory path + /// true if valid, false otherwise + public static bool IsValidDirectoryPath(string Path) + { + if (!String.IsNullOrEmpty(Path)) + { + bool bIsValid = !ContainsOnlyLegalChars(Path, CharSet_NotAllowedInDirectorPaths); + return bIsValid; + } + return false; + } + + /// + /// Check to see if directory and file name are valid + /// + /// filename including path information + /// true if valid, false otherwise + public static bool IsValidFileNameNPath(string FileNameNPath) + { + if(!String.IsNullOrEmpty(FileNameNPath)) + { + string path = Path.GetDirectoryName(FileNameNPath); + string file = Path.GetFileName(FileNameNPath); + bool bValid = IsValidDirectoryPath(path) && IsValidFileName(file); + return bValid; + } + return false; + } + + #endregion + } +} diff --git a/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache new file mode 100644 index 0000000..4e6e3ec Binary files /dev/null and b/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache differ diff --git a/obj/Debug/ResolveAssemblyReference.cache b/obj/Debug/ResolveAssemblyReference.cache new file mode 100644 index 0000000..bfa0f99 Binary files /dev/null and b/obj/Debug/ResolveAssemblyReference.cache differ diff --git a/obj/Debug/Sdaleo.csproj.FileListAbsolute.txt b/obj/Debug/Sdaleo.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..a8116ef --- /dev/null +++ b/obj/Debug/Sdaleo.csproj.FileListAbsolute.txt @@ -0,0 +1,10 @@ +C:\_ROOT_\PlexProjects\Sdaleo\obj\Debug\ResolveAssemblyReference.cache +C:\_ROOT_\PlexProjects\Target\Debug\Sdaleo.dll +C:\_ROOT_\PlexProjects\Target\Debug\Sdaleo.pdb +C:\_ROOT_\PlexProjects\Sdaleo\obj\Debug\Sdaleo.dll +C:\_ROOT_\PlexProjects\Sdaleo\obj\Debug\Sdaleo.pdb +C:\_ROOT_ (Sync'd)\PlexProjects\Target\Debug\Sdaleo.dll +C:\_ROOT_ (Sync'd)\PlexProjects\Target\Debug\Sdaleo.pdb +C:\_ROOT_ (Sync'd)\PlexProjects\Sdaleo\obj\Debug\ResolveAssemblyReference.cache +C:\_ROOT_ (Sync'd)\PlexProjects\Sdaleo\obj\Debug\Sdaleo.dll +C:\_ROOT_ (Sync'd)\PlexProjects\Sdaleo\obj\Debug\Sdaleo.pdb diff --git a/obj/Debug/Sdaleo.dll b/obj/Debug/Sdaleo.dll new file mode 100644 index 0000000..13c319f Binary files /dev/null and b/obj/Debug/Sdaleo.dll differ diff --git a/obj/Debug/Sdaleo.pdb b/obj/Debug/Sdaleo.pdb new file mode 100644 index 0000000..ea72e98 Binary files /dev/null and b/obj/Debug/Sdaleo.pdb differ diff --git a/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache b/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache new file mode 100644 index 0000000..3390f67 Binary files /dev/null and b/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache differ diff --git a/obj/Release/ResolveAssemblyReference.cache b/obj/Release/ResolveAssemblyReference.cache new file mode 100644 index 0000000..53b5c49 Binary files /dev/null and b/obj/Release/ResolveAssemblyReference.cache differ diff --git a/obj/Release/Sdaleo.csproj.FileListAbsolute.txt b/obj/Release/Sdaleo.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..e5d19a0 --- /dev/null +++ b/obj/Release/Sdaleo.csproj.FileListAbsolute.txt @@ -0,0 +1,5 @@ +C:\_ROOT_ (Sync'd)\PlexProjects\Target\Release\Sdaleo.dll +C:\_ROOT_ (Sync'd)\PlexProjects\Target\Release\Sdaleo.pdb +C:\_ROOT_ (Sync'd)\PlexProjects\Sdaleo\obj\Release\ResolveAssemblyReference.cache +C:\_ROOT_ (Sync'd)\PlexProjects\Sdaleo\obj\Release\Sdaleo.dll +C:\_ROOT_ (Sync'd)\PlexProjects\Sdaleo\obj\Release\Sdaleo.pdb diff --git a/obj/Release/Sdaleo.dll b/obj/Release/Sdaleo.dll new file mode 100644 index 0000000..34ea842 Binary files /dev/null and b/obj/Release/Sdaleo.dll differ diff --git a/obj/Release/Sdaleo.pdb b/obj/Release/Sdaleo.pdb new file mode 100644 index 0000000..1670890 Binary files /dev/null and b/obj/Release/Sdaleo.pdb differ