Ejemplo n.º 1
0
        internal override IEnumerable <Row> GetEntities(DataExtractorHelper schema)
        {
            foreach (var record in page.Records)
            {
                var dataRow   = schema.NewRow();
                var readState = new RecordReadState(schema.Columns.Count(x => x.UnderlyingType == ColumnType.Bit));

                int columnIndex = 0;
                foreach (DataColumn col in dataRow.Columns)
                {
                    var sqlType = SqlTypeFactory.Create(col, readState, new CompressionContext(CompressionLevel.Row, true));

                    IVariableLengthDataProxy dataProxy = record.GetPhysicalColumnBytes(columnIndex);

                    if (dataProxy == null)
                    {
                        dataRow[col] = null;
                    }
                    else
                    {
                        dataRow[col] = sqlType.GetValue(dataProxy.GetBytes().ToArray());
                    }

                    columnIndex++;
                }

                yield return(dataRow);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Starts at the data page (loc) and follows the NextPage pointer chain till the end.
        /// </summary>
        internal IEnumerable <Row> ScanLinkedDataPages(PagePointer loc, DataExtractorHelper schema,
                                                       CompressionContext compression, bool isSysTable)
        {
            while (PagePointer.Zero != loc && loc != null && loc.PageID > 0)
            {
                var recordParser = RecordEntityParser.CreateEntityParserForPage(loc, compression, Database, isSysTable);

                foreach (var dr in recordParser.GetEntities(schema))
                {
                    yield return(dr);
                }

                loc = recordParser.NextPage;
            }
        }
Ejemplo n.º 3
0
        internal override IEnumerable <Row> GetEntities(DataExtractorHelper schema)
        {
            foreach (var record in page.Records)
            {
                // Don't process forwarded blob fragments as they should only be processed from the referenced record
                if (_recordsToSkip.Contains(record.Type) || record.IsGhostForwardedRecord)
                {
                    continue;
                }

                short fixedOffset         = 0;
                short variableColumnIndex = 0;
                var   dataRow             = schema.NewRow();
                var   readState           = new RecordReadState(schema.BitColumnsCount);
                var   bitColumnBytes      = new byte[0];

                foreach (var col in schema.Columns)
                {
                    var    sqlType     = SqlTypeFactory.Create(col, readState, compression);
                    object columnValue = null;

                    // Sparse columns needs to retrieve their values from the sparse vector, contained in the very last
                    // variable length column in the record.
                    if (col.IsSparse)
                    {
                        // We may encounter records that don't have any sparse vectors, for instance if no sparse columns have values
                        if (record.SparseVector != null)
                        {
                            // Column ID's are stored as ints in general. In the sparse vector though, they're stored as shorts.
                            if (record.SparseVector.ColumnValues.ContainsKey((short)col.ColumnID))
                            {
                                columnValue = sqlType.GetValue(record.SparseVector.ColumnValues[(short)col.ColumnID]);
                            }
                        }
                    }
                    else
                    {
                        var nonSparseIndex = schema.NonSparseIndexes[col.Name];
                        // Before we even try to parse the column & make a null bitmap lookup, ensure that it's present in the record.
                        // There may be columns > record.NumberOfColumns caused by nullable columns added to the schema after the record was written.
                        if (nonSparseIndex < record.NumberOfColumns && col.UnderlyingType != ColumnType.Computed)
                        {
                            if (sqlType.IsVariableLength)
                            {
                                // If there's either no null bitmap, or the null bitmap defines the column as non-null.
                                if (!record.HasNullBitmap || !record.NullBitmap[nonSparseIndex])
                                {
                                    // If the current variable length column index exceeds the number of stored
                                    // variable length columns, the value is empty by definition (that is, 0 bytes, but not null).
                                    if (variableColumnIndex < record.NumberOfVariableLengthColumns)
                                    {
                                        var data = record.VariableLengthColumnData[variableColumnIndex].GetBytes()?.ToArray();
                                        columnValue = sqlType.GetValue(data ?? new byte[0]);
                                    }
                                    else
                                    {
                                        columnValue = sqlType.GetValue(new byte[0]);
                                    }
                                }

                                variableColumnIndex++;
                            }
                            else
                            {
                                // Must cache type FixedLength as it may change after getting a value (e.g. SqlBit)
                                var fixedLength = sqlType.FixedLength.Value;

                                if ((!record.HasNullBitmap || !record.NullBitmap[nonSparseIndex]) && col.UnderlyingType != ColumnType.Bit)
                                {
                                    var valueBytes = record.FixedLengthData.Skip(fixedOffset).Take(fixedLength).ToArray();

                                    // We may run out of fixed length bytes. In certain conditions a null integer may have been added without
                                    // there being a null bitmap. In such a case, we detect the null condition by there not being enough fixed
                                    // length bytes to process.
                                    if (valueBytes.Length > 0)
                                    {
                                        columnValue = sqlType.GetValue(valueBytes);
                                    }
                                }
                                else if (col.UnderlyingType == ColumnType.Bit && !schema.IsDroppedColumn(col))
                                {
                                    if (readState.IsFirstBit)
                                    {
                                        bitColumnBytes = record.FixedLengthData.Skip(fixedOffset).Take(fixedLength).ToArray();
                                    }

                                    var value = sqlType.GetValue(bitColumnBytes);
                                    columnValue = !record.HasNullBitmap || !record.NullBitmap[nonSparseIndex] ? value : null;
                                }

                                fixedOffset += fixedLength;
                            }
                        }
                        else if (col.UnderlyingType == ColumnType.Computed)
                        {
                            columnValue = sqlType.GetValue(null);
                        }
                        else if (!col.IsNullable)
                        {
                            columnValue = schema.GetDefaultValue(col, sqlType);
                        }
                    }

                    if (!schema.IsDroppedColumn(col))
                    {
                        dataRow[col] = columnValue;
                    }
                }

                yield return(dataRow);
            }
        }
Ejemplo n.º 4
0
        private IEnumerable <Row> ScanPartition(long partitionID, int partitionNumber, Row schema, bool isSysTable = true)
        {
            // Lookup partition
            var partition = Database.Dmvs.Partitions
                            .SingleOrDefault(p => p.PartitionID == partitionID && p.PartitionNumber == partitionNumber);

            if (partition == null)
            {
                throw new ArgumentException("Partition (" + partitionID + "." + partitionNumber + " does not exist.");
            }

            // Get allocation unit for in-row data
            var au = Database.Dmvs.SystemInternalsAllocationUnits
                     .SingleOrDefault(x => x.ContainerID == partition.PartitionID && x.Type == 1);

            if (au == null)
            {
                throw new ArgumentException("Partition (" + partition.PartitionID + "." + partition.PartitionNumber + " has no HOBT allocation unit.");
            }

            // Before we can scan either heaps or indices, we need to know the compression level as that's set at the partition level, and not at the record/page level.
            // We also need to know whether the partition is using vardecimals.
            var compression = new CompressionContext((CompressionLevel)partition.DataCompression, MetaData.PartitionHasVardecimalColumns(partition.PartitionID));

            var clusteredIndex = isSysTable ? null : Database.Dmvs.Indexes.SingleOrDefault(x => x.ObjectID == partition.ObjectID && x.Type == 1);

            var useClusteredIndex = isSysTable || clusteredIndex != null;

            var partitionColumns = isSysTable ? null : Database.Dmvs.SystemInternalsPartitionColumns.Where(x => x.PartitionID == partition.PartitionID).ToArray();

            var defaultConstraints = isSysTable ? null : Database.Dmvs.SysDefaultConstraints.Where(x => x.ParentObjectId == partition.ObjectID).ToArray();

            var schemaWrapper = new DataExtractorHelper(schema, Database.Dmvs, null, partitionColumns, defaultConstraints);

            // Heap tables won't have root pages, thus we can check whether a root page is defined for the HOBT allocation unit
            if (au.RootPagePointer != PagePointer.Zero && useClusteredIndex)
            {
                var currentPage = isSysTable ? au.FirstPagePointer : au.RootPagePointer;

                if (currentPage != au.FirstPagePointer)
                {
                    while (true)
                    {
                        var ciPage = Database.GetClusteredIndexPage(currentPage, isSysTable);

                        currentPage = ciPage.Records.Select(x => x.PageId).FirstOrDefault();

                        if (ciPage.Header.Level <= 1)
                        {
                            break;
                        }
                    }
                }

                // Index
                foreach (var row in ScanLinkedDataPages(currentPage, schemaWrapper, compression, isSysTable))
                {
                    yield return(row);
                }
            }
            else
            {
                // Heap
                foreach (var row in ScanHeap(au.FirstIamPagePointer, schemaWrapper, compression, isSysTable))
                {
                    yield return(row);
                }
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Scans a heap beginning from the provided IAM page and onwards.
        /// </summary>
        private IEnumerable <Row> ScanHeap(PagePointer loc, DataExtractorHelper schema, CompressionContext compression,
                                           bool isSysTable)
        {
            // Traverse the linked list of IAM pages until the tail pointer is zero
            while (loc != PagePointer.Zero)
            {
                // Before scanning, check that the IAM page itself is allocated
                var pfsPage = Database.GetPfsPage(PfsPage.GetPfsPointerForPage(loc));

                // If IAM page isn't allocated, there's nothing to return
                if (!pfsPage.GetPageDescription(loc.PageID).IsAllocated)
                {
                    yield break;
                }

                var iamPage = Database.GetIamPage(loc, isSysTable);

                // Create an array with all of the header slot pointers
                var iamPageSlots = new []
                {
                    iamPage.Slot0,
                    iamPage.Slot1,
                    iamPage.Slot2,
                    iamPage.Slot3,
                    iamPage.Slot4,
                    iamPage.Slot5,
                    iamPage.Slot6,
                    iamPage.Slot7
                };

                // Loop each header slot and yield the results, provided the header slot is allocated
                foreach (var slot in iamPageSlots.Where(x => x != PagePointer.Zero))
                {
                    var recordParser = RecordEntityParser.CreateEntityParserForPage(slot, compression, Database, isSysTable);

                    foreach (var dr in recordParser.GetEntities(schema))
                    {
                        yield return(dr);
                    }
                }

                // Then loop through allocated extents and yield results
                foreach (var extent in iamPage.GetAllocatedExtents())
                {
                    // Get PFS page that tracks this extent
                    var pfs = Database.GetPfsPage(PfsPage.GetPfsPointerForPage(extent.StartPage));

                    foreach (var pageLoc in extent.GetPagePointers())
                    {
                        // Check if page is allocated according to PFS page
                        var pfsDescription = pfs.GetPageDescription(pageLoc.PageID);

                        if (!pfsDescription.IsAllocated)
                        {
                            continue;
                        }

                        var recordParser = RecordEntityParser.CreateEntityParserForPage(pageLoc, compression, Database, isSysTable);

                        foreach (var dr in recordParser.GetEntities(schema))
                        {
                            yield return(dr);
                        }
                    }
                }

                // Update current IAM chain location to the tail pointer
                loc = iamPage.Header.NextPage;
            }
        }
Ejemplo n.º 6
0
 internal abstract IEnumerable <Row> GetEntities(DataExtractorHelper schema);