Submitted byCategory
Review Cycle
.
Public
Joachim Mutter/sysarc
on 09/24/2009 at 11:31 PM
SSiS\Code

Skip Rows from a Pipeline during a Transform-ScriptTask

If you want to make a Scripttask filtering rows, means skip rows on defined properties, you have to use the OutputBuffer Property (from the synchronized Buffer) ExclusionGroup and set this to an non zeror value.
Doing so, only rows will tranfered to the output, if you explicit call Row.DirectRowToOutput(). This method is only available, if ExclusionGroup is set to a non zero value.

This may be suitable for Converters and Consisty Checks, where you must filter out rows with inconvertable values and rows which doesn't match consitity Rules.


Wrong rows must not be transported, so you could use the ExclusionGrouping Property and the explicit transport method "Row.DirectRowToOutput0()" to transport only valid rows.
All other rows stop here and the second output transports instead the error information!





Imports System
Imports System.Data
Imports System.Math
Imports System.Text
Imports System.IO
Imports System.Collections.Generic
Imports Microsoft.SqlServer.Dts.Pipeline
Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper
Imports Microsoft.SqlServer.Dts.Runtime.Wrapper

Public Class ScriptMain
    Inherits UserComponent

    Private mErrorCol As Integer
    Private mErrorID As Integer
    Private mErrorDescription As String
    Private mErrorText As String
    Private mErrorRow As String
    Private mColumns As Columns
    Private mErrorHandlerBuffer As PipelineBuffer
    Private mErrorOutoutEnabled As Boolean
    Private mColumnName As String

    '_________________________________________________________________________
    ' Set the currentBuffer
    '_________________________________________________________________________
    Public Overrides Sub ProcessInput(ByVal InputID As Integer, ByVal Buffer As Microsoft.SqlServer.Dts.Pipeline.PipelineBuffer)
        mColumns.InputBuffer = Buffer   ' Must be before the MyBase....
        MyBase.ProcessInput(InputID, Buffer)
    End Sub

    '_________________________________________________________________________
    ' Build the Dictionary
    '_________________________________________________________________________
    Public Overrides Sub PreExecute()
        mColumns = New Columns(Me, False)
        Call mColumns.BuildColumnDictionary()
    End Sub

    Public Overrides Sub PrimeOutput(ByVal Outputs As Integer, ByVal OutputIDs() As Integer, ByVal Buffers() As PipelineBuffer)
        mErrorHandlerBuffer = Buffers(0)
        MyBase.PrimeOutput(Outputs, OutputIDs, Buffers)
    End Sub

    Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
        mErrorOutoutEnabled = False                 ' Standard : transport synchronous rows
        Try
            ConvertDateTime("ModifiedDate", "szModifiedDate")
            ConvertByteToString("Comment", "szComment")
        Catch ex As Exception
            MsgBox(ex.Message)
            mErrorOutoutEnabled = True              ' Enable error transport
            mErrorCol = mColumns.Item(mColumnName).Index
            mErrorID = 1000
            mErrorDescription = ex.Message
            mErrorText = "Error during Conversion"
            mErrorRow = mColumns.ColumnValues()
            Call CreateNewOutputRows()
        End Try

        If Not mErrorOutoutEnabled Then             ' If Error-Transport is enable => do not transport normal data
            Row.DirectRowToOutput0()                ' Only if ExcludeGroup is set to non zero, this method is visible
            '                                         And only if you call this method, a  row is transfered from
            '                                         Input0Buffer to Outpu0Buffer (the synchronious Output Buffer)
        End If
    End Sub

    Public Overrides Sub CreateNewOutputRows()
        Try
            If mErrorOutoutEnabled Then
                With Output1Buffer
                    .AddRow()
                    .ErrorCol = mErrorCol
                    .ErrorID = mErrorID
                    .ErrorDescription = mErrorDescription.Substring(0, Min(mErrorDescription.Length, 255))
                    .ErrorText = mErrorText.Substring(0, Min(mErrorText.Length, 255))
                    .ErrorRow() = mErrorRow.Substring(0, Min(mErrorRow.Length, 1024))
                End With
            End If
        Catch ex As Exception
            mErrorHandlerBuffer.RemoveRow()
        End Try
    End Sub

    Sub ConvertByteToString(ByVal colName As String, ByVal newColName As String)
        Dim value As String

        Try
            Dim obj As Object
            Try
                If Me.mColumns.Value(colName) Is Nothing Then Return
                obj = Me.mColumns.Value(colName)                                                ' Get the object
                Dim blob As BlobColumn = DirectCast(obj, BlobColumn)                            ' Cast it to a BlobData
                value = ByteArrayToString(blob.GetBlobData(0, Convert.ToInt32(blob.Length)))    ' Convert it to string
            Catch ex As Exception
                Me.ComponentMetaData.FireWarning(1000, "Convert", String.Format("[Non catched Error during 'ConvertByteToString'] {0} = '{1}' / Error = {2}", colName, obj, ex.Message), "", 0)
                Return
            End Try
            mColumns.Value(newColName) = value.Substring(0, Min(value.Length, mColumns.Item(newColName).Length))
        Catch ex As Exception
            Throw New Exception(String.Format("Error during conversion 'ConvertByteToString' of column {0} : {1}", colName, ex.Message))
        End Try
    End Sub

    Sub ConvertDateTime(ByVal colName As String, ByVal newColName As String)
        mColumnName = colName
        Dim value As Object

        Try
            Dim obj As Object
            Try
                If Me.mColumns.Value(colName) Is Nothing Then Return
                obj = Me.mColumns.Value(colName)                                                ' Get the object
                value = System.Convert.ToDateTime(obj)                                          ' Convert it to DateTime
            Catch ex As Exception
                Me.ComponentMetaData.FireWarning(1000, "Convert", String.Format("[Non catched Error during 'ConvertDateTime'] {0} = '{1}' / Error = {2}", colName, obj, ex.Message), "", 0)
                Return
            End Try
            Dim szDate As String = String.Format("{0:yyyy-MM-dd}", value)
            mColumns.Value(newColName) = szDate.Substring(0, Min(szDate.Length, mColumns.Item(newColName).Length))
        Catch ex As Exception
            Throw New Exception(String.Format("Error during conversion 'ConvertDateTime' of column {0} : {1}", colName, ex.Message))
        End Try
    End Sub

    Private Function StringToByteArray(ByVal str As String) As Byte()
        Dim enc As System.Text.ASCIIEncoding = New System.Text.ASCIIEncoding()
        Return enc.GetBytes(str)
    End Function

    Private Function ByteArrayToString(ByVal arr As Byte()) As String
        Dim enc As System.Text.ASCIIEncoding = New System.Text.ASCIIEncoding()
        Return enc.GetString(arr)
    End Function

