private ExpressionResult ResolveNullTestExpression(NullTestExpression expr)
        {
            var result = new NullTestExpressionResult(expr.Source)
            {
                TestType = expr.TestType
            };

            result.Argument = ResolveExpression(expr.Argument);
            return(result);
        }
        private EvalExpression ResolveExpression(QueryTreeDataInternal data, JToken expression, int?forcedRteNumber = null)
        {
            var exprType       = expression.First.Value <JProperty>().Name;
            var expressionData = expression?.First?.First;

            switch (exprType)
            {
            case "CONST":
            {
                var typeId = expressionData.SelectToken("consttype").Value <uint>();
                return(new ConstExpression(data)
                    {
                        TypeID = typeId,
                        DbType = PostgresDbTypeCovertUtility.Convert(EnumParsingSupport.ConvertUsingAttributeOrDefault <PostgresDbType, PostgresDbTypeIdentificationAttribute, long>(typeId, x => x.OID))
                    });
            }

            case "VAR":
            {
                var rteNumber       = forcedRteNumber.HasValue ? forcedRteNumber.Value : expressionData.SelectToken("varnoold").Value <int>();
                var attributeNumber = expressionData.SelectToken("varoattno").Value <int>();
                var levelUpIndex    = expressionData.SelectToken("varlevelsup").Value <int>();
                var typeId          = expressionData.SelectToken("vartype").Value <uint>();
                var dataToUse       = data;
                if (levelUpIndex > 0)
                {
                    for (int i = 0; i < levelUpIndex; i++)
                    {
                        dataToUse = dataToUse.Parent;
                    }
                }
                return(new VariableExpression(dataToUse, rteNumber, attributeNumber)
                    {
                        TypeID = typeId,
                        DbType = PostgresDbTypeCovertUtility.Convert(EnumParsingSupport.ConvertUsingAttributeOrDefault <PostgresDbType, PostgresDbTypeIdentificationAttribute, long>(typeId, x => x.OID))
                    });
            }

            case "RELABELTYPE":
            {
                var typeId = expressionData.SelectToken("resulttype").Value <uint>();
                expressionData = expressionData.SelectToken("arg");
                if (expressionData?.First?.Value <JProperty>().Name == "VAR")
                {
                    expressionData = expressionData.First.First;
                    var rteNumber       = forcedRteNumber.HasValue ? forcedRteNumber.Value : expressionData.SelectToken("varnoold").Value <int>();
                    var attributeNumber = expressionData.SelectToken("varoattno").Value <int>();
                    var levelUpIndex    = expressionData.SelectToken("varlevelsup").Value <int>();
                    var dataToUse       = data;
                    if (levelUpIndex > 0)
                    {
                        for (int i = 0; i < levelUpIndex; i++)
                        {
                            dataToUse = dataToUse.Parent;
                        }
                    }
                    return(new VariableExpression(dataToUse, rteNumber, attributeNumber)
                        {
                            TypeID = typeId,
                            DbType = PostgresDbTypeCovertUtility.Convert(EnumParsingSupport.ConvertUsingAttributeOrDefault <PostgresDbType, PostgresDbTypeIdentificationAttribute, long>(typeId, x => x.OID))
                        });
                }
                break;
            }

            case "FUNCEXPR":
            {
                var typeId = expressionData.SelectToken("funcresulttype").Value <uint>();
                var result = new FunctionExpression(data)
                {
                    ResultTypeID = typeId,
                    ResultDbType = PostgresDbTypeCovertUtility.Convert(EnumParsingSupport.ConvertUsingAttributeOrDefault <PostgresDbType, PostgresDbTypeIdentificationAttribute, long>(typeId, x => x.OID))
                };
                foreach (var argExpr in expressionData.SelectToken("args").Children())
                {
                    result.Arguments.Add(ResolveExpression(data, argExpr, forcedRteNumber));
                }
                return(result);
            }

            case "SUBLINK":
            {
                return(new SublinkExpression(data)
                    {
                        SubQuery = ProcessQuery(data, expressionData.SelectToken("subselect"))
                    });
            }

            case "BOOLEXPR":
            {
                var result = new BooleanExpression(data);
                result.Operator = expressionData.SelectToken("boolop").Value <string>();
                foreach (var argExpr in expressionData.SelectToken("args").Children())
                {
                    result.Arguments.Add(ResolveExpression(data, argExpr, forcedRteNumber));
                }
                return(result);
            }

            case "OPEXPR":
            {
                var typeId = expressionData.SelectToken("opresulttype").Value <uint>();
                var result = new OperatorExpression(data)
                {
                    ResultTypeID = typeId,
                    ResultDbType = PostgresDbTypeCovertUtility.Convert(EnumParsingSupport.ConvertUsingAttributeOrDefault <PostgresDbType, PostgresDbTypeIdentificationAttribute, long>(typeId, x => x.OID))
                };
                result.OperatorID = expressionData.SelectToken("opno").Value <uint>();
                foreach (var argExpr in expressionData.SelectToken("args").Children())
                {
                    result.Arguments.Add(ResolveExpression(data, argExpr, forcedRteNumber));
                }
                return(result);
            }

            case "AGGREF":
            {
                var result = new AggregateExpression(data);
                foreach (var argExpr in expressionData.SelectToken("args").Children())
                {
                    result.Arguments.Add(ResolveExpression(data, argExpr, forcedRteNumber));
                }
                return(result);
            }

            case "TARGETENTRY":
            {
                var expr = expressionData.SelectToken("expr");
                return(ResolveExpression(data, expr, forcedRteNumber));
            }

            case "SCALARARRAYOPEXPR":
            {
                var result = new OperatorExpression(data);
                result.OperatorID = expressionData.SelectToken("opno").Value <uint>();
                foreach (var argExpr in expressionData.SelectToken("args").Children())
                {
                    result.Arguments.Add(ResolveExpression(data, argExpr, forcedRteNumber));
                }
                return(result);
            }

            case "NULLTEST":
            {
                var result = new NullTestExpression(data);
                result.TestType = EnumParsingSupport.ConvertFromNumericOrDefault <NullTestType>(expressionData.SelectToken("nulltesttype").Value <int>());
                result.Argument = ResolveExpression(data, expressionData.SelectToken("arg"), forcedRteNumber);
                return(result);
            }

            case "SORTGROUPCLAUSE":
            {
                var tleSortGroupRef = expressionData.SelectToken("tleSortGroupRef").Value <int>();
                if (tleSortGroupRef > 0)
                {
                    var query = expression.Parent.Parent.Parent;
                    foreach (var t in query.SelectToken("targetList").Children())
                    {
                        if (tleSortGroupRef == t.First.First.SelectToken("ressortgroupref").Value <int>())
                        {
                            var expr = t.First.First.SelectToken("expr");
                            return(ResolveExpression(data, expr));
                        }
                    }
                }
                break;
            }
            }
            return(new UnknownExpression(data));
        }