public function escapeIdentifier($input, bool $join = true)
    {
        if (is_array($input)) {
            $input = array_map([$this, 'escapeIdentifier'], array_filter($input));
            return $join ? join(', ', $input) : $input;
        } elseif ($input instanceof Sql) {
            return $input->toString();
        } elseif ($input instanceof Identifier) {
            $input = $input->toString();
        }

        if (!is_string($input)) {
            throw new AgentException(sprintf('String, array and Query\Sql,Identifier type identifiers'.
                ' accepted only, %s given!', gettype($input)));
        }

        $input = trim($input);
        if ($input == '' || $input == '*') {
            return $input;
        }

        // functions, parentheses etc are not allowed
        if (strpos($input, '(') !== false) {
            throw new AgentException('Found parentheses in input, complex identifiers not allowed!');
        }

        // trim all non-word characters
        $input = preg_replace('~^[^\w]|[^\w]$~', '', $input);
        if ($input == '') {
            return $input;
        }

        // multiple fields
        if (strpos($input, ',')) {
            return $this->escapeIdentifier(Util::split(',', $input), $join);
        }

        // aliases
        if (strpos($input, ' ')) {
            return preg_replace_callback('~([^\s]+)\s+(AS\s+)?(\w+)~i', function ($match) {
                return $this->escapeIdentifier($match[1]) . (
                    ($as = trim($match[2])) ? ' '. strtoupper($as) .' ' : ' '
                ) . $this->escapeIdentifier($match[3]);
            }, $input);
        }

        // dots
        if (strpos($input, '.')) {
            return implode('.', array_map([$this, 'escapeIdentifier'], explode('.', $input)));
        }

        return $this->quoteField($input);
    }