예제 #1
0
        protected override async Task <object[]> ReadRecord(CancellationToken cancellationToken)
        {
            object[] newRow = null;
            var      pos    = 0;

            //this writes out duplicates of the primary reader when a duplicate match occurrs on the join table
            //i.e. outer join.
            if (_writeGroup)
            {
                //create a new row and write the primary fields out
                newRow = new object[FieldCount];
                for (var i = 0; i < _primaryFieldCount; i++)
                {
                    newRow[pos] = PrimaryTransform[i];
                    pos++;
                }

                var joinRow = _filterdGroupData[_writeGroupPosition];

                for (var i = 0; i < _referenceFieldCount; i++)
                {
                    newRow[pos] = joinRow[i];
                    pos++;
                }

                _writeGroupPosition++;

                //if last join record, then set the flag=false so the next read will read another primary row record.
                if (_writeGroupPosition >= _filterdGroupData.Count)
                {
                    _writeGroup = false;
                }

                return(newRow);
            }

            //read a new row from the primary table.
            if (await PrimaryTransform.ReadAsync(cancellationToken) == false)
            {
                return(null);
            }

            var joinMatchFound = false;

            //if input is sorted, then run a sortedjoin
            if (JoinAlgorithm == EJoinAlgorithm.Sorted)
            {
                //first read get a row from the join table.
                if (_firstRead)
                {
                    //get the first two rows from the join table.
                    _joinReaderOpen = await ReferenceTransform.ReadAsync(cancellationToken);

                    _groupsOpen = await ReadNextGroup();

                    _firstRead = false;
                }

                //loop through join table until we find a matching row.
                if (_joinColumns != null)
                {
                    while (_groupsOpen)
                    {
                        var joinFields = new object[_joinColumns.Length];
                        for (var i = 0; i < _joinColumns.Length; i++)
                        {
                            joinFields[i] = _joinColumns[i].SourceColumn == null ? _joinColumns[i].JoinValue : PrimaryTransform[_sourceKeyOrdinals[i]];
                        }

                        var compare = _joinKeyComparer.Compare(_groupFields, joinFields);
                        var done    = false;

                        switch (compare)
                        {
                        case 1:
                            joinMatchFound = false;
                            done           = true;
                            break;

                        case -1:
                            if (_groupsOpen)
                            {
                                _groupsOpen = await ReadNextGroup();
                            }

                            break;

                        case 0:
                            joinMatchFound = true;
                            done           = true;
                            break;
                        }

                        if (done)
                        {
                            break;
                        }
                    }
                }
            }
            else //if input is not sorted, then run a hash join.
            {
                //first read load the join table into memory
                if (_firstRead)
                {
                    _joinHashData   = new SortedDictionary <object[], List <object[]> >(new JoinKeyComparer());
                    _joinReaderOpen = await ReferenceTransform.ReadAsync(cancellationToken);

                    _groupsOpen = await ReadNextGroup();

                    //load all the join data into an a dictionary
                    while (_groupsOpen)
                    {
                        _joinHashData.Add(_groupFields, _groupData);
                        _groupsOpen = await ReadNextGroup();
                    }

                    _firstRead = false;
                }

                object[] sourceKeys;

                //set the values for the lookup
                if (_joinColumns != null)
                {
                    sourceKeys = new object[_joinColumns.Length];
                    for (var i = 0; i < _joinColumns.Length; i++)
                    {
                        sourceKeys[i] = _joinColumns[i].SourceColumn == null ? _joinColumns[i].JoinValue : PrimaryTransform[_sourceKeyOrdinals[i]];
                    }
                }
                else
                {
                    sourceKeys = new object[0];
                }

                if (_joinHashData.Keys.Contains(sourceKeys))
                {
                    _groupData     = _joinHashData[sourceKeys];
                    _groupsOpen    = true;
                    joinMatchFound = true;
                }
                else
                {
                    joinMatchFound = false;
                }
            }

            //create a new row and write the primary fields out
            newRow = new object[FieldCount];
            for (var i = 0; i < _primaryFieldCount; i++)
            {
                newRow[pos] = PrimaryTransform[i];
                pos++;
            }

            if (joinMatchFound)
            {
                //if there are additional join functions, we run them
                if (_joinFilters.Count == 0)
                {
                    _filterdGroupData = _groupData;
                }
                else
                {
                    _filterdGroupData = new List <object[]>();

                    //filter out the current group based on the functions defined.
                    foreach (var row in _groupData)
                    {
                        var matchFound = true;
                        foreach (var condition in _joinFilters)
                        {
                            foreach (var input in condition.Inputs.Where(c => c.IsColumn))
                            {
                                object value = null;
                                try
                                {
                                    if (input.Column.ReferenceTable == _referenceTableName)
                                    {
                                        value = row[ReferenceTransform.GetOrdinal(input.Column)];
                                    }
                                    else
                                    {
                                        value = PrimaryTransform[input.Column];
                                    }

                                    input.SetValue(value);
                                }
                                catch (Exception ex)
                                {
                                    throw new TransformException($"The join tansform {Name} failed setting parameters on the condition {condition.FunctionName} with the parameter {input.Name}.  {ex.Message}.", ex, value);
                                }
                            }

                            try
                            {
                                var invokeresult = condition.Invoke();

                                if ((bool)invokeresult == false)
                                {
                                    matchFound = false;
                                    break;
                                }
                            }
                            catch (FunctionIgnoreRowException)
                            {
                                matchFound = false;
                                TransformRowsIgnored++;
                                break;
                            }
                            catch (Exception ex)
                            {
                                throw new TransformException($"The join transform {Name} failed calling the function {condition.FunctionName}.  {ex.Message}.", ex);
                            }
                        }

                        if (matchFound)
                        {
                            _filterdGroupData.Add(row);
                        }
                    }
                }

                object[] joinRow = null;

                if (_filterdGroupData.Count > 0)
                {
                    if (_filterdGroupData.Count > 1)
                    {
                        switch (JoinDuplicateStrategy)
                        {
                        case EDuplicateStrategy.Abend:
                            throw new DuplicateJoinKeyException("The join transform failed as the selected columns on the join table " + ReferenceTableAlias + " are not unique.  To continue when duplicates occur set the join strategy to first, last or all.", ReferenceTableAlias, _groupFields);

                        case EDuplicateStrategy.First:
                            joinRow = _filterdGroupData[0];
                            break;

                        case EDuplicateStrategy.Last:
                            joinRow = _filterdGroupData.Last();
                            break;

                        case EDuplicateStrategy.All:
                            joinRow             = _filterdGroupData[0];
                            _writeGroup         = true;
                            _writeGroupPosition = 1;
                            break;

                        default:
                            throw new TransformException("The join transform failed due to an unknown join strategy " + JoinDuplicateStrategy);
                        }
                    }
                    else
                    {
                        joinRow = _filterdGroupData[0];
                    }

                    for (var i = 0; i < _referenceFieldCount; i++)
                    {
                        newRow[pos] = joinRow[i];
                        pos++;
                    }
                }
            }

            return(newRow);
        }