End Class

' ********************************************************************
' ********************************************************************
' Class for getting all Columns via key
' This class is only usable for Input and synchronious Output Buffers
' If there is a column form an other output buffer, we throw an error
' ********************************************************************
' ********************************************************************
Public Class Columns
#Region "Imports and initializing"
    'Imports Microsoft.SqlServer.Dts.Pipeline
    'Imports System.Collections.Generic
    '
    'Private mColumns As BuildColumnString
    ''_________________________________________________________________________
    '' Get the Pipeline Buffer for subsequent ordinal column access
    ''_________________________________________________________________________
    'Public Overrides Sub ProcessInput(ByVal InputID As Integer, ByVal Buffer As Microsoft.SqlServer.Dts.Pipeline.PipelineBuffer)
    '    mColumns.InputBuffer = Buffer   ' Must be before the MyBase....
    '    MyBase.ProcessInput(InputID, Buffer)
    'End Sub

    ''_________________________________________________________________________
    '' Get the Pipeline Buffer for subsequent ordinal column access in case
    '' of Source Type (Only Output Buffer)
    ''_________________________________________________________________________
    'Public Overrides Sub PrimeOutput(ByVal Outputs As Integer, ByVal OutputIDs() As Integer, ByVal Buffers() As Microsoft.SqlServer.Dts.Pipeline.PipelineBuffer)
    '    mColumns.Buffer = Buffers(0)   ' Must be before the MyBase....
    '    MyBase.PrimeOutput(Outputs, OutputIDs, Buffers)
    'End Sub

    ''_________________________________________________________________________
    '' Build the Dictionary
    ''_________________________________________________________________________
    'Public Overrides Sub PreExecute()
    '    mTools = new MyTools(Me, "Logging", "varCS")
    '    mColumns = New BuildColumnString(mTools, False)
    '    Call mColumns.BuildDictionary()
    '    MyBase.PreExecute()
    'End Sub
