} // select()

        public Query where (SelectItem selectItem, OperatorType operatorType, object operand)
        {
            return(where (new FilterItem(selectItem, operatorType, operand)));
        } // where()
        } // _QueryPartProcessor_FindFilterItem_impl_ class

        private FilterItem findFilterItem(string expression)
        {
            string upperExpression = expression.ToUpper();

            QueryPartCollectionProcessor collectionProcessor = new QueryPartCollectionProcessor();

            new QueryPartParser(collectionProcessor, expression, " AND ", " OR ").parse();

            List <String> tokens = collectionProcessor.getTokens();
            List <String> delims = collectionProcessor.getDelims();

            if (tokens.Count == 1)
            {
                expression      = tokens[0];
                upperExpression = expression.ToUpper();
            }
            else
            {
                //[J2N]  LogicalOperator.valueOf() <=> Enum.Parse(typeof(LogicalOperator), value)
                LogicalOperator logicalOperator = (LogicalOperator)Enum.Parse(typeof(LogicalOperator), delims[1].Trim());

                NList <FilterItem> filterItems = new NList <FilterItem>();
                for (int i = 0; i < tokens.Count; i++)
                {
                    string     token      = tokens[i];
                    FilterItem filterItem = findFilterItem(token);
                    filterItems.Add(filterItem);
                }
                return(new FilterItem(logicalOperator, filterItems));
            }

            //[J2Cc] operator identifier (a keyword in C#) => operator_var
            OperatorType operator_var = null;
            string       leftSide     = null;
            string       rightSide;

            {
                string         rightSideCandidate = null;
                OperatorType[] operators          = OperatorType.BUILT_IN_OPERATORS;
                foreach (OperatorType operatorCandidate in operators)
                {
                    string searchStr;
                    if (operatorCandidate.isSpaceDelimited())
                    {
                        searchStr = ' ' + operatorCandidate.toSql() + ' ';
                    }
                    else
                    {
                        searchStr = operatorCandidate.toSql();
                    }
                    int operatorIndex = upperExpression.IndexOf(searchStr);
                    if (operatorIndex > 0)
                    {
                        operator_var       = operatorCandidate;
                        leftSide           = expression.Substring(0, operatorIndex).Trim();
                        rightSideCandidate = expression.Substring(operatorIndex + searchStr.Length).Trim();
                        break;
                    }
                }

                if (operator_var == null)
                {
                    // check special cases for IS NULL and IS NOT NULL
                    if (expression.EndsWith(" IS NOT NULL"))
                    {
                        operator_var       = OperatorType.DIFFERENT_FROM;
                        leftSide           = expression.Substring(0, expression.LastIndexOf(" IS NOT NULL")).Trim();
                        rightSideCandidate = "NULL";
                    }
                    else if (expression.EndsWith(" IS NULL"))
                    {
                        operator_var       = OperatorType.EQUALS_TO;
                        leftSide           = expression.Substring(0, expression.LastIndexOf(" IS NULL")).Trim();
                        rightSideCandidate = "NULL";
                    }
                }

                rightSide = rightSideCandidate;
            }

            if (operator_var == null)
            {
                return(new FilterItem(expression));
            }

            SelectItem selectItem = findSelectItem(leftSide, false);

            if (selectItem == null)
            {
                return(new FilterItem(expression));
            }

            Object operand = null;

            if (operator_var == OperatorType.IN)
            {
                List <Object> list = new List <Object>();
                new QueryPartParser(new _QueryPartProcessor_FindFilterItem_impl_(this, list, operand, selectItem), rightSide, ",").parse();
                operand = list;
            }
            else
            {
                operand = createOperand(rightSide, selectItem, true);
            }

            return(new FilterItem(selectItem, operator_var, operand));
        } // findFilterItem()
        } // having()

        public Query having(FunctionType function, Column column, OperatorType operatorType, object operand)
        {
            SelectItem selectItem = new SelectItem(function, column);

            return(having(new FilterItem(selectItem, operatorType, operand)));
        }  // having()