internal DBSqlParserTable FindTableForColumn(
            DBSqlParserColumn column
            )
        {
            DBSqlParserTableCollection tables = Tables;
            int tableCount = tables.Count;

            for (int i = 0; i < tableCount; ++i)
            {
                DBSqlParserTable table = tables[i];

                // if the table name matches the correlation name, then we're certain
                // of a match
                if (string.Empty == column.DatabaseName &&
                    string.Empty == column.SchemaName &&
                    CatalogMatch(column.TableName, table.CorrelationName))
                {
                    return(table);
                }

                // otherwise, compare each part of the name (if they exist) with the
                // table and pick the one that matches all the parts that exist.
                if ((string.Empty == column.DatabaseName || CatalogMatch(column.DatabaseName, table.DatabaseName)) &&
                    (string.Empty == column.SchemaName || CatalogMatch(column.SchemaName, table.SchemaName)) &&
                    (string.Empty == column.TableName || CatalogMatch(column.TableName, table.TableName)))
                {
                    return(table);
                }
            }

            Debug.Assert(false, "Why didn't we find a match for the column?");
            return(null);
        }
        private void Parse2(
            string statementText
            )
        {
//			Debug.WriteLine(statementText);

            PARSERSTATE parserState = PARSERSTATE.NOTHINGYET;

            Token[] namePart    = new Token[4];
            int     currentPart = 0;

            Token alias = Token.Null;

            TokenType lastTokenType = TokenType.Null;

            int parenLevel = 0;

//			bool			distinctFound;

            _columns = null;
            _tables  = null;

            Match match = SqlTokenParser.Match(statementText);
            Token token = TokenFromMatch(match);

            while (true)
            {
//				Debug.WriteLine(String.Format("{0,-15} {1,-17} {2} {3}", parserState, token.Type.ToString(), parenLevel, token.Value));

                switch (parserState)
                {
                case PARSERSTATE.DONE:
                    return;

                case PARSERSTATE.NOTHINGYET:
                    switch (token.Type)
                    {
                    case TokenType.Keyword_SELECT:
                        parserState = PARSERSTATE.SELECT;
                        break;

                    default:
                        Debug.Assert(false, "no state defined!!!!we should never be here!!!");
                        throw ADP.InvalidOperation(Res.GetString(Res.ADP_SQLParserInternalError));
                    }
                    break;

                case PARSERSTATE.SELECT:
                    switch (token.Type)
                    {
                    case TokenType.Identifier:
                    case TokenType.QuotedIdentifier:
                        parserState = PARSERSTATE.COLUMN;
                        currentPart = 0;
                        namePart[0] = token;
                        break;

                    case TokenType.Keyword_FROM:
                        parserState = PARSERSTATE.FROM;
                        break;

                    case TokenType.Other_Star:
                        parserState = PARSERSTATE.COLUMNALIAS;
                        currentPart = 0;
                        namePart[0] = token;
                        break;

                    case TokenType.Keyword_DISTINCT:
//								distinctFound = true;
                        break;

                    case TokenType.Keyword_ALL:
                        break;

                    case TokenType.Other_LeftParen:
                        parserState = PARSERSTATE.EXPRESSION;
                        parenLevel++;
                        break;

                    case TokenType.Other_RightParen:
                        throw ADP.SyntaxErrorMissingParenthesis();

                    default:
                        parserState = PARSERSTATE.EXPRESSION;
                        break;
                    }
                    break;

                case PARSERSTATE.COLUMN:
                    switch (token.Type)
                    {
                    case TokenType.Identifier:
                    case TokenType.QuotedIdentifier:
                        if (TokenType.Other_Period != lastTokenType)
                        {
                            parserState = PARSERSTATE.COLUMNALIAS;
                            alias       = token;
                        }
                        else
                        {
                            namePart[++currentPart] = token;
                        }
                        break;

                    case TokenType.Other_Period:
                        if (currentPart > 3)
                        {
                            throw ADP.SyntaxErrorTooManyNameParts();
                        }

                        break;

                    case TokenType.Other_Star:
                        parserState             = PARSERSTATE.COLUMNALIAS;
                        namePart[++currentPart] = token;
                        break;

                    case TokenType.Keyword_AS:
                        break;

                    case TokenType.Keyword_FROM:
                    case TokenType.Other_Comma:
                        parserState = (token.Type == TokenType.Keyword_FROM) ? PARSERSTATE.FROM : PARSERSTATE.SELECT;
                        AddColumn(currentPart, namePart, alias);
                        currentPart = -1;
                        alias       = Token.Null;
                        break;

                    case TokenType.Other_LeftParen:
                        parserState = PARSERSTATE.EXPRESSION;
                        parenLevel++;
                        currentPart = -1;
                        break;

                    case TokenType.Other_RightParen:
                        throw ADP.SyntaxErrorMissingParenthesis();

                    default:
                        parserState = PARSERSTATE.EXPRESSION;
                        currentPart = -1;
                        break;
                    }
                    break;

                case PARSERSTATE.COLUMNALIAS:
                    switch (token.Type)
                    {
                    case TokenType.Keyword_FROM:
                    case TokenType.Other_Comma:
                        parserState = (token.Type == TokenType.Keyword_FROM) ? PARSERSTATE.FROM : PARSERSTATE.SELECT;
                        AddColumn(currentPart, namePart, alias);
                        currentPart = -1;
                        alias       = Token.Null;
                        break;

                    default:
                        throw ADP.SyntaxErrorExpectedCommaAfterColumn();
                    }
                    break;

                case PARSERSTATE.EXPRESSION:
                    switch (token.Type)
                    {
                    case TokenType.Identifier:
                    case TokenType.QuotedIdentifier:
                        if (0 == parenLevel)
                        {
                            alias = token;
                        }
                        break;

                    case TokenType.Keyword_FROM:
                    case TokenType.Other_Comma:
                        if (0 == parenLevel)
                        {
                            parserState = (token.Type == TokenType.Keyword_FROM) ? PARSERSTATE.FROM : PARSERSTATE.SELECT;
                            AddColumn(currentPart, namePart, alias);
                            currentPart = -1;
                            alias       = Token.Null;
                        }
                        else
                        {
                            if (token.Type == TokenType.Keyword_FROM)
                            {
                                throw ADP.SyntaxErrorUnexpectedFrom();
                            }
                        }
                        break;

                    case TokenType.Other_LeftParen:
                        parenLevel++;
                        break;

                    case TokenType.Other_RightParen:
                        parenLevel--;
                        break;
                    }
                    break;

                case PARSERSTATE.FROM:
                    switch (token.Type)
                    {
                    case TokenType.Identifier:
                    case TokenType.QuotedIdentifier:
                        parserState = PARSERSTATE.TABLE;
                        currentPart = 0;
                        namePart[0] = token;
                        break;

                    default:
                        throw ADP.SyntaxErrorExpectedIdentifier();
                    }
                    break;

                case PARSERSTATE.TABLE:
                    switch (token.Type)
                    {
                    case TokenType.Identifier:
                    case TokenType.QuotedIdentifier:
                        if (TokenType.Other_Period != lastTokenType)
                        {
                            parserState = PARSERSTATE.TABLEALIAS;
                            alias       = token;
                        }
                        else
                        {
                            namePart[++currentPart] = token;
                        }
                        break;

                    case TokenType.Other_Period:
                        if (currentPart > 2)
                        {
                            throw ADP.SyntaxErrorTooManyNameParts();
                        }

                        break;

                    case TokenType.Keyword_AS:
                        break;

                    case TokenType.Keyword_COMPUTE:
                    case TokenType.Keyword_FOR:
                    case TokenType.Keyword_GROUP:
                    case TokenType.Keyword_HAVING:
                    case TokenType.Keyword_INTERSECT:
                    case TokenType.Keyword_MINUS:
                    case TokenType.Keyword_ORDER:
                    case TokenType.Keyword_UNION:
                    case TokenType.Keyword_WHERE:
                    case TokenType.Null:

                    case TokenType.Other_Comma:
                        parserState = (TokenType.Other_Comma == token.Type) ? PARSERSTATE.FROM : PARSERSTATE.DONE;
                        AddTable(currentPart, namePart, alias);
                        currentPart = -1;
                        alias       = Token.Null;
                        break;

                    default:
                        throw ADP.SyntaxErrorExpectedNextPart();
                    }
                    break;

                case PARSERSTATE.TABLEALIAS:
                    switch (token.Type)
                    {
                    case TokenType.Keyword_COMPUTE:
                    case TokenType.Keyword_FOR:
                    case TokenType.Keyword_GROUP:
                    case TokenType.Keyword_HAVING:
                    case TokenType.Keyword_INTERSECT:
                    case TokenType.Keyword_MINUS:
                    case TokenType.Keyword_ORDER:
                    case TokenType.Keyword_UNION:
                    case TokenType.Keyword_WHERE:
                    case TokenType.Null:

                    case TokenType.Other_Comma:
                        parserState = (TokenType.Other_Comma == token.Type) ? PARSERSTATE.FROM : PARSERSTATE.DONE;
                        AddTable(currentPart, namePart, alias);
                        currentPart = -1;
                        alias       = Token.Null;
                        break;

                    default:
                        throw ADP.SyntaxErrorExpectedCommaAfterTable();
                    }
                    break;


                default:
                    Debug.Assert(false, "no state defined!!!!we should never be here!!!");
                    throw ADP.InvalidOperation(Res.GetString(Res.ADP_SQLParserInternalError));
                }

                lastTokenType = token.Type;

                match = match.NextMatch();
                token = TokenFromMatch(match);
            }
        }
        private void CompleteSchemaInformation()
        {
            DBSqlParserColumnCollection columns = Columns;
            DBSqlParserTableCollection  tables  = Tables;

            int columnCount = columns.Count;
            int tableCount  = tables.Count;

            // First, derive all of the information we can about each table
            for (int i = 0; i < tableCount; i++)
            {
                DBSqlParserTable            table        = tables[i];
                DBSqlParserColumnCollection tableColumns = GatherTableColumns(table);
                table.Columns = tableColumns;
            }

            // Next, derive all of the column information we can.
            for (int i = 0; i < columnCount; i++)
            {
                DBSqlParserColumn column = columns[i];
                DBSqlParserTable  table  = FindTableForColumn(column);

                if (!column.IsExpression)
                {
                    // If this is a '*' column, then we have to expand the '*' into
                    // its component parts.
                    if ("*" == column.ColumnName)
                    {
                        // Remove the existing "*" column entry and replace it with the
                        // complete list of columns in the table.
                        columns.RemoveAt(i);

                        // If this is a tablename.* column, then add references to the
                        // all columns in the specified table, otherwise add references
                        // to all columns in all tables.
                        if (String.Empty != column.TableName)
                        {
                            DBSqlParserColumnCollection tableColumns = table.Columns;
                            int tableColumnCount = tableColumns.Count;

                            for (int j = 0; j < tableColumnCount; ++j)
                            {
                                columns.Insert(i + j, tableColumns[j]);
                            }
                            columnCount += tableColumnCount - 1;                                // don't forget to adjust our loop end
                            i           += tableColumnCount - 1;
                        }
                        else
                        {
                            for (int k = 0; k < tableCount; k++)
                            {
                                table = tables[k];

                                DBSqlParserColumnCollection tableColumns = table.Columns;
                                int tableColumnCount = tableColumns.Count;

                                for (int j = 0; j < tableColumnCount; ++j)
                                {
                                    columns.Insert(i + j, tableColumns[j]);
                                }
                                columnCount += tableColumnCount - 1;                                    // don't forget to adjust our loop end
                                i           += tableColumnCount;
                            }
                        }
                    }
                    else
                    {
                        // if this isn't a '*' column, we find the table that the column belongs
                        // to, and ask it's column collection for the completed column info (that
                        // contains information about key values, etc.)
                        DBSqlParserColumn completedColumn = FindCompletedColumn(table, column);

                        if (null != completedColumn)                         // MDAC 87152
                        {
                            column.CopySchemaInfoFrom(completedColumn);
                        }
                        else
                        {
                            column.CopySchemaInfoFrom(table);
                        }
                    }
                }
            }

            // Finally, derive the key column information for each table
            for (int i = 0; i < tableCount; i++)
            {
                DBSqlParserTable table = tables[i];
                GatherKeyColumns(table);
            }
        }