// ===============================================================================
        //                                                                        Tokenize
        //                                                                        ========
        public InternalTokenType Next()
        {
            if (_position >= _sql.Length)
            {
                _token         = null;
                _tokenType     = InternalTokenType.EOF;
                _nextTokenType = InternalTokenType.EOF;
                return(_tokenType);
            }
            switch (_nextTokenType)
            {
            case InternalTokenType.SQL:
                ParseSql();
                break;

            case InternalTokenType.COMMENT:
                ParseComment();
                break;

            case InternalTokenType.ELSE:
                ParseElse();
                break;

            case InternalTokenType.BIND_VARIABLE:
                ParseBindVariable();
                break;

            default:
                ParseEof();
                break;
            }
            return(_tokenType);
        }
 protected void ParseBindVariable()
 {
     _token         = NextBindVariableName;
     _nextTokenType = InternalTokenType.SQL;
     _position++;
     _tokenType = InternalTokenType.BIND_VARIABLE;
 }
        protected void ParseSql()
        {
            int commentStartPos      = _sql.IndexOf("/*", _position);
            int lineCommentStartPos  = _sql.IndexOf("--", _position);
            int bindVariableStartPos = _sql.IndexOf("?", _position);
            int elseCommentStartPos  = -1;
            int elseCommentLength    = -1;

            if (bindVariableStartPos < 0)
            {
                bindVariableStartPos = _sql.IndexOf("?", _position);
            }
            if (lineCommentStartPos >= 0)
            {
                int skipPos = SkipWhitespace(lineCommentStartPos + 2);
                if (skipPos + 4 < _sql.Length &&
                    "ELSE" == _sql.Substring(skipPos, ((skipPos + 4) - skipPos)))
                {
                    elseCommentStartPos = lineCommentStartPos;
                    elseCommentLength   = skipPos + 4 - lineCommentStartPos;
                }
            }
            int nextStartPos = GetNextStartPos(commentStartPos,
                                               elseCommentStartPos, bindVariableStartPos);

            if (nextStartPos < 0)
            {
                _token         = _sql.Substring(_position);
                _nextTokenType = InternalTokenType.EOF;
                _position      = _sql.Length;
                _tokenType     = InternalTokenType.SQL;
            }
            else
            {
                _token     = _sql.Substring(_position, nextStartPos - _position);
                _tokenType = InternalTokenType.SQL;
                bool needNext = nextStartPos == _position;
                if (nextStartPos == commentStartPos)
                {
                    _nextTokenType = InternalTokenType.COMMENT;
                    _position      = commentStartPos + 2;
                }
                else if (nextStartPos == elseCommentStartPos)
                {
                    _nextTokenType = InternalTokenType.ELSE;
                    _position      = elseCommentStartPos + elseCommentLength;
                }
                else if (nextStartPos == bindVariableStartPos)
                {
                    _nextTokenType = InternalTokenType.BIND_VARIABLE;
                    _position      = bindVariableStartPos;
                }
                if (needNext)
                {
                    Next();
                }
            }
        }
        protected void ParseComment()
        {
            int commentEndPos = _sql.IndexOf("*/", _position);

            if (commentEndPos < 0)
            {
                ThrowEndCommentNotFoundException(_sql.Substring(_position));
            }
            _token         = _sql.Substring(_position, (commentEndPos - _position));
            _nextTokenType = InternalTokenType.SQL;
            _position      = commentEndPos + 2;
            _tokenType     = InternalTokenType.COMMENT;
        }
        public string SkipToken()
        {
            int  index   = _sql.Length;
            char quote   = _position < _sql.Length ? _sql.ToCharArray()[_position] : '\0';
            bool quoting = quote == '\'' || quote == '(';

            if (quote == '(')
            {
                quote = ')';
            }

            for (int i = quoting ? _position + 1 : _position; i < _sql.Length; ++i)
            {
                char c = _sql.ToCharArray()[i];
                if ((Char.IsWhiteSpace(c) || c == ',' || c == ')' || c == '(') &&
                    !quoting)
                {
                    index = i;
                    break;
                }
                else if (c == '/' && i + 1 < _sql.Length &&
                         _sql.ToCharArray()[i + 1] == '*')
                {
                    index = i;
                    break;
                }
                else if (c == '-' && i + 1 < _sql.Length &&
                         _sql.ToCharArray()[i + 1] == '-')
                {
                    index = i;
                    break;
                }
                else if (quoting && quote == '\'' && c == '\'' &&
                         (i + 1 >= _sql.Length || _sql.ToCharArray()[i + 1] != '\''))
                {
                    index = i + 1;
                    break;
                }
                else if (quoting && c == quote)
                {
                    index = i + 1;
                    break;
                }
            }
            _token         = _sql.Substring(_position, (index - _position));
            _tokenType     = InternalTokenType.SQL;
            _nextTokenType = InternalTokenType.SQL;
            _position      = index;
            return(_token);
        }
 protected void ParseEof()
 {
     _token         = null;
     _tokenType     = InternalTokenType.EOF;
     _nextTokenType = InternalTokenType.EOF;
 }
 protected void ParseElse()
 {
     _token         = null;
     _nextTokenType = InternalTokenType.SQL;
     _tokenType     = InternalTokenType.ELSE;
 }