#End Region
#Region "Private Properties"
    Private mInputBuffer As PipelineBuffer
    Protected mCols As Dictionary(Of String, ColumnInfo) = New Dictionary(Of String, ColumnInfo)
    Protected mColsInt As Dictionary(Of Integer, String) = New Dictionary(Of Integer, String)
    Protected mTools As MyTools
    Private mOutputFormatSimple As Boolean
    Private mIsWidthLimited As Boolean = True       ' Limit the maximum witdh of the Columns value for the ToString() Output to MAX_WITDH_FOR_TOSTING
    Private mDateFormatter As String = "{0:dd-MM-yyyy hh:mm:ss}"
    Private mNumericFormatter As String = "{0:0.000}"

    Const MAX_WITDH_FOR_TOSTING As Integer = 50     ' Value for limitation of the columns-value in ToString()

#End Region
#Region "Constructor"
    '=======================================================================
    ' Constructor
    '=======================================================================
    Sub New(ByRef tools As MyTools, ByVal OutputFormatSimple As Boolean)
        mOutputFormatSimple = OutputFormatSimple
        mTools = tools
    End Sub
#End Region

    ' _______________________________________________________________________
    ' Public Function CreateRowsFromFixedLengthFile()
    '   Read in a file and splits it up to the given columns (only Strings)
    '   and add this data to a row in the output buffer
    ' Parameter
    '   filename: Filename to open
    '   maxLineBytes:   Maximum length of line, this is only a secure value to be shure not to read more chars into linebuffer when epected
    '   szEOL: comma seperated list of ASCII Codes for the line end (i.e. "13,10" or only "10")
    '
    ' Example  
    ' Public Overrides Sub CreateNewOutputRows()
    '   Dim filename As String = mTools.Read("varFilename").ToString()
    '   Dim szEOL As String = mTools.Read("LineEndChar", "10").ToString()
    '   Dim maxLineBytes As Integer = Convert.ToInt16(mTools.Read("LineLength", 1024))
    '   mTools.log(MyTools.LOG_Info, Me.ComponentMetaData.Name, "Filename={0}, EOL='{1}', MaxLineLength={2}", filename, szEOL, maxLineBytes)
    '   mColumns.CreateRowsFromFixedLengthFile(filename, maxLineBytes, szEOL)
    ' End Sub
    ' _______________________________________________________________________
    Public Sub CreateRowsFromFixedLengthFile(ByVal filename As String, ByVal maxLineBytes As Integer, ByVal szEOL As String)
        Dim lineEndChar() As Integer = {10, 0}
        Dim i As Integer = 0
        Dim inputByte As Integer = 0
        Dim lastByte As Integer = 0
        Try
            '*************************************
            ' Get the LineEnd chars
            ' they should be given i.e. "13,10" or "10"
            '*************************************
            For Each eol As Integer In Split(szEOL, ",")
                lineEndChar(i) = System.Convert.ToInt16(eol)
                i += 1
            Next
            i = 0

            If filename.Length > 0 Then         ' Only if we had a filename
                Dim fp As TextReader
                Dim bytes As Long = 0
                Dim lines As Integer = 0
                Dim lineBytes As Integer = 0
                Dim array As StringBuilder = New StringBuilder()
                Try
                    fp = New StreamReader(filename) ' Open Filereader
                    Do While fp.Peek() >= 0
                        lastByte = inputByte        ' Remember last char, if we had a two byte EOL
                        inputByte = fp.Read()       ' Read charachter
                        bytes += 1                  ' Count chars

                        If lineBytes > maxLineBytes Then
                            Throw New Exception(String.Format("Cannot find lineEnd char in 1024 bytes, something must be wrong (Read bytes: {0}", bytes))
                        End If

                        array.Append(Convert.ToChar(inputByte)) ' Append the read in charachter to the buffer

                        If (lineEndChar(1) = 0 And inputByte = lineEndChar(0)) _
                        Or (lineEndChar(1) > 0 And inputByte = lineEndChar(1) And lastByte = lineEndChar(0)) Then
                            Dim off As Integer = 0
                            Dim index As Integer = 0
                            Dim szLine As String = array.ToString()

                            Me.Buffer.AddRow()            ' Append a new Row to ther output buffer

                            For Each colName As String In Split(Me.ColumnNames(","), ",")
                                Dim tmp As Columns.ColumnInfo = Me.ColInfo(colName)   ' Get the columns metadata
                                Dim part As String                              ' tmporary string to hold the fields content

                                If off + tmp.Length <= szLine.Length Then       ' If not each line contains all needed chars of the fixed-length-file
                                    part = szLine.Substring(off, tmp.Length)    ' Read the part with the defined length of the output field
                                ElseIf off < szLine.Length Then
                                    part = szLine.Substring(off)                ' Read until the end
                                Else
                                    part = ""                                   ' Ok, no more chars in Input string
                                End If

                                Me.Value(colName) = part.Replace(Convert.ToChar(lineEndChar(0)), "").Replace(Convert.ToChar(lineEndChar(1)), "").Trim()

                                off += tmp.Length                               ' Select the next field
                            Next
                            array = New StringBuilder()         ' Empty Line Buffer
                            lines += 1                          ' Count lines
                            lineBytes = 0                       ' set Line charachter Count to 0
                            'mColumns.ShowBufferContent()
                        End If
                    Loop
                Catch ex As Exception
                    mTools.log(MyTools.LOG_Warning, "Columns.CreateNewOutputRows", "Something wrong with file {0}, finsihed reading: Lines= {1}, Bytes= {2} --- Error: {3}", filename, lines, bytes, ex.ToString)
                Finally
                    fp.Close()
                End Try
                If lines = 0 And bytes > 0 Then
                    'MsgBox(String.Format("Finsihed reading: Lines= {0}, Bytes= {1}", lines, bytes), , "Error")
                    mTools.log(MyTools.LOG_Warning, "Columns.CreateNewOutputRows", "Something wrong with file {0}, finsihed reading: Lines= {1}, Bytes= {2}", filename, lines, bytes)
                Else
                    mTools.log(MyTools.LOG_Info, "Columns.CreateNewOutputRows", "Finsihed reading '{0}': Lines= {1}, Bytes= {2}", filename, lines, bytes)
                    'MsgBox(String.Format("Finsihed reading: Lines= {0}, Bytes= {1}", lines, bytes))
                End If
            End If
        Catch ex As Exception
            mTools.log(MyTools.LOG_Error, "CreateOutputRows", String.Format("[RowCount]: Error during read of {0}: {1}", filename, ex.Message))
        End Try
    End Sub

    Public Sub TrimAll(ByVal searchString As Char)
        Dim i As Integer
        Try
            For Each item As KeyValuePair(Of String, ColumnInfo) In mCols
                i = item.Value.Index
                If Not Me.Buffer.IsNull(i) Then
                    Dim tmp As String = Me.Buffer.Item(i).ToString()
                    Me.Buffer.Item(i) = tmp.Trim(searchString)
                End If
            Next
        Catch ex As Exception
            mTools.FireWarning(2001, ex.TargetSite.Name, "Error in TrimAll, index = " + CStr(i) + vbCrLf + ex.ToString & vbCr + ex.StackTrace.ToString)
        End Try
    End Sub

    Public Sub ReplaceAll(ByVal searchString As String, ByVal replaceString As String)
        Dim i As Integer
        Try
            For Each item As KeyValuePair(Of String, ColumnInfo) In mCols
                i = item.Value.Index
                If Not Me.Buffer.IsNull(i) Then
                    Dim tmp As String = Me.Buffer.Item(i).ToString()
                    If tmp.Contains(searchString) Then
                        Me.Buffer.Item(i) = tmp.Replace(searchString, replaceString)
                    End If
                End If
            Next
        Catch ex As Exception
            mTools.FireWarning(2002, ex.TargetSite.Name, "Error in ReplaceAll, index = " + CStr(i) + vbCrLf + ex.ToString & vbCr + ex.StackTrace.ToString)
        End Try
    End Sub

    ' _______________________________________________________________________
    ' Public Function Ascii()
    ' Splits a given string into its ascii and hex represntation and returns
    ' it in 16 char blocks
    ' _______________________________________________________________________
    Public Function Ascii(ByVal szString As String) As String
        Dim sb As StringBuilder = New StringBuilder()
        Dim sbv As StringBuilder = New StringBuilder()
        Dim sba As StringBuilder = New StringBuilder()
        Dim ii As Integer = 0

        For i As Integer = 0 To szString.Length - 1
            ii += 1
            Dim szVisible As String = "."
            Dim szChar As String = szString.Substring(i, 1)
            If Asc(szChar) > 31 And Asc(szChar) < 128 Then szVisible = szChar
            sbv.AppendFormat("{0}", szVisible)
            sba.AppendFormat("{0:X2} ", Asc(szChar))
            If ii >= 16 Then
                sb.AppendFormat("{0}::{1}", sbv.ToString(), sba.ToString).AppendLine()
                ii = 0
                sbv = New StringBuilder()
                sba = New StringBuilder()
            End If
        Next
        If ii < 16 Then
            For i As Integer = ii + 1 To 16
                sbv.Append(".")
                sba.Append("00 ")
            Next
            sb.AppendFormat("{0}::{1}", sbv.ToString(), sba.ToString).AppendLine()
        End If
        Return sb.ToString()
    End Function

