**Use case**
A friend wants to show me a set of queries, but is afraid to reveal the names of columns (domain area) and the values of constants.

**Describe the solution you'd like**
A simple ad-hoc solution that will be mostly acceptable.

Use Lexer to tokenize query and replace tokens. Use a list of english nouns or similar words for replacements. The user will specify a salt in command line to make deterministic pseudorandom unpredictable replacement.

Split identifiers to words according to their style (snake_case, CamelCase, ALL_CAPS). If identifier is too complex, treat it as a single word. These words will be replaced with english nouns selected by the value of a SipHash from the word and the salt. Save all replacements in a map to track collisions. In case of collision, add 1 to the salt and repeat to select another noun. Keep the style of replaced identifiers for convenience. Keep some words like `id`, `num`, `value` unreplaced.

For literals in a query: for numbers, dates, datetimes, apply a model similar to clickhouse-obfuscator. For string literals, keep punctuation charaters as is to keep the meaning of LIKE and regexp. Replace alphanumeric parts to a gibberish of similar length (maybe keeping alpha and numerics). Replace valid UTF-8 to another valid UTF-8 while keeping the number of leading zeros in bytes.

Keep the keywords in the query as is. (Lexer does not know about keywords, so we have to list them explicitly).
case Protocol::Server::Totals:
                continue;
            case Protocol::Server::Extremes:
                continue;
            case Protocol::Server::Log:
                continue;
            case Protocol::Server::Exception:
                packet.exception->rethrow();
                return;
            case Protocol::Server::EndOfStream:
                return;
            default:
                throw Exception(ErrorCodes::UNKNOWN_PACKET_FROM_SERVER, "Unknown packet {} from server {}",
                    packet.type, connection.getDescription());
        }
    }
}
void Suggest::fillWordsFromBlock(const Block & block)
{
    if (!block)
        return;
    if (block.columns() != 1)
        throw Exception("Wrong number of columns received for query to read words for suggestion", ErrorCodes::LOGICAL_ERROR);
    const ColumnString & column = typeid_cast<const ColumnString &>(*block.getByPosition(0).column);
    size_t rows = block.rows();
    for (size_t i = 0; i < rows; ++i)
        words.emplace_back(column.getDataAt(i).toString());
}
}