/// <summary>
 /// Create a LearningStoreXml from some data within a row of a
 /// LogableSqlCommand
 /// </summary>
 /// <param name="command">The LogableSqlCommand.  The current position is
 ///     not modified.</param>
 /// <param name="startingColumn">The index of the first column to be
 ///     examined.  On exit, this index contains the last column examined
 ///     plus one.</param>
 /// <returns>The <Typ>LearningStoreXml</Typ>, or null if a
 ///     value is not found.</returns>
 /// <remarks>Only examines one column.  Assumes that the column contains
 ///     an XML value.  If the column is non-null, a LearningStoreXml
 ///     is returned.  If the column is null, null is returned.
 /// </remarks>
 private static LearningStoreXml ReadXmlColumns(LogableSqlCommand command,
                                                ref int startingColumn)
 {
     if (command.IsDBNull(startingColumn))
     {
         startingColumn++;
         return(null);
     }
     else
     {
         SqlXml xml = command.GetSqlXml(startingColumn);
         startingColumn++;
         return(new LearningStoreXml(xml));
     }
 }
 /// <summary>
 /// Create a LearningStoreItemIdentifier from some data within a row of a
 /// LogableSqlCommand
 /// </summary>
 /// <param name="command">The LogableSqlCommand.  The current position is
 ///     not modified.</param>
 /// <param name="startingColumn">The index of the first column to be
 ///     examined.  On exit, this index contains the last column examined
 ///     plus one.</param>
 /// <param name="itemType">Information about the identifier type to be
 ///     created.</param>
 /// <returns>The<Typ>LearningStoreItemIdentifier</Typ>, or null if
 ///     a value is not found.</returns>
 /// <remarks>Only examines one column.  Assumes that the column contains
 ///     an int64 value, containing the key of the Id.  If the column is
 ///     non-null, a LearningStoreItemIdentifier is returned.  If the
 ///     column is null, null is returned.
 /// </remarks>
 private static LearningStoreItemIdentifier ReadItemIdentifierColumns(LogableSqlCommand command,
                                                                      ref int startingColumn, LearningStoreItemType itemType)
 {
     if (command.IsDBNull(startingColumn))
     {
         startingColumn++;
         return(null);
     }
     else
     {
         long idkey = command.GetInt64(startingColumn);
         startingColumn++;
         return(new LearningStoreItemIdentifier(itemType.Name, idkey));
     }
 }
        /// <summary>
        /// Create a LearningStoreItemIdentifier from a result within a LogableSqlCommand
        /// </summary>
        /// <param name="command">The LogableSqlCommand.  On exit, the entire
        ///     current result has been read.</param>
        /// <param name="itemType">Information about the item type that should be read.</param>
        /// <returns>The<Typ>LearningStoreItemIdentifier</Typ></returns>
        /// <remarks>Assumes that the result has one rows.  Assumes that the
        ///     columns within the row contain exactly the correct data
        ///     for the <Mth>ReadItemIdentifierColumns</Mth> method.</remarks>
        public static LearningStoreItemIdentifier ReadItemIdentifierResult(LogableSqlCommand command, LearningStoreItemType itemType)
        {
            // Check input parameters
            if (command == null)
            {
                throw new LearningComponentsInternalException("LSTR1000");
            }
            if (itemType == null)
            {
                throw new LearningComponentsInternalException("LSTR1010");
            }

            if (!command.Read())
            {
                throw new LearningComponentsInternalException("LSTR1020");
            }

            // Start at the first column
            int startingColumn = 0;

            // Read the item
            LearningStoreItemIdentifier id = ReadItemIdentifierColumns(command,
                                                                       ref startingColumn, itemType);

            // Verify that the correct number of values are in the row
            if (command.GetFieldCount() != startingColumn)
            {
                throw new LearningComponentsInternalException("LSTR1030");
            }

            if (command.Read())
            {
                throw new LearningComponentsInternalException("LSTR1040");
            }

            return(id);
        }
        [SuppressMessage("Microsoft.Maintainability", "CA1502")]  // Much of the complexity is due to simple switch statements
        public static DataTable ReadDataTableResult(LogableSqlCommand command, IList <LearningStoreViewColumn> columns, CultureInfo locale)
        {
            // Check input parameters
            if (command == null)
            {
                throw new LearningComponentsInternalException("LSTR1050");
            }
            if (columns == null)
            {
                throw new LearningComponentsInternalException("LSTR1060");
            }

            // Create the DataTable
            DataTable table = new DataTable();

            table.Locale = locale;

            // Add the columns
            foreach (LearningStoreViewColumn column in columns)
            {
                Type t = null;
                switch (column.ValueType.TypeCode)
                {
                case LearningStoreValueTypeCode.Boolean:
                    t = typeof(Boolean);
                    break;

                case LearningStoreValueTypeCode.DateTime:
                    t = typeof(DateTime);
                    break;

                case LearningStoreValueTypeCode.Double:
                    t = typeof(Double);
                    break;

                case LearningStoreValueTypeCode.Enumeration:
                    t = typeof(Int32);
                    break;

                case LearningStoreValueTypeCode.Int32:
                    t = typeof(Int32);
                    break;

                case LearningStoreValueTypeCode.ItemIdentifier:
                    t = typeof(LearningStoreItemIdentifier);
                    break;

                case LearningStoreValueTypeCode.Single:
                    t = typeof(Single);
                    break;

                case LearningStoreValueTypeCode.String:
                    t = typeof(String);
                    break;

                case LearningStoreValueTypeCode.Xml:
                    t = typeof(LearningStoreXml);
                    break;

                case LearningStoreValueTypeCode.ByteArray:
                    t = typeof(System.Byte[]);
                    break;

                case LearningStoreValueTypeCode.Guid:
                    t = typeof(Guid);
                    break;

                default:
                    throw new LearningComponentsInternalException("LSTR1070");
                }

                table.Columns.Add(column.Name, t);
            }

            // Begin loading the data
            table.BeginLoadData();

            // Enumerate through each row
            while (command.Read())
            {
                // Remember the current input column index
                int inputColumnIndex = 0;

                // Create a new array that will hold the items
                object[] data = new object[columns.Count];

                // Enumerate through each column
                for (int outputColumnIndex = 0; outputColumnIndex < columns.Count; outputColumnIndex++)
                {
                    // Get the column
                    LearningStoreViewColumn column = columns[outputColumnIndex];

                    // Read the value
                    switch (column.ValueType.TypeCode)
                    {
                    case LearningStoreValueTypeCode.Boolean:
                    case LearningStoreValueTypeCode.DateTime:
                    case LearningStoreValueTypeCode.Double:
                    case LearningStoreValueTypeCode.Int32:
                    case LearningStoreValueTypeCode.Single:
                    case LearningStoreValueTypeCode.String:
                    case LearningStoreValueTypeCode.Guid:
                    case LearningStoreValueTypeCode.Enumeration:
                    case LearningStoreValueTypeCode.ByteArray:
                        if (command.IsDBNull(inputColumnIndex))
                        {
                            data[outputColumnIndex] = null;
                        }
                        else
                        {
                            data[outputColumnIndex] = command.GetValue(inputColumnIndex);
                        }
                        inputColumnIndex++;
                        break;

                    case LearningStoreValueTypeCode.ItemIdentifier:
                        data[outputColumnIndex] = ReadItemIdentifierColumns(command, ref inputColumnIndex, column.ValueType.ReferencedItemType);
                        break;

                    case LearningStoreValueTypeCode.Xml:
                        data[outputColumnIndex] = ReadXmlColumns(command, ref inputColumnIndex);
                        break;

                    default:
                        throw new LearningComponentsInternalException("LSTR1080");
                    }
                }

                table.Rows.Add(data);
            }

            // Finish loading the data
            table.EndLoadData();
            table.AcceptChanges();

            return(table);
        }
        /// <summary>
        /// Get the schema information for this store from the cache or from the database.
        /// </summary>
        /// <param name="connectionString">Connection string used to access the store.</param>
        /// <param name="impersonationBehavior">Identifies which <c>WindowsIdentity</c> is used to
        ///     access the database when impersonation is involved.</param>
        /// <param name="debugLog">Location to which the debug log should be written, or
        ///     null if there isn't a debug log.</param>
        /// <returns>The schema information.</returns>
        private static LearningStoreSchema GetSchemaInformationFromCache(string connectionString,
                                                                         ImpersonationBehavior impersonationBehavior, TextWriter debugLog)
        {
            // Try to find the connection in the cache
            lock (s_allSchemasLock)
            {
                LearningStoreSchema schema;
                if (s_allSchemas.TryGetValue(connectionString, out schema))
                {
                    return(schema);
                }
            }

            // Not found in the cache -- so go get it from the database

            // This try/catch block is here for security reasons. Search MSDN for
            // "WrapVulnerableFinallyClausesInOuterTry" to see details.
            try
            {
                WindowsImpersonationContext impersonationContext = null;

                try
                {
                    // Impersonate if necessary
                    if (impersonationBehavior == ImpersonationBehavior.UseOriginalIdentity)
                    {
                        // Not adding it to the disposer, since that could fail (e.g., OutOfMemoryException),
                        // which could cause a security hole.  Instead, we'll clean it up manually later.
                        impersonationContext = WindowsIdentity.Impersonate(IntPtr.Zero);
                    }

                    using (Microsoft.LearningComponents.Disposer disposer = new Microsoft.LearningComponents.Disposer())
                    {
                        // Create a connection
                        SqlConnection connection = new SqlConnection(connectionString);
                        disposer.Push(connection);
                        connection.Open();

                        // Create a command to retrieve information from the configuration table
                        LogableSqlCommand command = new LogableSqlCommand(connection, debugLog);
                        disposer.Push(command);

                        // Execute
                        command.Execute(
                            "SELECT EngineVersion,\r\n" +
                            "    SchemaDefinition\r\n" +
                            "FROM Configuration\r\n");

                        // Read return values from the database
                        if (!command.Read())
                        {
                            throw new LearningComponentsInternalException("LSTR1500");
                        }
                        if (command.GetFieldCount() != 2)
                        {
                            throw new LearningComponentsInternalException("LSTR1510");
                        }
                        int           engineVersion = command.GetInt32(0);
                        SqlXml        schemaXml     = command.GetSqlXml(1);
                        XPathDocument schemaDoc;
                        using (XmlReader reader = schemaXml.CreateReader())
                        {
                            schemaDoc = new XPathDocument(reader);
                        }
                        LearningStoreSchema newSchema = LearningStoreSchema.CreateSchema(schemaDoc);
                        if (command.Read())
                        {
                            throw new LearningComponentsInternalException("LSTR1520");
                        }
                        if (command.NextResult())
                        {
                            throw new LearningComponentsInternalException("LSTR1530");
                        }

                        // Fail if a different engine created this
                        if (engineVersion != LearningStore.EngineVersion)
                        {
                            throw new InvalidOperationException(LearningStoreStrings.IncompatibleEngineVersion);
                        }

                        // Save it in the cache
                        lock (s_allSchemasLock)
                        {
                            LearningStoreSchema schema;
                            if (s_allSchemas.TryGetValue(connectionString, out schema))
                            {
                                return(schema);
                            }
                            s_allSchemas.Add(connectionString, newSchema);
                        }

                        return(newSchema);
                    }
                }
                finally
                {
                    if (impersonationContext != null)
                    {
                        impersonationContext.Dispose();
                    }
                }
            }
            catch
            {
                throw;
            }
        }