#Region "Init Function 'BuildDictionary'"
    ' _______________________________________________________________________
    ' Public Sub BuildDictionary()
    ' Build a dictionaray over the input Buffer as a Collection
    '
    ' This is really tricky, because we donot have the BufferManager here to get
    ' the real Index of a buffer item. Also in the overriden function "Input0_ProcessInputRow"
    ' we donot have a change to get the columns by Name, its only posibble only by index!
    ' So we must use this to get a InfoColumn dicionary, to handle all columns by Name!
    ' _______________________________________________________________________
    <CLSCompliant(False)> Public Sub BuildDictionary(ByVal main As ScriptMain, Optional ByVal isShowing As Boolean = False)
        Try
            Dim indexes() As Integer
            Dim offset As Integer = 0
            Dim isOnlyOutput As Boolean = True

#If VBC_VER = 8.0 Then
            Dim outputBuffer As IDTSOutput90
            Dim outputColumn As IDTSOutputColumn90
            Dim inputBuffer As IDTSInput90
            Dim inputColumn As IDTSInputColumn90
#Else
            Dim outputBuffer As IDTSOutput100
            Dim outputColumn As IDTSOutputColumn100
            Dim inputBuffer As IDTSInput100
            Dim inputColumn As IDTSInputColumn100
#End If

            Dim sb As StringBuilder = New StringBuilder
            For Each inputBuffer In main.ComponentMetaData.InputCollection
                indexes = main.GetColumnIndexes(inputBuffer.ID)                                 ' Get the indexes of this buffer
                offset = 0

                If isShowing Then
                    sb.AppendFormat("InputBufferID = {0}", inputBuffer.ID).AppendLine()              ' Only for info
                    sb.Append("=========================").AppendLine()
                End If

                For Each inputColumn In inputBuffer.InputColumnCollection
                    If isShowing Then sb.AppendFormat("{0}[{1}]   [{2} :: {3}]", inputColumn.Name, indexes(offset), inputColumn.DataType, inputColumn.Length).Append(vbCrLf) ' Only for info
                    mCols.Add(inputColumn.Name, New ColumnInfo(inputColumn, indexes(offset), inputBuffer.ID))
                    mColsInt.Add(indexes(offset), inputColumn.Name)
                    offset += 1
                Next
                isOnlyOutput = False
                MsgBox("Blubber")
                If isShowing Then sb.AppendLine() ' Only for info
            Next
            For Each outputBuffer In main.ComponentMetaData.OutputCollection     ' Ok, run over the output buffer and get additional synchronious columns
                indexes = main.GetColumnIndexes(outputBuffer.ID)                                 ' Get the indexes of this buffer
                offset = 0
                If isShowing Then
                    sb.AppendFormat("OutpuBufferID = {0}", outputBuffer.ID)                           ' Only for info
                    If outputBuffer.SynchronousInputID > 0 Then sb.AppendFormat("/SyncID = {0}", outputBuffer.SynchronousInputID)
                    sb.AppendLine().Append("=========================").AppendLine()
                End If
                For Each outputColumn In outputBuffer.OutputColumnCollection
                    If isShowing Then sb.AppendFormat("{0}[{1}]   [{2} :: {3}]", outputColumn.Name, indexes(offset), outputColumn.DataType, outputColumn.Length).Append(vbCrLf)
                    If outputBuffer.SynchronousInputID > 0 Or isOnlyOutput Then                       ' Take only the columns from the syncronized buffers
                        mCols.Add(outputColumn.Name, New ColumnInfo(outputColumn, indexes(offset), outputBuffer.SynchronousInputID))
                        mColsInt.Add(indexes(offset), outputColumn.Name)
                    End If
                    offset += 1
                Next
                If isShowing Then sb.AppendLine() ' Only for info
            Next
            If isShowing Then MsgBox(sb.ToString, , "Buffers") ' Only for info
        Catch ex As Exception
            mTools.FireError(2003, ex.TargetSite.Name, ex.ToString & vbCr + ex.StackTrace.ToString)
            'mMain.ComponentMetaData.FireError(2001, ex.TargetSite.Name, ex.ToString & vbCr + ex.StackTrace.ToString, "", 0, True)
        End Try
    End Sub
