public override void Open()
        {
            _build.Open();
            _probe.Open();
            BuildHashtable();

            _entry           = null;
            _entryEnumerator = null;
            _currentPhase    = Phase.ProduceMatch;
            _probeMatched    = true;
        }
        private void AddToHashtable(object keyValue, object[] values)
        {
            HashMatchEntry entry;

            _hashTable.TryGetValue(keyValue, out entry);

            if (entry == null)
            {
                entry = new HashMatchEntry();
            }
            else
            {
                var newEntry = new HashMatchEntry {
                    Next = entry
                };
                entry = newEntry;
            }

            entry.RowValues      = values;
            _hashTable[keyValue] = entry;
        }
        public override bool Read()
        {
            switch (_currentPhase)
            {
            case Phase.ProduceMatch:
            {
                var matchFound = false;
                _rowBuffer.SetProbe(_probe.RowBuffer);

                while (!matchFound)
                {
                    if (_entry != null)
                    {
                        _entry = _entry.Next;
                    }

                    if (_entry == null)
                    {
                        // All rows having the same key value are exhausted.

                        if (!_probeMatched && (_logicalOperator == BoundHashMatchOperator.FullOuter ||
                                               _logicalOperator == BoundHashMatchOperator.RightOuter))
                        {
                            _probeMatched = true;
                            _rowBuffer.SetBuild(null);
                            return(true);
                        }

                        // Read next row from probe input.

                        if (!_probe.Read())
                        {
                            // The probe input is exhausted. If we have a full outer or left outer
                            // join we are not finished. We have to return all rows from the build
                            // input that have not been matched with the probe input.

                            if (_logicalOperator == BoundHashMatchOperator.FullOuter ||
                                _logicalOperator == BoundHashMatchOperator.LeftOuter)
                            {
                                _currentPhase = Phase.ReturnUnmatchedRowsFromBuildInput;
                                _entry        = null;
                                goto case Phase.ReturnUnmatchedRowsFromBuildInput;
                            }

                            return(false);
                        }

                        // Get probe value

                        _probeMatched = false;
                        var probeValue = _probe.RowBuffer[_probeIndex];

                        // Seek first occurence of probe value

                        if (probeValue != null)
                        {
                            _hashTable.TryGetValue(probeValue, out _entry);
                        }
                    }

                    if (_entry != null)
                    {
                        _rowBuffer.SetBuild(_entry);

                        if (_remainder())
                        {
                            _entry.Matched = true;
                            matchFound     = true;
                            _probeMatched  = true;
                        }
                    }
                }

                return(true);
            }

            case Phase.ReturnUnmatchedRowsFromBuildInput:
            {
                var unmatchedFound = false;
                _rowBuffer.SetProbe(null);

                while (!unmatchedFound)
                {
                    if (_entry != null)
                    {
                        _entry = _entry.Next;
                    }

                    if (_entry == null)
                    {
                        if (_entryEnumerator == null)
                        {
                            _entryEnumerator = _hashTable.Values.GetEnumerator();
                        }

                        // All rows having the same key value are exhausted.
                        // Read next key from build input.

                        if (!_entryEnumerator.MoveNext())
                        {
                            // We have read all keys. So we are finished.
                            return(false);
                        }

                        _entry = _entryEnumerator.Current;
                    }

                    unmatchedFound = !_entry.Matched;
                }

                _rowBuffer.SetBuild(_entry);
                return(true);
            }

            default:
                throw ExceptionBuilder.UnexpectedValue(_currentPhase);
            }
        }
 public void SetBuild(HashMatchEntry entry)
 {
     _buildEntry.Entry      = entry;
     _build.ActiveRowBuffer = entry == null ? (RowBuffer)_buildNull : _buildEntry;
 }