예제 #2
0
        public override async Task <bool> Open(Int64 auditKey, SelectQuery query, CancellationToken cancellationToken)
        {
            AuditKey = auditKey;
            if (query == null)
            {
                query = new SelectQuery();
            }

            //only apply a sort if there is not already a sort applied.
            // if(query.Sorts == null || query.Sorts.Count == 0)
            query.Sorts = RequiredSortFields();

            var returnValue = await PrimaryTransform.Open(auditKey, query, cancellationToken);

            if (!returnValue)
            {
                return(false);
            }

            var referenceQuery = new SelectQuery()
            {
                Sorts = RequiredReferenceSortFields()
            };

            returnValue = await ReferenceTransform.Open(auditKey, referenceQuery, cancellationToken);

            if (!returnValue)
            {
                return(false);
            }

            //check if the primary and reference transform are sorted in the join
            if (SortFieldsMatch(RequiredSortFields(), PrimaryTransform.SortFields) && SortFieldsMatch(RequiredReferenceSortFields(), ReferenceTransform.SortFields))
            {
                JoinAlgorithm = EJoinAlgorithm.Sorted;
            }
            else
            {
                JoinAlgorithm = EJoinAlgorithm.Hash;
            }

            //store the ordinals for the joins to improve performance.
            if (_joinColumns == null)
            {
                _joinKeyOrdinals   = new int[0];
                _sourceKeyOrdinals = new int[0];
            }
            else
            {
                _joinKeyOrdinals   = new int[_joinColumns.Length];
                _sourceKeyOrdinals = new int[_joinColumns.Length];

                for (var i = 0; i < _joinColumns.Length; i++)
                {
                    _joinKeyOrdinals[i]   = ReferenceTransform.GetOrdinal(_joinColumns[i].JoinColumn.Name);
                    _sourceKeyOrdinals[i] = _joinColumns[i].SourceColumn == null ? -1 : PrimaryTransform.GetOrdinal(_joinColumns[i].SourceColumn.Name);
                }
            }


            return(true);
        }