} // parseAllJoinItems()

        // this method will be documented based on this example itemToken: FOO f
        // INNER JOIN BAR b ON f.id = b.id
        private FromItem parseJoinItem(FromItem leftFromItem, String itemToken, HashSet <FromItem> fromItems)
        {
            int indexOfJoin = itemToken.ToUpper().IndexOf(" JOIN ");

            // firstPart = "FOO f INNER"
            String firstPart = itemToken.Substring(0, indexOfJoin).Trim();

            // secondPart = "BAR b ON f.id = b.id"
            String secondPart = itemToken.Substring(indexOfJoin + " JOIN ".Length).Trim();

            int indexOfJoinType = firstPart.LastIndexOf(" ");

            // joinTypeString = "INNER"
            String   joinTypeString = firstPart.Substring(indexOfJoinType).Trim().ToUpper();
            JoinType joinType       = (JoinType)Enum.Parse(typeof(JoinType), joinTypeString);

            // firstTableToken = "FOO f"
            String firstTableToken = firstPart.Substring(0, indexOfJoinType).Trim();

            int indexOfOn = secondPart.ToUpper().IndexOf(" ON ");

            // secondTableToken = "BAR b"
            String secondTableToken = secondPart.Substring(0, indexOfOn).Trim();

            FromItem leftSide  = parseTableItem(firstTableToken);
            FromItem rightSide = parseTableItem(secondTableToken);

            fromItems.Add(leftSide);
            fromItems.Add(rightSide);

            // onClausess = ["f.id = b.id"]
            String[]     separators = { " AND " };
            String[]     onClauses  = secondPart.Substring(indexOfOn + " ON ".Length).Split(separators, StringSplitOptions.RemoveEmptyEntries);
            SelectItem[] leftOn     = new SelectItem[onClauses.Length];
            SelectItem[] rightOn    = new SelectItem[onClauses.Length];
            for (int i = 0; i < onClauses.Length; i++)
            {
                String onClause      = onClauses[i];
                int    indexOfEquals = onClause.IndexOf("=");
                // leftPart = "f.id"
                String leftPart = onClause.Substring(0, indexOfEquals).Trim();
                // rightPart = "b.id"
                String rightPart = onClause.Substring(indexOfEquals + 1).Trim();

                FromItem[] items = new FromItem[fromItems.Count];
                fromItems.CopyTo(items);
                leftOn[i]  = findSelectItem(leftPart, items);
                rightOn[i] = findSelectItem(rightPart, items);
            }

            FromItem leftItem = (leftFromItem != null) ? leftFromItem : leftSide;
            FromItem result   = new FromItem(joinType, leftItem, rightSide, leftOn, rightOn);

            result.setQuery(_query);
            return(result);
        } // parseJoinItem()
        } // parse()

        private FromItem parseTableItem(String itemToken)
        {
            // From token can be starting with [
            String tableNameToken;
            String aliasToken;

            char startDelimiter = itemToken.Trim()[0];

            if (delimiterMap.ContainsKey(startDelimiter))
            {
                char endDelimiter = delimiterMap[startDelimiter];
                int  endIndex     = itemToken.Trim().LastIndexOf(endDelimiter, itemToken.Trim().Length);
                if (endIndex <= 0)
                {
                    throw new QueryParserException("Not capable of parsing FROM token: " + itemToken + ". Expected end "
                                                   + endDelimiter);
                }
                tableNameToken = itemToken.Trim().Substring(1, endIndex).Trim();

                if (itemToken.Trim().Substring(1 + endIndex).Trim().Equals("", StringComparison.CurrentCultureIgnoreCase))
                {
                    /*
                     * As per code in FromClause Method: getItemByReference(FromItem
                     * item, String reference) if (alias == null && table != null &&
                     * reference.equals(table.getName())) { Either we have to change
                     * the code to add alias.equals("") there or return null here.
                     */
                    aliasToken = null;
                }
                else
                {
                    aliasToken = itemToken.Trim().Substring(1 + endIndex).Trim();
                }
            }
            else
            {
                // Default assumption is space being delimiter for tablename and
                // alias.. If otherwise use DoubleQuotes or [] around tableName
                String[] tokens = itemToken.Split(' ');
                tableNameToken = tokens[0];
                if (tokens.Length == 2)
                {
                    aliasToken = tokens[1];
                }
                else if (tokens.Length == 1)
                {
                    aliasToken = null;
                }
                else
                {
                    throw new QueryParserException("Not capable of parsing FROM token: " + itemToken);
                }
            }

            Table table = _dataContext.getTableByQualifiedLabel(tableNameToken);

            if (table == null)
            {
                throw new QueryParserException("Not capable of parsing FROM token: " + itemToken);
            }

            FromItem result = new FromItem(table);

            result.setAlias(aliasToken);
            result.setQuery(_query);
            return(result);
        } // parseTableItem()