#End Region
#Region "Properties"
    Public Property DateFormatter() As String
        Get
            Return mDateFormatter
        End Get
        Set(ByVal value As String)
            mDateFormatter = value
        End Set
    End Property

    Public Property NumericFormatter() As String
        Get
            Return mNumericFormatter
        End Get
        Set(ByVal value As String)
            mNumericFormatter = value
        End Set
    End Property
    Public ReadOnly Property Tools() As MyTools
        Get
            Return mTools
        End Get
    End Property
    Public Property IsLimieded() As Boolean
        Get
            Return mIsWidthLimited
        End Get
        Set(ByVal value As Boolean)
            mIsWidthLimited = value
        End Set
    End Property
    Public Property OutputFormatSimple() As Boolean
        Get
            OutputFormatSimple = mOutputFormatSimple
        End Get
        Set(ByVal value As Boolean)
            mOutputFormatSimple = value
        End Set
    End Property
    Public Property Buffer() As PipelineBuffer
        Get
            Buffer = mInputBuffer
        End Get
        Set(ByVal value As PipelineBuffer)
            mInputBuffer = value
        End Set
    End Property
    Public Sub ShowBufferContent()
        Dim sb As StringBuilder = New StringBuilder()
        Try
            MsgBox(Me.Buffer.ColumnCount)
        Catch ex As Exception
            MsgBox("Cannot get Buffer")
        End Try
        For i As Integer = 0 To mColsInt.Count - 1
            Dim col As ColumnInfo = mCols(mColsInt(i))
            Dim tmp As String
            Try
                tmp = Me.Buffer.Item(col.Index).ToString()
            Catch ex As Exception
                tmp = ex.Message
            End Try
            sb.AppendFormat("{0} [{1}[{2}]] = {3}", col.Name, col.Index, i, tmp).AppendLine()
        Next

        'For i As Integer = 0 To Me.Buffer.ColumnCount - 1
        '    Dim tmp As String
        '    Try
        '        tmp = Me.Buffer.Item(i).ToString()
        '        dim name as String = Me.Buffer.Item(i).
        '    Catch ex As Exception
        '        tmp = ex.Message
        '    End Try
        '    sb.AppendFormat("{0} = {1}", i, tmp).AppendLine()
        'Next
        MsgBox(sb.ToString, , "ShowBufferContent")
    End Sub
    Public ReadOnly Property GetStringFromBlob(ByVal colName As String) As String
        Get
            Dim obj As Object
            Try
                If Me.Value(colName) Is Nothing Then Return ""
                obj = Me.Value(colName)                                                ' Get the object
                Dim blob As BlobColumn = DirectCast(obj, BlobColumn)                            ' Cast it to a BlobData
                Return ByteArrayToString(blob.GetBlobData(0, Convert.ToInt32(blob.Length)))    ' Convert it to string
            Catch ex As Exception
                Throw New Exception(String.Format("Error during conversion 'ConvertByteToString' of column {0} : {1}", colName, ex.Message))
            End Try
        End Get
    End Property
    ' _______________________________________________________________________
    ' Public ReadOnly Property ColInfo(ByVal colName As String) As ColumnInfo
    '   Returns the ColumnInfo class for this column
    ' _______________________________________________________________________
    Public ReadOnly Property ColInfo(ByVal colName As String) As ColumnInfo
        Get
            Dim col As ColumnInfo = Nothing
            If mCols.ContainsKey(colName) Then
                col = mCols(colName)
            Else
                col = New ColumnInfo()
            End If
            Return col
        End Get
    End Property
    ' _______________________________________________________________________
    ' Property Value(ByVal colName As String) As Object
    '   Gets or sets the value of an column
    ' _______________________________________________________________________
    Property Value(ByVal colName As String) As Object
        Get
            Try
                Dim colInfo As ColumnInfo = mCols(colName)
                Return mInputBuffer.Item(colInfo.Index)
            Catch ex As Exception
                Throw New KeyNotFoundException(String.Format("Invalid column = {0} [{1}]", colName, ex.Message))
            End Try
        End Get
        Set(ByVal value As Object)
            Dim szType As String = "Unkown"
            Try                                                                     ' encapsulate to get the right error
                Dim colInfo As ColumnInfo = mCols(colName)
                If value Is Nothing Then
                    value = "nothing !!!"                                           ' For debugging
                    mInputBuffer.SetNull(colInfo.Index)                             ' Ok set it to null
                Else
                    mInputBuffer.Item(colInfo.Index) = value                        ' Ok, set the correct value
                    szType = mInputBuffer.Item(colInfo.Index).GetType().Name        ' For debugging
                End If
            Catch ex As KeyNotFoundException                                        ' OK, the columns doesn'tz exist
                Throw New KeyNotFoundException(String.Format("Invalid column = {0}", colName, ex.Message))
            Catch ex As Exception                                                   ' The column exoszt, but the value was wrong
                Throw New Exception(String.Format("Cannot set value for column '{0}'[{1}] = {2} [Error: {3}]", colName, szType, value.ToString(), ex.Message))
            End Try
        End Set
    End Property
    ' _______________________________________________________________________
    ' Public ReadOnly Property ToString(ByVal sep As String) As String
    '   Get all column values from the input buffer, comma seperated
    ' _______________________________________________________________________
    Public Shadows ReadOnly Property ToString(ByVal sep As String) As String
        Get
            Dim sb As StringBuilder = New StringBuilder()
            Try
                Dim localSep As String = ""
                Dim i As Integer
                For i = 0 To mColsInt.Count - 1
                    Dim col As ColumnInfo = mCols(mColsInt(i))
                    sb.AppendFormat("{0}{1}", localSep, Me.GetFormattedValue(col).Replace(sep, " "))    ' get the value (remove seperators in the content)
                    localSep = sep                                                                      ' the first value is without the seperator :-)
                Next
            Catch ex As Exception
                mTools.FireWarning(2004, ex.TargetSite.Name, ex.ToString & vbCr + ex.StackTrace.ToString)
            End Try
            Return (sb.ToString())                                             ' Return the whole string
        End Get
    End Property

    ' _______________________________________________________________________
    ' Public ReadOnly Property Header(ByVal sep As String) As String
    '   Get all column names from the input buffer, comma seperated
    ' _______________________________________________________________________
    Public ReadOnly Property ColumnNames(ByVal sep As String) As String
        Get
            Dim sb As StringBuilder = New StringBuilder()
            Try
                Dim localSep As String = ""
                Dim i As Integer
                For i = 0 To mColsInt.Count - 1
                    Dim col As ColumnInfo = mCols(mColsInt(i))
                    sb.AppendFormat("{0}{1}", localSep, col.Name.Replace(sep, " "))   ' get the value (remove seperators in the content)
                    localSep = sep                                                    ' the first value is without the seperator :-)
                Next
            Catch ex As Exception
                mTools.FireWarning(2004, ex.TargetSite.Name, ex.ToString & vbCr + ex.StackTrace.ToString)
            End Try
            Return (sb.ToString())                                             ' Return the whole string
        End Get
    End Property


