/// <summary>
        /// Query datas
        /// </summary>
        /// <typeparam name="T">Data type</typeparam>
        /// <param name="server">Database server</param>
        /// <param name="command">Command</param>
        /// <returns>Return datas</returns>
        public async Task <IEnumerable <T> > QueryAsync <T>(DatabaseServer server, ICommand command)
        {
            if (command.Query == null)
            {
                throw new EZNEWException($"{nameof(ICommand.Query)} is null");
            }

            #region query translation

            IQueryTranslator translator = PostgreSqlManager.GetQueryTranslator(DataAccessContext.Create(server, command));
            var    tranResult           = translator.Translate(command.Query);
            string joinScript           = tranResult.AllowJoin ? tranResult.JoinScript : string.Empty;

            #endregion

            #region script

            string cmdText;
            switch (command.Query.ExecutionMode)
            {
            case QueryExecutionMode.Text:
                cmdText = tranResult.ConditionString;
                break;

            case QueryExecutionMode.QueryObject:
            default:
                int    size                = command.Query.QuerySize;
                string objectName          = translator.DataAccessContext.GetCommandEntityObjectName(command);
                string sortString          = string.IsNullOrWhiteSpace(tranResult.SortString) ? string.Empty : $"ORDER BY {tranResult.SortString}";
                var    queryFields         = PostgreSqlManager.GetQueryFields(command.Query, command.EntityType, true);
                string outputFormatedField = string.Join(",", PostgreSqlManager.FormatQueryFields(translator.ObjectPetName, queryFields, true));
                if (string.IsNullOrWhiteSpace(tranResult.CombineScript))
                {
                    cmdText = $"{tranResult.PreScript}SELECT {outputFormatedField} FROM {PostgreSqlManager.WrapKeyword(objectName)} AS {translator.ObjectPetName} {joinScript} {(string.IsNullOrWhiteSpace(tranResult.ConditionString) ? string.Empty : $"WHERE {tranResult.ConditionString}")} {sortString} {(size > 0 ? $"LIMIT {size} OFFSET 0" : string.Empty)}";
                }
        /// <summary>
        /// Get database deletion command
        /// </summary>
        /// <param name="translator">Query translator</param>
        /// <param name="command">Command</param>
        /// <returns>Return a database deletion command</returns>
        DatabaseExecutionCommand GetDatabaseDeletionCommand(IQueryTranslator translator, DefaultCommand command)
        {
            translator.DataAccessContext.SetCommand(command);

            #region query translation

            var    tranResult      = translator.Translate(command.Query);
            string conditionString = string.Empty;
            if (!string.IsNullOrWhiteSpace(tranResult.ConditionString))
            {
                conditionString += "WHERE " + tranResult.ConditionString;
            }
            string preScript  = tranResult.PreScript;
            string joinScript = tranResult.AllowJoin ? tranResult.JoinScript : string.Empty;

            #endregion

            #region script

            string objectName = translator.DataAccessContext.GetCommandEntityObjectName(command);
            string cmdText;
            string wrapObjectName = PostgreSqlManager.WrapKeyword(objectName);
            if (string.IsNullOrWhiteSpace(joinScript))
            {
                cmdText = $"{preScript}DELETE FROM {wrapObjectName} AS {translator.ObjectPetName} {conditionString};";
            }
            else
            {
                string deleteTableShortName     = "DTB";
                string deleteJoinTableShortName = "DJTB";
                var    primaryKeyFormatedResult = FormatWrapJoinPrimaryKeys(command.EntityType, translator.ObjectPetName, deleteTableShortName, deleteJoinTableShortName);
                cmdText = $"{preScript}DELETE FROM {wrapObjectName} AS {deleteTableShortName} USING (SELECT {string.Join(",", primaryKeyFormatedResult.Item1)} FROM {wrapObjectName} AS {translator.ObjectPetName} {joinScript} {conditionString}) AS {deleteJoinTableShortName} WHERE {string.Join(" AND ", primaryKeyFormatedResult.Item2)};";
            }

            #endregion

            #region parameter

            CommandParameters parameters = PostgreSqlManager.ConvertParameter(command.Parameters) ?? new CommandParameters();
            var queryParameters          = PostgreSqlManager.ConvertParameter(tranResult.Parameters);
            parameters.Union(queryParameters);

            #endregion

            return(new DatabaseExecutionCommand()
            {
                CommandText = cmdText,
                CommandType = PostgreSqlManager.GetCommandType(command),
                MustAffectedData = command.MustAffectedData,
                Parameters = parameters,
                HasPreScript = !string.IsNullOrWhiteSpace(preScript)
            });
        }
        /// <summary>
        /// Execute database command
        /// </summary>
        /// <param name="server">Database server</param>
        /// <param name="executionOptions">Execution options</param>
        /// <param name="databaseExecutionCommands">Database execution commands</param>
        /// <param name="useTransaction">Whether use transaction</param>
        /// <returns>Return affected data number</returns>
        async Task <int> ExecuteDatabaseCommandAsync(DatabaseServer server, CommandExecutionOptions executionOptions, IEnumerable <DatabaseExecutionCommand> databaseExecutionCommands, bool useTransaction)
        {
            int  resultValue = 0;
            bool success     = true;

            using (var conn = PostgreSqlManager.GetConnection(server))
            {
                IDbTransaction transaction = null;
                if (useTransaction)
                {
                    transaction = PostgreSqlManager.GetExecutionTransaction(conn, executionOptions);
                }
                try
                {
                    foreach (var cmd in databaseExecutionCommands)
                    {
                        var cmdDefinition      = new CommandDefinition(cmd.CommandText, PostgreSqlManager.ConvertCmdParameters(cmd.Parameters), transaction: transaction, commandType: cmd.CommandType, cancellationToken: executionOptions?.CancellationToken ?? default);
                        var executeResultValue = await conn.ExecuteAsync(cmdDefinition).ConfigureAwait(false);

                        success      = success && (cmd.MustAffectedData ? executeResultValue > 0 : true);
                        resultValue += executeResultValue;
                        if (useTransaction && !success)
                        {
                            break;
                        }
                    }
                    if (!useTransaction)
                    {
                        return(resultValue);
                    }
                    if (success)
                    {
                        transaction.Commit();
                    }
                    else
                    {
                        resultValue = 0;
                        transaction.Rollback();
                    }
                    return(resultValue);
                }
                catch (Exception ex)
                {
                    resultValue = 0;
                    transaction?.Rollback();
                    throw ex;
                }
            }
        }
        Tuple <IEnumerable <string>, IEnumerable <string> > FormatWrapJoinFields(IEnumerable <EntityField> fields, string translatorObjectPetName, string sourceObjectPetName, string targetObjectPetName)
        {
            var joinItems = fields.Select(field =>
            {
                string fieldName = PostgreSqlManager.WrapKeyword(field.FieldName);
                return($"{sourceObjectPetName}.{fieldName} = {targetObjectPetName}.{fieldName}");
            });
            var queryItems = fields.Select(field =>
            {
                string fieldName = PostgreSqlManager.WrapKeyword(field.FieldName);
                return($"{translatorObjectPetName}.{fieldName}");
            });

            return(new Tuple <IEnumerable <string>, IEnumerable <string> >(queryItems, joinItems));
        }
        /// <summary>
        /// Get database execution command
        /// </summary>
        /// <param name="queryTranslator">Query translator</param>
        /// <param name="command">Command</param>
        /// <returns>Return a database execution command</returns>
        DatabaseExecutionCommand GetDatabaseExecutionCommand(IQueryTranslator queryTranslator, DefaultCommand command)
        {
            DatabaseExecutionCommand GetTextCommand()
            {
                return(new DatabaseExecutionCommand()
                {
                    CommandText = command.Text,
                    Parameters = PostgreSqlManager.ConvertParameter(command.Parameters),
                    CommandType = PostgreSqlManager.GetCommandType(command),
                    MustAffectedData = command.MustAffectedData,
                    HasPreScript = true
                });
            }

            if (command.ExecutionMode == CommandExecutionMode.CommandText)
            {
                return(GetTextCommand());
            }
            DatabaseExecutionCommand executionCommand;

            switch (command.OperationType)
            {
            case CommandOperationType.Insert:
                executionCommand = GetDatabaseInsertionCommand(queryTranslator, command);
                break;

            case CommandOperationType.Update:
                executionCommand = GetDatabaseUpdateCommand(queryTranslator, command);
                break;

            case CommandOperationType.Delete:
                executionCommand = GetDatabaseDeletionCommand(queryTranslator, command);
                break;

            default:
                executionCommand = GetTextCommand();
                break;
            }
            return(executionCommand);
        }
        public FieldConversionResult Convert(FieldConversionContext fieldConversionContext)
        {
            if (string.IsNullOrWhiteSpace(fieldConversionContext?.ConversionName))
            {
                return(null);
            }
            string formatedFieldName;

            switch (fieldConversionContext.ConversionName)
            {
            case FieldConversionNames.StringLength:
                formatedFieldName = string.IsNullOrWhiteSpace(fieldConversionContext.ObjectName)
                                        ? $"CHAR_LENGTH({fieldConversionContext.ObjectName}.{PostgreSqlManager.WrapKeyword(fieldConversionContext.FieldName)})"
                                        : $"CHAR_LENGTH({PostgreSqlManager.WrapKeyword(fieldConversionContext.FieldName)})";
                break;

            default:
                throw new EZNEWException($"{PostgreSqlManager.CurrentDatabaseServerType} does not support field conversion: {fieldConversionContext.ConversionName}");
            }
            return(new FieldConversionResult()
            {
                NewFieldName = formatedFieldName
            });
        }
        /// <summary>
        /// Get database insertion execution command
        /// </summary>
        /// <param name="translator">Query translator</param>
        /// <param name="command">Command</param>
        /// <returns>Return a database insertion command</returns>
        DatabaseExecutionCommand GetDatabaseInsertionCommand(IQueryTranslator translator, DefaultCommand command)
        {
            translator.DataAccessContext.SetCommand(command);
            string objectName         = translator.DataAccessContext.GetCommandEntityObjectName(command);
            var    fields             = DataManager.GetEditFields(CurrentDatabaseServerType, command.EntityType);
            var    fieldCount         = fields.GetCount();
            var    insertFormatResult = PostgreSqlManager.FormatInsertionFields(command.EntityType, fieldCount, fields, command.Parameters, translator.ParameterSequence);

            if (insertFormatResult == null)
            {
                return(null);
            }
            string            cmdText    = $"INSERT INTO {PostgreSqlManager.WrapKeyword(objectName)} ({string.Join(",", insertFormatResult.Item1)}) VALUES ({string.Join(",", insertFormatResult.Item2)});";
            CommandParameters parameters = insertFormatResult.Item3;

            translator.ParameterSequence += fieldCount;
            return(new DatabaseExecutionCommand()
            {
                CommandText = cmdText,
                CommandType = PostgreSqlManager.GetCommandType(command),
                MustAffectedData = command.MustAffectedData,
                Parameters = parameters
            });
        }
        /// <summary>
        /// Execute command
        /// </summary>
        /// <param name="server">Database server</param>
        /// <param name="executionOptions">Execution options</param>
        /// <param name="commands">Commands</param>
        /// <returns>Return the affected data numbers</returns>
        public async Task <int> ExecuteAsync(DatabaseServer server, CommandExecutionOptions executionOptions, IEnumerable <ICommand> commands)
        {
            #region group execution commands

            IQueryTranslator translator = PostgreSqlManager.GetQueryTranslator(DataAccessContext.Create(server));
            List <DatabaseExecutionCommand> databaseExecutionCommands = new List <DatabaseExecutionCommand>();
            var batchExecutionConfig = DataManager.GetBatchExecutionConfiguration(server.ServerType) ?? BatchExecutionConfiguration.Default;
            var groupStatementsCount = batchExecutionConfig.GroupStatementsCount;
            groupStatementsCount = groupStatementsCount < 0 ? 1 : groupStatementsCount;
            var groupParameterCount = batchExecutionConfig.GroupParametersCount;
            groupParameterCount = groupParameterCount < 0 ? 1 : groupParameterCount;
            StringBuilder     commandTextBuilder = new StringBuilder();
            CommandParameters parameters         = null;
            int  statementsCount  = 0;
            bool forceReturnValue = false;
            int  cmdCount         = 0;

            DatabaseExecutionCommand GetGroupExecuteCommand()
            {
                var executionCommand = new DatabaseExecutionCommand()
                {
                    CommandText      = commandTextBuilder.ToString(),
                    CommandType      = CommandType.Text,
                    MustAffectedData = forceReturnValue,
                    Parameters       = parameters
                };

                statementsCount = 0;
                translator.ParameterSequence = 0;
                commandTextBuilder.Clear();
                parameters       = null;
                forceReturnValue = false;
                return(executionCommand);
            }

            foreach (var cmd in commands)
            {
                DatabaseExecutionCommand databaseExecutionCommand = GetDatabaseExecutionCommand(translator, cmd as DefaultCommand);
                if (databaseExecutionCommand == null)
                {
                    continue;
                }

                //Trace log
                PostgreSqlManager.LogExecutionCommand(databaseExecutionCommand);

                cmdCount++;
                if (databaseExecutionCommand.PerformAlone)
                {
                    if (statementsCount > 0)
                    {
                        databaseExecutionCommands.Add(GetGroupExecuteCommand());
                    }
                    databaseExecutionCommands.Add(databaseExecutionCommand);
                    continue;
                }
                commandTextBuilder.AppendLine(databaseExecutionCommand.CommandText);
                parameters        = parameters == null ? databaseExecutionCommand.Parameters : parameters.Union(databaseExecutionCommand.Parameters);
                forceReturnValue |= databaseExecutionCommand.MustAffectedData;
                statementsCount++;
                if (translator.ParameterSequence >= groupParameterCount || statementsCount >= groupStatementsCount)
                {
                    databaseExecutionCommands.Add(GetGroupExecuteCommand());
                }
            }
            if (statementsCount > 0)
            {
                databaseExecutionCommands.Add(GetGroupExecuteCommand());
            }

            #endregion

            return(await ExecuteDatabaseCommandAsync(server, executionOptions, databaseExecutionCommands, executionOptions?.ExecutionByTransaction ?? cmdCount > 1).ConfigureAwait(false));
        }
        /// <summary>
        /// Get database update command
        /// </summary>
        /// <param name="translator">Query translator</param>
        /// <param name="command">Command</param>
        /// <returns>Return a database update command</returns>
        DatabaseExecutionCommand GetDatabaseUpdateCommand(IQueryTranslator translator, DefaultCommand command)
        {
            if (command?.Fields.IsNullOrEmpty() ?? true)
            {
                throw new EZNEWException($"No fields are set to update");
            }

            #region query translation

            translator.DataAccessContext.SetCommand(command);
            var    tranResult      = translator.Translate(command.Query);
            string conditionString = string.Empty;
            if (!string.IsNullOrWhiteSpace(tranResult.ConditionString))
            {
                conditionString += "WHERE " + tranResult.ConditionString;
            }
            string preScript  = tranResult.PreScript;
            string joinScript = tranResult.AllowJoin ? tranResult.JoinScript : string.Empty;

            #endregion

            #region script

            CommandParameters parameters    = PostgreSqlManager.ConvertParameter(command.Parameters) ?? new CommandParameters();
            string            objectName    = translator.DataAccessContext.GetCommandEntityObjectName(command);
            var           fields            = PostgreSqlManager.GetFields(command.EntityType, command.Fields);
            int           parameterSequence = translator.ParameterSequence;
            List <string> updateSetArray    = new List <string>();
            foreach (var field in fields)
            {
                var    parameterValue     = parameters.GetParameterValue(field.PropertyName);
                var    parameterName      = field.PropertyName;
                string newValueExpression = string.Empty;
                if (parameterValue != null)
                {
                    parameterSequence++;
                    parameterName = PostgreSqlManager.FormatParameterName(parameterName, parameterSequence);
                    parameters.Rename(field.PropertyName, parameterName);
                    if (parameterValue is IModificationValue)
                    {
                        var modifyValue = parameterValue as IModificationValue;
                        parameters.ModifyValue(parameterName, modifyValue.Value);
                        if (parameterValue is CalculationModificationValue)
                        {
                            var    calculateModifyValue = parameterValue as CalculationModificationValue;
                            string calChar = PostgreSqlManager.GetSystemCalculationOperator(calculateModifyValue.Operator);
                            newValueExpression = $"{translator.ObjectPetName}.{PostgreSqlManager.WrapKeyword(field.FieldName)}{calChar}{PostgreSqlManager.ParameterPrefix}{parameterName}";
                        }
                    }
                }
                if (string.IsNullOrWhiteSpace(newValueExpression))
                {
                    newValueExpression = $"{PostgreSqlManager.ParameterPrefix}{parameterName}";
                }
                updateSetArray.Add($"{PostgreSqlManager.WrapKeyword(field.FieldName)}={newValueExpression}");
            }
            string cmdText;
            string wrapObjName = PostgreSqlManager.WrapKeyword(objectName);
            if (string.IsNullOrWhiteSpace(joinScript))
            {
                cmdText = $"{preScript}UPDATE {wrapObjName} AS {translator.ObjectPetName} SET {string.Join(",", updateSetArray)} {conditionString};";
            }
            else
            {
                string updateTableShortName     = translator.ObjectPetName;
                string updateJoinTableShortName = "UJTB";
                var    primaryKeyFormatedResult = FormatWrapJoinPrimaryKeys(command.EntityType, translator.ObjectPetName, updateTableShortName, updateJoinTableShortName);
                cmdText = $"{preScript}UPDATE {wrapObjName} AS {updateTableShortName} SET {string.Join(",", updateSetArray)} FROM (SELECT {string.Join(",", primaryKeyFormatedResult.Item1)} FROM {wrapObjName} AS {translator.ObjectPetName} {joinScript} {conditionString}) AS {updateJoinTableShortName} WHERE {string.Join(" AND ", primaryKeyFormatedResult.Item2)};";
            }
            translator.ParameterSequence = parameterSequence;

            #endregion

            #region parameter

            var queryParameters = PostgreSqlManager.ConvertParameter(tranResult.Parameters);
            parameters.Union(queryParameters);

            #endregion

            return(new DatabaseExecutionCommand()
            {
                CommandText = cmdText,
                CommandType = PostgreSqlManager.GetCommandType(command),
                MustAffectedData = command.MustAffectedData,
                Parameters = parameters,
                HasPreScript = !string.IsNullOrWhiteSpace(preScript)
            });
        }
        /// <summary>
        /// Execute translation
        /// </summary>
        /// <param name="query">Query object</param>
        /// <param name="location">Query location</param>
        /// <param name="parameters">Parameters</param>
        /// <param name="objectName">Entity object name</param>
        /// <param name="useSort">Indicates whether use sort</param>
        /// <returns>Return a translation result</returns>
        public QueryTranslationResult ExecuteTranslation(IQuery query, QueryLocation location, CommandParameters parameters = null, string objectName = "", bool useSort = true)
        {
            if (query == null)
            {
                return(QueryTranslationResult.Empty);
            }
            StringBuilder conditionBuilder = new StringBuilder();

            if (query.ExecutionMode == QueryExecutionMode.QueryObject)
            {
                StringBuilder sortBuilder = new StringBuilder();
                parameters = parameters ?? new CommandParameters();
                objectName = string.IsNullOrWhiteSpace(objectName) ? DefaultObjectPetName : objectName;
                List <string> withScripts         = new List <string>();
                string        recurveTableName    = string.Empty;
                string        recurveTablePetName = string.Empty;

                #region condition

                if (!query.Conditions.IsNullOrEmpty())
                {
                    int index = 0;
                    foreach (var condition in query.Conditions)
                    {
                        var queryItemCondition = TranslateCondition(query, condition, parameters, objectName);
                        if (!queryItemCondition.WithScripts.IsNullOrEmpty())
                        {
                            withScripts.AddRange(queryItemCondition.WithScripts);
                            recurveTableName    = queryItemCondition.RecurveObjectName;
                            recurveTablePetName = queryItemCondition.RecurvePetName;
                        }
                        conditionBuilder.Append($" {(index > 0 ? condition.Connector.ToString().ToUpper() : string.Empty)} {queryItemCondition.ConditionString}");
                        index++;
                    }
                }

                #endregion

                #region sort

                if (useSort && !query.Sorts.IsNullOrEmpty())
                {
                    foreach (var orderItem in query.Sorts)
                    {
                        sortBuilder.Append($"{ConvertOrderCriterionName(query, objectName, orderItem)} {(orderItem.Desc ? DescKeyWord : AscKeyWord)},");
                    }
                }

                #endregion

                #region combine

                StringBuilder combineBuilder = new StringBuilder();
                if (!query.Combines.IsNullOrEmpty())
                {
                    foreach (var combineEntry in query.Combines)
                    {
                        if (combineEntry?.Query == null)
                        {
                            continue;
                        }
                        switch (combineEntry.Type)
                        {
                        case CombineType.Except:
                            var exceptFields   = GetCombineFields(query, combineEntry.Query);
                            var exceptQuery    = QueryManager.Create().SetEntityType(query.GetEntityType()).IsNull(exceptFields.First());
                            var exceptJoinItem = new JoinEntry()
                            {
                                Type             = JoinType.LeftJoin,
                                JoinObjectFilter = combineEntry.Query,
                                JoinCriteria     = exceptFields.Select(pk =>
                                {
                                    var pkJoinField = new JoinField()
                                    {
                                        Name = pk,
                                        Type = JoinFieldType.Field
                                    };
                                    return(RegularJoinCriterion.Create(FieldInfo.Create(pk), CriterionOperator.Equal, FieldInfo.Create(pk)) as IJoinCriterion);
                                }).ToList(),
                                JoinObjectExtraFilter = exceptQuery
                            };
                            query.Join(exceptJoinItem);
                            break;

                        case CombineType.Intersect:
                            var intersectFields = GetCombineFields(query, combineEntry.Query);
                            query.Join(intersectFields.ToDictionary(c => c, c => c), JoinType.InnerJoin, CriterionOperator.Equal, combineEntry.Query);
                            break;

                        default:
                            var    combineObjectPetName   = GetNewSubObjectPetName();
                            string combineObjectName      = DataAccessContext.GetCombineEntityObjectName(combineEntry.Query);
                            var    combineQueryResult     = ExecuteTranslation(combineEntry.Query, QueryLocation.Combine, parameters, combineObjectPetName, true);
                            string combineConditionString = string.IsNullOrWhiteSpace(combineQueryResult.ConditionString) ? string.Empty : $"WHERE {combineQueryResult.ConditionString}";
                            combineBuilder.Append($" {GetCombineOperator(combineEntry.Type)} SELECT {string.Join(",", PostgreSqlManager.FormatQueryFields(combineObjectPetName, query, query.GetEntityType(), true, false))} FROM {PostgreSqlManager.WrapKeyword(combineObjectName)} AS {combineObjectPetName} {(combineQueryResult.AllowJoin ? combineQueryResult.JoinScript : string.Empty)} {combineConditionString}");
                            if (!combineQueryResult.WithScripts.IsNullOrEmpty())
                            {
                                withScripts.AddRange(combineQueryResult.WithScripts);
                                recurveTableName    = combineQueryResult.RecurveObjectName;
                                recurveTablePetName = combineQueryResult.RecurvePetName;
                            }
                            break;
                        }
                    }
                }

                #endregion

                #region join

                bool          allowJoin          = true;
                StringBuilder joinBuilder        = new StringBuilder();
                StringBuilder joinExtraCondition = new StringBuilder();
                if (!query.Joins.IsNullOrEmpty())
                {
                    foreach (var joinEntry in query.Joins)
                    {
                        if (joinEntry == null || joinEntry.JoinObjectFilter == null)
                        {
                            continue;
                        }
                        if (joinEntry.JoinObjectFilter.GetEntityType() == null)
                        {
                            throw new EZNEWException("IQuery object must set entity type if use in join operation");
                        }
                        string joinObjectPetName = GetNewSubObjectPetName();
                        var    joinQueryResult   = ExecuteTranslation(joinEntry.JoinObjectFilter, QueryLocation.Join, parameters, joinObjectPetName, true);
                        if (string.IsNullOrWhiteSpace(joinQueryResult.CombineScript))
                        {
                            var joinResult = GetJoinCondition(query, joinEntry, parameters, objectName, joinObjectPetName);
                            if (!joinResult.WithScripts.IsNullOrEmpty())
                            {
                                withScripts.AddRange(joinResult.WithScripts);
                                recurveTableName    = joinResult.RecurveObjectName;
                                recurveTablePetName = joinResult.RecurvePetName;
                            }
                            var joinConnection = joinResult.ConditionString;
                            if (!string.IsNullOrWhiteSpace(joinQueryResult.ConditionString))
                            {
                                conditionBuilder.Append($"{(conditionBuilder.Length == 0 ? string.Empty : " AND ")}{joinQueryResult.ConditionString}");
                            }
                            if (!string.IsNullOrWhiteSpace(joinQueryResult.JoinExtraConditionString))
                            {
                                conditionBuilder.Append($"{(conditionBuilder.Length == 0 ? string.Empty : " AND ")}{joinQueryResult.JoinExtraConditionString}");
                            }
                            joinBuilder.Append($" {GetJoinOperator(joinEntry.Type)} {PostgreSqlManager.WrapKeyword(DataAccessContext.GetJoinEntityObjectName(joinEntry.JoinObjectFilter))} AS {joinObjectPetName}{joinConnection}");
                            if (joinEntry.JoinObjectExtraFilter != null)
                            {
                                var extraQueryResult = ExecuteTranslation(joinEntry.JoinObjectExtraFilter, QueryLocation.Join, parameters, joinObjectPetName, true);
                                if (!string.IsNullOrWhiteSpace(extraQueryResult.ConditionString))
                                {
                                    joinExtraCondition.Append(joinExtraCondition.Length > 0 ? $" AND {extraQueryResult.ConditionString}" : extraQueryResult.ConditionString);
                                }
                            }
                            if (joinQueryResult.AllowJoin && !string.IsNullOrWhiteSpace(joinQueryResult.JoinScript))
                            {
                                joinBuilder.Append($" {joinQueryResult.JoinScript}");
                            }
                        }
                        else
                        {
                            var combineJoinObjName = GetNewSubObjectPetName();
                            var joinResult         = GetJoinCondition(query, joinEntry, parameters, objectName, combineJoinObjName);
                            if (!joinResult.WithScripts.IsNullOrEmpty())
                            {
                                withScripts.AddRange(joinResult.WithScripts);
                                recurveTableName    = joinResult.RecurveObjectName;
                                recurveTablePetName = joinResult.RecurvePetName;
                            }
                            var joinConnection = joinResult.ConditionString;
                            joinBuilder.Append($" {GetJoinOperator(joinEntry.Type)} (SELECT {string.Join(",", PostgreSqlManager.FormatQueryFields(joinObjectPetName, joinEntry.JoinObjectFilter, joinEntry.JoinObjectFilter.GetEntityType(), false, false))} FROM {PostgreSqlManager.WrapKeyword(DataAccessContext.GetJoinEntityObjectName(joinEntry.JoinObjectFilter))} AS {joinObjectPetName} {(joinQueryResult.AllowJoin ? joinQueryResult.JoinScript : string.Empty)} {(string.IsNullOrWhiteSpace(joinQueryResult.ConditionString) ? string.Empty : "WHERE " + joinQueryResult.ConditionString)} {joinQueryResult.CombineScript}) AS {combineJoinObjName}{joinConnection}");
                        }
                        if (!joinQueryResult.WithScripts.IsNullOrEmpty())
                        {
                            withScripts.AddRange(joinQueryResult.WithScripts);
                            recurveTableName    = joinQueryResult.RecurveObjectName;
                            recurveTablePetName = joinQueryResult.RecurvePetName;
                        }
                    }
                }
                string joinScript = joinBuilder.ToString();

                #endregion

                #region recurve script

                string conditionString          = conditionBuilder.ToString();
                string joinExtraConditionString = joinExtraCondition.ToString();
                if (query.Recurve != null)
                {
                    allowJoin = false;
                    string nowConditionString = conditionString;
                    if (!string.IsNullOrWhiteSpace(joinExtraConditionString))
                    {
                        nowConditionString       = string.IsNullOrWhiteSpace(nowConditionString) ? joinExtraConditionString : $"{nowConditionString} AND {joinExtraConditionString}";
                        joinExtraConditionString = string.Empty;
                    }
                    EntityField recurveField         = DataManager.GetField(DatabaseServerType, query, query.Recurve.DataField);
                    EntityField recurveRelationField = DataManager.GetField(DatabaseServerType, query, query.Recurve.RelationField);
                    var         recurveTable         = GetNewRecurveTableName();
                    recurveTablePetName = recurveTable.Item1;
                    recurveTableName    = recurveTable.Item2;
                    conditionString     = $"{objectName}.{PostgreSqlManager.WrapKeyword(recurveField.FieldName)} IN (SELECT {recurveTablePetName}.{PostgreSqlManager.WrapKeyword(recurveField.FieldName)} FROM {recurveTableName} AS {recurveTablePetName})";
                    DataAccessContext.SetActivityQuery(query, location);
                    string queryObjectName = DataManager.GetEntityObjectName(DataAccessContext);
                    string withScript      =
                        $"{recurveTableName} AS (SELECT {objectName}.{PostgreSqlManager.WrapKeyword(recurveField.FieldName)},{objectName}.{PostgreSqlManager.WrapKeyword(recurveRelationField.FieldName)} FROM {PostgreSqlManager.WrapKeyword(queryObjectName)} AS {objectName} {joinScript} {(string.IsNullOrWhiteSpace(nowConditionString) ? string.Empty : $"WHERE {nowConditionString}")} " +
                        $"UNION ALL SELECT {objectName}.{PostgreSqlManager.WrapKeyword(recurveField.FieldName)},{objectName}.{PostgreSqlManager.WrapKeyword(recurveRelationField.FieldName)} FROM {PostgreSqlManager.WrapKeyword(queryObjectName)} AS {objectName} JOIN {recurveTableName} AS {recurveTablePetName} " +
                        $"ON {(query.Recurve.Direction == RecurveDirection.Up ? $"{objectName}.{PostgreSqlManager.WrapKeyword(recurveField.FieldName)}={recurveTablePetName}.{PostgreSqlManager.WrapKeyword(recurveRelationField.FieldName)}" : $"{objectName}.{PostgreSqlManager.WrapKeyword(recurveRelationField.FieldName)}={recurveTablePetName}.{PostgreSqlManager.WrapKeyword(recurveField.FieldName)}")})";