#End Region
#Region "Private methods"
    Private Function GetFormattedValue(ByVal col As ColumnInfo) As String
        Dim szContent As String
        Try
            If Not Me.Buffer.IsNull(col.Index) Then
                szContent = Me.Buffer.Item(col.Index).ToString()
                Select Case col.Type
                    Case DataType.DT_BYREF_DBDATE, DataType.DT_BYREF_DATE, DataType.DT_BYREF_DBTIME, DataType.DT_BYREF_DBTIMESTAMP
                        szContent = String.Format(Me.DateFormatter, Me.Buffer.Item(col.Index))
                    Case DataType.DT_BYREF_NUMERIC
                        szContent = String.Format(Me.NumericFormatter, Me.Buffer.Item(col.Index))
                    Case Else
                        If szContent.Length > MAX_WITDH_FOR_TOSTING And mIsWidthLimited Then
                            szContent = szContent.Substring(1, 50) + " ..."
                        Else
                            szContent = szContent.ToString()
                        End If
                End Select
            Else
                szContent = "NULL"
            End If
            If szContent.Length > MAX_WITDH_FOR_TOSTING And mIsWidthLimited Then szContent = szContent.Substring(1, 50) + " ..."
            If Me.mOutputFormatSimple Then
                Return szContent
            Else
                Return String.Format("""{0}"" [{1}]", szContent, col.Name)
            End If
        Catch ex As Exception
            Return String.Format("Invalid index = {0} [{1}]", col.Index.ToString(), col.Name)
        End Try
    End Function

    Private Function StringToByteArray(ByVal str As String) As Byte()
        Dim enc As System.Text.ASCIIEncoding = New System.Text.ASCIIEncoding()
        Return enc.GetBytes(str)
    End Function

    Private Function ByteArrayToString(ByVal arr As Byte()) As String
        Dim enc As System.Text.ASCIIEncoding = New System.Text.ASCIIEncoding()
        Return enc.GetString(arr)
    End Function
#End Region
#Region "Internal ColumnInfo class"
    Public Class ColumnInfo
        Public Name As String
        <CLSCompliant(False)> Public Type As DataType
        Public Index As Int32
        Public Length As Int32
        Public Precision As Int32
        Public Scale As Int32
        Public ID As Int32
        Public LineageID As Int32
        Public BufferID As Int32

        Overrides Function ToString() As String
            Dim sb As StringBuilder = New StringBuilder()
            sb.AppendFormat("Type = {0}", Me.Type).AppendLine()
            sb.AppendFormat("Index = {0}", Me.Index).AppendLine()
            sb.AppendFormat("Index = {0}", Me.Index).AppendLine()
            sb.AppendFormat("Precision = {0}", Me.Precision).AppendLine()
            sb.AppendFormat("Scale = {0}", Me.Scale).AppendLine()
            sb.AppendFormat("ID= {0}", Me.ID).AppendLine()
            sb.AppendFormat("LineageID = {0}", Me.LineageID).AppendLine()
            Return sb.ToString
        End Function

#If VBC_VER = 8.0 Then
        Sub New(ByVal col As IDTSInputColumn90, ByVal index As Integer, ByVal bufferID As Int32)
#Else
        <CLSCompliant(False)> Sub New(ByVal col As IDTSInputColumn100, ByVal index As Integer, ByVal bufferID As Int32)
#End If
            Me.Name = col.Name
            Me.Length = col.Length
            Me.Index = index
            Me.ID = col.ID
            Me.LineageID = col.LineageID
            Me.Precision = col.Precision
            Me.Scale = col.Scale
            Me.Type = col.DataType
            Me.BufferID = bufferID
        End Sub

#If VBC_VER = 8.0 Then
        Sub New(ByVal col As IDTSOutputColumn90, ByVal index As Integer, ByVal bufferID As Int32)
#Else
        <CLSCompliant(False)> Sub New(ByVal col As IDTSOutputColumn100, ByVal index As Integer, ByVal bufferID As Int32)
#End If
            Me.Name = col.Name
            Me.Length = col.Length
            Me.Index = index
            Me.ID = col.ID
            Me.LineageID = col.LineageID
            Me.Precision = col.Precision
            Me.Scale = col.Scale
            Me.Type = col.DataType
            Me.BufferID = bufferID
        End Sub
        Sub New()
            Me.Name = "Unkown"
            Me.Type = DataType.DT_I8
            Me.Index = -1
            Me.Length = -1
            Me.Precision = -1
            Me.Scale = -1
            Me.ID = -1
            Me.LineageID = -1
            Me.BufferID = -1
        End Sub
    End Class
#End Region
End Class